From 476ed7c29431b8736967e3e604a9fb3dbc46423d Mon Sep 17 00:00:00 2001 From: Dan Onoshko Date: Wed, 3 Sep 2014 22:00:03 +0700 Subject: [PATCH] . --- README.md | 4 + lib/parse.js | 186 ++++++++++++++++++++++++++++++++++++++++------- lib/translate.js | 140 +++++++++++++++++------------------ 3 files changed, 230 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 8475306f..71460e87 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,9 @@ From Git: git clone git://github.com/TrigenSoftware/ColaScript.git cd ColaScript npm link . + +Usage +=== Use it same as in [UglifyJS2](https://github.com/mishoo/UglifyJS2), except: @@ -485,6 +488,7 @@ Future plans return res; } } + - add `observe` modificator. - static typing - `@use` expressions diff --git a/lib/parse.js b/lib/parse.js index f0f0409f..5eaceaa6 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -256,6 +256,8 @@ Cola.Tokenizer = function ($TEXT, filename, is_js, html5_comments) { col : 0, tokcol : 0, newline_before : false, + in_class : false, + class_name : false, regex_allowed : false, comments_before : [] }; @@ -1154,26 +1156,11 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { body : this.block_(), end : this.prev() }); - - 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() - }); + return this.maybe_template_assign(false); case "[": + return this.maybe_template_assign(true); case "(": return this.simple_statement(); case ";": @@ -1270,6 +1257,87 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { } }); +Cola.Parser.prototype.maybe_template_assign = function (array) { + var _this = this; + if (!array) { + 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){ + var start = this.S.token, tobj = this.object_(false, false, true), top = this.S.token.value; + + if (tobj.vardef && top != "=") + this.token_error(this.S.token, "Invalid operator `" + top + "`."); + + this.next(); + + tobj = new Cola.AST_Assign({ + start : start, + left : tobj, + operator : top, + right : this.maybe_assign(false), + end : this.prev() + }); + + return new Cola.AST_SimpleStatement({ + start : tobj.start, + body : tobj, + end : tobj.end + }); + } + + return new Cola.AST_BlockStatement({ + start : this.S.token, + body : this.block_(), + end : this.prev() + }); + } else { + this.dumpS(); + var balance = 0, is_array = false; + this.next_until(function(){ + if(_this.is('punc', '[')) balance++; + else if(_this.is('punc', ']')) balance--; + + return balance == 0 || _this.is('eof'); + }); + is_array = this.next_is("operator"); + this.restoreS(); + + if(is_array){ + var start = this.S.token, tarr = this.array_(false, false, true), top = this.S.token.value; + + if (tarr.vardef && top != "=") + this.token_error(this.S.token, "Invalid operator `" + top + "`."); + + this.next(); + + tarr = new Cola.AST_Assign({ + start : start, + left : tarr, + operator : top, + right : this.maybe_assign(false), + end : this.prev() + }); + + return new Cola.AST_SimpleStatement({ + start : tarr.start, + body : tarr, + end : tarr.end + }); + } + + return this.simple_statement(); + } +}; + Cola.Parser.prototype.labeled_statement = function () { var label = this.as_symbol(Cola.AST_Label), _this = this; if (Cola.find_if(function(l){ return l.name == label.name }, this.S.labels)) { @@ -1367,10 +1435,17 @@ Cola.Parser.prototype.for_in = function (init) { }; Cola.Parser.prototype.class_ = function(){ + if(this.S.in_class) + this.token_error(this.prev(), "You can't define class in other class."); + + this.S.in_class = true; + var _this = this, name = this.is("name") ? this.as_symbol(Cola.AST_SymbolClass) : this.unexpected(), extends_ = false; + this.S.class_name = name.name; + if(this.is("keyword", "extends")){ this.next(); if(!this.is("name")) this.unexpected(); @@ -1391,6 +1466,39 @@ Cola.Parser.prototype.class_ = function(){ --_this.S.in_function; _this.S.in_loop = loop; _this.S.labels = labels; + + var mconstr = false, nconstrs = false; + a.forEach(function(member){ + if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_SymbolDefun && member.name.name == _this.S.class_name){ + if(member.type != "dynamic") + _this.token_error(member.start, "Constructor can't have returned type."); + + if(member.mods.length != 0) + _this.token_error(member.start, "Constructor can't have modificators."); + + if(nconstrs) + _this.token_error(member.start, "Main constructor must be defined before named constructors"); + + if(mconstr) + _this.token_error(member.start, "Main constructor can be defined only one time"); + + mconstr = true; + } else if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_Dot && + member.name.expression instanceof Cola.AST_SymbolDefun && member.name.expression.name == _this.S.class_name){ + if(member.type != "dynamic") + _this.token_error(member.start, "Constructor can't have returned type."); + + if(member.mods.length != 0) + _this.token_error(member.start, "Constructor can't have modificators."); + + nconstrs = true; + } else if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_Dot && member.mods.indexOf("static") != -1){ + _this.token_error(member.start, "Unexpected `static` modificator."); + } + }); + + _this.S.in_class = false; + _this.S.class_name = false; return a; })(this.S.in_loop, this.S.labels) }); @@ -1443,6 +1551,19 @@ Cola.Parser.prototype.function_ = function(ctor, type, mods) { //var args_skiped = false; if (name != null) name = this.subscripts(name, false); + + if(!this.S.in_class){ + if(name instanceof Cola.AST_Symbol){ + if(mods.length != 0) + this.token_error(name.start, "Function definition outside of class can't contain any modifer"); + } + + else { + if(mods.length != 0 && mods.indexOf("static") != -1) + this.token_error(name.start, "Prop definition can't contain `static` modifer"); + } + } + if (in_statement && !name) this.unexpected(); @@ -1588,11 +1709,11 @@ Cola.Parser.prototype.try_ = function () { }); }; -Cola.Parser.prototype.vardefs = function (no_in, in_const, type) { - var a = [], was_template = false; +Cola.Parser.prototype.vardefs = function (no_in, in_const, type, mods) { + var a = [], was_template = false, last; for (;;) { was_template = false; - a.push(new Cola.AST_VarDef({ + a.push(last = new Cola.AST_VarDef({ start : this.S.token, type : type, name : (function(_this){ @@ -1608,6 +1729,16 @@ Cola.Parser.prototype.vardefs = function (no_in, in_const, type) { value : this.is("operator", "=") ? (this.next(), this.expression(false, no_in)) : ( was_template ? this.expect_token("operator","=") : null ), end : this.prev() })); + + if (mods && mods.indexOf("const") != -1 && !last.value) + this.token_error(last.start, "`const` prop can't have `undefined` value"); + + if (mods && mods.indexOf("covert") != -1 && last.name instanceof Cola.AST_Symbol && !this.S.in_class) + this.token_error(last.start, "Unexpected `covert` modificator."); + + if (mods && mods.indexOf("static") != -1 && (!(last.name instanceof Cola.AST_Symbol) || !this.S.in_class)) + this.token_error(last.start, "Unexpected `static` modificator."); + if (!this.is("punc", ",")) break; this.next(); @@ -1619,7 +1750,7 @@ Cola.Parser.prototype.var_ = function(no_in, type, mods) { (!type || type == "var") && (type = "dynamic"); return new Cola.AST_Var({ start : this.prev(), - definitions : this.vardefs(no_in, false, type), + definitions : this.vardefs(no_in, false, type, mods), mods : mods, type : type, end : this.prev() @@ -1786,11 +1917,10 @@ Cola.Parser.prototype.expr_atom = function(allow_calls) { } if (!this.is_js && this.is("name")) { if(this.next_is("name")){ - type = this.S.token.value, this.next(); - var isfun = false; - this.dumpS(); + type = this.S.token.value, this.next(); + this.subscripts(this.as_symbol(Cola.AST_SymbolLambda), false); isfun = this.is("punc", "("); this.restoreS(); @@ -1894,7 +2024,7 @@ Cola.Parser.prototype.expr_list = function (closing, allow_trailing_comma, allow return a; }; -Cola.Parser.prototype.array_ = Cola.Parser.embed_tokens(function(is_template, is_var) { +Cola.Parser.prototype.array_ = Cola.Parser.embed_tokens(function(is_template, is_var, with_vardef) { this.expect("["); if(!this.is_js && !this.is("punc","]") && !this.is("punc",",") && !(this.is("name") && this.next_is("name"))){ @@ -1933,7 +2063,7 @@ Cola.Parser.prototype.array_ = Cola.Parser.embed_tokens(function(is_template, is 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) || this.peek().value == "var")) { + if (!is_var && with_vardef && this.is("name") && this.next_is("name") && (!Cola.cKEYWORDS(this.peek().value) || this.peek().value == "var")) { if (is_array === true) this.unexpected(); is_array = false; vardef = true; @@ -1992,7 +2122,7 @@ Cola.Parser.prototype.array_ = Cola.Parser.embed_tokens(function(is_template, is : new Cola.AST_ArrayTemplate({ elements: a, vardef : vardef }); }); -Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function(is_template, is_var) { +Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function(is_template, is_var, with_vardef) { this.expect("{"); var first = true, a = [], ptype, is_object = ( is_template ? false : null ), vardef = false, val; while (!this.is("punc", "}")) { @@ -2003,7 +2133,7 @@ Cola.Parser.prototype.object_ = Cola.Parser.embed_tokens(function(is_template, i 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) || name == "var")) { + if (!this.is_js && !is_var && with_vardef && this.is("name") && !this.next_is("punc", "(") && (!Cola.cKEYWORDS(name) || name == "var")) { vardef = true; ptype = name == "var" ? "dynamic" : name; name = this.as_name(); diff --git a/lib/translate.js b/lib/translate.js index ff750314..1d369b01 100644 --- a/lib/translate.js +++ b/lib/translate.js @@ -383,18 +383,13 @@ Cola.DefPropWithMods = function(def, mods){ right : def.value }); - if(mods.indexOf("static") != -1) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, def.start, "Prop definition outside of class can't contain `static` modifer"); + var dp = { properties : [] }; - if(mods.indexOf("const") != -1 && !def.value) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, def.start, "`const` prop can't have `undefined` value"); - - var dp = { properties : [ - new Cola.AST_ObjectKeyVal({ + if(def.value) + dp.properties.push(new Cola.AST_ObjectKeyVal({ key : "value", value : def.value - }) - ] }; + })); if(!(def.name.expression instanceof Cola.AST_Symbol && def.name.expression.name == "this" || def.name instanceof Cola.AST_Proto)) dp.properties.push(new Cola.AST_ObjectKeyVal({ @@ -418,7 +413,7 @@ Cola.DefPropWithMods = function(def, mods){ args : [ def.name.expression, def.name instanceof Cola.AST_Sub - ? def.name.property + ? def.name.property : new Cola.AST_String({ value: def.name.property }), new Cola.AST_Object(dp)], expression : new Cola.AST_Dot({ @@ -487,9 +482,6 @@ Cola.DefFunWithMods = function(func, mods){ }); } - if(mods.indexOf("static") != -1 && mods.indexOf("method") == -1) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, func.start, "Function definition outside of class can't contain `static` modifer"); - var sname = func.name, dp = { properties : [ new Cola.AST_ObjectKeyVal({ key : (function(node){ @@ -1123,46 +1115,34 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ var defCache = []; newNode = []; node.definitions.forEach(function(def, i){ if(def.name instanceof Cola.AST_SymbolVar){ - if(node.mods && node.mods.indexOf("const") != -1 && !def.value) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, def.start, "`const` var can't have `undefined` value"); - defCache.push(def); - } else if(def.value){ - - if(defCache.length != 0){ - if(!node.mods || node.mods.length == 0 || node.mods.indexOf("const") != -1 && node.mods.length == 1){ - newNode.push(node.mods.length == 1 ? new Cola.AST_Const(node) : node.clone()); - newNode[newNode.length - 1].definitions = defCache.map(function(def){ - def.name = new Cola.AST_SymbolConst(def.name); - return def; - }); - defCache = []; - } else - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, node.start, "Var definition can contain only `const` modifer"); + } else if(def.value || node.mods.indexOf("covert") != -1){ + if(defCache.length != 0 && (!node.mods || node.mods.length == 0 || node.mods.indexOf("const") != -1 && node.mods.length == 1)){ + newNode.push(node.mods.length == 1 ? new Cola.AST_Const(node) : node.clone()); + newNode[newNode.length - 1].definitions = defCache.map(function(def){ + def.name = new Cola.AST_SymbolConst(def.name); + return def; + }); + defCache = []; } var texpr = def.name; while(!(texpr.expression instanceof Cola.AST_Symbol || texpr.expression instanceof Cola.AST_Constant)) texpr = texpr.expression; if(texpr.expression instanceof Cola.AST_Symbol && !(texpr.expression instanceof Cola.AST_This)) texpr.expression = new Cola.AST_SymbolRef(texpr.expression); - newNode.push(Cola.DefPropWithMods(def, node.mods)); - newNode[newNode.length - 1] = new Cola.AST_SimpleStatement({ + newNode.push(Cola.DefPropWithMods(def, node.mods)); newNode[newNode.length - 1] = new Cola.AST_SimpleStatement({ body : newNode[newNode.length - 1] }); } }); - if(defCache.length != 0){ - if(!node.mods || node.mods.length == 0 || node.mods.indexOf("const") != -1 && node.mods.length == 1){ - newNode.push(node.mods && node.mods.length == 1 ? new Cola.AST_Const(node) : node.clone()); - newNode[newNode.length - 1].definitions = defCache.map(function(def){ - def.name = new Cola.AST_SymbolConst(def.name); - return def; - }); - defCache = []; - } else - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, node.start, "Var definition can contain only `const` modifer"); - + if(defCache.length != 0 && (!node.mods || node.mods.length == 0 || node.mods.indexOf("const") != -1 && node.mods.length == 1)){ + newNode.push(node.mods && node.mods.length == 1 ? new Cola.AST_Const(node) : node.clone()); + newNode[newNode.length - 1].definitions = defCache.map(function(def){ + def.name = new Cola.AST_SymbolConst(def.name); + return def; + }); + defCache = []; } node = newNode; @@ -1342,18 +1322,6 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ var has_main_constr = false; node.body.forEach(function(member){ if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_SymbolDefun && member.name.name == node.name.name){ - if(member.type != "dynamic") - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Constructor can't have returned type."); - - if(member.mods.length != 0) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Constructor can't have modificators."); - - if(main_constructors.some(function(constr){ return constr.name instanceof Cola.AST_Dot; })) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Main constructor must be defined before named constructors"); - - if(main_constructors.some(function(constr){ return constr.name instanceof Cola.AST_SymbolDefun && constr.name.name == node.name.name; })) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Constructor can be defined only one time"); - main_constructors.push(member); newNode.push(member); @@ -1379,15 +1347,6 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ if(member instanceof Cola.AST_Defun && member.name instanceof Cola.AST_Dot && member.name.expression instanceof Cola.AST_SymbolDefun && member.name.expression.name == node.name.name){ - if(member.type != "dynamic") - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Constructor can't have returned type."); - - if(member.mods.length != 0) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Constructor can't have modificators."); - - if(main_constructors.some(function(constr){ return constr.name instanceof Cola.AST_Dot && constr.name.property == member.name.property; })) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, member.start, "Constructor can be defined only one time"); - main_constructors.push(member); newNode.push(member); @@ -1416,7 +1375,50 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ property : member.name.name }); newNode.push(member); - } else { + } else + + if(member instanceof Cola.AST_Var && member.mods.indexOf("static") != -1){ + member.definitions.forEach(function(def){ + var texpr = def.name; + + if(!(texpr instanceof Cola.AST_Symbol)){ + while(!(texpr.expression instanceof Cola.AST_Symbol || texpr.expression instanceof Cola.AST_Constant)) texpr = texpr.expression; + } + + if(def.name instanceof Cola.AST_Symbol && (def.value || member.mods.indexOf("covert") != -1)){ + newNode.push(new Cola.AST_VarDef({ + name : new Cola.AST_Dot({ expression: node.name, property: def.name.name }), + value : def.value + })); + + member.mods.splice(member.mods.indexOf("static"), 1); + + newNode[newNode.length - 1] = new Cola.AST_Var({ + type : member.type, + mods : member.mods, + definitions : [newNode[newNode.length - 1]] + }); + } else + + if((def.value || member.mods.indexOf("covert") != -1) && !(texpr.expression instanceof Cola.AST_This)){ + texpr.expression = new Cola.AST_Dot({ expression: node.name, property: texpr.expression.name }); + newNode.push(new Cola.AST_VarDef({ + name : def.name, + value : def.value + })); + + member.mods.splice(member.mods.indexOf("static"), 1); + + newNode[newNode.length - 1] = new Cola.AST_Var({ + type : member.type, + mods : member.mods, + definitions : [newNode[newNode.length - 1]] + }); + } + }); + } + + else { if(member instanceof Cola.AST_Var) member.definitions.forEach(function(def){ var texpr = def.name; @@ -1436,7 +1438,7 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ }); if(!has_main_constr){ - newNode.push(new Cola.AST_Defun({ + newNode.unshift(new Cola.AST_Defun({ mods : [], type : "dynamic", name : new Cola.AST_SymbolDefun(node.name), @@ -1444,10 +1446,10 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ body : [] })); - main_constructors.push(newNode[newNode.length - 1]); + main_constructors.push(newNode[0]); if(node.extends){ - newNode[newNode.length - 1].body.push(new Cola.AST_SimpleStatement({ + newNode[0].body.push(new Cola.AST_SimpleStatement({ body : new Cola.AST_Call({ expression : new Cola.AST_SymbolRef({ name: "super" }), args : [] @@ -1634,9 +1636,6 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ 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; - if(node.mods && node.mods.length != 0) - Cola.Parser.prototype.token_error.call(Cola.Parser.prototype, node.start, "Function definition outside of class can't contain any modifer"); - node.argnames.forEach(function(val, i){ if(val.argtype == "positional"){ if(val.defval instanceof Cola.AST_Noop && onfront && !val.required) pos++, node.argnames[i] = val.name; @@ -2020,8 +2019,6 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ 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){ - if(node.body.left.vardef && node.body.operator != "=") Cola.Parser.prototype.unexpected.call(Cola.Parser.prototype, node.body.left.start); - node = node.body; var defs = []; @@ -2163,7 +2160,6 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ */ 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.left.vardef) Cola.Parser.prototype.unexpected.call(Cola.Parser.prototype, node.start); _ColaRuntime$$hash[Cola._ColaRuntime$$arguments_def.i] = true; var defs = [];