From 986269d9bb805dfc80e014d57773b26d382c1302 Mon Sep 17 00:00:00 2001 From: pmgl Date: Mon, 7 Nov 2022 14:56:18 +0100 Subject: [PATCH] delete variable or property, closes #155 (ms 2.0) --- .../languages/microscript/v2/compiler.coffee | 21 + .../js/languages/microscript/v2/compiler.js | 1419 +++++++++-------- .../js/languages/microscript/v2/parser.coffee | 9 + static/js/languages/microscript/v2/parser.js | 1373 ++++++++-------- .../languages/microscript/v2/processor.coffee | 7 + .../js/languages/microscript/v2/processor.js | 7 + .../languages/microscript/v2/program.coffee | 3 + static/js/languages/microscript/v2/program.js | 8 + .../languages/microscript/v2/routine.coffee | 2 + static/js/languages/microscript/v2/routine.js | 333 ++-- .../js/languages/microscript/v2/token.coffee | 1 + static/js/languages/microscript/v2/token.js | 16 +- static/lib/mode-microscript2.js | 4 +- 13 files changed, 1657 insertions(+), 1546 deletions(-) diff --git a/static/js/languages/microscript/v2/compiler.coffee b/static/js/languages/microscript/v2/compiler.coffee index e14d05b1..e87050b3 100644 --- a/static/js/languages/microscript/v2/compiler.coffee +++ b/static/js/languages/microscript/v2/compiler.coffee @@ -74,6 +74,8 @@ class Compiler return @compileDo(statement) else if statement instanceof Program.Sleep return @compileSleep(statement) + else if statement instanceof Program.Delete + return @compileDelete(statement) else if true console.info statement throw "Not implemented" @@ -655,6 +657,25 @@ class Compiler @routine.MUL sleep @routine.SLEEP sleep + compileDelete:(del)-> + if del.field instanceof Program.Variable + @routine.LOAD_THIS del + @routine.LOAD_VALUE del.field.identifier,del + @routine.DELETE del + return + else + @compile del.field.expression + + chain = del.field.chain + + for i in [0..chain.length-1] by 1 + @compile chain[i] + if i < chain.length-1 + @routine.LOAD_PROPERTY del + + @routine.DELETE del + return + exec:(context)-> @processor = new Processor() @processor.load @routine diff --git a/static/js/languages/microscript/v2/compiler.js b/static/js/languages/microscript/v2/compiler.js index cf2dae16..1a371726 100644 --- a/static/js/languages/microscript/v2/compiler.js +++ b/static/js/languages/microscript/v2/compiler.js @@ -1,120 +1,190 @@ var Compiler, LocalLayer; Compiler = (function() { - function Compiler(program) { - var i, j, len, ref, s; - this.program = program; - this.code_saves = []; - this.code = ""; - this.code = [this.code]; - this.routine = new Routine(); - this.locals = new Locals(this); - this.count = 0; - ref = this.program.statements; - for (i = j = 0, len = ref.length; j < len; i = ++j) { - s = ref[i]; - this.compile(s); - if (i < this.program.statements.length - 1) { - this.routine.POP(s); - } - } - this.routine.optimize(); - this.routine.resolveLabels(); - this.count += this.routine.opcodes.length; - this.routine.locals_size = this.locals.max_index; - } - - Compiler.prototype.compile = function(statement) { - if (statement instanceof Program.Value) { - return this.compileValue(statement); - } else if (statement instanceof Program.Operation) { - return this.compileOperation(statement); - } else if (statement instanceof Program.Assignment) { - return this.compileAssignment(statement); - } else if (statement instanceof Program.Variable) { - return this.compileVariable(statement); - } else if (statement instanceof Program.Function) { - return this.compileFunction(statement); - } else if (statement instanceof Program.FunctionCall) { - return this.compileFunctionCall(statement); - } else if (statement instanceof Program.While) { - return this.compileWhile(statement); - } - if (statement instanceof Program.SelfAssignment) { - return this.compileSelfAssignment(statement); - } else if (statement instanceof Program.Braced) { - return this.compileBraced(statement); - } else if (statement instanceof Program.CreateObject) { - return this.compileCreateObject(statement); - } else if (statement instanceof Program.Field) { - return this.compileField(statement); - } else if (statement instanceof Program.Negate) { - return this.compileNegate(statement); - } else if (statement instanceof Program.For) { - return this.compileFor(statement); - } else if (statement instanceof Program.ForIn) { - return this.compileForIn(statement); - } else if (statement instanceof Program.Not) { - return this.compileNot(statement); - } else if (statement instanceof Program.Return) { - return this.compileReturn(statement); - } else if (statement instanceof Program.Condition) { - return this.compileCondition(statement); - } else if (statement instanceof Program.Break) { - return this.compileBreak(statement); - } else if (statement instanceof Program.Continue) { - return this.compileContinue(statement); - } else if (statement instanceof Program.CreateClass) { - return this.compileCreateClass(statement); - } else if (statement instanceof Program.NewCall) { - return this.compileNewCall(statement); - } else if (statement instanceof Program.After) { - return this.compileAfter(statement); - } else if (statement instanceof Program.Every) { - return this.compileEvery(statement); - } else if (statement instanceof Program.Do) { - return this.compileDo(statement); - } else if (statement instanceof Program.Sleep) { - return this.compileSleep(statement); - } else if (true) { - console.info(statement); - throw "Not implemented"; + class Compiler { + constructor(program) { + var i, j, len, ref, s; + this.program = program; + this.code_saves = []; + this.code = ""; + this.code = [this.code]; + this.routine = new Routine(); + this.locals = new Locals(this); + this.count = 0; + ref = this.program.statements; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + s = ref[i]; + this.compile(s); + if (i < this.program.statements.length - 1) { + this.routine.POP(s); + } + } + this.routine.optimize(); + this.routine.resolveLabels(); + this.count += this.routine.opcodes.length; + this.routine.locals_size = this.locals.max_index; + } + + // console.info(@routine.toString()) + // console.info("total length: "+@count) + compile(statement) { + if (statement instanceof Program.Value) { + return this.compileValue(statement); + } else if (statement instanceof Program.Operation) { + return this.compileOperation(statement); + } else if (statement instanceof Program.Assignment) { + return this.compileAssignment(statement); + } else if (statement instanceof Program.Variable) { + return this.compileVariable(statement); + } else if (statement instanceof Program.Function) { + return this.compileFunction(statement); + } else if (statement instanceof Program.FunctionCall) { + return this.compileFunctionCall(statement); + } else if (statement instanceof Program.While) { + return this.compileWhile(statement); + } + if (statement instanceof Program.SelfAssignment) { + return this.compileSelfAssignment(statement); + } else if (statement instanceof Program.Braced) { + return this.compileBraced(statement); + } else if (statement instanceof Program.CreateObject) { + return this.compileCreateObject(statement); + } else if (statement instanceof Program.Field) { + return this.compileField(statement); + } else if (statement instanceof Program.Negate) { + return this.compileNegate(statement); + } else if (statement instanceof Program.For) { + return this.compileFor(statement); + } else if (statement instanceof Program.ForIn) { + return this.compileForIn(statement); + } else if (statement instanceof Program.Not) { + return this.compileNot(statement); + } else if (statement instanceof Program.Return) { + return this.compileReturn(statement); + } else if (statement instanceof Program.Condition) { + return this.compileCondition(statement); + } else if (statement instanceof Program.Break) { + return this.compileBreak(statement); + } else if (statement instanceof Program.Continue) { + return this.compileContinue(statement); + } else if (statement instanceof Program.CreateClass) { + return this.compileCreateClass(statement); + } else if (statement instanceof Program.NewCall) { + return this.compileNewCall(statement); + } else if (statement instanceof Program.After) { + return this.compileAfter(statement); + } else if (statement instanceof Program.Every) { + return this.compileEvery(statement); + } else if (statement instanceof Program.Do) { + return this.compileDo(statement); + } else if (statement instanceof Program.Sleep) { + return this.compileSleep(statement); + } else if (statement instanceof Program.Delete) { + return this.compileDelete(statement); + } else if (true) { + console.info(statement); + throw "Not implemented"; + } } - }; - Compiler.prototype.compileAssignment = function(statement) { - var arg_index, f, i, index, j, ref; - if (statement.local) { - if (statement.field instanceof Program.Variable) { - if (statement.expression instanceof Program.Function) { - index = this.locals.register(statement.field.identifier); - this.compile(statement.expression); - this.routine.arg1[this.routine.arg1.length - 1].import_self = index; - return this.routine.STORE_LOCAL(index, statement); - } else if (statement.expression instanceof Program.After || statement.expression instanceof Program.Do || statement.expression instanceof Program.Every) { - index = this.locals.register(statement.field.identifier); - arg_index = this.routine.arg1.length; - this.compile(statement.expression); - this.routine.arg1[arg_index].import_self = index; - return this.routine.STORE_LOCAL(index, statement); + compileAssignment(statement) { + var arg_index, f, i, index, j, ref; + if (statement.local) { + if (statement.field instanceof Program.Variable) { + if (statement.expression instanceof Program.Function) { + index = this.locals.register(statement.field.identifier); //# register function locally first + this.compile(statement.expression); //# then compile function which may refer to itself + this.routine.arg1[this.routine.arg1.length - 1].import_self = index; + return this.routine.STORE_LOCAL(index, statement); + } else if (statement.expression instanceof Program.After || statement.expression instanceof Program.Do || statement.expression instanceof Program.Every) { + index = this.locals.register(statement.field.identifier); //# register thread locally first + arg_index = this.routine.arg1.length; //# thread main routine will land here + this.compile(statement.expression); //# then compile function which may refer to itself + this.routine.arg1[arg_index].import_self = index; + return this.routine.STORE_LOCAL(index, statement); + } else { + this.compile(statement.expression); //# first compile expression which may refer to another local with same name + index = this.locals.register(statement.field.identifier); //# then register a local for that name + return this.routine.STORE_LOCAL(index, statement); + } } else { - this.compile(statement.expression); - index = this.locals.register(statement.field.identifier); - return this.routine.STORE_LOCAL(index, statement); + throw "illegal"; } } else { - throw "illegal"; + if (statement.field instanceof Program.Variable) { + if (this.locals.get(statement.field.identifier) != null) { + this.compile(statement.expression); + index = this.locals.get(statement.field.identifier); + this.routine.STORE_LOCAL(index, statement); + } else if (statement.expression instanceof Program.CreateClass) { + return this.compileUpdateClass(statement.expression, statement.field.identifier); + } else { + this.compile(statement.expression); + this.routine.STORE_VARIABLE(statement.field.identifier, statement); + } + } else { + f = statement.field; + if (f.expression instanceof Program.Variable) { + if (f.expression.identifier === "this") { + this.routine.LOAD_THIS(f); + } else if (this.locals.get(f.expression.identifier) != null) { + index = this.locals.get(f.expression.identifier); + this.routine.LOAD_LOCAL_OBJECT(index, f.expression); + } else if (f.expression.identifier === "global") { + this.routine.LOAD_GLOBAL(f); + } else { + this.routine.LOAD_VARIABLE_OBJECT(f.expression.identifier, statement); + } + } else { + this.compile(f.expression); + this.routine.MAKE_OBJECT(statement); + } + for (i = j = 0, ref = f.chain.length - 2; j <= ref; i = j += 1) { + this.compile(f.chain[i]); + this.routine.LOAD_PROPERTY_OBJECT(f.chain[i]); + } + this.compile(f.chain[f.chain.length - 1]); + this.compile(statement.expression); + return this.routine.STORE_PROPERTY(statement); + } + } + } + + compileSelfAssignment(statement) { + var c, f, i, index, j, op, ref; + switch (statement.operation) { + case Token.TYPE_PLUS_EQUALS: + op = "ADD"; + break; + case Token.TYPE_MINUS_EQUALS: + op = "SUB"; + break; + case Token.TYPE_MULTIPLY_EQUALS: + op = "MUL"; + break; + case Token.TYPE_DIVIDE_EQUALS: + op = "DIV"; + break; + case Token.TYPE_MODULO_EQUALS: + op = "MODULO"; + break; + case Token.TYPE_AND_EQUALS: + op = "BINARY_AND"; + break; + case Token.TYPE_OR_EQUALS: + op = "BINARY_OR"; } - } else { if (statement.field instanceof Program.Variable) { if (this.locals.get(statement.field.identifier) != null) { - this.compile(statement.expression); index = this.locals.get(statement.field.identifier); + this.routine.LOAD_LOCAL(index, statement); + this.compile(statement.expression); + this.routine[op](statement, 1); this.routine.STORE_LOCAL(index, statement); - } else if (statement.expression instanceof Program.CreateClass) { - return this.compileUpdateClass(statement.expression, statement.field.identifier); } else { + this.routine.LOAD_VARIABLE(statement.field.identifier, statement); this.compile(statement.expression); + this.routine[op](statement, 1); this.routine.STORE_VARIABLE(statement.field.identifier, statement); } } else { @@ -124,7 +194,7 @@ Compiler = (function() { this.routine.LOAD_THIS(f); } else if (this.locals.get(f.expression.identifier) != null) { index = this.locals.get(f.expression.identifier); - this.routine.LOAD_LOCAL_OBJECT(index, f.expression); + this.routine.LOAD_LOCAL_OBJECT(index, statement); } else if (f.expression.identifier === "global") { this.routine.LOAD_GLOBAL(f); } else { @@ -138,636 +208,593 @@ Compiler = (function() { this.compile(f.chain[i]); this.routine.LOAD_PROPERTY_OBJECT(f.chain[i]); } + c = f.chain[f.chain.length - 1]; this.compile(f.chain[f.chain.length - 1]); + this.routine.LOAD_PROPERTY_ATOP(statement); this.compile(statement.expression); + this.routine[op](statement, 1); return this.routine.STORE_PROPERTY(statement); } } - }; - Compiler.prototype.compileSelfAssignment = function(statement) { - var c, f, i, index, j, op, ref; - switch (statement.operation) { - case Token.TYPE_PLUS_EQUALS: - op = "ADD"; - break; - case Token.TYPE_MINUS_EQUALS: - op = "SUB"; - break; - case Token.TYPE_MULTIPLY_EQUALS: - op = "MUL"; - break; - case Token.TYPE_DIVIDE_EQUALS: - op = "DIV"; - break; - case Token.TYPE_MODULO_EQUALS: - op = "MODULO"; - break; - case Token.TYPE_AND_EQUALS: - op = "BINARY_AND"; - break; - case Token.TYPE_OR_EQUALS: - op = "BINARY_OR"; - } - if (statement.field instanceof Program.Variable) { - if (this.locals.get(statement.field.identifier) != null) { - index = this.locals.get(statement.field.identifier); - this.routine.LOAD_LOCAL(index, statement); - this.compile(statement.expression); - this.routine[op](statement, 1); - this.routine.STORE_LOCAL(index, statement); - } else { - this.routine.LOAD_VARIABLE(statement.field.identifier, statement); - this.compile(statement.expression); - this.routine[op](statement, 1); - this.routine.STORE_VARIABLE(statement.field.identifier, statement); - } - } else { - f = statement.field; - if (f.expression instanceof Program.Variable) { - if (f.expression.identifier === "this") { - this.routine.LOAD_THIS(f); - } else if (this.locals.get(f.expression.identifier) != null) { - index = this.locals.get(f.expression.identifier); - this.routine.LOAD_LOCAL_OBJECT(index, statement); - } else if (f.expression.identifier === "global") { - this.routine.LOAD_GLOBAL(f); - } else { - this.routine.LOAD_VARIABLE_OBJECT(f.expression.identifier, statement); + compileOperation(op) { + var jump, ref, ref1; + if ((ref = op.operation) === "+" || ref === "-" || ref === "*" || ref === "/" || ref === "%" || ref === "&" || ref === "|" || ref === "<<" || ref === ">>") { + this.compile(op.term1); + this.compile(op.term2); + switch (op.operation) { + case "+": + this.routine.ADD(op); + break; + case "-": + this.routine.SUB(op); + break; + case "*": + this.routine.MUL(op); + break; + case "/": + this.routine.DIV(op); + break; + case "%": + this.routine.MODULO(op); + break; + case "&": + this.routine.BINARY_AND(op); + break; + case "|": + this.routine.BINARY_OR(op); + break; + case "<<": + this.routine.SHIFT_LEFT(op); + break; + case ">>": + this.routine.SHIFT_RIGHT(op); } + } else if ((ref1 = op.operation) === "==" || ref1 === "!=" || ref1 === "<" || ref1 === ">" || ref1 === "<=" || ref1 === ">=") { + this.compile(op.term1); + this.compile(op.term2); + switch (op.operation) { + case "==": + this.routine.EQ(op); + break; + case "!=": + this.routine.NEQ(op); + break; + case "<": + this.routine.LT(op); + break; + case ">": + this.routine.GT(op); + break; + case "<=": + this.routine.LTE(op); + break; + case ">=": + this.routine.GTE(op); + } + } else if (op.operation === "and") { + jump = this.routine.createLabel("and"); + this.compile(op.term1); + this.routine.JUMPN_NOPOP(jump, op); + this.routine.POP(op); + this.compile(op.term2); + return this.routine.setLabel(jump); + } else if (op.operation === "or") { + jump = this.routine.createLabel("or"); + this.compile(op.term1); + this.routine.JUMPY_NOPOP(jump, op); + this.routine.POP(op); + this.compile(op.term2); + return this.routine.setLabel(jump); + } else if (op.operation === "^") { + this.compile(op.term1); + this.compile(op.term2); + return this.routine.BINARY_OP(Compiler.predefined_binary_functions.pow, op); } else { - this.compile(f.expression); - this.routine.MAKE_OBJECT(statement); - } - for (i = j = 0, ref = f.chain.length - 2; j <= ref; i = j += 1) { - this.compile(f.chain[i]); - this.routine.LOAD_PROPERTY_OBJECT(f.chain[i]); + return ""; } - c = f.chain[f.chain.length - 1]; - this.compile(f.chain[f.chain.length - 1]); - this.routine.LOAD_PROPERTY_ATOP(statement); - this.compile(statement.expression); - this.routine[op](statement, 1); - return this.routine.STORE_PROPERTY(statement); } - }; - Compiler.prototype.compileOperation = function(op) { - var jump, ref, ref1; - if ((ref = op.operation) === "+" || ref === "-" || ref === "*" || ref === "/" || ref === "%" || ref === "&" || ref === "|" || ref === "<<" || ref === ">>") { - this.compile(op.term1); - this.compile(op.term2); - switch (op.operation) { - case "+": - this.routine.ADD(op); - break; - case "-": - this.routine.SUB(op); - break; - case "*": - this.routine.MUL(op); - break; - case "/": - this.routine.DIV(op); - break; - case "%": - this.routine.MODULO(op); - break; - case "&": - this.routine.BINARY_AND(op); - break; - case "|": - this.routine.BINARY_OR(op); - break; - case "<<": - this.routine.SHIFT_LEFT(op); - break; - case ">>": - this.routine.SHIFT_RIGHT(op); - } - } else if ((ref1 = op.operation) === "==" || ref1 === "!=" || ref1 === "<" || ref1 === ">" || ref1 === "<=" || ref1 === ">=") { - this.compile(op.term1); - this.compile(op.term2); - switch (op.operation) { - case "==": - this.routine.EQ(op); - break; - case "!=": - this.routine.NEQ(op); - break; - case "<": - this.routine.LT(op); - break; - case ">": - this.routine.GT(op); - break; - case "<=": - this.routine.LTE(op); - break; - case ">=": - this.routine.GTE(op); - } - } else if (op.operation === "and") { - jump = this.routine.createLabel("and"); - this.compile(op.term1); - this.routine.JUMPN_NOPOP(jump, op); - this.routine.POP(op); - this.compile(op.term2); - return this.routine.setLabel(jump); - } else if (op.operation === "or") { - jump = this.routine.createLabel("or"); - this.compile(op.term1); - this.routine.JUMPY_NOPOP(jump, op); - this.routine.POP(op); - this.compile(op.term2); - return this.routine.setLabel(jump); - } else if (op.operation === "^") { - this.compile(op.term1); - this.compile(op.term2); - return this.routine.BINARY_OP(Compiler.predefined_binary_functions.pow, op); - } else { - return ""; + compileBraced(expression) { + this.compile(expression.expression); } - }; - Compiler.prototype.compileBraced = function(expression) { - this.compile(expression.expression); - }; + compileNegate(expression) { + if (expression.expression instanceof Program.Value && expression.expression.type === Program.Value.TYPE_NUMBER) { + return this.routine.LOAD_VALUE(-expression.expression.value, expression); + } else { + this.compile(expression.expression); + return this.routine.NEGATE(expression); + } + } - Compiler.prototype.compileNegate = function(expression) { - if (expression.expression instanceof Program.Value && expression.expression.type === Program.Value.TYPE_NUMBER) { - return this.routine.LOAD_VALUE(-expression.expression.value, expression); - } else { + compileNot(expression) { this.compile(expression.expression); - return this.routine.NEGATE(expression); + return this.routine.NOT(expression); } - }; - Compiler.prototype.compileNot = function(expression) { - this.compile(expression.expression); - return this.routine.NOT(expression); - }; - - Compiler.prototype.compileValue = function(value) { - var i, j, ref; - switch (value.type) { - case Program.Value.TYPE_NUMBER: - this.routine.LOAD_VALUE(value.value, value); - break; - case Program.Value.TYPE_STRING: - this.routine.LOAD_VALUE(value.value, value); - break; - case Program.Value.TYPE_ARRAY: - this.routine.CREATE_ARRAY(value); - for (i = j = 0, ref = value.value.length - 1; j <= ref; i = j += 1) { - this.routine.LOAD_VALUE(i, value); - this.compile(value.value[i]); - this.routine.CREATE_PROPERTY(value); - } + compileValue(value) { + var i, j, ref; + switch (value.type) { + case Program.Value.TYPE_NUMBER: + this.routine.LOAD_VALUE(value.value, value); + break; + case Program.Value.TYPE_STRING: + this.routine.LOAD_VALUE(value.value, value); + break; + case Program.Value.TYPE_ARRAY: + this.routine.CREATE_ARRAY(value); + for (i = j = 0, ref = value.value.length - 1; j <= ref; i = j += 1) { + this.routine.LOAD_VALUE(i, value); + this.compile(value.value[i]); + this.routine.CREATE_PROPERTY(value); + } + } } - }; - Compiler.prototype.compileVariable = function(variable) { - var index, v; - v = variable.identifier; - if (v === "this") { - return this.routine.LOAD_THIS(variable); - } else if (v === "global") { - return this.routine.LOAD_GLOBAL(variable); - } else if (Compiler.predefined_values[v] != null) { - return this.routine.LOAD_VALUE(Compiler.predefined_values[v], variable); - } else if (this.locals.get(v) != null) { - index = this.locals.get(v); - return this.routine.LOAD_LOCAL(index, variable); - } else { - return this.routine.LOAD_VARIABLE(v, variable); + compileVariable(variable) { + var index, v; + v = variable.identifier; + if (v === "this") { + return this.routine.LOAD_THIS(variable); + } else if (v === "global") { + return this.routine.LOAD_GLOBAL(variable); + } else if (Compiler.predefined_values[v] != null) { + return this.routine.LOAD_VALUE(Compiler.predefined_values[v], variable); + } else if (this.locals.get(v) != null) { + index = this.locals.get(v); + return this.routine.LOAD_LOCAL(index, variable); + } else { + return this.routine.LOAD_VARIABLE(v, variable); + } } - }; - Compiler.prototype.compileField = function(field) { - var c, i, id, index, j, k, len, ref, ref1; - c = field.chain[field.chain.length - 1]; - if (c instanceof Program.Value && c.value === "type") { - if (field.chain.length === 1) { - if (field.expression instanceof Program.Variable) { - id = field.expression.identifier; - if (this.locals.get(id) != null) { - index = this.locals.get(id); - this.routine.LOAD_LOCAL(index, field); - this.routine.TYPE(field); - } else if (Compiler.predefined_values[id] != null) { - this.routine.LOAD_VALUE("number", field); - } else if ((Compiler.predefined_unary_functions[id] != null) || Compiler.predefined_binary_functions[id]) { - this.routine.LOAD_VALUE("function", field); + compileField(field) { + var c, i, id, index, j, k, len, ref, ref1; + c = field.chain[field.chain.length - 1]; + if (c instanceof Program.Value && c.value === "type") { + if (field.chain.length === 1) { + if (field.expression instanceof Program.Variable) { // variable.type + id = field.expression.identifier; + if (this.locals.get(id) != null) { + index = this.locals.get(id); + this.routine.LOAD_LOCAL(index, field); + this.routine.TYPE(field); + } else if (Compiler.predefined_values[id] != null) { + this.routine.LOAD_VALUE("number", field); + } else if ((Compiler.predefined_unary_functions[id] != null) || Compiler.predefined_binary_functions[id]) { + this.routine.LOAD_VALUE("function", field); + } else { + this.routine.VARIABLE_TYPE(id, field.expression); + } } else { - this.routine.VARIABLE_TYPE(id, field.expression); + this.compile(field.expression); + this.routine.TYPE(field); } } else { this.compile(field.expression); - this.routine.TYPE(field); + for (i = j = 0, ref = field.chain.length - 3; j <= ref; i = j += 1) { + this.compile(field.chain[i]); + this.routine.LOAD_PROPERTY(field); + } + this.compile(field.chain[field.chain.length - 2]); + this.routine.PROPERTY_TYPE(field.expression); } } else { this.compile(field.expression); - for (i = j = 0, ref = field.chain.length - 3; j <= ref; i = j += 1) { - this.compile(field.chain[i]); + ref1 = field.chain; + for (k = 0, len = ref1.length; k < len; k++) { + c = ref1[k]; + this.compile(c); this.routine.LOAD_PROPERTY(field); } - this.compile(field.chain[field.chain.length - 2]); - this.routine.PROPERTY_TYPE(field.expression); } - } else { + } + + compileFieldParent(field) { + var c, i, j, ref; this.compile(field.expression); - ref1 = field.chain; - for (k = 0, len = ref1.length; k < len; k++) { - c = ref1[k]; + for (i = j = 0, ref = field.chain.length - 2; j <= ref; i = j += 1) { + c = field.chain[i]; this.compile(c); this.routine.LOAD_PROPERTY(field); } } - }; - - Compiler.prototype.compileFieldParent = function(field) { - var c, i, j, ref; - this.compile(field.expression); - for (i = j = 0, ref = field.chain.length - 2; j <= ref; i = j += 1) { - c = field.chain[i]; - this.compile(c); - this.routine.LOAD_PROPERTY(field); - } - }; - Compiler.prototype.compileFunctionCall = function(call) { - var a, funk, i, index, j, k, l, len, len1, len2, len3, len4, m, n, ref, ref1, ref2, ref3, ref4; - if (call.expression instanceof Program.Field) { - ref = call.args; - for (i = j = 0, len = ref.length; j < len; i = ++j) { - a = ref[i]; - this.compile(a); - } - this.compileFieldParent(call.expression); - this.compile(call.expression.chain[call.expression.chain.length - 1]); - return this.routine.FUNCTION_APPLY_PROPERTY(call.args.length, call); - } else if (call.expression instanceof Program.Variable) { - if (Compiler.predefined_unary_functions[call.expression.identifier] != null) { - funk = Compiler.predefined_unary_functions[call.expression.identifier]; - if (call.args.length > 0) { - this.compile(call.args[0]); - } else { - this.routine.LOAD_VALUE(0, call); - } - return this.routine.UNARY_OP(funk, call); - } else if (Compiler.predefined_binary_functions[call.expression.identifier] != null) { - funk = Compiler.predefined_binary_functions[call.expression.identifier]; - if (call.args.length > 0) { - this.compile(call.args[0]); - } else { - this.routine.LOAD_VALUE(0, call); + compileFunctionCall(call) { + var a, funk, i, index, j, k, l, len, len1, len2, len3, len4, m, n, ref, ref1, ref2, ref3, ref4; + if (call.expression instanceof Program.Field) { + ref = call.args; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + a = ref[i]; + this.compile(a); } - if (call.args.length > 1) { - this.compile(call.args[1]); + this.compileFieldParent(call.expression); + this.compile(call.expression.chain[call.expression.chain.length - 1]); + return this.routine.FUNCTION_APPLY_PROPERTY(call.args.length, call); + } else if (call.expression instanceof Program.Variable) { + if (Compiler.predefined_unary_functions[call.expression.identifier] != null) { + funk = Compiler.predefined_unary_functions[call.expression.identifier]; + if (call.args.length > 0) { + this.compile(call.args[0]); + } else { + this.routine.LOAD_VALUE(0, call); + } + return this.routine.UNARY_OP(funk, call); + } else if (Compiler.predefined_binary_functions[call.expression.identifier] != null) { + funk = Compiler.predefined_binary_functions[call.expression.identifier]; + if (call.args.length > 0) { + this.compile(call.args[0]); + } else { + this.routine.LOAD_VALUE(0, call); + } + if (call.args.length > 1) { + this.compile(call.args[1]); + } else { + this.routine.LOAD_VALUE(0, call); + } + return this.routine.BINARY_OP(funk, call); + } else if (call.expression.identifier === "super") { + ref1 = call.args; + for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) { + a = ref1[i]; + this.compile(a); + } + return this.routine.SUPER_CALL(call.args.length, call); + } else if (this.locals.get(call.expression.identifier) != null) { + ref2 = call.args; + for (i = l = 0, len2 = ref2.length; l < len2; i = ++l) { + a = ref2[i]; + this.compile(a); + } + index = this.locals.get(call.expression.identifier); + this.routine.LOAD_LOCAL(index, call); + return this.routine.FUNCTION_CALL(call.args.length, call); } else { - this.routine.LOAD_VALUE(0, call); - } - return this.routine.BINARY_OP(funk, call); - } else if (call.expression.identifier === "super") { - ref1 = call.args; - for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) { - a = ref1[i]; - this.compile(a); + ref3 = call.args; + for (i = m = 0, len3 = ref3.length; m < len3; i = ++m) { + a = ref3[i]; + this.compile(a); + } + this.routine.LOAD_VALUE(call.expression.identifier, call); + return this.routine.FUNCTION_APPLY_VARIABLE(call.args.length, call); } - return this.routine.SUPER_CALL(call.args.length, call); - } else if (this.locals.get(call.expression.identifier) != null) { - ref2 = call.args; - for (i = l = 0, len2 = ref2.length; l < len2; i = ++l) { - a = ref2[i]; + } else { + ref4 = call.args; + for (n = 0, len4 = ref4.length; n < len4; n++) { + a = ref4[n]; this.compile(a); } - index = this.locals.get(call.expression.identifier); - this.routine.LOAD_LOCAL(index, call); + this.compile(call.expression); return this.routine.FUNCTION_CALL(call.args.length, call); + } + } + + compileFor(forloop) { + var for_continue, for_end, for_start, iterator, save_break, save_continue; + iterator = this.locals.register(forloop.iterator); + this.locals.allocate(); // range_to + this.locals.allocate(); // step + this.compile(forloop.range_from); + this.routine.STORE_LOCAL(iterator, forloop); + this.routine.POP(forloop); + this.compile(forloop.range_to); + if (forloop.range_by !== 0) { + this.compile(forloop.range_by); } else { - ref3 = call.args; - for (i = m = 0, len3 = ref3.length; m < len3; i = ++m) { - a = ref3[i]; - this.compile(a); - } - this.routine.LOAD_VALUE(call.expression.identifier, call); - return this.routine.FUNCTION_APPLY_VARIABLE(call.args.length, call); + this.routine.LOAD_VALUE(0, forloop); } - } else { - ref4 = call.args; - for (n = 0, len4 = ref4.length; n < len4; n++) { - a = ref4[n]; - this.compile(a); + for_start = this.routine.createLabel("for_start"); + for_continue = this.routine.createLabel("for_continue"); + for_end = this.routine.createLabel("for_end"); + this.routine.FORLOOP_INIT([iterator, for_end], forloop); + this.routine.setLabel(for_start); + this.locals.push(); + save_break = this.break_label; + save_continue = this.continue_label; + this.break_label = for_end; + this.continue_label = for_continue; + this.compileSequence(forloop.sequence); + this.break_label = save_break; + this.continue_label = save_continue; + this.routine.setLabel(for_continue); + this.routine.FORLOOP_CONTROL([iterator, for_start], forloop); + this.routine.setLabel(for_end); + return this.locals.pop(); + } + + compileForIn(forloop) { + var for_continue, for_end, for_start, iterator, save_break, save_continue; + iterator = this.locals.register(forloop.iterator); + this.locals.allocate(); // array + this.locals.allocate(); // index + this.compile(forloop.list); + for_start = this.routine.createLabel("for_start"); + for_continue = this.routine.createLabel("for_continue"); + for_end = this.routine.createLabel("for_end"); + this.routine.FORIN_INIT([iterator, for_end], forloop); + this.routine.setLabel(for_start); + this.locals.push(); + save_break = this.break_label; + save_continue = this.continue_label; + this.break_label = for_end; + this.continue_label = for_continue; + this.compileSequence(forloop.sequence); + this.break_label = save_break; + this.continue_label = save_continue; + this.routine.setLabel(for_continue); + this.routine.FORIN_CONTROL([iterator, for_start], forloop); + this.routine.setLabel(for_end); + return this.locals.pop(); + } + + compileSequence(sequence) { + var i, j, ref; + for (i = j = 0, ref = sequence.length - 1; j <= ref; i = j += 1) { + if (!sequence[i].nopop) { + this.routine.POP(sequence[i]); + } + this.compile(sequence[i]); } - this.compile(call.expression); - return this.routine.FUNCTION_CALL(call.args.length, call); } - }; - Compiler.prototype.compileFor = function(forloop) { - var for_continue, for_end, for_start, iterator, save_break, save_continue; - iterator = this.locals.register(forloop.iterator); - this.locals.allocate(); - this.locals.allocate(); - this.compile(forloop.range_from); - this.routine.STORE_LOCAL(iterator, forloop); - this.routine.POP(forloop); - this.compile(forloop.range_to); - if (forloop.range_by !== 0) { - this.compile(forloop.range_by); - } else { - this.routine.LOAD_VALUE(0, forloop); - } - for_start = this.routine.createLabel("for_start"); - for_continue = this.routine.createLabel("for_continue"); - for_end = this.routine.createLabel("for_end"); - this.routine.FORLOOP_INIT([iterator, for_end], forloop); - this.routine.setLabel(for_start); - this.locals.push(); - save_break = this.break_label; - save_continue = this.continue_label; - this.break_label = for_end; - this.continue_label = for_continue; - this.compileSequence(forloop.sequence); - this.break_label = save_break; - this.continue_label = save_continue; - this.routine.setLabel(for_continue); - this.routine.FORLOOP_CONTROL([iterator, for_start], forloop); - this.routine.setLabel(for_end); - return this.locals.pop(); - }; - - Compiler.prototype.compileForIn = function(forloop) { - var for_continue, for_end, for_start, iterator, save_break, save_continue; - iterator = this.locals.register(forloop.iterator); - this.locals.allocate(); - this.locals.allocate(); - this.compile(forloop.list); - for_start = this.routine.createLabel("for_start"); - for_continue = this.routine.createLabel("for_continue"); - for_end = this.routine.createLabel("for_end"); - this.routine.FORIN_INIT([iterator, for_end], forloop); - this.routine.setLabel(for_start); - this.locals.push(); - save_break = this.break_label; - save_continue = this.continue_label; - this.break_label = for_end; - this.continue_label = for_continue; - this.compileSequence(forloop.sequence); - this.break_label = save_break; - this.continue_label = save_continue; - this.routine.setLabel(for_continue); - this.routine.FORIN_CONTROL([iterator, for_start], forloop); - this.routine.setLabel(for_end); - return this.locals.pop(); - }; - - Compiler.prototype.compileSequence = function(sequence) { - var i, j, ref; - for (i = j = 0, ref = sequence.length - 1; j <= ref; i = j += 1) { - if (!sequence[i].nopop) { - this.routine.POP(sequence[i]); + compileWhile(whiloop) { + var end, save_break, save_continue, start; + this.locals.push(); + start = this.routine.createLabel("while_start"); + end = this.routine.createLabel("while_end"); + this.routine.LOAD_VALUE(0, whiloop); + this.routine.setLabel(start); + this.compile(whiloop.condition); + this.routine.JUMPN(end); + save_break = this.break_label; + save_continue = this.continue_label; + this.break_label = end; + this.continue_label = start; + this.compileSequence(whiloop.sequence); + this.routine.JUMP(start, whiloop); + this.break_label = save_break; + this.continue_label = save_continue; + this.routine.setLabel(end); + return this.locals.pop(); + } + + compileBreak(statement) { + if (this.break_label != null) { + return this.routine.JUMP(this.break_label); } - this.compile(sequence[i]); } - }; - Compiler.prototype.compileWhile = function(whiloop) { - var end, save_break, save_continue, start; - this.locals.push(); - start = this.routine.createLabel("while_start"); - end = this.routine.createLabel("while_end"); - this.routine.LOAD_VALUE(0, whiloop); - this.routine.setLabel(start); - this.compile(whiloop.condition); - this.routine.JUMPN(end); - save_break = this.break_label; - save_continue = this.continue_label; - this.break_label = end; - this.continue_label = start; - this.compileSequence(whiloop.sequence); - this.routine.JUMP(start, whiloop); - this.break_label = save_break; - this.continue_label = save_continue; - this.routine.setLabel(end); - return this.locals.pop(); - }; - - Compiler.prototype.compileBreak = function(statement) { - if (this.break_label != null) { - return this.routine.JUMP(this.break_label); + compileContinue(statement) { + if (this.continue_label != null) { + return this.routine.JUMP(this.continue_label); + } } - }; - Compiler.prototype.compileContinue = function(statement) { - if (this.continue_label != null) { - return this.routine.JUMP(this.continue_label); + compileFunction(func) { + var r; + r = this.compileFunctionBody(func); + return this.routine.LOAD_ROUTINE(r, func); } - }; - - Compiler.prototype.compileFunction = function(func) { - var r; - r = this.compileFunctionBody(func); - return this.routine.LOAD_ROUTINE(r, func); - }; - Compiler.prototype.compileFunctionBody = function(func) { - var a, i, index, j, k, l, label, len, local_index, locals, m, r, ref, ref1, ref2, ref3, routine; - routine = this.routine; - locals = this.locals; - this.routine = new Routine(func.args != null ? func.args.length : 0); - this.locals = new Locals(this, locals); - local_index = this.locals.index; - if (func.args != null) { - for (i = j = ref = func.args.length - 1; j >= 0; i = j += -1) { - a = func.args[i]; - index = this.locals.register(a.name); - this.routine.STORE_LOCAL(index, func); - this.routine.POP(func); - } - for (i = k = 0, ref1 = func.args.length - 1; k <= ref1; i = k += 1) { - a = func.args[i]; - if (a["default"] != null) { - index = this.locals.get(a.name); - label = this.routine.createLabel("default_arg"); - this.routine.LOAD_LOCAL(index, func); - this.routine.JUMPY(label, func); - this.compile(a["default"]); + compileFunctionBody(func) { + var a, i, index, j, k, l, label, len, local_index, locals, m, r, ref, ref1, ref2, ref3, routine; + routine = this.routine; + locals = this.locals; + this.routine = new Routine(func.args != null ? func.args.length : 0); + this.locals = new Locals(this, locals); + local_index = this.locals.index; + if (func.args != null) { + for (i = j = ref = func.args.length - 1; j >= 0; i = j += -1) { + a = func.args[i]; + index = this.locals.register(a.name); this.routine.STORE_LOCAL(index, func); this.routine.POP(func); - this.routine.setLabel(label); + } + for (i = k = 0, ref1 = func.args.length - 1; k <= ref1; i = k += 1) { + a = func.args[i]; + if (a.default != null) { + index = this.locals.get(a.name); + label = this.routine.createLabel("default_arg"); + this.routine.LOAD_LOCAL(index, func); + this.routine.JUMPY(label, func); + this.compile(a.default); + this.routine.STORE_LOCAL(index, func); + this.routine.POP(func); + this.routine.setLabel(label); + } } } - } - if (func.sequence.length > 0) { - for (i = l = 0, ref2 = func.sequence.length - 1; l <= ref2; i = l += 1) { - this.compile(func.sequence[i]); - if (i < func.sequence.length - 1) { - this.routine.POP(func.sequence[i]); - } else { - this.routine.RETURN(func.sequence[i]); + if (func.sequence.length > 0) { + for (i = l = 0, ref2 = func.sequence.length - 1; l <= ref2; i = l += 1) { + this.compile(func.sequence[i]); + if (i < func.sequence.length - 1) { + this.routine.POP(func.sequence[i]); + } else { + this.routine.RETURN(func.sequence[i]); + } } + } else { + this.routine.LOAD_VALUE(0, func); + this.routine.RETURN(func); + } + index = 0; + ref3 = this.locals.imports; + for (m = 0, len = ref3.length; m < len; m++) { + i = ref3[m]; + this.routine.OP_INSERT(OPCODES.LOAD_IMPORT, func, index, index * 3); + this.routine.OP_INSERT(OPCODES.STORE_LOCAL, func, i.index, index * 3 + 1); + this.routine.OP_INSERT(OPCODES.POP, func, 0, index * 3 + 2); + this.routine.import_refs.push(i.source); + index += 1; + } + this.routine.optimize(); + this.routine.resolveLabels(); + this.count += this.routine.opcodes.length; + r = this.routine; + // console.info r.toString() + this.routine.locals_size = this.locals.max_index; + this.routine = routine; + this.locals = locals; + return r; + } + + compileReturn(ret) { + if (ret.expression != null) { + this.compile(ret.expression); + return this.routine.RETURN(ret); + } else { + this.routine.LOAD_VALUE(0, ret); + return this.routine.RETURN(ret); } - } else { - this.routine.LOAD_VALUE(0, func); - this.routine.RETURN(func); - } - index = 0; - ref3 = this.locals.imports; - for (m = 0, len = ref3.length; m < len; m++) { - i = ref3[m]; - this.routine.OP_INSERT(OPCODES.LOAD_IMPORT, func, index, index * 3); - this.routine.OP_INSERT(OPCODES.STORE_LOCAL, func, i.index, index * 3 + 1); - this.routine.OP_INSERT(OPCODES.POP, func, 0, index * 3 + 2); - this.routine.import_refs.push(i.source); - index += 1; - } - this.routine.optimize(); - this.routine.resolveLabels(); - this.count += this.routine.opcodes.length; - r = this.routine; - this.routine.locals_size = this.locals.max_index; - this.routine = routine; - this.locals = locals; - return r; - }; - - Compiler.prototype.compileReturn = function(ret) { - if (ret.expression != null) { - this.compile(ret.expression); - return this.routine.RETURN(ret); - } else { - this.routine.LOAD_VALUE(0, ret); - return this.routine.RETURN(ret); } - }; - Compiler.prototype.compileCondition = function(condition) { - var c, chain, condition_end, condition_next, i, j, ref; - chain = condition.chain; - this.routine.LOAD_VALUE(0, condition); - condition_end = this.routine.createLabel("condition_end"); - for (i = j = 0, ref = chain.length - 1; j <= ref; i = j += 1) { - condition_next = this.routine.createLabel("condition_next"); - c = chain[i]; - this.compile(c.condition); - this.routine.JUMPN(condition_next); - this.locals.push(); - this.compileSequence(c.sequence); - this.locals.pop(); - this.routine.JUMP(condition_end, condition); - this.routine.setLabel(condition_next); - if (i === chain.length - 1 && (c["else"] != null)) { + compileCondition(condition) { + var c, chain, condition_end, condition_next, i, j, ref; + chain = condition.chain; + this.routine.LOAD_VALUE(0, condition); + condition_end = this.routine.createLabel("condition_end"); + for (i = j = 0, ref = chain.length - 1; j <= ref; i = j += 1) { + condition_next = this.routine.createLabel("condition_next"); + c = chain[i]; + this.compile(c.condition); + this.routine.JUMPN(condition_next); this.locals.push(); - this.compileSequence(c["else"]); + this.compileSequence(c.sequence); this.locals.pop(); + this.routine.JUMP(condition_end, condition); + this.routine.setLabel(condition_next); + if (i === chain.length - 1 && (c.else != null)) { + this.locals.push(); + this.compileSequence(c.else); + this.locals.pop(); + } } + this.routine.setLabel(condition_end); } - this.routine.setLabel(condition_end); - }; - Compiler.prototype.formatField = function(field) { - if (field === "constructor") { - field = "_constructor"; + formatField(field) { + if (field === "constructor") { + field = "_constructor"; + } + return field.toString().replace(/"/g, "\\\""); + } + + compileCreateObject(statement) { + var f, j, len, ref; + this.routine.CREATE_OBJECT(statement); + ref = statement.fields; + for (j = 0, len = ref.length; j < len; j++) { + f = ref[j]; + this.routine.LOAD_VALUE(f.field, statement); + this.compile(f.value); + this.routine.CREATE_PROPERTY(statement); + } } - return field.toString().replace(/"/g, "\\\""); - }; - Compiler.prototype.compileCreateObject = function(statement) { - var f, j, len, ref; - this.routine.CREATE_OBJECT(statement); - ref = statement.fields; - for (j = 0, len = ref.length; j < len; j++) { - f = ref[j]; - this.routine.LOAD_VALUE(f.field, statement); - this.compile(f.value); - this.routine.CREATE_PROPERTY(statement); + compileCreateClass(statement) { + var f, j, len, ref, variable; + if (statement.ext != null) { + statement.ext.nowarning = true; + this.compile(statement.ext); + } else { + this.routine.LOAD_VALUE(0, statement); + } + variable = (statement.ext != null) && statement.ext instanceof Program.Variable ? statement.ext.identifier : 0; + this.routine.CREATE_CLASS(variable, statement); + ref = statement.fields; + for (j = 0, len = ref.length; j < len; j++) { + f = ref[j]; + this.routine.LOAD_VALUE(f.field, statement); + this.compile(f.value); + this.routine.CREATE_PROPERTY(statement); + } } - }; - Compiler.prototype.compileCreateClass = function(statement) { - var f, j, len, ref, variable; - if (statement.ext != null) { - statement.ext.nowarning = true; - this.compile(statement.ext); - } else { - this.routine.LOAD_VALUE(0, statement); + compileUpdateClass(statement, variable) { + this.compileCreateClass(statement); + return this.routine.UPDATE_CLASS(variable, statement); } - variable = (statement.ext != null) && statement.ext instanceof Program.Variable ? statement.ext.identifier : 0; - this.routine.CREATE_CLASS(variable, statement); - ref = statement.fields; - for (j = 0, len = ref.length; j < len; j++) { - f = ref[j]; - this.routine.LOAD_VALUE(f.field, statement); - this.compile(f.value); - this.routine.CREATE_PROPERTY(statement); - } - }; - Compiler.prototype.compileUpdateClass = function(statement, variable) { - this.compileCreateClass(statement); - return this.routine.UPDATE_CLASS(variable, statement); - }; + compileNewCall(statement) { + var a, call, i, j, len, ref; + call = statement.expression; + this.routine.LOAD_VALUE(0, statement); // reserve spot on stack for the class instance + ref = call.args; + for (i = j = 0, len = ref.length; j < len; i = ++j) { + a = ref[i]; + this.compile(a); + } + this.compile(call.expression); + this.routine.NEW_CALL(call.args.length, statement); + return this.routine.POP(statement); // pop return value of class constructor + } + + compileAfter(after) { + var r; + r = this.compileFunctionBody(after); + this.routine.LOAD_ROUTINE(r, after); + this.compile(after.delay); + if ((after.multiplier != null) && after.multiplier !== 1) { + this.routine.LOAD_VALUE(after.multiplier, after); + this.routine.MUL(after); + } + return this.routine.AFTER(after); + } - Compiler.prototype.compileNewCall = function(statement) { - var a, call, i, j, len, ref; - call = statement.expression; - this.routine.LOAD_VALUE(0, statement); - ref = call.args; - for (i = j = 0, len = ref.length; j < len; i = ++j) { - a = ref[i]; - this.compile(a); - } - this.compile(call.expression); - this.routine.NEW_CALL(call.args.length, statement); - return this.routine.POP(statement); - }; + compileEvery(every) { + var r; + r = this.compileFunctionBody(every); + this.routine.LOAD_ROUTINE(r, every); + this.compile(every.delay); + if ((every.multiplier != null) && every.multiplier !== 1) { + this.routine.LOAD_VALUE(every.multiplier, every); + this.routine.MUL(every); + } + return this.routine.EVERY(every); + } - Compiler.prototype.compileAfter = function(after) { - var r; - r = this.compileFunctionBody(after); - this.routine.LOAD_ROUTINE(r, after); - this.compile(after.delay); - if ((after.multiplier != null) && after.multiplier !== 1) { - this.routine.LOAD_VALUE(after.multiplier, after); - this.routine.MUL(after); + compileDo(dostuff) { + var r; + r = this.compileFunctionBody(dostuff); + this.routine.LOAD_ROUTINE(r, dostuff); + return this.routine.DO(dostuff); } - return this.routine.AFTER(after); - }; - Compiler.prototype.compileEvery = function(every) { - var r; - r = this.compileFunctionBody(every); - this.routine.LOAD_ROUTINE(r, every); - this.compile(every.delay); - if ((every.multiplier != null) && every.multiplier !== 1) { - this.routine.LOAD_VALUE(every.multiplier, every); - this.routine.MUL(every); + compileSleep(sleep) { + this.compile(sleep.delay); + if ((sleep.multiplier != null) && sleep.multiplier !== 1) { + this.routine.LOAD_VALUE(sleep.multiplier, sleep); + this.routine.MUL(sleep); + } + return this.routine.SLEEP(sleep); } - return this.routine.EVERY(every); - }; - Compiler.prototype.compileDo = function(dostuff) { - var r; - r = this.compileFunctionBody(dostuff); - this.routine.LOAD_ROUTINE(r, dostuff); - return this.routine.DO(dostuff); - }; + compileDelete(del) { + var chain, i, j, ref; + if (del.field instanceof Program.Variable) { + this.routine.LOAD_THIS(del); + this.routine.LOAD_VALUE(del.field.identifier, del); + this.routine.DELETE(del); + } else { + this.compile(del.field.expression); + chain = del.field.chain; + for (i = j = 0, ref = chain.length - 1; j <= ref; i = j += 1) { + this.compile(chain[i]); + if (i < chain.length - 1) { + this.routine.LOAD_PROPERTY(del); + } + } + this.routine.DELETE(del); + } + } - Compiler.prototype.compileSleep = function(sleep) { - this.compile(sleep.delay); - if ((sleep.multiplier != null) && sleep.multiplier !== 1) { - this.routine.LOAD_VALUE(sleep.multiplier, sleep); - this.routine.MUL(sleep); + exec(context) { + this.processor = new Processor(); + this.processor.load(this.routine); + return this.processor.run(context); } - return this.routine.SLEEP(sleep); - }; - Compiler.prototype.exec = function(context) { - this.processor = new Processor(); - this.processor.load(this.routine); - return this.processor.run(context); }; Compiler.predefined_unary_functions = { @@ -816,18 +843,45 @@ Compiler = (function() { Compiler.predefined_values = { PI: Math.PI, - "true": 1, - "false": 0 + true: 1, + false: 0 }; return Compiler; -})(); - -this.Locals = (function() { - function Locals(compiler, parent) { +}).call(this); + +// meta.global +// meta.print + +// meta.sin = (x)->Math.sin(x) +// meta.cos = (x)->Math.cos(x) +// meta.tan = (x)->Math.tan(x) +// meta.acos = (x)->Math.acos(x) +// meta.asin = (x)->Math.asin(x) +// meta.atan = (x)->Math.atan(x) +// meta.atan2 = (y,x)->Math.atan2(y,x) + +// meta.sind = (x)->Math.sin(x/180*Math.PI) +// meta.cosd = (x)->Math.cos(x/180*Math.PI) +// meta.tand = (x)->Math.tan(x/180*Math.PI) +// meta.acosd = (x)->Math.acos(x)*180/Math.PI +// meta.asind = (x)->Math.asin(x)*180/Math.PI +// meta.atand = (x)->Math.atan(x)*180/Math.PI +// meta.atan2d = (y,x)->Math.atan2(y,x)*180/Math.PI + +// meta.log = (x)->Math.log(x) +// meta.exp = (x)->Math.exp(x) + +// meta.random = new Random(0) + +// meta.PI = Math.PI +// meta.true = 1 +// meta.false = 0 +this.Locals = class Locals { + constructor(compiler, parent = null) { this.compiler = compiler; - this.parent = parent != null ? parent : null; + this.parent = parent; this.layers = []; this.index = 0; this.max_index = 0; @@ -835,30 +889,33 @@ this.Locals = (function() { this.imports = []; } - Locals.prototype.increment = function() { + increment() { var spot; spot = this.index++; this.max_index = Math.max(this.index, this.max_index); return spot; - }; + } - Locals.prototype.push = function() { + push() { return this.layers.push(new LocalLayer(this)); - }; + } - Locals.prototype.pop = function() { + pop() { + // resetting the @index below was causing erasure of outer locals + // when used after the block ; such reset is not needed + //@index = @layers[@layers.length-1].start_index return this.layers.splice(this.layers.length - 1, 1); - }; + } - Locals.prototype.register = function(name) { + register(name) { return this.layers[this.layers.length - 1].register(name); - }; + } - Locals.prototype.allocate = function() { + allocate() { return this.layers[this.layers.length - 1].allocate(); - }; + } - Locals.prototype.get = function(name) { + get(name) { var i, index, j, ref, v; for (i = j = ref = this.layers.length - 1; j >= 0; i = j += -1) { v = this.layers[i].get(name); @@ -879,35 +936,31 @@ this.Locals = (function() { } } return null; - }; - - return Locals; + } -})(); +}; -LocalLayer = (function() { - function LocalLayer(locals1) { +LocalLayer = class LocalLayer { + constructor(locals1) { this.locals = locals1; this.start_index = this.locals.index; this.registered = {}; } - LocalLayer.prototype.register = function(name) { + register(name) { return this.registered[name] = this.locals.increment(); - }; + } - LocalLayer.prototype.allocate = function() { + allocate() { return this.locals.increment(); - }; + } - LocalLayer.prototype.get = function(name) { + get(name) { if (this.registered[name] != null) { return this.registered[name]; } else { return null; } - }; - - return LocalLayer; + } -})(); +}; diff --git a/static/js/languages/microscript/v2/parser.coffee b/static/js/languages/microscript/v2/parser.coffee index dd6feade..d22a29ac 100644 --- a/static/js/languages/microscript/v2/parser.coffee +++ b/static/js/languages/microscript/v2/parser.coffee @@ -221,6 +221,7 @@ class @Parser when Token.TYPE_EVERY then @parseEvery token when Token.TYPE_DO then @parseDo token when Token.TYPE_SLEEP then @parseSleep token + when Token.TYPE_DELETE then @parseDelete token else @tokenizer.pushBack token @@ -659,3 +660,11 @@ class @Parser @tokenizer.pushBack token return new Program.Sleep sleep,delay,multiplier + + parseDelete:(del)-> + v = @parseExpression() + + if not v? or (v not instanceof Program.Variable and v not instanceof Program.Field) + @error "expecting variable name or property access after keyword `delete`" + else + return new Program.Delete del,v \ No newline at end of file diff --git a/static/js/languages/microscript/v2/parser.js b/static/js/languages/microscript/v2/parser.js index 0a282ff0..c9696477 100644 --- a/static/js/languages/microscript/v2/parser.js +++ b/static/js/languages/microscript/v2/parser.js @@ -1,801 +1,812 @@ this.Parser = (function() { - function Parser(input, filename) { - this.input = input; - this.filename = filename != null ? filename : ""; - if (/^\s*\/\/\s*javascript\s*\n/.test(this.input)) { - this.input = 'system.javascript("""\n\n' + this.input.replace(/\\/g, "\\\\") + '\n\n""")'; - } - this.tokenizer = new Tokenizer(this.input, this.filename); - this.program = new Program(); - this.current_block = []; - this.current = { - line: 1, - column: 1 - }; - this.verbose = false; - this.nesting = 0; - this.object_nesting = 0; - this.not_terminated = []; - this.api_reserved = { - screen: true, - audio: true, - keyboard: true, - gamepad: true, - sprites: true, - sounds: true, - music: true, - assets: true, - asset_manager: true, - maps: true, - touch: true, - mouse: true, - fonts: true, - Sound: true, - Image: true, - Sprite: true, - Map: true, - system: true, - storage: true, - print: true, - random: true, - Function: true, - List: true, - Object: true, - String: true, - Number: true - }; - } - - Parser.prototype.nextToken = function() { - var token; - token = this.tokenizer.next(); - if (token == null) { - this.unexpected_eof = true; - throw "Unexpected end of file"; - } - return this.current = token; - }; - - Parser.prototype.nextTokenOptional = function() { - var token; - token = this.tokenizer.next(); - if (token != null) { - this.current = token; + class Parser { + constructor(input, filename = "") { + this.input = input; + this.filename = filename; + if (/^\s*\/\/\s*javascript\s*\n/.test(this.input)) { + this.input = 'system.javascript("""\n\n' + this.input.replace(/\\/g, "\\\\") + '\n\n""")'; + } + this.tokenizer = new Tokenizer(this.input, this.filename); + this.program = new Program(); + this.current_block = []; + this.current = { + line: 1, + column: 1 + }; + this.verbose = false; + this.nesting = 0; + this.object_nesting = 0; + this.not_terminated = []; + this.api_reserved = { + screen: true, + audio: true, + keyboard: true, + gamepad: true, + sprites: true, + sounds: true, + music: true, + assets: true, + asset_manager: true, + maps: true, + touch: true, + mouse: true, + fonts: true, + Sound: true, + Image: true, + Sprite: true, + Map: true, + system: true, + storage: true, + print: true, + random: true, + Function: true, + List: true, + Object: true, + String: true, + Number: true + }; + } + + nextToken() { + var token; + token = this.tokenizer.next(); + if (token == null) { + this.unexpected_eof = true; + throw "Unexpected end of file"; + } + return this.current = token; } - return token; - }; - Parser.prototype.parse = function() { - var err, expression, nt, token; - try { - this.warnings = []; - while (true) { - expression = this.parseLine(); - if ((expression == null) && !this.tokenizer.finished()) { - token = this.tokenizer.next(); - if ((token != null) && token.reserved_keyword) { - if (token.value === "end") { - this.error("Too many 'end'"); + nextTokenOptional() { + var token; + token = this.tokenizer.next(); + if (token != null) { + this.current = token; + } + return token; + } + + parse() { + var err, expression, nt, token; + try { + this.warnings = []; + while (true) { + expression = this.parseLine(); + if ((expression == null) && !this.tokenizer.finished()) { + token = this.tokenizer.next(); + if ((token != null) && token.reserved_keyword) { + if (token.value === "end") { + this.error("Too many 'end'"); + } else { + this.error(`Misuse of reserved keyword: '${token.value}'`); + } } else { - this.error("Misuse of reserved keyword: '" + token.value + "'"); + this.error("Unexpected data"); } - } else { - this.error("Unexpected data"); + } + if (expression === null) { + break; + } + this.current_block.push(expression); + this.program.add(expression); + if (this.verbose) { + console.info(expression); } } - if (expression === null) { - break; - } - this.current_block.push(expression); - this.program.add(expression); - if (this.verbose) { - console.info(expression); + return this; + } catch (error1) { + err = error1; + //console.info "Error at line: #{@current.line} column: #{@current.column}" + if (this.not_terminated.length > 0 && err === "Unexpected end of file") { + nt = this.not_terminated[this.not_terminated.length - 1]; + return this.error_info = { + error: `Unterminated '${nt.value}' ; no matching 'end' found`, + line: nt.line, + column: nt.column + }; + } else { + return this.error_info = { + error: err, + line: this.current.line, + column: this.current.column + }; } } - return this; - } catch (error1) { - err = error1; - if (this.not_terminated.length > 0 && err === "Unexpected end of file") { - nt = this.not_terminated[this.not_terminated.length - 1]; - return this.error_info = { - error: "Unterminated '" + nt.value + "' ; no matching 'end' found", - line: nt.line, - column: nt.column - }; - } else { - return this.error_info = { - error: err, - line: this.current.line, - column: this.current.column - }; - } - } - }; - - Parser.prototype.parseLine = function() { - var token; - token = this.nextTokenOptional(); - if (token == null) { - return null; - } - switch (token.type) { - case Token.TYPE_RETURN: - return new Program.Return(token, this.parseExpression()); - case Token.TYPE_BREAK: - return new Program.Break(token); - case Token.TYPE_CONTINUE: - return new Program.Continue(token); - case Token.TYPE_LOCAL: - return this.parseLocalAssignment(token); - default: - this.tokenizer.pushBack(token); - return this.parseExpression(); } - }; - Parser.prototype.parseExpression = function(filter, first_function_call) { - var access, expression; - if (first_function_call == null) { - first_function_call = false; - } - expression = this.parseExpressionStart(); - if (expression == null) { - return null; - } - while (true) { - access = this.parseExpressionSuffix(expression, filter); - if (access == null) { - return expression; + //console.error err + parseLine() { + var token; + token = this.nextTokenOptional(); + if (token == null) { + return null; } - if (first_function_call && access instanceof Program.FunctionCall) { - return access; + switch (token.type) { + case Token.TYPE_RETURN: + return new Program.Return(token, this.parseExpression()); + case Token.TYPE_BREAK: + return new Program.Break(token); + case Token.TYPE_CONTINUE: + return new Program.Continue(token); + case Token.TYPE_LOCAL: + return this.parseLocalAssignment(token); + default: + this.tokenizer.pushBack(token); + return this.parseExpression(); } - expression = access; } - }; - Parser.prototype.assertExpression = function(filter, first_function_call) { - var exp; - if (first_function_call == null) { - first_function_call = false; - } - exp = this.parseExpression(filter, first_function_call); - if (exp == null) { - throw "Expression expected"; - } - return exp; - }; - - Parser.prototype.parseExpressionSuffix = function(expression, filter) { - var field, identifier, token; - token = this.nextTokenOptional(); - if (token == null) { - return (filter === "self" ? expression : null); - } - switch (token.type) { - case Token.TYPE_DOT: - if (expression instanceof Program.Value && expression.type === Program.Value.TYPE_NUMBER) { - this.tokenizer.pushBack(token); - return null; - } else { - this.tokenizer.changeNumberToIdentifier(); - identifier = this.assertBroadIdentifier("Expected identifier"); - return Program.CreateFieldAccess(token, expression, new Program.Value(identifier, Program.Value.TYPE_STRING, identifier.value)); - } - break; - case Token.TYPE_OPEN_BRACKET: - field = this.assertExpression(); - this.assert(Token.TYPE_CLOSED_BRACKET, "Expected ']'"); - return Program.CreateFieldAccess(token, expression, field); - case Token.TYPE_OPEN_BRACE: - return this.parseFunctionCall(token, expression); - case Token.TYPE_EQUALS: - return this.parseAssignment(token, expression); - case Token.TYPE_PLUS_EQUALS: - return this.parseSelfAssignment(token, expression, token.type); - case Token.TYPE_MINUS_EQUALS: - return this.parseSelfAssignment(token, expression, token.type); - case Token.TYPE_MULTIPLY_EQUALS: - return this.parseSelfAssignment(token, expression, token.type); - case Token.TYPE_DIVIDE_EQUALS: - return this.parseSelfAssignment(token, expression, token.type); - case Token.TYPE_MODULO_EQUALS: - case Token.TYPE_AND_EQUALS: - case Token.TYPE_OR_EQUALS: - return this.parseSelfAssignment(token, expression, token.type); - default: - if (filter === "self") { - this.tokenizer.pushBack(token); + parseExpression(filter, first_function_call = false) { + var access, expression; + expression = this.parseExpressionStart(); + if (expression == null) { + return null; + } + while (true) { + access = this.parseExpressionSuffix(expression, filter); + if (access == null) { return expression; - } else if (token.is_binary_operator && filter !== "noop") { - return this.parseBinaryOperation(token, expression); - } else { - this.tokenizer.pushBack(token); - return null; } - } - }; - - Parser.prototype.parseExpressionStart = function() { - var next, token; - token = this.nextTokenOptional(); - if (token == null) { - return null; - } - switch (token.type) { - case Token.TYPE_IDENTIFIER: - return new Program.Variable(token, token.value); - case Token.TYPE_NUMBER: - return this.parseNumberExpression(token); - case Token.TYPE_PLUS: - return this.assertExpression(); - case Token.TYPE_MINUS: - return this.parseExpressionSuffix(new Program.Negate(token, this.assertExpression("noop")), "self"); - case Token.TYPE_NOT: - return this.parseExpressionSuffix(new Program.Not(token, this.assertExpression("noop")), "self"); - case Token.TYPE_STRING: - return this.parseStringExpression(token); - case Token.TYPE_IF: - return this.parseIf(token); - case Token.TYPE_FOR: - return this.parseFor(token); - case Token.TYPE_WHILE: - return this.parseWhile(token); - case Token.TYPE_OPEN_BRACE: - return this.parseBracedExpression(token); - case Token.TYPE_OPEN_BRACKET: - return this.parseArray(token); - case Token.TYPE_FUNCTION: - return this.parseFunction(token); - case Token.TYPE_OBJECT: - return this.parseObject(token); - case Token.TYPE_CLASS: - return this.parseClass(token); - case Token.TYPE_NEW: - return this.parseNew(token); - case Token.TYPE_DOT: - next = this.assert(Token.TYPE_NUMBER, "malformed number"); - if (!Number.isInteger(next.value)) { - throw "malformed number"; + if (first_function_call && access instanceof Program.FunctionCall) { + return access; } - return new Program.Value(token, Program.Value.TYPE_NUMBER, Number.parseFloat("." + next.string_value)); - case Token.TYPE_AFTER: - return this.parseAfter(token); - case Token.TYPE_EVERY: - return this.parseEvery(token); - case Token.TYPE_DO: - return this.parseDo(token); - case Token.TYPE_SLEEP: - return this.parseSleep(token); - default: - this.tokenizer.pushBack(token); - return null; - } - }; - - Parser.prototype.parseNumberExpression = function(number) { - return new Program.Value(number, Program.Value.TYPE_NUMBER, number.value); - }; - - Parser.prototype.parseStringExpression = function(string) { - var token; - token = this.nextTokenOptional(); - if (token == null) { - return new Program.Value(string, Program.Value.TYPE_STRING, string.value); - } else { - this.tokenizer.pushBack(token); - return new Program.Value(string, Program.Value.TYPE_STRING, string.value); + expression = access; + } } - }; - Parser.prototype.parseArray = function(bracket) { - var res, token; - res = []; - while (true) { - token = this.nextToken(); - if (token.type === Token.TYPE_CLOSED_BRACKET) { - return new Program.Value(bracket, Program.Value.TYPE_ARRAY, res); - } else if (token.type === Token.TYPE_COMMA) { - continue; - } else { - this.tokenizer.pushBack(token); - res.push(this.assertExpression()); + assertExpression(filter, first_function_call = false) { + var exp; + exp = this.parseExpression(filter, first_function_call); + if (exp == null) { + throw "Expression expected"; } + return exp; } - }; - Parser.prototype.parseBinaryOperation = function(operation, term1) { - var ops, terms, token; - ops = [new Program.Operation(operation, operation.value)]; - terms = [term1]; - terms.push(this.assertExpression("noop")); - while (true) { + parseExpressionSuffix(expression, filter) { + var field, identifier, token; token = this.nextTokenOptional(); if (token == null) { - break; + return (filter === "self" ? expression : null); } - if (!token.is_binary_operator) { - this.tokenizer.pushBack(token); - break; + switch (token.type) { + case Token.TYPE_DOT: + if (expression instanceof Program.Value && expression.type === Program.Value.TYPE_NUMBER) { + this.tokenizer.pushBack(token); + return null; + } else { + this.tokenizer.changeNumberToIdentifier(); + identifier = this.assertBroadIdentifier("Expected identifier"); + return Program.CreateFieldAccess(token, expression, new Program.Value(identifier, Program.Value.TYPE_STRING, identifier.value)); + } + break; + case Token.TYPE_OPEN_BRACKET: + field = this.assertExpression(); + this.assert(Token.TYPE_CLOSED_BRACKET, "Expected ']'"); + return Program.CreateFieldAccess(token, expression, field); + case Token.TYPE_OPEN_BRACE: + return this.parseFunctionCall(token, expression); + case Token.TYPE_EQUALS: + return this.parseAssignment(token, expression); + case Token.TYPE_PLUS_EQUALS: + return this.parseSelfAssignment(token, expression, token.type); + case Token.TYPE_MINUS_EQUALS: + return this.parseSelfAssignment(token, expression, token.type); + case Token.TYPE_MULTIPLY_EQUALS: + return this.parseSelfAssignment(token, expression, token.type); + case Token.TYPE_DIVIDE_EQUALS: + return this.parseSelfAssignment(token, expression, token.type); + case Token.TYPE_MODULO_EQUALS: + case Token.TYPE_AND_EQUALS: + case Token.TYPE_OR_EQUALS: + return this.parseSelfAssignment(token, expression, token.type); + default: + if (filter === "self") { + this.tokenizer.pushBack(token); + return expression; + } else if (token.is_binary_operator && filter !== "noop") { + return this.parseBinaryOperation(token, expression); + } else { + this.tokenizer.pushBack(token); + return null; + } } - ops.push(new Program.Operation(token, token.value)); - terms.push(this.assertExpression("noop")); } - return Program.BuildOperations(ops, terms); - }; - Parser.prototype.parseAssignment = function(token, expression) { - var res; - if (!(expression instanceof Program.Variable) && !(expression instanceof Program.Field)) { - throw "Expected variable identifier or property"; - } - if (this.object_nesting === 0 && expression instanceof Program.Variable && this.api_reserved[expression.identifier]) { - this.warnings.push({ - type: "assigning_api_variable", - identifier: expression.identifier, - line: token.line, - column: token.column - }); - } - if (expression instanceof Program.Field) { - this.object_nesting += 1; - res = new Program.Assignment(token, expression, this.assertExpression()); - this.object_nesting -= 1; - } else { - res = new Program.Assignment(token, expression, this.assertExpression()); - } - return res; - }; - - Parser.prototype.parseSelfAssignment = function(token, expression, operation) { - if (!(expression instanceof Program.Variable) && !(expression instanceof Program.Field)) { - throw "Expected variable identifier or property"; + parseExpressionStart() { + var next, token; + token = this.nextTokenOptional(); + if (token == null) { + return null; + } + switch (token.type) { + case Token.TYPE_IDENTIFIER: // variable name + return new Program.Variable(token, token.value); + case Token.TYPE_NUMBER: + return this.parseNumberExpression(token); + case Token.TYPE_PLUS: + return this.assertExpression(); + case Token.TYPE_MINUS: + return this.parseExpressionSuffix(new Program.Negate(token, this.assertExpression("noop")), "self"); + case Token.TYPE_NOT: + return this.parseExpressionSuffix(new Program.Not(token, this.assertExpression("noop")), "self"); + case Token.TYPE_STRING: + return this.parseStringExpression(token); + case Token.TYPE_IF: + return this.parseIf(token); + case Token.TYPE_FOR: + return this.parseFor(token); + case Token.TYPE_WHILE: + return this.parseWhile(token); + case Token.TYPE_OPEN_BRACE: + return this.parseBracedExpression(token); + case Token.TYPE_OPEN_BRACKET: + return this.parseArray(token); + case Token.TYPE_FUNCTION: + return this.parseFunction(token); + case Token.TYPE_OBJECT: + return this.parseObject(token); + case Token.TYPE_CLASS: + return this.parseClass(token); + case Token.TYPE_NEW: + return this.parseNew(token); + case Token.TYPE_DOT: + next = this.assert(Token.TYPE_NUMBER, "malformed number"); + if (!Number.isInteger(next.value)) { + throw "malformed number"; + } + return new Program.Value(token, Program.Value.TYPE_NUMBER, Number.parseFloat(`.${next.string_value}`)); + case Token.TYPE_AFTER: + return this.parseAfter(token); + case Token.TYPE_EVERY: + return this.parseEvery(token); + case Token.TYPE_DO: + return this.parseDo(token); + case Token.TYPE_SLEEP: + return this.parseSleep(token); + case Token.TYPE_DELETE: + return this.parseDelete(token); + default: + this.tokenizer.pushBack(token); + return null; + } } - return new Program.SelfAssignment(token, expression, operation, this.assertExpression()); - }; - - Parser.prototype.parseLocalAssignment = function(local) { - var identifier; - identifier = this.assert(Token.TYPE_IDENTIFIER, "Expected identifier"); - this.assert(Token.TYPE_EQUALS, "Expected '='"); - return new Program.Assignment(local, new Program.Variable(identifier, identifier.value), this.assertExpression(), true); - }; - Parser.prototype.parseBracedExpression = function(open) { - var expression, token; - expression = this.assertExpression(); - token = this.nextToken(); - if (token.type === Token.TYPE_CLOSED_BRACE) { - return new Program.Braced(open, expression); - } else { - return this.error("missing closing parenthese"); + parseNumberExpression(number) { + return new Program.Value(number, Program.Value.TYPE_NUMBER, number.value); } - }; - Parser.prototype.parseFunctionCall = function(brace_token, expression) { - var args, start, token; - args = []; - this.last_function_call = new Program.FunctionCall(brace_token, expression, args); - this.last_function_call.argslimits = []; - while (true) { + parseStringExpression(string) { + var token; token = this.nextTokenOptional(); if (token == null) { - return this.error("missing closing parenthese"); - } else if (token.type === Token.TYPE_CLOSED_BRACE) { - return new Program.FunctionCall(token, expression, args); - } else if (token.type === Token.TYPE_COMMA) { - continue; + return new Program.Value(string, Program.Value.TYPE_STRING, string.value); } else { this.tokenizer.pushBack(token); - start = token.start; - args.push(this.assertExpression()); - this.last_function_call.argslimits.push({ - start: start, - end: this.tokenizer.index - 1 - }); + return new Program.Value(string, Program.Value.TYPE_STRING, string.value); } } - }; - - Parser.prototype.addTerminable = function(token) { - return this.not_terminated.push(token); - }; - - Parser.prototype.endTerminable = function() { - if (this.not_terminated.length > 0) { - this.not_terminated.splice(this.not_terminated.length - 1, 1); - } - }; - Parser.prototype.parseFunction = function(funk) { - var args, line, sequence, token; - this.nesting += 1; - this.addTerminable(funk); - args = this.parseFunctionArgs(); - sequence = []; - while (true) { - token = this.nextToken(); - if (token.type === Token.TYPE_END) { - this.nesting -= 1; - this.endTerminable(); - return new Program.Function(funk, args, sequence, token); - } else { - this.tokenizer.pushBack(token); - line = this.parseLine(); - if (line != null) { - sequence.push(line); + parseArray(bracket) { + var res, token; + res = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_CLOSED_BRACKET) { + return new Program.Value(bracket, Program.Value.TYPE_ARRAY, res); + } else if (token.type === Token.TYPE_COMMA) { + continue; } else { - this.error("Unexpected data while parsing function"); + this.tokenizer.pushBack(token); + res.push(this.assertExpression()); } } } - }; - Parser.prototype.parseFunctionArgs = function() { - var args, exp, last, token; - token = this.nextToken(); - args = []; - last = null; - if (token.type !== Token.TYPE_OPEN_BRACE) { - return this.error("Expected opening parenthese"); + parseBinaryOperation(operation, term1) { + var ops, terms, token; + ops = [new Program.Operation(operation, operation.value)]; + terms = [term1]; + terms.push(this.assertExpression("noop")); + while (true) { + token = this.nextTokenOptional(); + if (token == null) { + break; + } + if (!token.is_binary_operator) { + this.tokenizer.pushBack(token); + break; + } + ops.push(new Program.Operation(token, token.value)); + terms.push(this.assertExpression("noop")); + } + return Program.BuildOperations(ops, terms); } - while (true) { - token = this.nextToken(); - if (token.type === Token.TYPE_CLOSED_BRACE) { - return args; - } else if (token.type === Token.TYPE_COMMA) { - last = null; - continue; - } else if (token.type === Token.TYPE_EQUALS && last === "argument") { - exp = this.assertExpression(); - args[args.length - 1]["default"] = exp; - } else if (token.type === Token.TYPE_IDENTIFIER) { - last = "argument"; - args.push({ - name: token.value + + parseAssignment(token, expression) { + var res; + if (!(expression instanceof Program.Variable) && !(expression instanceof Program.Field)) { + throw "Expected variable identifier or property"; + } + if (this.object_nesting === 0 && expression instanceof Program.Variable && this.api_reserved[expression.identifier]) { + this.warnings.push({ + type: "assigning_api_variable", + identifier: expression.identifier, + line: token.line, + column: token.column }); + } + if (expression instanceof Program.Field) { + this.object_nesting += 1; + res = new Program.Assignment(token, expression, this.assertExpression()); + this.object_nesting -= 1; } else { - return this.error("Unexpected token"); + res = new Program.Assignment(token, expression, this.assertExpression()); } + return res; } - }; - Parser.prototype.warningAssignmentCondition = function(expression) { - if (expression instanceof Program.Assignment) { - return this.warnings.push({ - type: "assignment_as_condition", - line: expression.token.line, - column: expression.token.column - }); + parseSelfAssignment(token, expression, operation) { + if (!(expression instanceof Program.Variable) && !(expression instanceof Program.Field)) { + throw "Expected variable identifier or property"; + } + return new Program.SelfAssignment(token, expression, operation, this.assertExpression()); } - }; - Parser.prototype.parseIf = function(iftoken) { - var chain, current, line, token; - this.addTerminable(iftoken); - current = { - condition: this.assertExpression(), - sequence: [] - }; - this.warningAssignmentCondition(current.condition); - chain = []; - token = this.nextToken(); - if (token.type !== Token.TYPE_THEN) { - return this.error("Expected 'then'"); - } - while (true) { + parseLocalAssignment(local) { + var identifier; + identifier = this.assert(Token.TYPE_IDENTIFIER, "Expected identifier"); + this.assert(Token.TYPE_EQUALS, "Expected '='"); + return new Program.Assignment(local, new Program.Variable(identifier, identifier.value), this.assertExpression(), true); + } + + parseBracedExpression(open) { + var expression, token; + expression = this.assertExpression(); token = this.nextToken(); - if (token.type === Token.TYPE_ELSIF) { - chain.push(current); - current = { - condition: this.assertExpression(), - sequence: [] - }; - this.warningAssignmentCondition(current.condition); - this.assert(Token.TYPE_THEN, "Expected 'then'"); - } else if (token.type === Token.TYPE_ELSE) { - current["else"] = []; - } else if (token.type === Token.TYPE_END) { - chain.push(current); - this.endTerminable(); - return new Program.Condition(iftoken, chain); + if (token.type === Token.TYPE_CLOSED_BRACE) { + return new Program.Braced(open, expression); } else { - this.tokenizer.pushBack(token); - line = this.parseLine(); - if (line == null) { - throw Error("Unexpected data while parsing if"); - } - if (current["else"] != null) { - current["else"].push(line); + return this.error("missing closing parenthese"); + } + } + + parseFunctionCall(brace_token, expression) { + var args, start, token; + args = []; + this.last_function_call = new Program.FunctionCall(brace_token, expression, args); + this.last_function_call.argslimits = []; + while (true) { + token = this.nextTokenOptional(); + if (token == null) { + return this.error("missing closing parenthese"); + } else if (token.type === Token.TYPE_CLOSED_BRACE) { + return new Program.FunctionCall(token, expression, args); + } else if (token.type === Token.TYPE_COMMA) { + continue; } else { - current.sequence.push(line); + this.tokenizer.pushBack(token); + start = token.start; + args.push(this.assertExpression()); + this.last_function_call.argslimits.push({ + start: start, + end: this.tokenizer.index - 1 + }); } } } - }; - Parser.prototype.assert = function(type, error) { - var token; - token = this.nextToken(); - if (token.type !== type) { - throw error; + addTerminable(token) { + return this.not_terminated.push(token); } - return token; - }; - Parser.prototype.assertBroadIdentifier = function(error) { - var token; - token = this.nextToken(); - if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) { - token.type = Token.TYPE_IDENTIFIER; - } - if (token.type !== Token.TYPE_IDENTIFIER) { - throw error; + endTerminable() { + if (this.not_terminated.length > 0) { + this.not_terminated.splice(this.not_terminated.length - 1, 1); + } } - return token; - }; - Parser.prototype.error = function(text) { - throw text; - }; + parseFunction(funk) { + var args, line, sequence, token; + this.nesting += 1; + this.addTerminable(funk); + args = this.parseFunctionArgs(); + sequence = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_END) { + this.nesting -= 1; + this.endTerminable(); + return new Program.Function(funk, args, sequence, token); + } else { + this.tokenizer.pushBack(token); + line = this.parseLine(); + if (line != null) { + sequence.push(line); + } else { + this.error("Unexpected data while parsing function"); + } + } + } + } - Parser.prototype.parseFor = function(fortoken) { - var iterator, list, range_by, range_from, range_to, token; - iterator = this.assertExpression(); - if (iterator instanceof Program.Assignment) { - range_from = iterator.expression; - iterator = iterator.field; + parseFunctionArgs() { + var args, exp, last, token; token = this.nextToken(); - if (token.type !== Token.TYPE_TO) { - return this.error("Expected 'to'"); + args = []; + last = null; + if (token.type !== Token.TYPE_OPEN_BRACE) { + return this.error("Expected opening parenthese"); } - range_to = this.assertExpression(); - token = this.nextToken(); - if (token.type === Token.TYPE_BY) { - range_by = this.assertExpression(); - } else { - range_by = 0; - this.tokenizer.pushBack(token); + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_CLOSED_BRACE) { + return args; + } else if (token.type === Token.TYPE_COMMA) { + last = null; + continue; + } else if (token.type === Token.TYPE_EQUALS && last === "argument") { + exp = this.assertExpression(); + args[args.length - 1].default = exp; + } else if (token.type === Token.TYPE_IDENTIFIER) { + last = "argument"; + args.push({ + name: token.value + }); + } else { + return this.error("Unexpected token"); + } } - return new Program.For(fortoken, iterator.identifier, range_from, range_to, range_by, this.parseSequence(fortoken)); - } else if (iterator instanceof Program.Variable) { - this.assert(Token.TYPE_IN, "Error expected keyword 'in'"); - list = this.assertExpression(); - return new Program.ForIn(fortoken, iterator.identifier, list, this.parseSequence(fortoken)); - } else { - return this.error("Malformed for loop"); } - }; - - Parser.prototype.parseWhile = function(whiletoken) { - var condition; - condition = this.assertExpression(); - return new Program.While(whiletoken, condition, this.parseSequence(whiletoken)); - }; - Parser.prototype.parseSequence = function(start_token) { - var line, sequence, token; - if (start_token != null) { - this.addTerminable(start_token); + warningAssignmentCondition(expression) { + if (expression instanceof Program.Assignment) { + return this.warnings.push({ + type: "assignment_as_condition", + line: expression.token.line, + column: expression.token.column + }); + } } - this.nesting += 1; - sequence = []; - while (true) { + + parseIf(iftoken) { + var chain, current, line, token; + this.addTerminable(iftoken); + current = { + condition: this.assertExpression(), + sequence: [] + }; + this.warningAssignmentCondition(current.condition); + chain = []; token = this.nextToken(); - if (token.type === Token.TYPE_END) { - if (start_token != null) { + if (token.type !== Token.TYPE_THEN) { + return this.error("Expected 'then'"); + } + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_ELSIF) { + chain.push(current); + current = { + condition: this.assertExpression(), + sequence: [] + }; + this.warningAssignmentCondition(current.condition); + this.assert(Token.TYPE_THEN, "Expected 'then'"); + } else if (token.type === Token.TYPE_ELSE) { + current.else = []; + } else if (token.type === Token.TYPE_END) { + chain.push(current); this.endTerminable(); + return new Program.Condition(iftoken, chain); + } else { + this.tokenizer.pushBack(token); + line = this.parseLine(); + if (line == null) { + throw Error("Unexpected data while parsing if"); + } + if (current.else != null) { + current.else.push(line); + } else { + current.sequence.push(line); + } } - this.nesting -= 1; - return sequence; - } else { - this.tokenizer.pushBack(token); - line = this.parseLine(); - if (line == null) { - this.error("Unexpected data"); - } - sequence.push(line); } } - return sequence; - }; - Parser.prototype.parseObject = function(object) { - var exp, fields, token; - this.nesting += 1; - this.object_nesting += 1; - this.addTerminable(object); - fields = []; - while (true) { + assert(type, error) { + var token; token = this.nextToken(); - if (token.type === Token.TYPE_END) { - this.nesting -= 1; - this.object_nesting -= 1; - this.endTerminable(); - return new Program.CreateObject(object, fields); - } else { - if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) { - token.type = Token.TYPE_IDENTIFIER; - } - if (token.type === Token.TYPE_STRING) { - token.type = Token.TYPE_IDENTIFIER; - } - if (token.type === Token.TYPE_IDENTIFIER) { - this.assert(Token.TYPE_EQUALS, "Expected '='"); - exp = this.assertExpression(); - fields.push({ - field: token.value, - value: exp - }); - } else { - return this.error("Malformed object"); - } + if (token.type !== type) { + throw error; } + return token; } - }; - Parser.prototype.parseClass = function(object) { - var exp, ext, fields, token; - this.nesting += 1; - this.object_nesting += 1; - this.addTerminable(object); - fields = []; - token = this.nextToken(); - if (token.type === Token.TYPE_EXTENDS) { - ext = this.assertExpression(); + assertBroadIdentifier(error) { + var token; token = this.nextToken(); + if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) { + token.type = Token.TYPE_IDENTIFIER; + } + if (token.type !== Token.TYPE_IDENTIFIER) { + throw error; + } + return token; } - while (true) { - if (token.type === Token.TYPE_END) { - this.nesting -= 1; - this.object_nesting -= 1; - this.endTerminable(); - return new Program.CreateClass(object, ext, fields); - } else { - if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) { - token.type = Token.TYPE_IDENTIFIER; - } - if (token.type === Token.TYPE_STRING) { - token.type = Token.TYPE_IDENTIFIER; + + error(text) { + throw text; + } + + parseFor(fortoken) { + var iterator, list, range_by, range_from, range_to, token; + iterator = this.assertExpression(); + if (iterator instanceof Program.Assignment) { + range_from = iterator.expression; + iterator = iterator.field; + token = this.nextToken(); + if (token.type !== Token.TYPE_TO) { + return this.error("Expected 'to'"); } - if (token.type === Token.TYPE_IDENTIFIER) { - this.assert(Token.TYPE_EQUALS, "Expected '='"); - exp = this.assertExpression(); - fields.push({ - field: token.value, - value: exp - }); + range_to = this.assertExpression(); + token = this.nextToken(); + if (token.type === Token.TYPE_BY) { + range_by = this.assertExpression(); } else { - return this.error("Malformed object"); + range_by = 0; + this.tokenizer.pushBack(token); } + return new Program.For(fortoken, iterator.identifier, range_from, range_to, range_by, this.parseSequence(fortoken)); + } else if (iterator instanceof Program.Variable) { + this.assert(Token.TYPE_IN, "Error expected keyword 'in'"); + list = this.assertExpression(); + return new Program.ForIn(fortoken, iterator.identifier, list, this.parseSequence(fortoken)); + } else { + return this.error("Malformed for loop"); } - token = this.nextToken(); } - }; - Parser.prototype.parseNew = function(token) { - var exp; - exp = this.assertExpression(null, true); - return new Program.NewCall(token, exp); - }; + parseWhile(whiletoken) { + var condition; + condition = this.assertExpression(); + return new Program.While(whiletoken, condition, this.parseSequence(whiletoken)); + } - Parser.prototype.multipliers = { - millisecond: 1, - milliseconds: 1, - second: 1000, - seconds: 1000, - minute: 60000, - minutes: 60000, - hour: 60000 * 60, - hours: 60000 * 60, - day: 60000 * 60 * 24, - days: 60000 * 60 * 24 - }; + parseSequence(start_token) { + var line, sequence, token; + if (start_token != null) { + this.addTerminable(start_token); + } + this.nesting += 1; + sequence = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_END) { + if (start_token != null) { + this.endTerminable(); + } + this.nesting -= 1; + return sequence; + } else { + this.tokenizer.pushBack(token); + line = this.parseLine(); + if (line == null) { + this.error("Unexpected data"); + } + sequence.push(line); + } + } + return sequence; + } - Parser.prototype.parseAfter = function(after) { - var delay, line, multiplier, sequence, token; - this.nesting += 1; - this.addTerminable(after); - delay = this.assertExpression(); - token = this.nextToken(); - multiplier = null; - if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) { - multiplier = this.multipliers[token.value]; + parseObject(object) { + var exp, fields, token; + this.nesting += 1; + this.object_nesting += 1; + this.addTerminable(object); + fields = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_END) { + this.nesting -= 1; + this.object_nesting -= 1; + this.endTerminable(); + return new Program.CreateObject(object, fields); + } else { + if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) { + token.type = Token.TYPE_IDENTIFIER; + } + if (token.type === Token.TYPE_STRING) { + token.type = Token.TYPE_IDENTIFIER; + } + if (token.type === Token.TYPE_IDENTIFIER) { + this.assert(Token.TYPE_EQUALS, "Expected '='"); + exp = this.assertExpression(); + fields.push({ + field: token.value, + value: exp + }); + } else { + return this.error("Malformed object"); + } + } + } + } + + parseClass(object) { + var exp, ext, fields, token; + this.nesting += 1; + this.object_nesting += 1; + this.addTerminable(object); + fields = []; token = this.nextToken(); + if (token.type === Token.TYPE_EXTENDS) { + ext = this.assertExpression(); + token = this.nextToken(); + } + while (true) { + if (token.type === Token.TYPE_END) { + this.nesting -= 1; + this.object_nesting -= 1; + this.endTerminable(); + return new Program.CreateClass(object, ext, fields); + } else { + if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) { + token.type = Token.TYPE_IDENTIFIER; + } + if (token.type === Token.TYPE_STRING) { + token.type = Token.TYPE_IDENTIFIER; + } + if (token.type === Token.TYPE_IDENTIFIER) { + this.assert(Token.TYPE_EQUALS, "Expected '='"); + exp = this.assertExpression(); + fields.push({ + field: token.value, + value: exp + }); + } else { + return this.error("Malformed object"); + } + } + token = this.nextToken(); + } } - if ((token == null) || token.type !== Token.TYPE_DO) { - this.error("Expected keyword 'do'"); + + parseNew(token) { + var exp; + exp = this.assertExpression(null, true); + return new Program.NewCall(token, exp); } - sequence = []; - while (true) { + + parseAfter(after) { + var delay, line, multiplier, sequence, token; + this.nesting += 1; + this.addTerminable(after); + delay = this.assertExpression(); token = this.nextToken(); - if (token.type === Token.TYPE_END) { - this.nesting -= 1; - this.endTerminable(); - return new Program.After(after, delay, sequence, token, multiplier); - } else { - this.tokenizer.pushBack(token); - line = this.parseLine(); - if (line != null) { - sequence.push(line); + multiplier = null; + if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) { + multiplier = this.multipliers[token.value]; + token = this.nextToken(); + } + if ((token == null) || token.type !== Token.TYPE_DO) { + this.error("Expected keyword 'do'"); + } + sequence = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_END) { + this.nesting -= 1; + this.endTerminable(); + return new Program.After(after, delay, sequence, token, multiplier); } else { - this.error("Unexpected data while parsing after"); + this.tokenizer.pushBack(token); + line = this.parseLine(); + if (line != null) { + sequence.push(line); + } else { + this.error("Unexpected data while parsing after"); + } } } } - }; - Parser.prototype.parseEvery = function(every) { - var delay, line, multiplier, sequence, token; - this.nesting += 1; - this.addTerminable(every); - delay = this.assertExpression(); - token = this.nextToken(); - multiplier = null; - if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) { - multiplier = this.multipliers[token.value]; + parseEvery(every) { + var delay, line, multiplier, sequence, token; + this.nesting += 1; + this.addTerminable(every); + delay = this.assertExpression(); token = this.nextToken(); + multiplier = null; + if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) { + multiplier = this.multipliers[token.value]; + token = this.nextToken(); + } + if ((token == null) || token.type !== Token.TYPE_DO) { + this.error("Expected keyword 'do'"); + } + sequence = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_END) { + this.nesting -= 1; + this.endTerminable(); + return new Program.Every(every, delay, sequence, token, multiplier); + } else { + this.tokenizer.pushBack(token); + line = this.parseLine(); + if (line != null) { + sequence.push(line); + } else { + this.error("Unexpected data while parsing after"); + } + } + } } - if ((token == null) || token.type !== Token.TYPE_DO) { - this.error("Expected keyword 'do'"); - } - sequence = []; - while (true) { - token = this.nextToken(); - if (token.type === Token.TYPE_END) { - this.nesting -= 1; - this.endTerminable(); - return new Program.Every(every, delay, sequence, token, multiplier); - } else { - this.tokenizer.pushBack(token); - line = this.parseLine(); - if (line != null) { - sequence.push(line); + + parseDo(do_token) { + var line, sequence, token; + this.nesting += 1; + this.addTerminable(do_token); + sequence = []; + while (true) { + token = this.nextToken(); + if (token.type === Token.TYPE_END) { + this.nesting -= 1; + this.endTerminable(); + return new Program.Do(do_token, sequence, token); } else { - this.error("Unexpected data while parsing after"); + this.tokenizer.pushBack(token); + line = this.parseLine(); + if (line != null) { + sequence.push(line); + } else { + this.error("Unexpected data while parsing after"); + } } } } - }; - Parser.prototype.parseDo = function(do_token) { - var line, sequence, token; - this.nesting += 1; - this.addTerminable(do_token); - sequence = []; - while (true) { + parseSleep(sleep) { + var delay, multiplier, token; + delay = this.assertExpression(); token = this.nextToken(); - if (token.type === Token.TYPE_END) { - this.nesting -= 1; - this.endTerminable(); - return new Program.Do(do_token, sequence, token); - } else { - this.tokenizer.pushBack(token); - line = this.parseLine(); - if (line != null) { - sequence.push(line); + multiplier = null; + if (token != null) { + if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) { + multiplier = this.multipliers[token.value]; } else { - this.error("Unexpected data while parsing after"); + this.tokenizer.pushBack(token); } } + return new Program.Sleep(sleep, delay, multiplier); } - }; - Parser.prototype.parseSleep = function(sleep) { - var delay, multiplier, token; - delay = this.assertExpression(); - token = this.nextToken(); - multiplier = null; - if (token != null) { - if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) { - multiplier = this.multipliers[token.value]; + parseDelete(del) { + var v; + v = this.parseExpression(); + if ((v == null) || (!(v instanceof Program.Variable) && !(v instanceof Program.Field))) { + return this.error("expecting variable name or property access after keyword `delete`"); } else { - this.tokenizer.pushBack(token); + return new Program.Delete(del, v); } } - return new Program.Sleep(sleep, delay, multiplier); + + }; + + Parser.prototype.multipliers = { + millisecond: 1, + milliseconds: 1, + second: 1000, + seconds: 1000, + minute: 60000, + minutes: 60000, + hour: 60000 * 60, + hours: 60000 * 60, + day: 60000 * 60 * 24, + days: 60000 * 60 * 24 }; return Parser; -})(); +}).call(this); diff --git a/static/js/languages/microscript/v2/processor.coffee b/static/js/languages/microscript/v2/processor.coffee index bc86ace1..3de328bc 100644 --- a/static/js/languages/microscript/v2/processor.coffee +++ b/static/js/languages/microscript/v2/processor.coffee @@ -549,6 +549,13 @@ class @Processor stack_index -= 2 op_index++ + when 26 # OPCODE_DELETE + obj = stack[stack_index-1] + field = stack[stack_index] + delete obj[field] + stack[stack_index -= 1] = 0 + op_index++ + when 27 # OPCODE_UPDATE_CLASS name = arg1[op_index] # TODO: set classname to variable name diff --git a/static/js/languages/microscript/v2/processor.js b/static/js/languages/microscript/v2/processor.js index 03440ca0..b3e9a7dd 100644 --- a/static/js/languages/microscript/v2/processor.js +++ b/static/js/languages/microscript/v2/processor.js @@ -660,6 +660,13 @@ this.Processor = class Processor { stack_index -= 2; op_index++; break; + case 26: // OPCODE_DELETE + obj = stack[stack_index - 1]; + field = stack[stack_index]; + delete obj[field]; + stack[stack_index -= 1] = 0; + op_index++; + break; case 27: // OPCODE_UPDATE_CLASS name = arg1[op_index]; // TODO: set classname to variable name diff --git a/static/js/languages/microscript/v2/program.coffee b/static/js/languages/microscript/v2/program.coffee index 8f2047d9..f723f915 100644 --- a/static/js/languages/microscript/v2/program.coffee +++ b/static/js/languages/microscript/v2/program.coffee @@ -158,6 +158,9 @@ class @Program.Do class @Program.Sleep constructor:(@token,@delay,@multiplier)-> +class @Program.Delete + constructor:(@token,@field)-> + @Program.Precedence = "^":21 "/":20 diff --git a/static/js/languages/microscript/v2/program.js b/static/js/languages/microscript/v2/program.js index ba88970f..784c1d66 100644 --- a/static/js/languages/microscript/v2/program.js +++ b/static/js/languages/microscript/v2/program.js @@ -341,6 +341,14 @@ this.Program.Sleep = class Sleep { }; +this.Program.Delete = class Delete { + constructor(token1, field1) { + this.token = token1; + this.field = field1; + } + +}; + this.Program.Precedence = { "^": 21, "/": 20, diff --git a/static/js/languages/microscript/v2/routine.coffee b/static/js/languages/microscript/v2/routine.coffee index 1d9163f3..a46d264f 100644 --- a/static/js/languages/microscript/v2/routine.coffee +++ b/static/js/languages/microscript/v2/routine.coffee @@ -148,6 +148,7 @@ class @Routine EVERY:(ref)-> @OP OPCODES.EVERY,ref DO:(ref)-> @OP OPCODES.DO,ref SLEEP:(ref)-> @OP OPCODES.SLEEP,ref + DELETE:(ref)-> @OP OPCODES.DELETE,ref UNARY_OP:(f,ref)-> @OP OPCODES.UNARY_OP,ref,f BINARY_OP:(f,ref)-> @OP OPCODES.BINARY_OP,ref,f @@ -193,6 +194,7 @@ class @OPCODES_CLASS @set "STORE_VARIABLE",23 @set "CREATE_PROPERTY",24 @set "STORE_PROPERTY",25 + @set "DELETE",26 @set "UPDATE_CLASS", 27 @set "CREATE_CLASS", 28 diff --git a/static/js/languages/microscript/v2/routine.js b/static/js/languages/microscript/v2/routine.js index 1552913e..205d8cb7 100644 --- a/static/js/languages/microscript/v2/routine.js +++ b/static/js/languages/microscript/v2/routine.js @@ -1,5 +1,5 @@ -this.Routine = (function() { - function Routine(num_args) { +this.Routine = class Routine { + constructor(num_args) { this.num_args = num_args; this.ops = []; this.opcodes = []; @@ -14,7 +14,7 @@ this.Routine = (function() { this.import_self = -1; } - Routine.prototype.clone = function() { + clone() { var r; r = new Routine(this.num_args); r.opcodes = this.opcodes; @@ -22,27 +22,24 @@ this.Routine = (function() { r.ref = this.ref; r.locals_size = this.locals_size; return r; - }; + } - Routine.prototype.createLabel = function(str) { + createLabel(str = "label") { var name; - if (str == null) { - str = "label"; - } return name = ":" + str + "_" + this.label_count++; - }; + } - Routine.prototype.setLabel = function(name) { + setLabel(name) { return this.labels[name] = this.opcodes.length; - }; + } - Routine.prototype.optimize = function() { + optimize() { if (this.transpile) { new Transpiler().transpile(this); } - }; + } - Routine.prototype.removeable = function(index) { + removeable(index) { var label, ref1, value; ref1 = this.labels; for (label in ref1) { @@ -52,9 +49,9 @@ this.Routine = (function() { } } return true; - }; + } - Routine.prototype.remove = function(index) { + remove(index) { var label, ref1, value; ref1 = this.labels; for (label in ref1) { @@ -69,12 +66,12 @@ this.Routine = (function() { this.arg1.splice(index, 1); this.ref.splice(index, 1); return true; - }; + } - Routine.prototype.resolveLabels = function() { + resolveLabels() { var i, j, ref1, ref2, ref3, results; results = []; - for (i = j = 0, ref1 = this.opcodes.length - 1; 0 <= ref1 ? j <= ref1 : j >= ref1; i = 0 <= ref1 ? ++j : --j) { + for (i = j = 0, ref1 = this.opcodes.length - 1; (0 <= ref1 ? j <= ref1 : j >= ref1); i = 0 <= ref1 ? ++j : --j) { if ((ref2 = this.opcodes[i]) === OPCODES.JUMP || ref2 === OPCODES.JUMPY || ref2 === OPCODES.JUMPN || ref2 === OPCODES.JUMPY_NOPOP || ref2 === OPCODES.JUMPN_NOPOP) { if (this.labels[this.arg1[i]]) { results.push(this.arg1[i] = this.labels[this.arg1[i]]); @@ -92,22 +89,16 @@ this.Routine = (function() { } } return results; - }; + } - Routine.prototype.OP = function(code, ref, v1) { - if (v1 == null) { - v1 = 0; - } + OP(code, ref, v1 = 0) { this.opcodes.push(code); this.arg1.push(v1); return this.ref.push(ref); - }; + } - Routine.prototype.OP_INSERT = function(code, ref, v1, index) { + OP_INSERT(code, ref, v1 = 0, index) { var label, ref1, value; - if (v1 == null) { - v1 = 0; - } this.opcodes.splice(index, 0, code); this.arg1.splice(index, 0, v1); this.ref.splice(index, 0, ref); @@ -118,263 +109,261 @@ this.Routine = (function() { this.labels[label] += 1; } } - }; + } - Routine.prototype.TYPE = function(ref) { + TYPE(ref) { return this.OP(OPCODES.TYPE, ref); - }; + } - Routine.prototype.VARIABLE_TYPE = function(variable, ref) { + VARIABLE_TYPE(variable, ref) { return this.OP(OPCODES.VARIABLE_TYPE, ref, variable); - }; + } - Routine.prototype.PROPERTY_TYPE = function(ref) { + PROPERTY_TYPE(ref) { return this.OP(OPCODES.PROPERTY_TYPE, ref); - }; + } - Routine.prototype.LOAD_THIS = function(ref) { + LOAD_THIS(ref) { return this.OP(OPCODES.LOAD_THIS, ref); - }; + } - Routine.prototype.LOAD_GLOBAL = function(ref) { + LOAD_GLOBAL(ref) { return this.OP(OPCODES.LOAD_GLOBAL, ref); - }; + } - Routine.prototype.LOAD_VALUE = function(value, ref) { + LOAD_VALUE(value, ref) { return this.OP(OPCODES.LOAD_VALUE, ref, value); - }; + } - Routine.prototype.LOAD_LOCAL = function(index, ref) { + LOAD_LOCAL(index, ref) { return this.OP(OPCODES.LOAD_LOCAL, ref, index); - }; + } - Routine.prototype.LOAD_VARIABLE = function(variable, ref) { + LOAD_VARIABLE(variable, ref) { return this.OP(OPCODES.LOAD_VARIABLE, ref, variable); - }; + } - Routine.prototype.LOAD_LOCAL_OBJECT = function(index, ref) { + LOAD_LOCAL_OBJECT(index, ref) { return this.OP(OPCODES.LOAD_LOCAL_OBJECT, ref, index); - }; + } - Routine.prototype.LOAD_VARIABLE_OBJECT = function(variable, ref) { + LOAD_VARIABLE_OBJECT(variable, ref) { return this.OP(OPCODES.LOAD_VARIABLE_OBJECT, ref, variable); - }; + } - Routine.prototype.POP = function(ref) { + POP(ref) { return this.OP(OPCODES.POP, ref); - }; + } - Routine.prototype.LOAD_PROPERTY = function(ref) { + LOAD_PROPERTY(ref) { return this.OP(OPCODES.LOAD_PROPERTY, ref); - }; + } - Routine.prototype.LOAD_PROPERTY_OBJECT = function(ref) { + LOAD_PROPERTY_OBJECT(ref) { return this.OP(OPCODES.LOAD_PROPERTY_OBJECT, ref); - }; + } - Routine.prototype.CREATE_OBJECT = function(ref) { + CREATE_OBJECT(ref) { return this.OP(OPCODES.CREATE_OBJECT, ref); - }; + } - Routine.prototype.MAKE_OBJECT = function(ref) { + MAKE_OBJECT(ref) { return this.OP(OPCODES.MAKE_OBJECT, ref); - }; + } - Routine.prototype.CREATE_ARRAY = function(ref) { + CREATE_ARRAY(ref) { return this.OP(OPCODES.CREATE_ARRAY, ref); - }; + } - Routine.prototype.CREATE_CLASS = function(parent_var, ref) { + CREATE_CLASS(parent_var, ref) { return this.OP(OPCODES.CREATE_CLASS, ref, parent_var); - }; + } - Routine.prototype.UPDATE_CLASS = function(variable, ref) { + UPDATE_CLASS(variable, ref) { return this.OP(OPCODES.UPDATE_CLASS, ref, variable); - }; + } - Routine.prototype.NEW_CALL = function(args, ref) { + NEW_CALL(args, ref) { return this.OP(OPCODES.NEW_CALL, ref, args); - }; + } - Routine.prototype.ADD = function(ref, self) { - if (self == null) { - self = 0; - } + ADD(ref, self = 0) { return this.OP(OPCODES.ADD, ref, self); - }; + } - Routine.prototype.SUB = function(ref, self) { - if (self == null) { - self = 0; - } + SUB(ref, self = 0) { return this.OP(OPCODES.SUB, ref, self); - }; + } - Routine.prototype.MUL = function(ref) { + MUL(ref) { return this.OP(OPCODES.MUL, ref); - }; + } - Routine.prototype.DIV = function(ref) { + DIV(ref) { return this.OP(OPCODES.DIV, ref); - }; + } - Routine.prototype.MODULO = function(ref) { + MODULO(ref) { return this.OP(OPCODES.MODULO, ref); - }; + } - Routine.prototype.BINARY_AND = function(ref) { + BINARY_AND(ref) { return this.OP(OPCODES.BINARY_AND, ref); - }; + } - Routine.prototype.BINARY_OR = function(ref) { + BINARY_OR(ref) { return this.OP(OPCODES.BINARY_OR, ref); - }; + } - Routine.prototype.SHIFT_LEFT = function(ref) { + SHIFT_LEFT(ref) { return this.OP(OPCODES.SHIFT_LEFT, ref); - }; + } - Routine.prototype.SHIFT_RIGHT = function(ref) { + SHIFT_RIGHT(ref) { return this.OP(OPCODES.SHIFT_RIGHT, ref); - }; + } - Routine.prototype.NEGATE = function(ref) { + NEGATE(ref) { return this.OP(OPCODES.NEGATE, ref); - }; + } - Routine.prototype.LOAD_PROPERTY_ATOP = function(ref) { + LOAD_PROPERTY_ATOP(ref) { return this.OP(OPCODES.LOAD_PROPERTY_ATOP, ref); - }; + } - Routine.prototype.EQ = function(ref) { + EQ(ref) { return this.OP(OPCODES.EQ, ref); - }; + } - Routine.prototype.NEQ = function(ref) { + NEQ(ref) { return this.OP(OPCODES.NEQ, ref); - }; + } - Routine.prototype.LT = function(ref) { + LT(ref) { return this.OP(OPCODES.LT, ref); - }; + } - Routine.prototype.GT = function(ref) { + GT(ref) { return this.OP(OPCODES.GT, ref); - }; + } - Routine.prototype.LTE = function(ref) { + LTE(ref) { return this.OP(OPCODES.LTE, ref); - }; + } - Routine.prototype.GTE = function(ref) { + GTE(ref) { return this.OP(OPCODES.GTE, ref); - }; + } - Routine.prototype.NOT = function(ref) { + NOT(ref) { return this.OP(OPCODES.NOT, ref); - }; + } - Routine.prototype.FORLOOP_INIT = function(iterator, ref) { + FORLOOP_INIT(iterator, ref) { return this.OP(OPCODES.FORLOOP_INIT, ref, iterator); - }; + } - Routine.prototype.FORLOOP_CONTROL = function(args, ref) { + FORLOOP_CONTROL(args, ref) { return this.OP(OPCODES.FORLOOP_CONTROL, ref, args); - }; + } - Routine.prototype.FORIN_INIT = function(args, ref) { + FORIN_INIT(args, ref) { return this.OP(OPCODES.FORIN_INIT, ref, args); - }; + } - Routine.prototype.FORIN_CONTROL = function(args, ref) { + FORIN_CONTROL(args, ref) { return this.OP(OPCODES.FORIN_CONTROL, ref, args); - }; + } - Routine.prototype.JUMP = function(index, ref) { + JUMP(index, ref) { return this.OP(OPCODES.JUMP, ref, index); - }; + } - Routine.prototype.JUMPY = function(index, ref) { + JUMPY(index, ref) { return this.OP(OPCODES.JUMPY, ref, index); - }; + } - Routine.prototype.JUMPN = function(index, ref) { + JUMPN(index, ref) { return this.OP(OPCODES.JUMPN, ref, index); - }; + } - Routine.prototype.JUMPY_NOPOP = function(index, ref) { + JUMPY_NOPOP(index, ref) { return this.OP(OPCODES.JUMPY_NOPOP, ref, index); - }; + } - Routine.prototype.JUMPN_NOPOP = function(index, ref) { + JUMPN_NOPOP(index, ref) { return this.OP(OPCODES.JUMPN_NOPOP, ref, index); - }; + } - Routine.prototype.STORE_LOCAL = function(index, ref) { + STORE_LOCAL(index, ref) { return this.OP(OPCODES.STORE_LOCAL, ref, index); - }; + } - Routine.prototype.STORE_VARIABLE = function(field, ref) { + STORE_VARIABLE(field, ref) { return this.OP(OPCODES.STORE_VARIABLE, ref, field); - }; + } - Routine.prototype.CREATE_PROPERTY = function(ref) { + CREATE_PROPERTY(ref) { return this.OP(OPCODES.CREATE_PROPERTY, ref); - }; + } - Routine.prototype.STORE_PROPERTY = function(ref) { + STORE_PROPERTY(ref) { return this.OP(OPCODES.STORE_PROPERTY, ref); - }; + } - Routine.prototype.LOAD_ROUTINE = function(value, ref) { + LOAD_ROUTINE(value, ref) { return this.OP(OPCODES.LOAD_ROUTINE, ref, value); - }; + } - Routine.prototype.FUNCTION_CALL = function(args, ref) { + FUNCTION_CALL(args, ref) { return this.OP(OPCODES.FUNCTION_CALL, ref, args); - }; + } - Routine.prototype.FUNCTION_APPLY_VARIABLE = function(args, ref) { + FUNCTION_APPLY_VARIABLE(args, ref) { return this.OP(OPCODES.FUNCTION_APPLY_VARIABLE, ref, args); - }; + } - Routine.prototype.FUNCTION_APPLY_PROPERTY = function(args, ref) { + FUNCTION_APPLY_PROPERTY(args, ref) { return this.OP(OPCODES.FUNCTION_APPLY_PROPERTY, ref, args); - }; + } - Routine.prototype.SUPER_CALL = function(args, ref) { + SUPER_CALL(args, ref) { return this.OP(OPCODES.SUPER_CALL, ref, args); - }; + } - Routine.prototype.RETURN = function(ref) { + RETURN(ref) { return this.OP(OPCODES.RETURN, ref); - }; + } - Routine.prototype.AFTER = function(ref) { + AFTER(ref) { return this.OP(OPCODES.AFTER, ref); - }; + } - Routine.prototype.EVERY = function(ref) { + EVERY(ref) { return this.OP(OPCODES.EVERY, ref); - }; + } - Routine.prototype.DO = function(ref) { + DO(ref) { return this.OP(OPCODES.DO, ref); - }; + } - Routine.prototype.SLEEP = function(ref) { + SLEEP(ref) { return this.OP(OPCODES.SLEEP, ref); - }; + } - Routine.prototype.UNARY_OP = function(f, ref) { + DELETE(ref) { + return this.OP(OPCODES.DELETE, ref); + } + + UNARY_OP(f, ref) { return this.OP(OPCODES.UNARY_OP, ref, f); - }; + } - Routine.prototype.BINARY_OP = function(f, ref) { + BINARY_OP(f, ref) { return this.OP(OPCODES.BINARY_OP, ref, f); - }; + } - Routine.prototype.toString = function() { + toString() { var i, j, len, op, ref1, s; s = ""; ref1 = this.opcodes; @@ -382,19 +371,18 @@ this.Routine = (function() { op = ref1[i]; s += OPCODES[op]; if (this.arg1[i] != null) { - s += " " + this.arg1[i]; + //if typeof @arg1[i] != "function" + s += ` ${this.arg1[i]}`; } s += "\n"; } return s; - }; - - return Routine; + } -})(); +}; -this.OPCODES_CLASS = (function() { - function OPCODES_CLASS() { +this.OPCODES_CLASS = class OPCODES_CLASS { + constructor() { this.table = {}; this.set("TYPE", 1); this.set("VARIABLE_TYPE", 2); @@ -417,6 +405,7 @@ this.OPCODES_CLASS = (function() { this.set("STORE_VARIABLE", 23); this.set("CREATE_PROPERTY", 24); this.set("STORE_PROPERTY", 25); + this.set("DELETE", 26); this.set("UPDATE_CLASS", 27); this.set("CREATE_CLASS", 28); this.set("NEW_CALL", 29); @@ -462,13 +451,11 @@ this.OPCODES_CLASS = (function() { this.set("SLEEP", 113); } - OPCODES_CLASS.prototype.set = function(op, code) { + set(op, code) { this[op] = code; return this[code] = op; - }; - - return OPCODES_CLASS; + } -})(); +}; this.OPCODES = new this.OPCODES_CLASS; diff --git a/static/js/languages/microscript/v2/token.coffee b/static/js/languages/microscript/v2/token.coffee index dd9304a1..09e4b1ed 100644 --- a/static/js/languages/microscript/v2/token.coffee +++ b/static/js/languages/microscript/v2/token.coffee @@ -116,5 +116,6 @@ class @Token @Token.predefined["every"] = @Token.TYPE_EVERY @Token.predefined["do"] = @Token.TYPE_DO @Token.predefined["sleep"] = @Token.TYPE_SLEEP +@Token.predefined["delete"] = @Token.TYPE_DELETE @Token.predefined["local"] = @Token.TYPE_LOCAL diff --git a/static/js/languages/microscript/v2/token.js b/static/js/languages/microscript/v2/token.js index 27c26311..e9d14b85 100644 --- a/static/js/languages/microscript/v2/token.js +++ b/static/js/languages/microscript/v2/token.js @@ -1,5 +1,5 @@ -this.Token = (function() { - function Token(tokenizer, type, value, string_value) { +this.Token = class Token { + constructor(tokenizer, type, value, string_value) { this.tokenizer = tokenizer; this.type = type; this.value = value; @@ -16,13 +16,11 @@ this.Token = (function() { this.is_binary_operator = (this.type >= 30 && this.type <= 39) || (this.type >= 200 && this.type <= 201) || (this.type >= 2 && this.type <= 7); } - Token.prototype.toString = function() { + toString() { return this.value + " : " + this.type; - }; - - return Token; + } -})(); +}; this.Token.TYPE_EQUALS = 1; @@ -48,6 +46,8 @@ this.Token.TYPE_OPEN_BRACE = 20; this.Token.TYPE_CLOSED_BRACE = 21; +// @Token.TYPE_OPEN_CURLY_BRACE = 22 +// @Token.TYPE_CLOSED_CURLY_BRACE = 23 this.Token.TYPE_OPEN_BRACKET = 24; this.Token.TYPE_CLOSED_BRACKET = 25; @@ -196,4 +196,6 @@ this.Token.predefined["do"] = this.Token.TYPE_DO; this.Token.predefined["sleep"] = this.Token.TYPE_SLEEP; +this.Token.predefined["delete"] = this.Token.TYPE_DELETE; + this.Token.predefined["local"] = this.Token.TYPE_LOCAL; diff --git a/static/lib/mode-microscript2.js b/static/lib/mode-microscript2.js index 6bc0aa50..833c833f 100644 --- a/static/lib/mode-microscript2.js +++ b/static/lib/mode-microscript2.js @@ -297,9 +297,9 @@ var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightR var Microscript2HighlightRules = function() { var mapper = this.createKeywordMapper({ - keyword: "do|after|every|sleep|else|elsif|end|function|if|in|to|local|then|or|and|not|object|class|extends|new|constructor|for|while", + keyword: "do|after|every|sleep|else|elsif|end|function|if|in|to|local|then|or|and|not|object|class|extends|new|constructor|for|while|delete", "keyword.control": "by|return|break|continue", - "support.function": "screen|system|audio|gamepad|keyboard|touch|mouse|storage|asset_manager|print|time|type|log|max|PI|pow|random|ceil|round|floor|abs|sqrt|min|exp|sin|atan|concat|sortList|cos|sin|tan|acos|asin|atan|atan2|sind|cosd|tand|acosd|asind|atand|atan2d|Function|Number|String|List|Object|Image|Sprite|Sound", + "support.function": "screen|system|audio|gamepad|keyboard|touch|mouse|storage|asset_manager|print|type|log|max|PI|pow|random|ceil|round|floor|abs|sqrt|min|exp|sin|atan|concat|sortList|cos|sin|tan|acos|asin|atan|atan2|sind|cosd|tand|acosd|asind|atand|atan2d|Function|Number|String|List|Object|Image|Sprite|Sound", "support.constant": "true|false|PI", "variable.language": "this|type|super" },"identifier") ;