diff --git a/README.md b/README.md index 3e18c4a4..7ecada3f 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ ColaScript is a language that compiles in JavaScript. This language is similar t print(str) => console.log(str); -- named arguments +- named arguments, status: done hello(String name:) => console.log("Hello @name!"); hello(name: 'dangreen'); // Hello dangreen! @@ -241,13 +241,13 @@ ColaScript is a language that compiles in JavaScript. This language is similar t hello(name: "World") => console.log("Hello @name!"); hello(); // Hello World! -- defaults for positional arguments +- defaults for positional arguments, status: done - hello(String name = "World!") => console.log("Hello @name!"); + hello(String name = "World") => console.log("Hello @name!"); hello('dangreen'); // Hello dangreen! hello(); // Hello World! -- some arguments into array +- some arguments into array, status: done main(name, skills...){ console.log("My name is @name, my skills:"); diff --git a/lib/ast.js b/lib/ast.js index b7366fbc..fa35cef8 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -391,6 +391,21 @@ Cola.AST_Defun = Cola.DEFNODE("Defun", "type", { $documentation: "A function definition" }, Cola.AST_Lambda); +Cola.AST_Namedarg = Cola.DEFNODE("Namedarg", "start end name value", { + $documentation: "Named argument", + $propdoc: { + value: "Value of named argument" + } +}, Cola.AST_SymbolRef); + +Cola.AST_Defarg = Cola.DEFNODE("Defarg", "start end name type argtype defval", { + $documentation: "A function argument expression", + $propdoc: { + type: "Data type", + argtype: "positional/named/splated" + } +}, Cola.AST_SymbolFunarg); + /* -----[ JUMPS ]----- */ Cola.AST_Jump = Cola.DEFNODE("Jump", null, { diff --git a/lib/parse.js b/lib/parse.js index f7803ccf..6af8f6a3 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -643,7 +643,9 @@ Cola.Tokenizer.prototype.handle_slash = function () { Cola.Tokenizer.prototype.handle_dot = function () { this.next(); - if (!this.is_js && this.peek() == '.') return this.next(), this.token("punc", ".."); + if (!this.is_js && this.peek() == '.' && this.peek(1) != ".") return this.next(), this.token("punc", ".."); + else if (!this.is_js && this.peek() == '.' && this.peek(1) == ".") return this.next(), this.next(), this.token("punc", "..."); + return Cola.is_digit(this.peek().charCodeAt(0)) ? this.read_num(".") : this.token("punc", "."); @@ -945,7 +947,7 @@ Cola.Parser.prototype.expect_token = function (type, val) { Cola.Parser.prototype.expect = function (punc) { return this.expect_token("punc", punc); }; Cola.Parser.prototype.can_insert_semicolon = function () { - if(!this.is_js) return false; // ColaScript + if(!this.is_js) return false; return !this.options.strict && ( this.S.token.nlb || this.is("eof") || this.is("punc", "}") ); @@ -1021,7 +1023,6 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { } this.restoreS(); - if(isfun) return this.function_(Cola.AST_Defun); } @@ -1221,10 +1222,39 @@ Cola.Parser.prototype.for_in = function (init) { }); }; +Cola.Parser.prototype.as_funcarg = function(splatedexist) { + var name = this.as_symbol(Cola.AST_SymbolFunarg), type = name, argtype = 'positional', defval = new Cola.AST_Noop(); + if(this.is("name")) name = this.as_symbol(Cola.AST_SymbolFunarg); + if(this.is("punc", "...")){ + if(splatedexist) this.token_error(this.S, "Unexpected token: splated argument can be only one."); + if(type != name && type.name != "Array") this.token_error(this.S, "Unexpected token: splated argument must have `Array` type."); + this.next(); + argtype = "splated"; + } else if(this.is("operator", "=")){ + this.next(); + defval = this.expression(false); + } else if(this.is("punc",":")){ + this.next(); + argtype = "named"; + if(!this.is("punc",",") && !this.is("punc",")")){ + defval = this.expression(false); + } + } + + return new Cola.AST_Defarg({ + name : name, + type : argtype == "splated" ? "Array" : type == name ? "dynamic" : type.name, + argtype : argtype, + defval : defval, + start : type.start, + end : this.prev() + }); +}; + Cola.Parser.prototype.function_ = function(ctor, type) { !type && (type = "dynamic"); - var in_statement = ctor === Cola.AST_Defun, _this = this; + var in_statement = ctor === Cola.AST_Defun, _this = this, splatedexist = false; var name = this.is("name") ? this.as_symbol(in_statement ? Cola.AST_SymbolDefun : Cola.AST_SymbolLambda) : null; if (in_statement && !name) this.unexpected(); @@ -1235,7 +1265,8 @@ Cola.Parser.prototype.function_ = function(ctor, type) { argnames: (function(first, a){ while (!_this.is("punc", ")")) { if (first) first = false; else _this.expect(","); - a.push(_this.as_symbol(Cola.AST_SymbolFunarg)); + a.push(_this.is_js ? _this.as_symbol(Cola.AST_SymbolFunarg) : _this.as_funcarg(splatedexist)); + splatedexist = a[a.length - 1].argtype == "splated"; } _this.next(); return a; @@ -1511,7 +1542,7 @@ Cola.Parser.prototype.expr_atom = function(allow_calls) { if (this.is("operator", "new")) { return this.new_(); } - var start = this.S.token; + var type, start = this.S.token; if (this.is("punc")) { switch (start.value) { case "(": @@ -1529,7 +1560,6 @@ Cola.Parser.prototype.expr_atom = function(allow_calls) { isfun = (this.next(), (this.is('punc','{') || this.is('punc','=>'))); this.restoreS(); - if(isfun) return this.function_(Cola.AST_Function); } @@ -1546,6 +1576,30 @@ Cola.Parser.prototype.expr_atom = function(allow_calls) { } this.unexpected(); } + if (!this.is_js && this.is("name")) { + if(Cola.is_token(this.peek(), "name")){ + type = this.S.token.value, this.next(); + return this.function_(Cola.AST_Defun, type); + } + + var _this = this, balance = 1, isfun = false; + this.dumpS(); + + this.next(); + if(this.is('punc', '(')){ + this.next(); + this.next_until(function(){ + if(_this.is('punc', '(')) balance++; + else if(_this.is('punc', ')')) balance--; + + return balance == 0 || _this.is('eof'); + }); + isfun = (this.next(), (this.is('punc','{') || this.is('punc','=>'))); + } + + this.restoreS(); + if(isfun) return this.function_(Cola.AST_Defun); + } if (this.is("keyword", "function")) { this.next(); var func = this.function_(Cola.AST_Function); @@ -1559,16 +1613,31 @@ Cola.Parser.prototype.expr_atom = function(allow_calls) { this.unexpected(); }; -Cola.Parser.prototype.expr_list = function (closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; +Cola.Parser.prototype.expr_list = function (closing, allow_trailing_comma, allow_empty, allow_named_args) { + var first = true, a = [], name; while (!this.is("punc", closing)) { if (first) first = false; else this.expect(","); if (allow_trailing_comma && this.is("punc", closing)) break; if (this.is("punc", ",") && allow_empty) { a.push(new Cola.AST_Hole({ start: this.S.token, end: this.S.token })); - } else { - a.push(this.expression(false)); - } + } else + if(this.is("name") && allow_named_args){ + name = Cola.$_cola_clone(this.S.token); + this.dumpS(); + this.next(); + if(this.is("punc",":")){ + this.next(); + a.push(new Cola.AST_Namedarg({ + name : name.value, + value : this.expression(false), + start : name, + end : this.prev() + })); + } else { + this.restoreS(); + a.push(this.expression(false)) + } + } else a.push(this.expression(false)); } this.next(); return a; @@ -1733,7 +1802,7 @@ Cola.Parser.prototype.subscripts = function(expr, allow_calls) { return this.subscripts(new Cola.AST_Call({ start : start, expression : expr, - args : this.expr_list(")"), + args : this.expr_list(")", false, false, !this.is_js), end : this.prev() }), true); } diff --git a/lib/std.js b/lib/std.js index 0071873d..f772955b 100644 --- a/lib/std.js +++ b/lib/std.js @@ -115,12 +115,29 @@ Cola.$_cola_array_asplice = function $_cola_array_asplice(_array, _from, _to, _a } Cola.$_cola_array_asplice.i = 8; -Cola.$_cola = Cola.$_cola_is + Cola.$_cola_isnt + Cola.$_cola_modulo + Cola.$_cola_isset + Cola.$_cola_isntset + Cola.$_cola_clone + Cola.$_cola_array_last + Cola.$_cola_array_range + Cola.$_cola_array_asplice; +Cola.$_cola_func_named_args = function $_cola_func_named_args(_args){ + this.$ = _args; +} +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).$; + for(var i in nargs) if(nargs.hasOwnProperty(i)) + _args[i] = nargs[i]; + } +} +Cola.$_cola_func_set_named_args.i = 10; + +Cola.$_cola = + Cola.$_cola_is + Cola.$_cola_isnt + Cola.$_cola_modulo + Cola.$_cola_isset + + Cola.$_cola_isntset + Cola.$_cola_clone + Cola.$_cola_array_last + Cola.$_cola_array_range + + Cola.$_cola_array_asplice + Cola.$_cola_func_named_args + Cola.$_cola_func_set_named_args; Cola.Compressor.StdFuncs = { - $_cola_is : true, - $_cola_isnt : true, - $_cola_modulo : true, - $_cola_isset : true, + $_cola_is : true, + $_cola_isnt : true, + $_cola_modulo : true, + $_cola_isset : true, $_cola_isntset : true }; diff --git a/lib/translate.js b/lib/translate.js index 4b9f8998..ad6a5e60 100644 --- a/lib/translate.js +++ b/lib/translate.js @@ -51,16 +51,29 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ var newNode, props = {}, parent = this.parent(); node = node.clone(); + /* + main(){ + console.log("hello world"); + } + + to + + window.addEventListener('DOMContentLoaded', + function main(){ + console.log("hello world"); + }, false); + + */ if(options.main_binding && parent instanceof Cola.AST_Toplevel && node instanceof Cola.AST_Defun && node.name instanceof Cola.AST_SymbolDefun && node.name.name == "main"){ props = { - args : [new Cola.AST_String({ value : options.main_event }), node, new Cola.AST_False()] + args : [new Cola.AST_String({ value : options.main_event }), node, new Cola.AST_False()], + expression : new Cola.AST_Dot({ + property : 'addEventListener', + //start : props.start, + //end : new Cola.AST_Token({ nlb : false, type : 'name', value : 'pow' }), + expression : new Cola.AST_SymbolRef({ name : 'window' }) + }) }; - props.expression = new Cola.AST_Dot({ - property : 'addEventListener', - //start : props.start, - //end : new Cola.AST_Token({ nlb : false, type : 'name', value : 'pow' }), - expression : new Cola.AST_SymbolRef({ name : 'window' }) - }); node = new Cola.AST_SimpleStatement({ body : new Cola.AST_Call(props), @@ -69,40 +82,64 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }); } else + /* + 5 ** 2 + + to + + Math.pow(5, 2) + + */ if(node instanceof Cola.AST_Binary && node.operator == '**'){ props = { - args : [node.left, node.right], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : 'Math' }), - end : node.left //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.left, node.right], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : 'Math' }), + end : node.left, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_Dot({ + property : 'pow', + //start : props.start, + //end : new Cola.AST_Token({ nlb : false, type : 'name', value : 'pow' }), + expression : new Cola.AST_SymbolRef({ name : 'Math' }) + }) }; - props.expression = new Cola.AST_Dot({ - property : 'pow', - //start : props.start, - //end : new Cola.AST_Token({ nlb : false, type : 'name', value : 'pow' }), - expression : new Cola.AST_SymbolRef({ name : 'Math' }) - }); node = new Cola.AST_Call(props); } else + /* + 5 %% 2 + + to + + $_cola_modulo(5, 2) + + */ if(node instanceof Cola.AST_Binary && node.operator == '%%'){ $_cola_hash[Cola.$_cola_modulo.i] = true; props = { - args : [node.left, node.right], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_modulo' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.left, node.right], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_modulo' }), + end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_modulo' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_modulo' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + a ?= b; + + to + + if($_cola_isntset(a)) a = b; + + */ if(node instanceof Cola.AST_SimpleStatement && node.body instanceof Cola.AST_Assign && node.body.operator == '?='){ if(node.body.left instanceof Cola.AST_Sub && node.body.left.property instanceof Cola.AST_Noop){ props = { @@ -114,7 +151,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ props = { operator : "-", left : new Cola.AST_Dot(props), - right : new Cola.AST_Number({ value : 1}) + right : new Cola.AST_Number({ value : 1 }) }; node.body.left.property = new Cola.AST_Binary(props); @@ -124,15 +161,15 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ node.body.operator = '='; props = { - args : [node.body.left] + args : [node.body.left], //start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isntset' }), //end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_isntset' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_isntset' - //start : props.start, - //end : props.start - }); node = new Cola.AST_If({ body : node.clone(), @@ -142,6 +179,14 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }); } else + /* + func(a ?= b); + + to + + func($_cola_isntset(a) ? a = b : a); + + */ if(node instanceof Cola.AST_Assign && node.operator == '?='/* && !(parent instanceof Cola.AST_SimpleStatement)*/){ if(node.left instanceof Cola.AST_Sub && node.left.property instanceof Cola.AST_Noop){ props = { @@ -163,15 +208,15 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ node.operator = '='; props = { - args : [node.left] + args : [node.left], //start : new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isntset' }), //end : new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_isntset' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_isntset' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Conditional({ start : node.start, //new Cola.AST_Token({ nlb : false, type : 'punc', value : '(' }), @@ -182,89 +227,141 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }); } else + /* + a ? b + + to + + $_cola_isset(a) ? a : b + + */ if(node instanceof Cola.AST_Conditional && node.alternative instanceof Cola.AST_Noop){ $_cola_hash[Cola.$_cola_isset.i] = true; props = { - args : [node.condition], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isset' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.condition], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isset' }), + end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_isset' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_isset' - //start : props.start, - //end : props.start - }); node.alternative = node.consequent; node.consequent = node.condition; node.condition = new Cola.AST_Call(props); } else + /* + 123 is Number + + to + + $_cola_is(123, Number) + + */ if(node instanceof Cola.AST_Binary && node.operator == 'is'){ $_cola_hash[Cola.$_cola_is.i] = true; props = { - args : [node.left, node.right], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_is' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.left, node.right], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_is' }), + end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_is' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_is' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + true isnt String + + to + + $_cola_isnt(true, String); + + */ if(node instanceof Cola.AST_Binary && node.operator == 'isnt'){ $_cola_hash[Cola.$_cola_isnt.i] = true; props = { - args : [node.left, node.right], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isnt' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.left, node.right], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isnt' }), + end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_isnt' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_isnt' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + isset a + + or + + a?? + + to + + $_cola_isset(a) + + */ if(node instanceof Cola.AST_UnaryPostfix && node.operator == '??' || node instanceof Cola.AST_UnaryPrefix && node.operator == 'isset'){ $_cola_hash[Cola.$_cola_isset.i] = true; props = { - args : [node.expression], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isset' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.expression], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_isset' }), + end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_isset' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_isset' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + a = clone b + + to + + a = $_cola_clone(b) + + */ if(node instanceof Cola.AST_UnaryPrefix && node.operator == 'clone'){ $_cola_hash[Cola.$_cola_clone.i] = true; props = { - args : [node.expression], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_clone' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.expression], + start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_clone' }), + end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + expression : new Cola.AST_SymbolRef({ + name : '$_cola_clone' + //start : props.start, + //end : props.start + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_clone' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + arr[] = 123 + + to + + arr.push(123) + + */ if(node instanceof Cola.AST_Assign && node.operator == "=" && node.left instanceof Cola.AST_Sub && node.left.property instanceof Cola.AST_Noop){ props = { property : "push", @@ -282,11 +379,17 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ node = new Cola.AST_Call(props); } else + /* + arr[] /= 2 + + to + + arr[arr.length - 1] /= 2 + + */ if(node instanceof Cola.AST_Assign && node.operator != "=" && node.left instanceof Cola.AST_Sub && node.left.property instanceof Cola.AST_Noop){ props = { property : "length", - //start : node.left.start, - //end : new Cola.AST_Token({ nlb : false, type : 'name', value : 'push' }), expression : node.left.expression }; props = { @@ -298,43 +401,61 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ node.left.property = new Cola.AST_Binary(props); } else + /* + func(arr[]) + + to + + func($_cola_array_last(arr)) + + */ if(node instanceof Cola.AST_Sub && node.property instanceof Cola.AST_Noop){ $_cola_hash[Cola.$_cola_array_last.i] = true; props = { - args : [node.expression], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_array_last' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.expression], + start : node.start, + end : node.end, + expression : new Cola.AST_SymbolRef({ + name : '$_cola_array_last' + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_array_last' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + arr[0..1] = 123 + + to + + $_cola_array_asplice(arr, 0, 1, 123) + + */ if(node instanceof Cola.AST_Assign && node.operator == '=' && node.left instanceof Cola.AST_Sub && node.left.property instanceof Cola.AST_ArrayRange){ $_cola_hash[Cola.$_cola_array_asplice.i] = true; props = { - args : [node.left.expression, node.left.property.from, node.left.property.to, node.right], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_array_last' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.left.expression, node.left.property.from, node.left.property.to, node.right], + start : node.start, + end : node.end, + expression : new Cola.AST_SymbolRef({ + name : '$_cola_array_asplice' + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_array_asplice' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + func(arr[0..1]) + + to + + func(arr.slice(0, 1 + 1)) + + */ if(node instanceof Cola.AST_Sub && node.property instanceof Cola.AST_ArrayRange){ props = { property : "slice", - //start : node.left.start, - //end : new Cola.AST_Token({ nlb : false, type : 'name', value : 'push' }), expression : node.expression }; props = { @@ -343,45 +464,293 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ left : node.property.to, right : new Cola.AST_Number({ value : 1}) })], - start : node.start, //props.start, - end : node.end, //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }), + start : node.start, + end : node.end, expression : new Cola.AST_Dot(props) }; node = new Cola.AST_Call(props); } else + /* + [0..3] + + to + + $_cola_array_range(0, 3) + + */ if(node instanceof Cola.AST_ArrayRange){ $_cola_hash[Cola.$_cola_array_range.i] = true; props = { - args : [node.from, node.to], - start : node.start, //new Cola.AST_Token({ nlb : false, type : 'name', value : '$_cola_clone' }), - end : node.end //new Cola.AST_Token({ nlb : false, type : 'punc', value : ')' }) + args : [node.from, node.to], + start : node.start, + end : node.end, + expression : new Cola.AST_SymbolRef({ + name : '$_cola_array_range' + }) }; - props.expression = new Cola.AST_SymbolRef({ - name : '$_cola_array_range' - //start : props.start, - //end : props.start - }); node = new Cola.AST_Call(props); } else + /* + func(a, b, name : name, c) + + to + + func(a, b, c, new $_cola_func_named_args({ name : name })) + + */ + if(node instanceof Cola.AST_Call){ + props = { + properties : [] + }; + + var delQueue = []; + node.args.forEach(function(val, i){ + if(!(val instanceof Cola.AST_Namedarg)) return; + $_cola_hash[Cola.$_cola_func_named_args.i] = true; + delQueue.push(i); + props.properties.push(new Cola.AST_ObjectKeyVal({ + key : val.name, + value : val.value, + start : val.start, + end : val.end + })); + }); + + if(delQueue.length != 0){ + delQueue.reverse().forEach(function(val){ + node.args.splice(val, 1); + }); + + props = { + args : [new Cola.AST_Object(props)], + start : node.start, + end : node.end, + expression : new Cola.AST_SymbolRef({ + name : '$_cola_func_named_args' + }) + }; + + node.args.push(new Cola.AST_New(props)); + } + } else + + /* + func(String s, Number n:, Array list..., Boolean b = false, h: 123){ + + } + + to + + 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, + n = arguments.n, + h = arguments.h !== undefined ? arguments.h : 123; + } + + */ + if((node instanceof Cola.AST_Function || node instanceof Cola.AST_Defun) && node.argnames.length != 0){ + var posed = [], named = [], onfront = true, delQueue = [], pos = 0, splated, aftersplated = -1; + node.argnames.forEach(function(val, i){ + if(val.argtype == "positional"){ + if(val.defval instanceof Cola.AST_Noop && onfront) pos++, node.argnames[i] = val.name; + else { + onfront = false; + delQueue.push(i); + posed.push({ pos : pos++, val : val }); + } + splated && splated.after++; + } else if(val.argtype == "named"){ + delQueue.push(i); + named.push(val); + } else if(val.argtype == "splated"){ + onfront = false; + delQueue.push(i); + splated = { pos : pos++, after : 0, val : val }; + } + }); + + if(delQueue.length != 0) + delQueue.reverse().forEach(function(val){ + node.argnames.splice(val, 1); + }); + + props = { + type : "dynamic", + definitions : [] + }; + + posed.forEach(function(val, i){ + var pos = val.pos; val = val.val; + + if(splated && (pos - 1 == splated.pos || pos + 1 == splated.pos)){ + aftersplated = 0; + props.definitions.push(new Cola.AST_VarDef({ + name : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + value : null + })); + + props.definitions.push(new Cola.AST_VarDef({ + name : splated.val.name, + value : new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "<=", + left : new Cola.AST_Number({ value : splated.pos + splated.after + 1 }), + right : new Cola.AST_Dot({ + expression : new Cola.AST_SymbolRef({ name : 'arguments' }), + 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 : [ + new Cola.AST_SymbolRef({ name : 'arguments' }), + new Cola.AST_Number({ value : splated.pos }), + new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + right : new Cola.AST_Binary({ + operator : '-', + left : new Cola.AST_Dot({ + property : "length", + expression : new Cola.AST_SymbolRef({ name : 'arguments' }) + }), + right : new Cola.AST_Number({ value : splated.after }) + }) + }) + ] + }), + alternative : new Cola.AST_Seq({ + car : new Cola.AST_Assign({ + operator : '=', + left : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + right : new Cola.AST_Number({ value : splated.pos }) + }), + cdr : new Cola.AST_Array({ elements : [] }) + }) + }) + })); + + splated = false; + } + + if(val.defval instanceof Cola.AST_Noop) props.definitions.push(new Cola.AST_VarDef({ + name : val.name, + value : new Cola.AST_Sub({ + expression : new Cola.AST_SymbolRef({ name : 'arguments' }), + property : aftersplated == -1 + ? new Cola.AST_Number({ value : pos }) + : new Cola.AST_Binary({ + operator : '+', + left : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + right : new Cola.AST_Number({ value : aftersplated++ }) + }) + }) + })); + else props.definitions.push(new Cola.AST_VarDef({ + name : val.name, + value : new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "!==", + left : new Cola.AST_Sub({ + expression : new Cola.AST_SymbolRef({ name : 'arguments' }), + property : aftersplated == -1 + ? new Cola.AST_Number({ value : pos }) + : new Cola.AST_Binary({ + operator : '+', + left : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + right : new Cola.AST_Number({ value : aftersplated }) + }) + }), + right : new Cola.AST_SymbolRef({ name : 'undefined' }) + }), + consequent : new Cola.AST_Sub({ + expression : new Cola.AST_SymbolRef({ name : 'arguments' }), + property : aftersplated == -1 + ? new Cola.AST_Number({ value : pos }) + : new Cola.AST_Binary({ + operator : '+', + left : new Cola.AST_SymbolRef({ name : '$_cola_i' }), + right : new Cola.AST_Number({ value : aftersplated++ }) + }) + }), + alternative : val.defval + }) + })); + }); + + named.forEach(function(val, i){ + if(val.defval instanceof Cola.AST_Noop) props.definitions.push(new Cola.AST_VarDef({ + name : 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, + value : new Cola.AST_Conditional({ + condition : new Cola.AST_Binary({ + operator : "!==", + left : new Cola.AST_Dot({ + expression : new Cola.AST_SymbolRef({ name : 'arguments' }), + property : val.name.name + }), + right : new Cola.AST_SymbolRef({ name : 'undefined' }) + }), + consequent : new Cola.AST_Dot({ + expression : new Cola.AST_SymbolRef({ name : 'arguments' }), + property : val.name.name + }), + alternative : val.defval + }) + })); + }); + + if(delQueue.length != 0 || named.length != 0) node.body.unshift(new Cola.AST_Var(props)); + + if(named.length != 0){ + $_cola_hash[Cola.$_cola_func_named_args.i] = true; + $_cola_hash[Cola.$_cola_func_set_named_args.i] = true; + node.body.unshift(new Cola.AST_SimpleStatement({ + body : new Cola.AST_Call({ + args : [new Cola.AST_SymbolRef({ name : 'arguments' })], + expression : new Cola.AST_SymbolRef({ name : '$_cola_func_set_named_args' }) + }) + })); + } + } else + + /* + "test @a @{b} {{c}}" + + to + + "test "+a+" "+b+" "+c + + */ if(node instanceof Cola.AST_StringTemplate){ newNode = new Cola.AST_Binary({ operator : '+', left : node.body[0], right : node.body[1] - //start : node.body[0].start, - //end : node.body[1].end }); for(var i = 2; i < node.body.length; i++) newNode = new Cola.AST_Binary({ operator : '+', left : newNode, right : node.body[i] - //start : newNode.start, - //end : node.body[i].end }); newNode.start = node.start; @@ -390,6 +759,19 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ node = newNode; } else + /* + / + ([\w-\.]+) + @ + ((?:[\w]+\.)+) + ([a-zA-Z]{2,4}) + / + + to + + /([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})/ + + */ 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'); }