This project has a few main goals
-
Read/Write less code.
-
Generate code that looks hand-written, so it is easy to work on even without the original input.
-
Stay a superset of standard ES5 JavaScript, with a few mostly non-intrusive breaks.
To get a first glimpse of output, try running tersejs examples.tjs
in this repository.
Currently only runs on linux 64bit. Other platforms should work, if you manage to compile indentation_to_braces.hs
and put it in bin
.
-
Indentation sensitivity: Each level of indentation gets transformed into a block between
{
}
-
Easier object creation, based on lexical scoping rather than hacking classes into javascript.
-
Anonymous functions - Courtesy of lambda_chop macros
-
Piping
-
Constructs for reducing line noise and allow minimum use of parentheses.
bin/tersejs [-o outFile -s <sweet.js options>] infile
If no output file is specified with -o
, result is printed to stdout.
// Object/module definition
// @ is just shorthand for 'self', which is an object returned by the end of a @@-block
// @foo and self.foo are equivalent and both can be used
module Foo
constructor start
c = start;// lexically scoped within Foo. var keyword not needed
@printOnInc = true; // Object property, equivalent to self.printOnInc
endvars // Finish variable declarations
// Lexically scoped function within Foo
private reset
c = 0
// Public method of Foo
public next
++c // can access local variable within Foo
if @printOnInc
console.log! c
if c > 10
reset!
endmodule
var f = makeFoo! 2; // Create foo with start=2
f.next!; // prints 3
f.printOnInc=false
f.next!; // nothing
f.printOnInc=true
f.next!; // prints 5
// Pipes
10 >> triple >> console.log; // console.log(triple(10))
// Reverse pipe, function application
// This just surrounds everything that follows in parens
foo | bar | 10, baz | 30; // foo(bar(10, baz(30)));
// Lift-Execute
// Applies each tuple to a given function
foo <-
1,2
3,4
//Output:
//foo(1,2);
//foo(3,4);
//Function invocation (call with no arguments)
foo!; // foo();
//Object cascading
foo.bar..
.num = .memFoo!; // foo.bar.num = foo.bar.memFoo();
var posX = .pos.x; // var x = foo.bar.pos.x;
//Property copying
foo.bar{a b c} := bab.zoo; // Assigns properties a,b and c from bab.zoo to foo.bar
// Output:
//foo.bar.a = bab.zoo.a;
//foo.bar.b = bab.zoo.b;
//foo.bar.c = bab.zoo.c;
// Partial application
var bar = foo~42; // bar = function(b,c){ return foo(42, b, c); }
// Named functions
fn foo a b
console.log| 'Foo with a='+a+' b='+b;
//Function names can be object properties
fn foo.bar x
console.log("I am foo.bar with value "+x);
// Anonymous functions
var f = λ x y
return x + y; // function(x,y){return x+y;}/
//use arrow for automatic return
var f = λ x y -> x+y
//lam is a synonym for λ, this also works
var triple = lam x -> x*3;
// Curry by wrapping arguments in parens
var always = λ(x y) -> x
always(42)(12) === 42;
// Placeholders using square brackets and `#`. Automatic return
var str = λ[#.toString()];
var sub = λ[# - #];
sub(2, 1) === 1;
// Shorthand property lambdas
var names = arr.map| λ.name;
//do-block, wraps block in (function(){}())
var someGlobalState;
do
var tmp = 41;
var tmp2 = tmp+1;
someGlobalState.update| tmp2;
// tmp and tmp2 not in scope outside of do-block
// Bound functions.
// => arrow makes sure the anonymous function is bound to the current 'this'-value
this.num = 42;
DB.getResource| 'important_thing', λ resp =>
console.log| "DB responded with "+resp;
console.log| this.num+" is still 42";
-
natefaubion for writing lambda_chop, and helping me a lot in learning sweet.js.