diff --git a/README.md b/README.md index 4aa331b1..3790d699 100644 --- a/README.md +++ b/README.md @@ -376,7 +376,29 @@ Future plans Object data = someData; int data.getFriendsCount() => this.friends.length; - + +- dotal getters and setters definition + + covert int get Math.rand() => 123; + covert int set Math.rand(int val) => console.log(val); + + to + + _ColaRuntime$$updateProperty(Math, "rand", { + get: function rand() { + return 123; + }, + configurable: true + }); + + _ColaRuntime$$updateProperty(Math, "rand", { + set: function rand() { + var val = arguments[0] !== undefined ? arguments[0] : _ColaRuntime$$error("Argument `val` is required!"); + return console.log(val); + }, + configurable: true + }); + - operator `?.`. status: done - operator `?` to sign an argument as not-required. status: done diff --git a/lib/ast.js b/lib/ast.js index 566f7365..08416672 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -378,6 +378,21 @@ Cola.AST_Toplevel = Cola.DEFNODE("Toplevel", "globals language", { } }, Cola.AST_Scope); +Cola.AST_Class = Cola.DEFNODE("Class", "name extends", { + $documentation: "Base class for classes", + $propdoc: { + name: "[AST_SymbolClass] the name of this class", + extends: "[AST_Node] class for extend" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.name._walk(visitor); + this.extends._walk(visitor); + Cola.walk_body(this, visitor); + }); + } +}, Cola.AST_Scope); + Cola.AST_Lambda = Cola.DEFNODE("Lambda", "name argnames uses_arguments", { $documentation: "Base class for functions", $propdoc: { @@ -928,6 +943,10 @@ Cola.AST_SymbolConst = Cola.DEFNODE("SymbolConst", null, { $documentation: "A constant declaration" }, Cola.AST_SymbolDeclaration); +Cola.AST_SymbolClass = Cola.DEFNODE("SymbolClass", null, { + $documentation: "Symbol defining a class", +}, Cola.AST_SymbolDeclaration); + Cola.AST_SymbolFunarg = Cola.DEFNODE("SymbolFunarg", "type", { $documentation: "Symbol naming a function argument", }, Cola.AST_SymbolVar); diff --git a/lib/parse.js b/lib/parse.js index 97326482..c19fa071 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -49,13 +49,13 @@ !this.Cola && (this.Cola = {}); Cola.KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with'; -Cola.cKEYWORDS = Cola.KEYWORDS.replace(' void', '') + ' static covert get set when clone is isnt class singleton injector'; +Cola.cKEYWORDS = Cola.KEYWORDS.replace(' void', '') + ' static covert get set when clone is isnt class extends singleton injector'; Cola.KEYWORDS_ATOM = 'false null true'; Cola.cKEYWORDS_ATOM = Cola.KEYWORDS_ATOM + ' on yes off no'; Cola.RESERVED_WORDS = 'abstract boolean byte char double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield'; -Cola.cRESERVED_WORDS = Cola.RESERVED_WORDS.replace(' class', '').replace(' static', '') + " " + Cola.cKEYWORDS_ATOM + " " + Cola.cKEYWORDS; +Cola.cRESERVED_WORDS = Cola.RESERVED_WORDS.replace(' class', '').replace(' extends', '').replace(' static', '') + " " + Cola.cKEYWORDS_ATOM + " " + Cola.cKEYWORDS; Cola.RESERVED_WORDS += " " + Cola.KEYWORDS_ATOM + " " + Cola.KEYWORDS; Cola.KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case'; @@ -1035,6 +1035,21 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { this.next(); } + if(!this.is_js && this.is("keyword", "function")){ + this.next(); + return this.function_(Cola.AST_Defun, false, mods); + } + + if(!this.is_js && this.is("keyword", "get")){ + this.next(); + return this.function_(Cola.AST_Getter, false, mods); + } + + if(!this.is_js && this.is("keyword", "set")){ + this.next(); + return this.function_(Cola.AST_Setter, false, mods); + } + if(!this.is_js && this.is("keyword", "var")){ this.next(); return tmp = this.var_(false, false, mods), this.semicolon(), tmp; @@ -1049,7 +1064,7 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { ctor = Cola.AST_Getter; this.next(); } else if(this.is("keyword", "set")){ - cotr = Cola.AST_Setter; + ctor = Cola.AST_Setter; this.next(); } else if(this.is("keyword", "function")) this.next(); @@ -1195,6 +1210,9 @@ Cola.Parser.prototype.statement = Cola.Parser.embed_tokens(function() { case "for": return this.for_(); + case "class": + return this.class_(); + case "function": return this.function_(Cola.AST_Defun); @@ -1348,6 +1366,36 @@ Cola.Parser.prototype.for_in = function (init) { }); }; +Cola.Parser.prototype.class_ = function(){ + var _this = this, + name = this.is("name") ? this.as_symbol(Cola.AST_SymbolClass) : this.unexpected(), + extends_ = false; + + if(this.is("keyword", "extends")){ + this.next(); + if(!this.is("name")) this.unexpected(); + extends_ = this.subscripts((extends_ = this.as_symbol(Cola.AST_SymbolRef)), true); + } + + return new Cola.AST_Class({ + name: name, + extends: extends_, + body: (function(loop, labels){ + ++_this.S.in_function; + _this.S.in_directives = true; + _this.S.in_loop = 0; + _this.S.labels = []; + + var tmp, a = _this.block_(); + + --_this.S.in_function; + _this.S.in_loop = loop; + _this.S.labels = labels; + return a; + })(this.S.in_loop, this.S.labels) + }); +}; + Cola.Parser.prototype.as_funcarg = function(splatedexist) { var name = this.as_symbol(Cola.AST_SymbolFunarg), type = name, argtype = 'positional', defval = new Cola.AST_Noop, required = true; @@ -1388,8 +1436,9 @@ Cola.Parser.prototype.as_funcarg = function(splatedexist) { Cola.Parser.prototype.function_ = function(ctor, type, mods) { !type && (type = "dynamic"); + !mods && (mods = []); - var in_statement = ctor === Cola.AST_Defun, _this = this, splatedexist = false; + var in_statement = ctor === Cola.AST_Defun || Cola.AST_Setter || Cola.AST_Getter, _this = this, splatedexist = false; var name = this.is("name") ? this.as_symbol(in_statement ? Cola.AST_SymbolDefun : Cola.AST_SymbolLambda) : null; if (name != null) name = this.subscripts(name, false); if (in_statement && !name) @@ -1418,8 +1467,8 @@ Cola.Parser.prototype.function_ = function(ctor, type, mods) { ? (_this.next(), [new Cola.AST_Return({ start: new Cola.AST_Token({ nlb : false, type : 'keyword', value : 'return' }), value: (function(){ - tmp = _this.expression(ctor === Cola.AST_Defun); - if ( ctor === Cola.AST_Defun ) { + tmp = _this.expression(ctor === Cola.AST_Defun || ctor === Cola.AST_Setter || ctor === Cola.AST_Getter); + if ( ctor === Cola.AST_Defun || ctor === Cola.AST_Setter || ctor === Cola.AST_Getter ) { _this.semicolon(); //_this.next(); } diff --git a/lib/std.js b/lib/std.js index 72f6421f..ef6cc22a 100644 --- a/lib/std.js +++ b/lib/std.js @@ -137,13 +137,21 @@ Cola._ColaRuntime$$array_modulo_access = function _ColaRuntime$$array_modulo_acc }; Cola._ColaRuntime$$array_modulo_access.i = 13; -Cola._ColaRuntime$$arguments_def = { i : 14 }; +Cola._ColaRuntime$$updateProperty = function _ColaRuntime$$updateProperty(_object, _propname, _props) { + var _dprops = Object.getOwnPropertyDescriptor(_object, _propname) || {}; + for(var key in _props) + if(_props.hasOwnProperty(key)) _dprops[key] = _props[key]; + return Object.defineProperty(_object, _propname, _dprops); +}; +Cola._ColaRuntime$$updateProperty.i = 14; + +Cola._ColaRuntime$$arguments_def = { i : 15 }; Cola.$_cola = Cola._ColaRuntime$$is + Cola._ColaRuntime$$isnt + Cola._ColaRuntime$$modulo + Cola._ColaRuntime$$isset + Cola._ColaRuntime$$isntset + Cola._ColaRuntime$$clone + Cola._ColaRuntime$$array_last + Cola._ColaRuntime$$array_range + Cola._ColaRuntime$$array_asplice + Cola._ColaRuntime$$func_named_args + Cola._ColaRuntime$$func_set_named_args + Cola._ColaRuntime$$error + - Cola._ColaRuntime$$array_negate_access + Cola._ColaRuntime$$array_modulo_access + + Cola._ColaRuntime$$array_negate_access + Cola._ColaRuntime$$array_modulo_access + Cola._ColaRuntime$$updateProperty + "var arguments;"; Cola.Compressor.StdFuncs = { diff --git a/lib/translate.js b/lib/translate.js index aec71248..7f302a4c 100644 --- a/lib/translate.js +++ b/lib/translate.js @@ -393,6 +393,10 @@ Cola.DefPropWithMods = function(def, mods){ new Cola.AST_ObjectKeyVal({ key : "value", value : def.value + }), + new Cola.AST_ObjectKeyVal({ + key : "configurable", + value : new Cola.AST_True }) ] }; @@ -423,27 +427,70 @@ Cola.DefPropWithMods = function(def, mods){ }; Cola.DefFunWithMods = function(func, mods){ - if(mods.length == 0) return new Cola.AST_Assign({ - start : func.start, - end : func.end, - operator : '=', - left : func.name, - right : (function(node){ - node.name = new Cola.AST_SymbolLambda({ - start : node.name.start, - end : node.name.end, - name : node.name.property + if(mods.length == 0 || !mods){ + if(func instanceof Cola.AST_Defun) + return new Cola.AST_Assign({ + start : func.start, + end : func.end, + operator : '=', + left : func.name, + right : (function(node){ + node.name = new Cola.AST_SymbolLambda({ + start : node.name.start, + end : node.name.end, + name : node.name.property + }); + return new Cola.AST_Function(node); + })(func) }); - return new Cola.AST_Function(node); - })(func) - }); + else if(func instanceof Cola.AST_Getter) + return new Cola.AST_Call({ + expression : new Cola.AST_Dot({ + expression : func.name.expression, + property : "__defineGetter__" + }), + args : [ + new Cola.AST_String({ value: func.name.property}), + (function(node){ + node.name = new Cola.AST_SymbolLambda({ + start : node.name.start, + end : node.name.end, + name : node.name.property + }); + return new Cola.AST_Function(node); + })(func) + ], + }); + else if(func instanceof Cola.AST_Setter) + return new Cola.AST_Call({ + expression : new Cola.AST_Dot({ + expression : node.name.expression, + property : "__defineSetter__" + }), + args : [ + new Cola.AST_String({ value: func.name.property}), + (function(node){ + node.name = new Cola.AST_SymbolLambda({ + start : node.name.start, + end : node.name.end, + name : node.name.property + }); + return new Cola.AST_Function(node); + })(func) + ], + }); + } if(mods.indexOf("static") != -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 : "value", + key : (function(node){ + if(node instanceof Cola.AST_Getter) return "get"; + if(node instanceof Cola.AST_Setter) return "set"; + return "value"; + })(func), value : (function(node){ node.name = new Cola.AST_SymbolLambda({ start : node.name.start, @@ -454,11 +501,17 @@ Cola.DefFunWithMods = function(func, mods){ })(func) }), new Cola.AST_ObjectKeyVal({ - key : "writable", + key : "configurable", value : new Cola.AST_True }) ] }; + if(!(func instanceof Cola.AST_Getter || func instanceof Cola.AST_Setter)) + dp.properties.push(new Cola.AST_ObjectKeyVal({ + key : "writable", + value : new Cola.AST_True + })); + if(mods.indexOf("covert") == -1) dp.properties.push(new Cola.AST_ObjectKeyVal({ key : "enumerable", @@ -472,10 +525,12 @@ Cola.DefFunWithMods = function(func, mods){ ? sname.property : new Cola.AST_String({ value: sname.property }), new Cola.AST_Object(dp)], - expression : new Cola.AST_Dot({ - expression : new Cola.AST_SymbolRef({ name: "Object" }), - property : "defineProperty" - }) + expression : func instanceof Cola.AST_Getter || func instanceof Cola.AST_Setter + ? new Cola.AST_SymbolRef({ name: "_ColaRuntime$$updateProperty" }) + : new Cola.AST_Dot({ + expression : new Cola.AST_SymbolRef({ name: "Object" }), + property : "defineProperty" + }) }); }; @@ -1067,7 +1122,10 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ 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; + 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"); @@ -1088,7 +1146,10 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ 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; + 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"); @@ -1105,13 +1166,15 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ Math.rand = function rand(){} */ - if(node instanceof Cola.AST_Defun && !(node.name instanceof Cola.AST_SymbolDefun)){ + if((node instanceof Cola.AST_Defun || node instanceof Cola.AST_Setter || node instanceof Cola.AST_Getter) && !(node.name instanceof Cola.AST_SymbolDefun)){ var texpr = node.name; while(!(texpr.expression instanceof Cola.AST_SymbolDefun)) texpr = texpr.expression; texpr.expression = new Cola.AST_SymbolRef(texpr.expression); node = Cola.DefFunWithMods(node, node.mods); + if(node instanceof Cola.AST_Call && node.expression instanceof Cola.AST_SymbolRef && node.expression.name == "_ColaRuntime$$updateProperty") _ColaRuntime$$hash[Cola._ColaRuntime$$updateProperty.i] = true; + node = new Cola.AST_SimpleStatement({ body : node }); @@ -1159,6 +1222,19 @@ Cola.AST_Toplevel.prototype.toJavaScript = function(options){ } } else + /* + class Test extends Test2 { + + int i = 123; + + Test(){ + + } + + } + + */ + /* func(String s, Number n:, Array list..., Boolean b = false, h: 123){