-
Notifications
You must be signed in to change notification settings - Fork 48
additions
Assigns to an existing variable without declaring a new one.
$ coco -bce 'a = 1; new -> a := 2; b = 3'
var a;
a = 1;
new function(){
var b;
a = 2;
b = 3;
};
$ coco -ce 'x := 0'
assignment to undeclared variable "x" on line 1
This is essential because (unlike CoffeeScript) our =
always declares the variable in current scope.
Normal compound assignments can be desugared using this operator: a += 1
<=> a := a + 1
ref. https://github.com/jashkenas/coffee-script/issues/712
Any assignment operator can be conditional when prefixed with &&
, ||
, ?
or !?
.
$ coco -bce 'a.b |||= c.d ?= e'
var ref$;
a.b || (a.b |= (ref$ = c.d) != null ? ref$ : c.d = e);
$ coco -bce '[x, y] &&= z'
var x, y;
x && (x = z[0]), y && (y = z[1]);
Compound assignments for unary operators.
$ coco -bcs
# syntax: UnaryOp+ AssignOp LHSExpression
+ = x # numberize
!! = x # enbool
-~-~ = x # intcasting bicrement
var x;
x = +x;
x = !!x;
x = -~-~x;
You can specify a default value to each function parameter or destructuring target, using one of logical operators (||
&&
?
!?
).
$ coco -bce '(o || {}) -> [@a ? b] = c'
(function(o){
var ref$;
o || (o = {});
return this.a = (ref$ = c[0]) != null ? ref$ : b, c;
});
- For parameters,
=
can be used in place of?
.
Performs destructuring into an object's properties.
$ coco -bcs
x[a, b] = y
x{a, b} = y
x[a] = y[0], x[b] = y[1];
x.a = y.a, x.b = y.b;
You can provide a name to a destructuring pattern, which will be used for the intermediate variable instead of a temporary one.
$ coco -bcs
([p, q]:a) ->
{{x}:b, [y]:c} = o # short for {b: {x}:b, c: [y]:c}
var b, x, c, y;
(function(a){
var p, q;
p = a[0], q = a[1];
});
b = o.b, x = b.x, c = o.c, y = c[0];
Performs assignment only when the right-hand-side value exists.
$ coco -bcs
[, left, rite]? = /(\w+)\s*=\s*(\w+)/exec input
({when, where}?) -> go where, when
var left, rite, ref$;
if ((ref$ = /(\w+)\s*=\s*(\w+)/.exec(input)) != null) {
left = ref$[1], rite = ref$[2];
}
References the left-hand-side of nearest assignment, letting you build your own compound assignments.
$ coco -bcs
document.querySelector('#wrapme').textContent = "(#<>)"
var ref$;
(ref$ = document.querySelector('#wrapme')).textContent = "(" + ref$.textContent + ")";
- Does not cross-scope. E.g.
f = -> <>
is invalid. - Stands for left reference.
Performs assignments and flags the declared variables as read-only. Redeclaration/reassignment on them will be a compile error.
$ coco -s
const a = 0
a++
SyntaxError: increment of constant "a" on line 2
Plain ol' var
without initialization and redeclaration.
$ coco -ps
var a, b
a is b is undefined
true
$ coco -e '(x) -> var x'
SyntaxError: redeclaration of "x" on line 1
Creates the same name property of target expression(s) on exports
or top-level this
.
$ coco -bcs
export a, b.c
export
d: e
function f then g
export const h = 1
var h, out$ = typeof exports != 'undefined' && exports || this;
out$.a = a;
out$.c = b.c;
out$.d = e;
out$.f = f;
function f(){
return g;
}
out$.h = h = 1;
- Named expressions (variable, dot-identifier access,
function
declaration,class
) are exported with those names. - All other expressions get all own properties exported.
In addition to identifiers, our dot operators accept many more things as their right operand. Numbers, strings, parentheses, brackets and braces.
$ coco -bce 'x.0."1".(2).[3]'
x[0]["1"][2][3];
Therefore we don't technically have the bracket notation for property access in {Java,Coffee}Script sense. o[x]
is just short for o.[x]
.
Compound assignments for .
.
$ coco -bce 'location.href.=replace /^http:/, \https:'
location.href = location.href.replace(/^http:/, 'https:');
$ coco -bce 'a.+=0'
a += a[0];
$ coco -bce '[b, c].=reverse()'
var b, c, ref$;
ref$ = [b, c].reverse(), b = ref$[0], c = ref$[1];
- Is at same precedence as
.
. - Consumes all dot/call chains to the right.
Retrieves an object's method as bound to the object.
$ coco -bce o.p.~m
bind$(o.p, 'm');
function bind$(obj, key){
return function(){ return obj[key].apply(obj, arguments) };
}
$ coco -ps
[2 5 9]map 42~toString
# desugars to: [2, 5, 9].map -> 42.toString.apply 42, arguments
[ '101010', '132', '46' ]
In other words, o.~m
sort of emulates o.m.bind(o)
in ES5.
Postfix brackets can take multiple arguments, in which case they collect retrieved values into an array.
$ coco -bce 'x[a, b]'
[x[a], x[b]];
object slice x{a, b: c}
_
Postfix curly braces extract the selected properties into a new object.
$ coco -bce 'x{a: b, c}'
({
a: x.b,
c: x.c
});
An asterisk within an indexer represents the length of the indexee.
$ coco -bce 'a[*] = b'
a[a.length] = b;
$ coco -bce 'arr()[* - 1]'
var ref$;
(ref$ = arr())[ref$.length - 1];
$ coco -bce '{(* >> 1): mid} = a'
var mid;
mid = a[a.length >> 1];
semiautovivification .@
.@@
Ensures that the property exists as an object or array. x.@y
desugars to (x.y ||= {})
.
$ coco -bcs
root.@obj.@@arr.push it
A@D@@I
var ref$;
((ref$ = root.obj || (root.obj = {})).arr || (ref$.arr = [])).push(it);
(ref$ = A.D || (A.D = {})).I || (ref$.I = []);
$ coco -se
setXYZ = (
point # target object to set the coordinates
point.x, point.y, point.z
) -> point
setXYZ {} 2 3 5
{ x: 2, y: 3, z: 5 }
Function parameters can be:
- written multi-line, using the same syntax as array items.
- any assignable expressions.
Declares or creates a named function, without touching the nasty JScript bug.
$ coco -bcs
# syntax: "function" Name? ParameterList? Block
function equal a, b
a is b
add = function (x, y)
x + y
~function bound then this
var add, this$ = this;
function equal(a, b){
return a === b;
}
add = (function(){
function add(x, y){
return x + y;
}
return add;
}());
function bound(){
return this$;
}
$ coco -s
function f
f = ->
SyntaxError: redeclaration of function "f" on line 2
- Parentheses around parameter list can be omitted in the same way that
f(a)
can bef a
. - Prefix
~
to bind parentthis
. - The declared variable is read-only.
Represents the first argument of the current function, like in Groovy's closure. Available only when no parameters are declared.
$ coco -bce 'I = -> it'
var I;
I = function(it){
return it;
};
A unary operator that calls a function with no arguments, helping you write less parentheses.
$ coco -bce 'do f; do ->'
f();
(function(){})();
Sugar for ()
.
$ coco -bce 'f! g?!'
f()(typeof g == 'function' ? g() : void 8);
IIFE sugars
Short for the JS idiom (function(c){...}.call(a, b))
.
$ coco -bcs
# syntax: "let" ThisAssignment? Assignments* Block
let (this = a, b = c)
'use strict'
assert @ is a
assert b is c
r = let # short for `let ()`
let c, @d # short for `let (c = c, d = @d)`
c + d
var r;
(function(b){
'use strict';
assert(this === a);
assert(b === c);
}.call(a, c));
r = (function(){
return (function(c, d){
return c + d;
}.call(this, c, this.d));
}.call(this));
Short for new ->
, saving precious three key strokes.
$ coco -bcs
point = new
@x = 9
@y = 6
var point;
point = new function(){
this.x = 9;
this.y = 6;
};
$ coco -se
# pseudo object comprehension
flip = (obj) -> new
@[v] = k for own k, v in obj
flip \flop
{ f: '0', l: '1', o: '2', p: '3' }
As in class
constructor, no implicit return is generated.
thisplat f(...)
_
Shorthand to delegate the current context to a function.
$ coco -bce 'f ...'
f.apply(this, arguments);
backcall <- f
_
Sugar for flattening nested callbacks.
$ coco -bcs
<~ f
e <- g this
return if e
( x
y
) <- h ..., z
var this$ = this;
f(function(){
return g(this$, function(e){
if (e) {
return;
}
return h(function(x, y){}, z);
});
});
- Can only appear on the top level of a block.
- Consumes all consecutive lines of that block as the function body.
-
<-
for plain,<~
for bound. -
...
can be used to specify the callback position when there are other arguments after it.
Negating a function literal or the callee of a backcall suppresses the implicit return
.
$ coco -bcs
setTimeout !->
!function say
console.log it
<-! setTimeout
say \yes
setTimeout(function(){
function say(it){
console.log(it);
}
setTimeout(function(){
say('yes');
});
});
Implicit calls don't cross spaced dots, allowing you to chain methods without parentheses.
$ coco -bcs
obj.foo x, y .bar z
.baz!
obj.foo(x, y).bar(z).baz();
Function literals within loops are defined outside.
$ coco -bcs
sums = for a of as
a.reduce (x, y) -> x + y
var a, sums, res$, i$, ref$, len$;
res$ = [];
for (i$ = 0, len$ = (ref$ = as).length; i$ < len$; ++i$) {
a = ref$[i$];
res$.push(a.reduce(fn$));
}
sums = res$;
function fn$(x, y){
return x + y;
}
do
with an indented block represents a pair of parenthesis (unless followed by while
/until
), either as grouping or calling.
$ coco -bcs
r = do
f do
a
b
g()
var r;
r = (f(a, b), g());
Our class
defines the constructor as a bare function and properties (prototype members) as bare objects, both on top level under the class block.
$ coco -bcs
class exports.C extends P
/* constructor */
-> super ...
/* properties */
member: 'U'
method: -> super @member, ..static()
/* any code */
$private = 42
@static = -> $private
var C;
exports.C = C = (function(superclass){
/* constructor */
C.displayName = 'C';
var $private, prototype = extend$(C, superclass).prototype, constructor = C;
function C(){
superclass.apply(this, arguments);
}
/* properties */
prototype.member = 'U';
prototype.method = function(){
return superclass.prototype.method.call(this, this.member, constructor['static']());
};
/* any code */;
$private = 42;
C['static'] = function(){
return $private;
};
return C;
}(P));
function extend$(sub, sup){
function fun(){} fun.prototype = (sub.superclass = sup).prototype;
(sub.prototype = new fun).constructor = sub;
if (typeof sup.extended == 'function') sup.extended(sub);
return sub;
}
In short,
class C extends P
-> /* constructor */
{'properties'}
...
desugars roughly to
C = let superclass = P
function C
/* constructor */
C.displayName = 'C'
C extends P
{prototype} = constructor = C
let this = C
prototype <<< {'properties'}
...
C
The constructor:
- receives
displayName
property, useful for debugging, reflection etc. - is accessible as
constructor
(or..
).
Using the wavy arrow ~>
for constructor makes the class to be new
-free, like native Array
which works with or without new
.
$ coco -bce 'Bound = class then (@name) ~>'
var Bound;
Bound = (function(){
Bound.displayName = 'Bound';
var prototype = Bound.prototype, constructor = Bound;
function Bound(name){
var this$ = this instanceof ctor$ ? this : new ctor$;
this$.name = name;
return this$;
} function ctor$(){} ctor$.prototype = prototype;
return Bound;
}());
This form allows the constructor to return non-object values.
Make sure to return this
when you're returning the instance early.
super
is an alias to superclass
or the nearest method (a function defined via top-level object under class
).
When a super
starts an access/call chain, the next call auto-passes current this
.
$ coco -bce 'super.classMethod!'
superclass.classMethod.call(this);
$ coco -bce 'super::anotherMethod!'
superclass.prototype.anotherMethod.call(this);
You can specify mixin objects to be merged into prototype
at the tail of class
line.
$ coco -bce 'class implements M, N then O'
(function(){
var prototype = constructor.prototype;
importAll$(prototype, arguments[0]);
importAll$(prototype, arguments[1]);
O;
function constructor(){}
return constructor;
}(M, N));
function importAll$(obj, src){
for (var key in src) obj[key] = src[key];
return obj;
}
A generic way to loop within certain numeric ranges.
$ coco -bce 'for i from x to y then'
var i, to$;
for (i = x, to$ = y; i <= to$; ++i) {}
$ coco -bce 'for i from x til y then'
var i, to$;
for (i = x, to$ = y; i < to$; ++i) {}
$ coco -bce 'for i from x to y by -1 then'
var i, to$;
for (i = x, to$ = y; i >= to$; --i) {}
$ coco -bce 'for i from x to y by z then'
var i, step$, to$;
for (i = x, to$ = y, step$ = z; step$ < 0 ? i >= to$ : i <= to$; i += step$) {}
$ coco -bce 'for i til x then'
var i, to$;
for (i = 0, to$ = x; i < to$; ++i) {}
-
to
for inclusive,til
for exclusive. -
by
optionally specifies the step value. -
from
clause is optional, implyingfrom 0
.
A tighter version of for
-then
-let
, keeping the loop variables local to the inner scope.
$ coco -s
n = 42
for let n to 2
process.on \exit -> console.log n
console.log n
42
0
1
2
postconditional _
The traditional do
-while
(or until
) loop.
$ coco -bcs
# syntax: "do" Block "while"|"until" Condition
do
do then
while x
until y
do {
do {} while (x);
} while (!y);
while
/until
accepts an update clause after test clause, enabling full emulation of JS for
wrt continue
.
$ coco -bcs
until ok(), step()
continue if hop()
jump()
for (; !ok(); step()) {
if (hop()) {
continue;
}
jump();
}
Preconditional loops can have an else
clause, which runs when the loop body didn't run.
$ coco -bce 'while f() then g() else h()'
var yet$;
for (yet$ = true; f();) {
yet$ = false;
g();
} if (yet$) {
h();
}
Sugar for while true
.
$ coco -bce 'continue for ever'
for (;;) {}
switch
(as in JS) with multiple conditions and auto break
insertions.
$ coco -bcs
switch n
case 1 then 2
case 3 4 then 5
case [6 7] then 8; fallthrough
default 9
switch
case a
break
case c[d, e]
f
switch (n) {
case 1:
2;
break;
case 3:
case 4:
5;
break;
case 6:
case 7:
8;
// fallthrough
default:
9;
}
switch (false) {
case !a:
break;
case !(c[d] || c[e]):
f;
}
Basically the same as CoffeeScript's switch-when-else, except ours:
- requires less indentation.
-
case
/default
are placed at the same level asswitch
.
-
- supports falling through.
- If the last expression of
case
block isfallthrough
, it becomes a comment instead ofbreak
.
- If the last expression of
- expands arrays in
case
conditions.
Incidentally this is pretty similar to Go's switch
.
case
can be omitted. This form is handy for refactoring nested if
s, e.g.:
unless a()
b()
unless c()
d()
↓
switch
break if a()
b()
break if c()
d()
$ coco -bce 'try x catch throw e'
var e;
try {
x;
} catch (e$) {
e = e$;
throw e;
}
$ coco -pe 'try throw 0 catch'
0
The catchee:
- can be omitted and defaults to
e
. - is function-scoped. See coffee#2422.
- is returned when the body is empty.
Each that
in those blocks implicitly refers to the condition value.
$ coco -bcs
that if a
that while b?
switch c case d then that
switch case e then that
var that;
if (that = a) {
that;
}
while ((that = b) != null) {
that;
}
switch (that = c) {
case d:
that;
}
switch (false) {
case !(that = e):
that;
}
An alternative syntax for chained if
-else
s, reminiscent of Arc's if, Clojure's cond etc.
$ coco -bcs
# syntax: IF INDENT (Condition Block)+ (ELSE Block)? DEDENT
r = if
a
b
c then d
else
e
var r;
r = a
? b
: c ? d : e;
$ coco -bce ':label block or expression'
label: {
block || expression;
}
$ coco -se
:pythagoras for a from 1 to 9
for b from a to 99
h = Math.sqrt a*a + b*b
if h % 1 == 0
console.log a, b, h
continue pythagoras
:plain
\end
break plain
\unreachable
3 4 5
5 12 13
6 8 10
7 24 25
8 15 17
9 12 15
end
The syntax is backward from JS to disambiguate from the implicit object literal.
Labeling a function (literal, IIFE sugar, or backcall) gives it a name instead of creating a useless block.
$ coco -bcs
:f ->
:g let
<-:h f
(function f(){
return (function g(){
return f(function h(){});
}.call(this));
});
Infix operators that copy enumerable properties from the right operand to left, and return the left value.
$ coco -bce 'x <<< y <<<< z'
import$(importAll$(x, y), z);
function importAll$(obj, src){
for (var key in src) obj[key] = src[key];
return obj;
}
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
$ coco -bce 'import {y, (z)}'
this.y = y;
this[z] = z;
-
<<<
is for own properties. It gets optimized to a series of assignments if the right operand is an object literal. -
import
andimport all
are available as aliases.
Copies properties from target object(s) into current this
.
$ coco -bcs
import a, b
import all c
import
f: g
h: i
import$(this, a);
import$(this, b);
importAll$(this, c);
this.f = g;
this.h = i;
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
function importAll$(obj, src){
for (var key in src) obj[key] = src[key];
return obj;
}
Unary ^
creates a prototypal child of the operand.
$ coco -pe '[c = ^(p = {0}); c.0; c.hasOwnProperty 0; p.isPrototypeOf c]'
[ {}, 0, false, true ]
$ coco -bce 'child = ^parent'
var child;
child = clone$(parent);
function clone$(it){
function fun(){} fun.prototype = it;
return new fun;
}
A bare array to the right of instanceof
is expanded into or
chains.
$ coco -bce 'o instanceof [C, K]'
o instanceof C || o instanceof K;
If used in an expression, delete
returns the original value as opposed to the useless
JS behavior.
$ coco -bce 'f delete @x; delete @y'
var ref$;
f((ref$ = this.x, delete this.x, ref$));
delete this.y;
The counterpart of ?
.
$ coco -bce '@a !?= b !? c.d!?'
this.a != null && (this.a = typeof b == 'undefined' || b === null
? b
: c.d == null);
$ coco -bce '@x **= y ** z'
this.x = Math.pow(this.x, Math.pow(y, z));
The precedence and associativity are set to the same as *
//
, not to complicate the hierarchy further.
Binary operators that return the lesser/greater value of the two.
$ coco -bce 'r = a <? b; @c >?= d'
var r;
r = a < b ? a : b;
this.c >= d || (this.c = d);
$ coco -pe '4 >? 3 + 2'
5
- Precedence is same as
<<
.
Unary operators affect each item when applied to an array literal.
$ coco -bcs
@inverts = ~[a, b]
++player<[str def]>
this.inverts = [~a, ~b];
++player['str'], ++player['def'];
Introduces a block, setting the indentation level to the start of the next token.
$ coco -bcs
if a => b
c
if (a) {
b;
c;
}
When the left operand of *
is a (syntactically obvious) string/array, it is repeated [right operand] times.
$ coco -bcs
[1] * 2
'x' * 3
'z' * y
[1, 1];
'xxx';
repeatString$('z', y);
function repeatString$(str, n){
for (var r = ''; n > 0; (n >>= 1) && (str += str)) if (n & 1) r += str;
return r;
}
The helper function (generated when the right operand is large or non-constant) uses O(logN) algorithm, making "#x" * y
more efficient than the idiom Array(-~y).join('x')
.
When the right operand of *
is a string literal, [].join
is called on the left.
$ coco -bce 'a * "-"'
var join$ = [].join;
join$.call(a, "-");
When the right operand of -
//
is a string/regex literal, ''.replace
/''.split
is called on the left.
$ coco -bce 'x - /r/; y / "s"'
var replace$ = ''.replace, split$ = ''.split;
replace$.call(x, /r/, '');
split$.call(y, "s");
$ coco -pe '({} - /\w/g) / " "'
[ '[', ']' ]
Hyphened alphabets are allowed within an identifier in place of their upper case representations.
$ coco -bce 'is-array'
isArray;
$ coco -pe 'Array.is-array []'
true
A literal that compiles to an undefined
value.
$ coco -bcs
void
(void, a) -> void
[,,]
(function(arg$, a){});
[void 8, void 8];
- Simply ignored when on top-level or
return
ed. - Works as a placeholder within function parameters or destructuring assignment.
- Implied when
,
follows(
,[
, or another,
.
Simple strings without whitespace can be written by prefixing a backslash rather than enclosing with single quotes.
$ coco -bce '\\ + \" + \word + \"'
'\\' + '"' + 'word' + '"';
Note that closing symbols ()
]
}
,
;
) are disallowed after the first character, so that you can naturally write:
prompt(\?, \!)
- Syntax borrowed from Clojure's character literal.
Sugar for a bracketted list of strings, either as an array or indexer.
$ coco -bce 'f <[ array of strings ]>'
f(["array", "of", "strings"]);
$ coco -bce 'o<[ property names ]>'
[o['property'], o['names']];
Property names within object literals can be dynamically set using parentheses or interpolated strings.
$ coco -bce 'o = {(paren): 1, "str#ing": 2, (shorthand = 3)}'
var shorthand, o, ref$, ref2$;
o = (ref$ = {}, ref$[paren] = 1, ref$["str" + ing] = 2, ref$[ref2$ = shorthand = 3] = ref2$, ref$);
Mixes an object's own properties into the created object.
$ coco -bcs
poq = {p, ...o, q}
abc =
a: true
...: b
...: c
var poq, abc, ref$;
poq = (ref$ = {
p: p
}, import$(ref$, o), ref$.q = q, ref$);
abc = (ref$ = {
a: true
}, import$(ref$, b), import$(ref$, c));
function import$(obj, src){
var own = {}.hasOwnProperty;
for (var key in src) if (own.call(src, key)) obj[key] = src[key];
return obj;
}
$ coco -bce '{+x, -y}'
({
x: true,
y: false
});
ref. https://github.com/jashkenas/coffee-script/issues/885
$ coco -bcs
a:~ (@a) -> # setter if the function has one argument
b:~ -> @b # getter if none
c:~ # indent and line them up to define both
-> @c
(@c) ->
# uses `Object.defineProperty` when imported
import x:~ ->
({
set a(a){
this.a = a;
},
get b(){
return this.b;
},
get c(){
return this.c;
},
set c(c){
this.c = c;
}
});
Object.defineProperty(this, 'x', {
get: function(){},
configurable: true,
enumerable: true
});
implicit array a = then b; c
_
Some operators (:
=
:=
<<<
<<<<
return
throw
!
~
delete
typeof
) can take a block on the right, which becomes an array when it contains multiple items.
$ coco -bcs
list =
1
2
atom =
3
var list, atom;
list = [1, 2];
atom = 3;
Leading star denotes an expression or array of expressions (thanks to implicit array).
$ coco -bcs
points =
* x:0 y:1
* x:2 y:3
var points;
points = [
{
x: 0,
y: 1
}, {
x: 2,
y: 3
}
];
$ coco -se
* * 0 1
* 2
[ [ 0, 1 ], 2 ]
This is simply an alias to [] = =>
(empty assignment taking a block arrow). The last example is same as writing:
[] =
[] =
0, 1
[] =
2
Borrowing from Smalltalk, numbers can have any base between 2 to 36 in the form RRrXXX.
$ coco -bce '[2r101010, 8r52, 36r16]'
[42, 42, 42];
Underscores within numbers, and alphabets after decimals are ignored.
$ coco -pe '[0xDead_Beef 7_heads]'
[ 3735928559, 7 ]
Expands to comma separated characters or numbers.
$ coco -bce
# syntax: CharOrNum ("to"|"til") CharOrNum ("by" Num)?
[\A to \C]
{98 to 97}
f -3 til 4 by 2
["A", "B", "C"];
({
98: 98,
97: 97
});
f(-3, -1, 1, 3);
$ coco -bcs
//
heregex
#{ y } # normal interpolation
#{ z } # sets the flag part
//?
RegExp('heregex' + y, z);
Same as .source
, but on compile time. Useful for building large regexes piece by piece.
$ coco -bce '/\\/$; //\b#word\b//$'
'\\\\';
'\\b' + word + '\\b';
$ coco -bce '@@0 @@'
arguments[0](arguments);
Read: @rgument @rray
constructor shorthand ..
_
$ coco -bce '@..classMethod ..'
this.constructor.classMethod(constructor);
...
in an array desugars to ...[]
, which can be used to force implicit array or ignore intermediate items in destructuring.
$ coco -bcs
empty =
...
[first, ..., last] = array
var empty, first, last;
empty = [];
first = array[0], last = array[array.length - 1];
Variables can be interpolated brace-free.
$ coco -bce '"(#id)"'
"(" + id + ")";
- Includes special variables, namely
this
,@
,&
, and<>
.
Prefixing %
to an interpolated string gives you the raw parts as array.
$ coco -bce '%"#x #y"'
[x, " ", y];
Commas after non-callable literals can be omitted when spaced.
$ coco -bce '[null true 1 "2" [3] ->]'
[null, true, 1, "2", [3], function(){}];
automatic dot insertion @0\!
_
Dots before {number,string,identifier}s can be omitted unless spaced.
$ coco -bce '@1"!"l'
this[1]["!"].l;
Similarly:
-
?
becomes?.
if surrounded without space.-
a?b
=>a?.b
-
c?=b
=>c?.=d
-
-
~
,@
and@@
become.~
/.@
/.@@
when they follow previous token without space.
\
cancels subsequent whitespaces a la Perl6.
$ coco -bcs
o\ p # triggers ADI
f \
x # continues line and triggers implicit call
o.p;
f(x);
yada yada yada ...
Short for throw Error('unimplemented')
on top level.
$ coco -e ...
Error: unimplemented
Works just as JS with no propagation to compilation.
$ coco -bce 'f /* implicit call */ x'
f(x);
Special variable available in following constructions.
Binary operator that sets &
to the left operand, then returns right.
$ coco -bce 'f x |> & + & |> g &'
var x$;
x$ = f(x);
x$ = x$ + x$;
g(x$);
- Closes implicit call.
- Has the lowest precedence, even lower than post-
if
etc.
Iterates over array-like target setting &
to each value.
$ coco -pe 'for process.argv => ~&' 1 2
Sets &
to target, runs block, then returns the target value.
$ coco -bcs
# syntax: "with" Expression Block
xhr = with new XMLHttpRequest
&open \GET \data
&send null
var xhr, x$;
xhr = (x$ = new XMLHttpRequest, x$.open('GET', 'data'), x$.send(null), x$);
- Analogue to Common Lisp's anaphoric-prog1, Ruby's Object#tap, Io's Object do, etc.
The with
keyword is optional on top level. This form requires at least one &
within the block.
$ coco -bcs
document.createElement \button
&textContent = 'Run'
&style
&border-width = '3px'
&font-weight = 'bold'
var x$, y$;
x$ = document.createElement('button');
x$.textContent = 'Run';
y$ = x$.style;
y$.borderWidth = '3px';
y$.fontWeight = 'bold';
$ coco -e 'a => b'
SyntaxError: unreferred cascadee on line 1
$ coco ast
Failed at: ast.co
ReferenceError: typo is not defined
at Object.<anonymous> (/usr/tmp/ast.co:248:1)
244| }
245| }
246| return fromJSON;
247| }());
248+ typo;
249| Negatable = {
250| show: function(){
251| return this.negated && '!';
252| },
at Module._compile (module.js:402:26)
at Object.run (/usr/local/lib/coco/lib/node.js:19:19)
at compileScript (/usr/local/lib/coco/lib/command.js:172:14)
at /usr/local/lib/coco/lib/command.js:130:18
at /usr/local/lib/coco/lib/command.js:103:12
at [object Object].<anonymous> (fs.js:107:5)
at [object Object].emit (events.js:61:17)
at afterRead (fs.js:878:12)
at wrapper (fs.js:245:17)
$ coco -icb
coco -cb> document.body
......... &style.color = \purple
......... &textContent = \rose
var x$;
x$ = document.body;
x$.style.color = 'purple';
x$.textContent = 'rose';
coco -cb>
--json
modifies the behavior of --ast
and --compile
.
$ coco -aje 3
{
"type": "Block",
"lines": [
{
"type": "Literal",
"value": "3",
"line": 1
}
]
}
$ coco -cje '{6 9}'
{
"6": 6,
"9": 9
}
-
-aj
: Serializes the AST in JSON. -
-cj
: Evaluates input, then prints the result in JSON.