satyr/coco

Assignment

nondeclaring assignment :=

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

conditional assignments && +=

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]);  unary assignments ! = x 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;


assignment defaults (o || {}) ->[a ? b] = c

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 ?.

subdestructuring x[a, b] = yx{a, b} = y

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;  named destructuring ({p, q}:o) -> 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];


soak assign a? = b

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]; }  lef <> 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. explicit variable declarations constant const x = 0 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


uninitialized var x

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


exporting export x, y

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. Property Access dot X 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].

accessignment .=.+=

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. binding access .~ 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. array slice x[a, b] 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 });  length star [*] 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 = []);  Function extended parameters $ 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.

function declaration function f(a, b) then

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;
}
return x + y;
}
}());
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 be f a.
• Prefix ~ to bind parent this.
• The declared variable is read-only.

implicit argument it

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; };  do-call do f A unary operator that calls a function with no arguments, helping you write less parentheses. $ coco -bce 'do f; do ->'
f();
(function(){})();


bang-call f!

Sugar for ().

$coco -bce 'f! g?!' f()(typeof g == 'function' ? g() : void 8);  IIFE sugars with arguments let this = a, b = c then ... 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));


with new context new then ...

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.

hushing auto-return !(a) ->a <-! f

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'); }); });  paren-free method chains o.f x, y .g z 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();


don't make functions within a loop

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;
}


Construction

do-block do then

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());  simple class 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 ..). bound constructor 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. simple super 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);  mixins implements M, N 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; }  loop in range forfromtotilby 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, implying from 0.

scoped

for-let

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);


with update clause while i < l, ++i

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(); }  with else clause while f() then g() else h() 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();
}


forever for ever

Sugar for while true.

$coco -bce 'continue for ever' for (;;) {}  switching switchcasedefault 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 as switch.
• supports falling through.
• If the last expression of case block is fallthrough, it becomes a comment instead of break.
• 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 ifs, e.g.:

unless a()
b()
unless c()
d()


switch
break if a()
b()
break if c()
d()


auto-catch

$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.

anaphoric if/while/switch-case that

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; }  cond if => a then b else c An alternative syntax for chained if-elses, 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;


labels :label

$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)); });  Operator property copy <<<<<<< 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 and import all are available as aliases. importing import a, b 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; }  clone ^o 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; }  any-instanceof o instanceof [C, K] 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;


pluck v = delete o.p

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;


inexistence !?

The counterpart of ?.

$coco -bce '@a !?= b !? c.d!?' this.a != null && (this.a = typeof b == 'undefined' || b === null ? b : c.d == null);  pow ** $ 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.

min/max <?>?

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 spread +[a, b]

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'];  block arrow => Introduces a block, setting the indentation level to the start of the next token. $ coco -bcs
if a => b
c

if (a) {
b;
c;
}


string/array repetition 'x' * y

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'). array joining a * '-' When the right operand of * is a string literal, [].join is called on the left. $ coco -bce 'a * "-"'
var join$= [].join; join$.call(a, "-");


string subtraction/division x - /r/y / 's'

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) / " "'
[ '[', ']' ]


Literal

hyphened identifiers is-array

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


undefined/no-op literal void

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 returned.
• Works as a placeholder within function parameters or destructuring assignment.
• Implied when , follows (, [, or another ,.

word literal \plus\+

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. quoted words <[ q w ]> 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']];  dynakey {(a+b): c}{"#key": val} 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$);  object splat {...o} 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 });  accessor properties x:~ -> $ 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.

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  numbers with variable radix 25rCoco Borrowing from Smalltalk, numbers can have any base between 2 to 36 in the form RRrXXX. $ coco -bce '[2r101010, 8r52, 36r16]'
[42, 42, 42];


number comment 42_000_ms

Underscores within numbers, and alphabets after decimals are ignored.

$coco -pe '[0xDead_Beef 7_heads]' [ 3735928559, 7 ]  character/number ranges \A to \C1 til 10 by 2 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);  regex string /\\/$

Same as .source, but on compile time. Useful for building large regexes piece by piece.

$coco -bce '/\\/$; //\b#word\b//$' '\\\\'; '\\b' + word + '\\b';  arguments shorthand @@ $ coco -bce '@@0 @@'
arguments[0](arguments);


$coco -bce '@..classMethod ..' this.constructor.classMethod(constructor);  empty splat [...] ... 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];


variable interpolation "#x"

Variables can be interpolated brace-free.

$coco -bce '"(#id)"' "(" + id + ")";  • Includes special variables, namely this, @, &, and <>. unjoined interpolation %"#x #y" Prefixing % to an interpolated string gives you the raw parts as array. $ coco -bce '%"#x #y"'
[x, " ", y];


Miscellaneous

automatic comma insertion [0 1]

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.

unspacing o\ p

\ 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


inline block comment f /* */ x

Works just as JS with no propagation to compilation.

$coco -bce 'f /* implicit call */ x' f(x);  Reference & Special variable available in following constructions. pipe |> 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.

map for xs => ...

Iterates over array-like target setting & to each value.

$coco -pe 'for process.argv => ~&' 1 2  tap with x => ... 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. cascade o => &p 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  CLI compiled code in stack trace $ 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 wrapper (fs.js:245:17)


interactive compilation

$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 output --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.