diff --git a/README.md b/README.md index 25e2ddf7..64179da3 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ ColaScript is a language that compiles in JavaScript. This language is similar t ..info += ", student"; -- `a > b > c` +- `a > b > c`, status: done if( 0 < x < 100 ) console.log("x E (0; 100)"); @@ -112,18 +112,6 @@ ColaScript is a language that compiles in JavaScript. This language is similar t case 35: 'hot'; }; -- `with` scoping, status: it need?? - - with(document.body.querySelectorAll('ul').childNodes){ - var txt = 'text'; - - forEach((li){ - li.innerHTML = txt; - }); - } - - console.log(txt); // undefined - ## Vars - declaration with type, status: done, only declaration @@ -133,10 +121,10 @@ ColaScript is a language that compiles in JavaScript. This language is similar t Object obj = {}; String str = ""; -- multiple assignment +- multiple assignment, status: done [a, b, c] = [b, c, a]; - {poet: {String name, address: [street, city]}} = futurists; + var {poet: {String name, address: [street, city]}} = futurists; [a, ..., b] = someArray; @@ -325,5 +313,5 @@ ColaScript is a language that compiles in JavaScript. This language is similar t ### Statistic -- 34 features ( without classes ) -- 27 done +- 33 features ( without classes ) +- 29 done diff --git a/lib/ast.js b/lib/ast.js index af5f0475..eed6b658 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -398,7 +398,7 @@ Cola.AST_Namedarg = Cola.DEFNODE("Namedarg", "start end name value", { } }, Cola.AST_SymbolRef); -Cola.AST_Defarg = Cola.DEFNODE("Defarg", "start end name type argtype defval", { +Cola.AST_ArgDef = Cola.DEFNODE("ArgDef", "start end name type argtype defval", { $documentation: "A function argument expression", $propdoc: { type: "Data type", @@ -563,7 +563,7 @@ Cola.AST_Const = Cola.DEFNODE("Const", null, { $documentation: "A `const` statement" }, Cola.AST_Definitions); -Cola.AST_VarDef = Cola.DEFNODE("VarDef", "name value", { +Cola.AST_VarDef = Cola.DEFNODE("VarDef", "name value type", { $documentation: "A variable declaration; only appears in a AST_Definitions node", $propdoc: { name: "[AST_SymbolVar|AST_SymbolConst] name of the variable", @@ -759,7 +759,7 @@ Cola.AST_Assign = Cola.DEFNODE("Assign", null, { /* -----[ LITERALS ]----- */ -Cola.AST_Array = Cola.DEFNODE("Array", "elements", { +Cola.AST_Array = Cola.DEFNODE("Array", "elements template vardef", { $documentation: "An array literal", $propdoc: { elements: "[AST_Node*] array of elements" @@ -773,7 +773,11 @@ Cola.AST_Array = Cola.DEFNODE("Array", "elements", { } }); -Cola.AST_ArrayRange = Cola.DEFNODE("ArrayRange", "from to", { +Cola.AST_ArrayTemplate = Cola.DEFNODE("ArrayTemplate", null, { + $documentation: "Array assignment template.", +}, Cola.AST_Array); + +Cola.AST_ArrayRange = Cola.DEFNODE("ArrayRange", "from to triple", { $documentation: "An array range.", $propdoc: { from: "[AST_Node] range from", @@ -787,7 +791,7 @@ Cola.AST_ArrayRange = Cola.DEFNODE("ArrayRange", "from to", { } }); -Cola.AST_Object = Cola.DEFNODE("Object", "properties", { +Cola.AST_Object = Cola.DEFNODE("Object", "properties template vardef", { $documentation: "An object literal", $propdoc: { properties: "[AST_ObjectProperty*] array of properties" @@ -801,7 +805,11 @@ Cola.AST_Object = Cola.DEFNODE("Object", "properties", { } }); -Cola.AST_ObjectProperty = Cola.DEFNODE("ObjectProperty", "key value", { +Cola.AST_ObjectTemplate = Cola.DEFNODE("ObjectTemplate", null, { + $documentation: "Object assignment template.", +}, Cola.AST_Object); + +Cola.AST_ObjectProperty = Cola.DEFNODE("ObjectProperty", "key value type", { $documentation: "Base class for literal object properties", $propdoc: { key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.", diff --git a/lib/parse.js b/lib/parse.js index 3b2d370c..db9d7e89 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -140,6 +140,8 @@ Cola.OPERATORS.push('void'); Cola.OPERATORS = Cola.makePredicate(Cola.OPERATORS); +Cola.COMPARISON = Cola.makePredicate("< > <= >= == === != !=="); + Cola.WHITESPACE_CHARS = Cola.makePredicate(Cola.characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); Cola.PUNC_BEFORE_EXPRESSION = Cola.makePredicate(Cola.characters("[{(,.;:")); @@ -256,7 +258,8 @@ Cola.Tokenizer = function ($TEXT, filename, is_js, html5_comments) { regex_allowed : false, comments_before : [] }; - this.dumps = {}; + this.dumps = []; + this.dumpi = -1; if(!is_js) this.S.string = { at : [ new Cola.Tokenizer.StringInfo() ], @@ -301,11 +304,13 @@ Cola.Tokenizer.with_eof_error = function (eof_error, cont) { }; Cola.Tokenizer.prototype.dumpS = function () { - this.dumps = Cola.clone(this.S); + this.dumps[++this.dumpi] = Cola.clone(this.S); }; Cola.Tokenizer.prototype.restoreS = function () { - this.S = this.dumps; + if(this.dumpi == -1) return; + this.S = this.dumps[this.dumpi]; + delete this.dumps[this.dumpi--]; }; Cola.Tokenizer.prototype.peek = function (offset) { return this.S.text.charAt(this.S.pos + (offset ? offset : 0)); }; @@ -791,11 +796,10 @@ Cola.cPRECEDENCE = Cola.mergeTokens( ["^"], ["&"], ["==", "===", "!=", "!=="], - ["<", ">", "<=", ">=", "in", "instanceof"], + ["<", ">", "<=", ">=", "in", "instanceof", "is", "isnt"], [">>", "<<", ">>>"], ["+", "-"], - ["*", "/", "%"], - ["is", "isnt", "**", "%%"] + ["*", "/", "%", "**", "%%"] ], {} ); @@ -837,7 +841,8 @@ Cola.Parser = function ($TEXT, options) { }; this.S.input.context = function(){ return _this.tokenizer.context() }; this.S.token = this.next(); - this.dumps = {}; + this.dumps = []; + this.dumpi = -1; if(this.is_js){ this.UNARY_PREFIX = Cola.UNARY_PREFIX; @@ -877,13 +882,15 @@ Cola.Parser.prototype.parse = function () { }; Cola.Parser.prototype.dumpS = function () { - this.dumps = Cola.clone(this.S); + this.dumps[++this.dumpi] = Cola.clone(this.S); this.tokenizer.dumpS(); }; Cola.Parser.prototype.restoreS = function () { + if(this.dumpi == -1) return; this.tokenizer.restoreS(); - this.S = this.dumps; + this.S = this.dumps[this.dumpi]; + delete this.dumps[this.dumpi--]; }; Cola.Parser.prototype.next_until = function (until) { @@ -900,6 +907,10 @@ Cola.Parser.prototype.is = function (type, value) { Cola.Parser.prototype.peek = function () { return this.S.peeked || (this.S.peeked = this.S.input()); }; +Cola.Parser.prototype.next_is = function (type, value) { + return Cola.is_token(this.peek(), type, value); +}; + Cola.Parser.prototype.next = function () { this.S.prev = this.S.token; if (this.S.peeked) { @@ -968,7 +979,7 @@ Cola.Parser.prototype.parenthesised = function () { Cola.Parser.embed_tokens = function (parser) { return function() { var start = this.S.token; - var expr = parser.call(this); + var expr = parser.apply(this, arguments); var end = this.prev(); expr.start = start; expr.end = end; @@ -1000,9 +1011,9 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { return this.simple_statement(); case "name": - if(!this.is_js && Cola.is_token(this.peek(), "name")){ + if(!this.is_js && this.next_is("name")){ type = this.S.token.value, this.next(); - if(Cola.is_token(this.peek(), "punc", "(")) return this.function_(Cola.AST_Defun, type); + if(this.next_is("punc", "(")) return this.function_(Cola.AST_Defun, type); return tmp = this.var_(false, type), this.semicolon(), tmp; } @@ -1026,18 +1037,31 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { if(isfun) return this.function_(Cola.AST_Defun); } - return Cola.is_token(this.peek(), "punc", ":") + return this.next_is("punc", ":") ? this.labeled_statement() : this.simple_statement(); case "punc": switch (this.S.token.value) { case "{": + this.dumpS(); + var balance = 0, is_object = false; + this.next_until(function(){ + if(_this.is('punc', '{')) balance++; + else if(_this.is('punc', '}')) balance--; + + return balance == 0 || _this.is('eof'); + }); + is_object = this.next_is("operator"); + this.restoreS(); + + if (is_object) return this.simple_statement(); return new Cola.AST_BlockStatement({ start : this.S.token, body : this.block_(), end : this.prev() }); + case "[": case "(": return this.simple_statement(); @@ -1241,7 +1265,7 @@ Cola.Parser.prototype.as_funcarg = function(splatedexist) { } } - return new Cola.AST_Defarg({ + return new Cola.AST_ArgDef({ name : name, type : argtype == "splated" ? "Array" : type == name ? "dynamic" : type.name, argtype : argtype, @@ -1392,13 +1416,20 @@ Cola.Parser.prototype.try_ = function () { }); }; -Cola.Parser.prototype.vardefs = function (no_in, in_const) { - var a = []; +Cola.Parser.prototype.vardefs = function (no_in, in_const, type) { + var a = [], was_template = false; for (;;) { + was_template = false; a.push(new Cola.AST_VarDef({ start : this.S.token, - name : this.as_symbol(in_const ? Cola.AST_SymbolConst : Cola.AST_SymbolVar), - value : this.is("operator", "=") ? (this.next(), this.expression(false, no_in)) : null, + type : type, + name : (function(_this){ + was_template = !_this.is_js && ( _this.is("punc","[") || _this.is("punc","{") ); + if (!_this.is_js && _this.is("punc","[")) return _this.array_(true, true); + if (!_this.is_js && _this.is("punc","{")) return _this.object_(true, true); + return _this.as_symbol(in_const ? Cola.AST_SymbolConst : Cola.AST_SymbolVar); + })(this), + value : this.is("operator", "=") ? (this.next(), this.expression(false, no_in)) : ( was_template ? this.expect_token("operator","=") : null ), end : this.prev() })); if (!this.is("punc", ",")) @@ -1412,7 +1443,7 @@ Cola.Parser.prototype.var_ = function(no_in, type) { !type && (type = "dynamic"); return new Cola.AST_Var({ start : this.prev(), - definitions : this.vardefs(no_in, false), + definitions : this.vardefs(no_in, false, type), type : type, end : this.prev() }); @@ -1577,7 +1608,7 @@ Cola.Parser.prototype.expr_atom = function(allow_calls) { this.unexpected(); } if (!this.is_js && this.is("name")) { - if(Cola.is_token(this.peek(), "name")){ + if(this.next_is("name")){ type = this.S.token.value, this.next(); return this.function_(Cola.AST_Defun, type); } @@ -1643,32 +1674,107 @@ Cola.Parser.prototype.expr_list = function (closing, allow_trailing_comma, allow return a; }; -Cola.Parser.prototype.array_ = Cola.Parser.embed_tokens(function() { +Cola.Parser.prototype.array_ = Cola.Parser.embed_tokens(function(is_template, is_var) { this.expect("["); - - if(!this.is_js && !this.is("punc","]")){ + + if(!this.is_js && !this.is("punc","]") && !this.is("punc",",") && !(this.is("name") && this.next_is("name"))){ this.dumpS(); - var tmp, from = this.expression(true, false, true); - if(this.is("punc","..")){ + var tmp, from = this.expression(false, false, true), triple; + if((this.is("punc","..") || this.is("punc","...")) && !this.next_is("punc", ",") && !this.next_is("punc", "]")){ + triple = this.is("punc","..."); this.next(); return new Cola.AST_ArrayRange({ - from : from, - to : (tmp = this.expression(true, false, true), this.expect("]"), tmp), - start : from.start, - end : this.prev() + from : from, + to : (tmp = this.expression(true, false, true), this.expect("]"), tmp), + triple : triple, + start : from.start, + end : this.prev() }); } this.restoreS(); } - - return new Cola.AST_Array({ + + if(this.is_js) return new Cola.AST_Array({ elements: this.expr_list("]", !this.options.strict, true) }); + + var is_array = ( is_template ? false : null ), vardef = false, first = true, a = [], val, skiped = false; + while (!this.is("punc", "]")) { + if (first) first = false; else this.expect(","); + + if (this.is("punc", ",") || this.is("punc", "]")) { + a.push(new Cola.AST_Hole({ start: this.S.token, end: this.S.token })); + if (!this.options.strict && this.is("punc", "]")) break; + } else + if (this.is("punc", "...") && is_array !== true) { + if (skiped) this.unexpected(); + this.next(); + skiped = true; + is_array = false; + a.push(new Cola.AST_Noop()); + } else + if (!is_var && this.is("name") && this.next_is("name") && !Cola.cKEYWORDS(this.peek().value)) { + if (is_array === true) this.unexpected(); + is_array = false; + vardef = true; + a.push(new Cola.AST_VarDef({ + start : this.S.token, + type : this.S.token.value, + name : (function(_this){ + _this.next(); + val = _this.as_symbol(Cola.AST_SymbolVar); + if (_this.is("punc", "...") && is_array !== true) { + if (skiped) _this.unexpected(); + _this.next(); + skiped = true; + is_array = false; + val.splated = true; + } + return val; + })(this), + value : null, + end : this.prev() + })) + } else { + if (is_array === false && this.is("punc","[")) val = this.array_(true, is_var); + else if (is_array === false && this.is("punc","{")) val = this.object_(true, is_var); + else val = this.expression(false); + + if (val.vardef) vardef = true; + if (this.is("punc", "...") && is_array !== true) { + if (skiped) this.unexpected(); + this.next(); + skiped = true; + is_array = false; + val.splated = true; + } + + if (val instanceof Cola.AST_ObjectTemplate || val instanceof Cola.AST_ArrayTemplate) { + if (is_array === true) this.unexpected(); + is_array = false; + } + if (!(val instanceof Cola.AST_SymbolRef || + val instanceof Cola.AST_ObjectTemplate || val instanceof Cola.AST_ArrayTemplate || + !is_var && ( val instanceof Cola.AST_Dot || val instanceof Cola.AST_Sub ) || + val instanceof Cola.AST_Object && val.template == true || + val instanceof Cola.AST_Array && val.template == true)) { + + if (is_array === false) this.unexpected(); + is_array = true; + } + a.push(val); + } + } + this.next(); + + return is_array === true || is_array === null + ? new Cola.AST_Array({ elements: a, template: is_array === null, vardef : vardef }) + : new Cola.AST_ArrayTemplate({ elements: a, vardef : vardef }); }); -Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function() { +Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function(is_template, is_var) { this.expect("{"); - var first = true, a = []; + var first = true, a = [], ptype, is_object = ( is_template ? false : null ), vardef = false, val; while (!this.is("punc", "}")) { if (first) first = false; else this.expect(","); if (!this.options.strict && this.is("punc", "}")) @@ -1677,10 +1783,18 @@ Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function() { var start = this.S.token; var type = start.type; var name = this.as_property_name(); + if (!this.is_js && !is_var && this.is("name") && !this.next_is("punc", "(") && !Cola.cKEYWORDS(name)) { + vardef = true; + ptype = name; + name = this.as_name(); + } else ptype = false; if (type == "name" && !this.is("punc", ":")) { if (name == "get") { + if (!this.is_js && is_object === false) this.unexpected(); + is_object = true; a.push(new Cola.AST_ObjectGetter({ start : start, + type : ptype, key : this.as_atom_node(), value : this.function_(Cola.AST_Accessor), end : this.prev() @@ -1688,8 +1802,11 @@ Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function() { continue; } if (name == "set") { + if (!this.is_js && is_object === false) this.unexpected(); + is_object = true; a.push(new Cola.AST_ObjectSetter({ start : start, + type : ptype, key : this.as_atom_node(), value : this.function_(Cola.AST_Accessor), end : this.prev() @@ -1697,16 +1814,47 @@ Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function() { continue; } } - this.expect(":"); + if (!this.is_js && !this.is("punc",":")) { + if (is_object === true) this.unexpected(); + is_object = false; + val = new Cola.AST_Noop(); + } else { + this.expect(":"); + + if (is_object === false && this.is("punc","[")) val = this.array_(true, is_var); + else if (is_object === false && this.is("punc","{")) val = this.object_(true, is_var); + else val = this.expression(false); + + if (ptype && !(val instanceof Cola.AST_SymbolRef)) this.unexpected(val.start); + if (val.vardef) vardef = true; + + if (val instanceof Cola.AST_ObjectTemplate || val instanceof Cola.AST_ArrayTemplate) { + if (is_object === true || ptype) this.unexpected(); + is_object = false; + } + if (!(val instanceof Cola.AST_SymbolRef || + val instanceof Cola.AST_ObjectTemplate || val instanceof Cola.AST_ArrayTemplate || + !is_var && ( val instanceof Cola.AST_Dot || val instanceof Cola.AST_Sub ) || + val instanceof Cola.AST_Object && val.template == true || + val instanceof Cola.AST_Array && val.template == true)) { + + if (is_object === false) this.unexpected(); + is_object = true; + } + } a.push(new Cola.AST_ObjectKeyVal({ start : start, + type : ptype, key : name, - value : this.expression(false), + value : val, end : this.prev() })); } this.next(); - return new Cola.AST_Object({ properties: a }); + + return is_object === true || is_object === null + ? new Cola.AST_Object({ properties: a, template: is_object === null, vardef : vardef }) + : new Cola.AST_ObjectTemplate({ properties: a, vardef : vardef }); }); Cola.Parser.prototype.as_property_name = function () { @@ -1772,19 +1920,22 @@ Cola.Parser.prototype.subscripts = function(expr, allow_calls) { if (this.is("punc", "[")) { this.next(); - var prop; + var prop, triple; if(this.is_js) prop = this.expression(true); else if(this.is("punc","]")) prop = new Cola.AST_Noop(); else { - prop = this.expression(true, false, true); + if(this.is("punc","..") || this.is("punc","...")) prop = new Cola.AST_Number({ value : 0 }); + else prop = this.expression(true, false, true); this.dumpS(); - if(this.is("punc","..")){ + if(this.is("punc","..") || this.is("punc","...")){ + triple = this.is("punc","..."); this.next(); prop = new Cola.AST_ArrayRange({ - from : prop, - to : this.expression(true, false, true), - start : prop.start, - end : this.prev() + from : prop, + to : ( this.is("punc","]") ? new Cola.AST_Noop() : this.expression(true, false, true) ), + triple : triple, + start : prop.start, + end : this.prev() }); } else this.restoreS(); } @@ -1835,20 +1986,45 @@ Cola.Parser.prototype.make_unary = function (ctor, op, expr) { return new ctor({ operator: op, expression: expr }); }; -Cola.Parser.prototype.expr_op = function(left, min_prec, no_in) { - var op = this.is("operator") ? this.S.token.value : null; +/* + a <= b < c == d + + as + + (((a <= b) && (b < c)) && c == d) + +*/ +Cola.Parser.prototype.expr_op = function(left, min_prec, no_in, is_comp, rightest) { + var op = this.is("operator") ? this.S.token.value : null, cop = Cola.COMPARISON(op); if (op == "in" && no_in) op = null; var prec = op != null ? this.PRECEDENCE[op] : null; + if (!this.is_js && is_comp && cop) { + this.next(); + var right = this.maybe_unary(true); + return this.expr_op(new Cola.AST_Binary({ + start : left.start, + left : left, + operator : "&&", + right : new Cola.AST_Binary({ + start : rightest.start, + left : rightest, + operator : op, + right : right, + end : right.end + }), + end : right.end + }), min_prec, no_in, true, right); + } if (prec != null && prec > min_prec) { this.next(); - var right = this.expr_op(this.maybe_unary(true), prec, no_in); + var right = !this.is_js && cop ? this.maybe_unary(true) : this.expr_op(this.maybe_unary(true), prec, no_in); return this.expr_op(new Cola.AST_Binary({ start : left.start, left : left, operator : op, right : right, end : right.end - }), min_prec, no_in); + }), min_prec, no_in, cop, right); } return left; }; @@ -1934,6 +2110,8 @@ Cola.Parser.prototype.expression = function(commas, no_in, in_dd) { var expr = this.maybe_assign(no_in); if (!in_dd && !this.is_js && this.is("punc", "..")) return this.cascade(expr, start); if (commas && this.is("punc", ",")) { + if (expr instanceof Cola.AST_Assign && (expr.left instanceof Cola.AST_ArrayTemplate || expr.left instanceof Cola.AST_ObjectTemplate || + (expr.left instanceof Cola.AST_Array || expr.left instanceof Cola.AST_Object) && expr.left.template) && expr.left.vardef) this.unexpected(); this.next(); return new Cola.AST_Seq({ start : start, diff --git a/lib/std.js b/lib/std.js index 8497460b..4941d9cb 100644 --- a/lib/std.js +++ b/lib/std.js @@ -122,7 +122,7 @@ Cola.$_cola_func_named_args.i = 9; Cola.$_cola_func_set_named_args = function $_cola_func_set_named_args(_args){ if(_args[_args.length - 1] instanceof $_cola_func_named_args){ - var nargs = [].pop.call(_args).$; + var nargs = _args[_args.length - 1].$; for(var i in nargs) if(nargs.hasOwnProperty(i)) _args[i] = nargs[i]; } diff --git a/lib/transform.js b/lib/transform.js index 09d27e89..978cce8d 100644 --- a/lib/transform.js +++ b/lib/transform.js @@ -51,7 +51,8 @@ Cola.TreeTransformer = function (before, after) { this.before = before; this.after = after; } -Cola.TreeTransformer.prototype = new Cola.TreeWalker; + +Cola.TreeTransformer.prototype.__proto__ = new Cola.TreeWalker; (function(undefined){ @@ -79,7 +80,14 @@ Cola.TreeTransformer.prototype = new Cola.TreeWalker; function do_list(list, tw) { return Cola.MAP(list, function(node){ - return node.transform(tw, true); + + var r = node.transform(tw, true); + + r = r instanceof Array + ? Cola.MAP.splice(r) + : r; + + return r; }); }; diff --git a/lib/translate.js b/lib/translate.js index 62df4fe7..76a5b53b 100644 --- a/lib/translate.js +++ b/lib/translate.js @@ -46,8 +46,8 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ main_event : 'DOMContentLoaded' }); - var $_cola_ast = Cola.parse(Cola.$_cola, { is_js : true}), $_cola_hash = {}, _this, - tt = new Cola.TreeTransformer(function(node, descend){ + var $_cola_ast = Cola.parse(Cola.$_cola, { is_js : true }), $_cola_hash = {}, _this, + tt = new Cola.TreeTransformer(function(node, descend, in_list){ var newNode, props = {}, parent = this.parent(); node = node.clone(); @@ -442,6 +442,13 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }) }; + if(node.left.property.to instanceof Cola.AST_Noop) props.args[2] = new Cola.AST_Number({ value : '9e9' }); + else if(node.left.property.triple) props.args[2] = new Cola.AST_Binary({ + operator : "-", + left : node.left.property.to, + right : new Cola.AST_Number({ value : 1 }) + }); + node = new Cola.AST_Call(props); } else @@ -459,16 +466,20 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ expression : node.expression }; props = { - args : [node.property.from, new Cola.AST_Binary({ - operator : "+", - left : node.property.to, - right : new Cola.AST_Number({ value : 1}) - })], + args : [node.property.from], start : node.start, end : node.end, expression : new Cola.AST_Dot(props) }; + if(!node.property.triple && !(node.property.to instanceof Cola.AST_Noop)) props.args[1] = new Cola.AST_Binary({ + operator : "+", + left : node.property.to, + right : new Cola.AST_Number({ value : 1 }) + }); else + if(!(node.property.to instanceof Cola.AST_Noop)) props.args[1] = node.property.to; + + node = new Cola.AST_Call(props); } else @@ -491,6 +502,12 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }) }; + if(node.triple) props.args[1] = new Cola.AST_Binary({ + operator : "-", + left : node.to, + right : new Cola.AST_Number({ value : 1 }) + }); + node = new Cola.AST_Call(props); } else @@ -548,7 +565,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ function func(s){ $_cola_func_set_named_args(arguments); var $_cola_i, list = 3 <= arguments.length ? [].slice.call(arguments, 1, $_cola_i = arguments.length - 1) : ($_cola_i = 2, []), - b = arguments[$_cola_i+0] !== undefiend ? arguments[$_cola_i+0] : false, + b = arguments[$_cola_i+0] !== undefined ? arguments[$_cola_i+0] : false, n = arguments.n, h = arguments.h !== undefined ? arguments.h : 123; } @@ -591,12 +608,13 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ if(val.argtype == "splated"){ aftersplated = 0; props.definitions.push(new Cola.AST_VarDef({ - name : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + type : "int", + name : new Cola.AST_SymbolVar({ name : '$_cola_i' }), value : null })); props.definitions.push(new Cola.AST_VarDef({ - name : splated.val.name, + name : new Cola.AST_SymbolVar(splated.val.name), value : new Cola.AST_Conditional({ condition : new Cola.AST_Binary({ operator : "<=", @@ -645,7 +663,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ else if(val.defval instanceof Cola.AST_Noop) props.definitions.push(new Cola.AST_VarDef({ - name : val.name, + name : new Cola.AST_SymbolVar(val.name), value : new Cola.AST_Sub({ expression : new Cola.AST_SymbolRef({ name : 'arguments' }), property : aftersplated == -1 @@ -658,7 +676,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }) })); else props.definitions.push(new Cola.AST_VarDef({ - name : val.name, + name : new Cola.AST_SymbolVar(val.name), value : new Cola.AST_Conditional({ condition : new Cola.AST_Binary({ operator : "!==", @@ -691,14 +709,14 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ named.forEach(function(val, i){ if(val.defval instanceof Cola.AST_Noop) props.definitions.push(new Cola.AST_VarDef({ - name : val.name, + name : new Cola.AST_SymbolVar(val.name), value : new Cola.AST_Dot({ expression : new Cola.AST_SymbolRef({ name : 'arguments' }), property : val.name.name }) })); else props.definitions.push(new Cola.AST_VarDef({ - name : val.name, + name : new Cola.AST_SymbolVar(val.name), value : new Cola.AST_Conditional({ condition : new Cola.AST_Binary({ operator : "!==", @@ -742,32 +760,37 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ ; to + fix: this and arguments objects + (function($_cola_expr, arguments){ + $_cola_expr[0] = yes; + $_cola_expr.foo = bar; + $_cola_expr.baz(); - (function($_cola_ml_expr){ - $_cola_ml_expr[0] = yes; - $_cola_ml_expr.foo = bar; - $_cola_ml_expr.baz(); + (function($_cola_expr, arguments){ + $_cola_expr.subfoo = no; + $_cola_expr.subaz(); - (function($_cola_ml_expr){ - $_cola_ml_expr.subfoo = no; - $_cola_ml_expr.subaz(); + return $_cola_expr; + }).call(this, $_cola_expr.sub, arguments); - return $_cola_ml_expr; - })($_cola_ml_expr.sub); - - return $_cola_ml_expr; - })(obj); + return $_cola_expr; + }).call(this, obj, arguments); */ if(node instanceof Cola.AST_Cascade){ props = { type : "dynamic", body : [], - argnames : [new Cola.AST_Defarg({ + argnames : [new Cola.AST_ArgDef({ argtype : "positional", type : "dynamic", defval : new Cola.AST_Noop(), - name : new Cola.AST_SymbolFunarg({ name : "$_cola_ml_expr" }) + name : new Cola.AST_SymbolFunarg({ name : "$_cola_expr", start : node.expression.start, end : node.expression.end }) + }), new Cola.AST_ArgDef({ + argtype : "positional", + type : "dynamic", + defval : new Cola.AST_Noop(), + name : new Cola.AST_SymbolFunarg({ name : "arguments", start : new Cola.AST_Token(), end : new Cola.AST_Token() }) })] }; @@ -790,13 +813,13 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ if(expr instanceof Cola.AST_Array || expr instanceof Cola.AST_ArrayRange) Expr = new Cola.AST_Sub({ start : Expr.start, end : Expr.end, - expression : new Cola.AST_SymbolRef({ name : "$_cola_ml_expr" }), + expression : new Cola.AST_SymbolRef({ name : "$_cola_expr" }), property : expr instanceof Cola.AST_ArrayRange ? expr : ( expr.elements.length == 0 ? new Cola.AST_Noop() : expr.elements[0] ) }); else if(expr instanceof Cola.AST_SymbolRef) Expr = new Cola.AST_Dot({ start : Expr.start, end : Expr.end, - expression : new Cola.AST_SymbolRef({ name : "$_cola_ml_expr" }), + expression : new Cola.AST_SymbolRef({ name : "$_cola_expr" }), property : Expr.name }); } else { @@ -804,14 +827,14 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ expr = new Cola.AST_Sub({ start : expr.start, end : expr.end, - expression : new Cola.AST_SymbolRef({ name : "$_cola_ml_expr" }), + expression : new Cola.AST_SymbolRef({ name : "$_cola_expr" }), property : expr instanceof Cola.AST_ArrayRange ? expr : ( expr.elements.length == 0 ? new Cola.AST_Noop() : expr.elements[0] ) }); else expr = new Cola.AST_Dot({ start : expr.start, end : expr.end, - expression : new Cola.AST_SymbolRef({ name : "$_cola_ml_expr" }), + expression : new Cola.AST_SymbolRef({ name : "$_cola_expr" }), property : expr.name }); @@ -829,17 +852,667 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }); props.body.push(new Cola.AST_Return({ - value : new Cola.AST_SymbolRef({ name : "$_cola_ml_expr" }) + value : new Cola.AST_SymbolRef({ name : "$_cola_expr" }) })); + + props = { + expression : new Cola.AST_Function(props), + property : "call" + } node = new Cola.AST_Call({ start : node.start, end : node.end, - args : [node.expression], - expression : new Cola.AST_Function(props) + args : [new Cola.AST_SymbolRef({ name : "this" }), node.expression, new Cola.AST_SymbolRef({ name : "arguments" })], + expression : new Cola.AST_Dot(props) }); } else + /* + var [c, [b, b2], ..., { key : a }] = obj; + var { "key" : d } = { key : "val" }; + + to + + var c = obj[0], b = obj[1][0], b2 = obj[1][1], $_cola_i = obj.length - 1, a = obj[$_cola_i++].key; + var $_cola_tmp = { key : "val" }, d = $_cola_tmp["key"]; + + */ + if(node instanceof Cola.AST_Var){ + var defs = []; + node.definitions.forEach(function(def, i){ + if(!(def.name instanceof Cola.AST_ArrayTemplate || def.name instanceof Cola.AST_ObjectTemplate)){ + defs.push(def); + return; + } + + var Symbol = def.value instanceof Cola.AST_SymbolRef + ? def.value + : new Cola.AST_SymbolRef({ name : "$_cola_tmp" }); + if(!(def.value instanceof Cola.AST_SymbolRef)) defs.push(new Cola.AST_VarDef({ + type : node.type, + name : new Cola.AST_SymbolVar(Symbol), + value : def.value + })); + + (function _rec(def, symbol, uid){ + var skiped = false, k = 0, is_arrayt = def instanceof Cola.AST_ArrayTemplate, _ = is_arrayt ? def.elements : def.properties; + _.forEach( is_arrayt + ? function(el, j){ + if(el instanceof Cola.AST_SymbolRef && el.splated){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : null + })); + el.splated = undefined; + defs.push(new Cola.AST_VarDef({ + name : new Cola.AST_SymbolVar(el), + value : new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "<=", + left : new Cola.AST_Number({ value : _.length }), + right : new Cola.AST_Dot({ + expression : symbol, + property : "length" + }) + }), + consequent : new Cola.AST_Call({ + expression : new Cola.AST_Dot({ + property : "call", + expression : new Cola.AST_Dot({ + property : "slice", + expression : new Cola.AST_Array({ elements : [] }) + }) + }), + args : [ + symbol, + new Cola.AST_Number({ value : j }), + new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length - j - 1 }) + }) + }) + ] + }), + alternative : new Cola.AST_Seq({ + car : new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : j }) + }), + cdr : new Cola.AST_Array({ elements : [] }) + }) + }) + })); + } else + if(el instanceof Cola.AST_SymbolRef) defs.push(new Cola.AST_VarDef({ + start : node.start, + end : node.end, + type : node.type, + name : new Cola.AST_SymbolVar(el), + value : new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }) + })); else + if(el instanceof Cola.AST_Noop){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length -1 - j }) + }) + })); + } else + if(el instanceof Cola.AST_Hole || el instanceof Cola.AST_ArrayTemplate && el.elements.length == 0 || el instanceof Cola.AST_ObjectTemplate && el.properties.length == 0) + k++; + else + _rec(el, new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }), uid + "_"); + } + : function(el, j){ + if(el.value instanceof Cola.AST_SymbolRef || el.value instanceof Cola.AST_Noop && el.start.type == "name") defs.push(new Cola.AST_VarDef({ + start : node.start, + end : node.end, + type : node.type, + name : el.value instanceof Cola.AST_Noop ? new Cola.AST_SymbolVar({ name : el.key }) : new Cola.AST_SymbolVar(el.value), + value : el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }) + })); else + _rec(el.value, el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }), uid + "_"); + }); + })(def.name, Symbol, "_"); + }); + + node.definitions = defs; + } else + + /* + { String name, age : ages.age } = pro; + + to + + var name = pro.name; + ages.age = pro.age; + + */ + if(node.body instanceof Cola.AST_Assign && (node.body.left instanceof Cola.AST_ArrayTemplate || node.body.left instanceof Cola.AST_ObjectTemplate || + (node.body.left instanceof Cola.AST_Array || node.body.left instanceof Cola.AST_Object) && node.body.left.template) && + node instanceof Cola.AST_SimpleStatement){ + node = node.body; + var defs = []; + + var Symbol = node.right instanceof Cola.AST_SymbolRef + ? node.right + : new Cola.AST_SymbolRef({ name : "$_cola_tmp" }); + if(!(node.right instanceof Cola.AST_SymbolRef)) defs.push(new Cola.AST_VarDef({ + type : "dynamic", + name : new Cola.AST_SymbolVar(Symbol), + value : node.right + })); + + (function _rec(def, symbol, uid){ + var skiped = false, k = 0, is_arrayt = def instanceof Cola.AST_Array || def instanceof Cola.AST_ArrayTemplate, _ = is_arrayt ? def.elements : def.properties; + _.forEach( is_arrayt + ? function(el, j){ + if(el instanceof Cola.AST_VarDef && el.name.splated){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : null + })); + el.name.splated = undefined; + el.value = new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "<=", + left : new Cola.AST_Number({ value : _.length }), + right : new Cola.AST_Dot({ + expression : symbol, + property : "length" + }) + }), + consequent : new Cola.AST_Call({ + expression : new Cola.AST_Dot({ + property : "call", + expression : new Cola.AST_Dot({ + property : "slice", + expression : new Cola.AST_Array({ elements : [] }) + }) + }), + args : [ + symbol, + new Cola.AST_Number({ value : j }), + new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length - j - 1 }) + }) + }) + ] + }), + alternative : new Cola.AST_Seq({ + car : new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : j }) + }), + cdr : new Cola.AST_Array({ elements : [] }) + }) + }); + defs.push(el); + } else + if((el instanceof Cola.AST_SymbolRef || el instanceof Cola.AST_Sub || el instanceof Cola.AST_Dot) && el.splated){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : null + })); + el.splated = undefined; + defs.push(new Cola.AST_Assign({ + operator : "=", + left : el, + right : new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "<=", + left : new Cola.AST_Number({ value : _.length }), + right : new Cola.AST_Dot({ + expression : symbol, + property : "length" + }) + }), + consequent : new Cola.AST_Call({ + expression : new Cola.AST_Dot({ + property : "call", + expression : new Cola.AST_Dot({ + property : "slice", + expression : new Cola.AST_Array({ elements : [] }) + }) + }), + args : [ + symbol, + new Cola.AST_Number({ value : j }), + new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length - j - 1 }) + }) + }) + ] + }), + alternative : new Cola.AST_Seq({ + car : new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : j }) + }), + cdr : new Cola.AST_Array({ elements : [] }) + }) + }) + })); + } else + if(el instanceof Cola.AST_VarDef){ + el.value = new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }); + defs.push(el); + } else + if(el instanceof Cola.AST_SymbolRef || el instanceof Cola.AST_Sub || el instanceof Cola.AST_Dot) defs.push(new Cola.AST_Assign({ + operator : "=", + left : el, + right : new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }) + })); else + if(el instanceof Cola.AST_Noop){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length -1 - j }) + }) + })); + } else + if(el instanceof Cola.AST_Hole || el instanceof Cola.AST_ArrayTemplate && el.elements.length == 0 || el instanceof Cola.AST_ObjectTemplate && el.properties.length == 0) + k++; + else + _rec(el, new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }), uid + "_"); + } + : function(el, j){ + if(el.type && (el.value instanceof Cola.AST_SymbolRef || el.value instanceof Cola.AST_Noop && el.start.type == "name")) defs.push(new Cola.AST_VarDef({ + start : node.start, + end : node.end, + type : el.type, + name : el.value instanceof Cola.AST_Noop ? new Cola.AST_SymbolVar({ name : el.key }) : new Cola.AST_SymbolVar(el.value), + value : el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }) + })); else + if(el.value instanceof Cola.AST_SymbolRef || el.value instanceof Cola.AST_Sub || el.value instanceof Cola.AST_Dot || el.value instanceof Cola.AST_Noop && el.start.type == "name") defs.push(new Cola.AST_Assign({ + operator : "=", + left : el.value instanceof Cola.AST_Noop ? new Cola.AST_SymbolRef({ name : el.key }) : el.value, + right : el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }) + })); else + _rec(el.value, el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }), uid + "_"); + }); + })(node.left, Symbol, "_"); + + if (defs.length == 0) return node; + node = []; + + var sdef, sdefs = [], prev = defs[0].CTOR; + defs.forEach(function _(def, i){ + sdef = false; + + if(def instanceof prev) sdefs.push(def); + else { + if(prev == Cola.AST_VarDef) sdef = new Cola.AST_Var({ + type : "dynamic", + definitions : sdefs + }); else if(sdefs.length == 1) sdef = sdefs[0] + else { + sdefs.reverse().forEach(function(def){ + if(!sdef) sdef = def; + else sdef = new Cola.AST_Seq({ + car : def, + cdr : sdef + }); + }); + } + + node.push(!(sdef instanceof Cola.AST_Var) + ? new Cola.AST_SimpleStatement({ body : sdef }) + : sdef + ); + prev = def.CTOR; + sdefs = [def]; + } + + if(i == defs.length - 1) _(false); + }); + } else + + /* + func({ a : aname, b : bname } = obj) + + to + + func((function($_cola_expr, arguments){ + aname = obj.a; + bname = obj.b; + + return $_cola_expr; + }).call(this, obj, arguments)) + + */ + if(node instanceof Cola.AST_Assign && (node.left instanceof Cola.AST_ArrayTemplate || node.left instanceof Cola.AST_ObjectTemplate || + (node.left instanceof Cola.AST_Array || node.left instanceof Cola.AST_Object) && node.left.template)){ + if(node.vardef) Cola.Parser.prototype.unexpected.call({}, node.start); + + var defs = []; + + var Symbol = node.right instanceof Cola.AST_SymbolRef + ? node.right + : new Cola.AST_SymbolRef({ name : "$_cola_expr" }); + + (function _rec(def, symbol, uid){ + var skiped = false, k = 0, is_arrayt = def instanceof Cola.AST_Array || def instanceof Cola.AST_ArrayTemplate, _ = is_arrayt ? def.elements : def.properties; + _.forEach( is_arrayt + ? function(el, j){ + if((el instanceof Cola.AST_SymbolRef || el instanceof Cola.AST_Sub || el instanceof Cola.AST_Dot) && el.splated){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : null + })); + el.splated = undefined; + defs.push(new Cola.AST_Assign({ + operator : "=", + left : el, + right : new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "<=", + left : new Cola.AST_Number({ value : _.length }), + right : new Cola.AST_Dot({ + expression : symbol, + property : "length" + }) + }), + consequent : new Cola.AST_Call({ + expression : new Cola.AST_Dot({ + property : "call", + expression : new Cola.AST_Dot({ + property : "slice", + expression : new Cola.AST_Array({ elements : [] }) + }) + }), + args : [ + symbol, + new Cola.AST_Number({ value : j }), + new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length - j - 1 }) + }) + }) + ] + }), + alternative : new Cola.AST_Seq({ + car : new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : j }) + }), + cdr : new Cola.AST_Array({ elements : [] }) + }) + }) + })); + } else + if(el instanceof Cola.AST_SymbolRef || el instanceof Cola.AST_Sub || el instanceof Cola.AST_Dot) defs.push(new Cola.AST_Assign({ + operator : "=", + left : el, + right : new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }) + })); else + if(el instanceof Cola.AST_Noop){ + skiped = true; + defs.push(new Cola.AST_VarDef({ + type : "int", + name : new Cola.AST_SymbolVar({ name : "$_cola" + uid + "i" }), + value : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : symbol + }), + right : new Cola.AST_Number({ value : _.length -1 - j }) + }) + })); + } else + if(el instanceof Cola.AST_Hole || el instanceof Cola.AST_ArrayTemplate && el.elements.length == 0 || el instanceof Cola.AST_ObjectTemplate && el.properties.length == 0) + k++; + else + _rec(el, new Cola.AST_Sub({ + expression : symbol, + property : !skiped + ? new Cola.AST_Number({ value : j }) + : new Cola.AST_Binary({ + operator : "+", + left : new Cola.AST_SymbolRef({ name : "$_cola" + uid + "i" }), + right : new Cola.AST_Number({ value : k++ }) + }) + }), uid + "_"); + } + : function(el, j){ + if(el.value instanceof Cola.AST_SymbolRef || el.value instanceof Cola.AST_Sub || el.value instanceof Cola.AST_Dot || el.value instanceof Cola.AST_Noop && el.start.type == "name") defs.push(new Cola.AST_Assign({ + operator : "=", + left : el.value instanceof Cola.AST_Noop ? new Cola.AST_SymbolRef({ name : el.key }) : el.value, + right : el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }) + })); else + _rec(el.value, el.start.type == "name" + ? new Cola.AST_Dot({ + expression : symbol, + property : el.key + }) + : new Cola.AST_Sub({ + expression : symbol, + property : new Cola.AST_String({ value : el.key }) + }), uid + "_"); + }); + })(node.left, Symbol, "_"); + + if (defs.length == 0) return node; + props = { + type : "dynamic", + body : [], + argnames : [new Cola.AST_ArgDef({ + argtype : "positional", + type : "dynamic", + defval : new Cola.AST_Noop(), + name : new Cola.AST_SymbolFunarg({ name : "$_cola_expr", start : node.right.start, end : node.right.end }) + }), new Cola.AST_ArgDef({ + argtype : "positional", + type : "dynamic", + defval : new Cola.AST_Noop(), + name : new Cola.AST_SymbolFunarg({ name : "arguments", start : new Cola.AST_Token(), end : new Cola.AST_Token() }) + })] + }; + + var sdef, sdefs = [], prev = defs[0].CTOR; + defs.forEach(function _(def, i){ + sdef = false; + + if(def instanceof prev) sdefs.push(def); + else { + if(prev == Cola.AST_VarDef) sdef = new Cola.AST_Var({ + type : "dynamic", + definitions : sdefs + }); else if(sdefs.length == 1) sdef = sdefs[0] + else { + sdefs.reverse().forEach(function(def){ + if(!sdef) sdef = def; + else sdef = new Cola.AST_Seq({ + car : def, + cdr : sdef + }); + }); + } + + props.body.push(!(sdef instanceof Cola.AST_Var) + ? new Cola.AST_SimpleStatement({ body : sdef }) + : sdef + ); + prev = def.CTOR; + sdefs = [def]; + } + + if(i == defs.length - 1) _(false); + }); + + props = { + expression : new Cola.AST_Function(props), + property : "call" + } + + node = new Cola.AST_Call({ + start : node.start, + end : node.end, + args : [new Cola.AST_SymbolRef({ name : "this" }), node.right, new Cola.AST_SymbolRef({ name : "arguments" })], + expression : new Cola.AST_Dot(props) + }); + } else + /* "test @a @{b} {{c}}" @@ -883,8 +1556,14 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ if(node instanceof Cola.AST_RegExp && (node.value.indexOf('\n') != -1 || /\/[\w]*x[\w]*$/.test(node.value))){ node.value = node.value.replace(/[\r\n\s]/g,'').replace(/(\/[\w]*)x([\w]*$)/, '$1$2'); } - - node._descend(node, this); + + if(node instanceof Array){ + _this = this; + node.forEach(function(nd){ + nd._descend(nd, _this); + }) + } else node._descend(node, this); + return node; });