added things
@@ -0,0 +1,968 @@
|
||||
var Compiler, LocalLayer;
|
||||
|
||||
Compiler = (function() {
|
||||
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(JSON.stringify @routine.export())
|
||||
// @routine = new Routine(0).import( @routine.export() )
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
throw "illegal";
|
||||
}
|
||||
} 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.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";
|
||||
}
|
||||
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);
|
||||
}
|
||||
} 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]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
op.term1.nowarning = true;
|
||||
op.term2.nowarning = true;
|
||||
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");
|
||||
op.term1.nowarning = true;
|
||||
op.term2.nowarning = true;
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
compileNot(expression) {
|
||||
expression.expression.nowarning = true;
|
||||
this.compile(expression.expression);
|
||||
return this.routine.NOT(expression);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
compileField(field) {
|
||||
var c, i, id, index, j, k, len, ref, ref1;
|
||||
if (field.expression.identifier === "keyboard" || field.expression.identifier === "gamepad") {
|
||||
field.nowarning = true;
|
||||
}
|
||||
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.compile(field.expression);
|
||||
this.routine.TYPE(field);
|
||||
}
|
||||
} else {
|
||||
this.compile(field.expression);
|
||||
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);
|
||||
ref1 = field.chain;
|
||||
for (k = 0, len = ref1.length; k < len; k++) {
|
||||
c = ref1[k];
|
||||
this.compile(c);
|
||||
this.routine.LOAD_PROPERTY(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compileFieldParent(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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
ref4 = call.args;
|
||||
for (n = 0, len4 = ref4.length; n < len4; n++) {
|
||||
a = ref4[n];
|
||||
this.compile(a);
|
||||
}
|
||||
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 {
|
||||
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();
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
compileContinue(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);
|
||||
}
|
||||
|
||||
compileFunctionBody(func) {
|
||||
var a, args, i, index, j, k, l, label, len, local_index, locals, m, numargs, 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;
|
||||
this.routine.uses_arguments = true;
|
||||
if (func.args != null) {
|
||||
if (this.routine.uses_arguments) {
|
||||
args = this.locals.register("arguments");
|
||||
this.routine.STORE_LOCAL(args, func);
|
||||
this.routine.POP(func);
|
||||
}
|
||||
numargs = this.locals.register("+numargs");
|
||||
this.routine.STORE_LOCAL(numargs, func);
|
||||
this.routine.POP(func);
|
||||
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_VALUE(i, func);
|
||||
this.routine.LOAD_LOCAL(numargs, func);
|
||||
this.routine.LT(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]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.routine.LOAD_VALUE(0, func);
|
||||
this.routine.RETURN(func);
|
||||
}
|
||||
if ((func.args != null) && !this.locals.arguments_used) {
|
||||
this.routine.uses_arguments = false;
|
||||
this.routine.remove(0);
|
||||
this.routine.remove(0);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
c.condition.nowarning = true;
|
||||
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)) {
|
||||
this.locals.push();
|
||||
this.compileSequence(c.else);
|
||||
this.locals.pop();
|
||||
}
|
||||
}
|
||||
this.routine.setLabel(condition_end);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
compileUpdateClass(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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
compileDo(dostuff) {
|
||||
var r;
|
||||
r = this.compileFunctionBody(dostuff);
|
||||
this.routine.LOAD_ROUTINE(r, dostuff);
|
||||
return this.routine.DO(dostuff);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
exec(context) {
|
||||
this.processor = new Processor();
|
||||
this.processor.load(this.routine);
|
||||
return this.processor.run(context);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Compiler.predefined_unary_functions = {
|
||||
"round": Math.round,
|
||||
"floor": Math.floor,
|
||||
"ceil": Math.ceil,
|
||||
"abs": Math.abs,
|
||||
"sqrt": Math.sqrt,
|
||||
"sin": Math.sin,
|
||||
"cos": Math.cos,
|
||||
"tan": Math.tan,
|
||||
"acos": Math.acos,
|
||||
"asin": Math.asin,
|
||||
"atan": Math.atan,
|
||||
"sind": function(x) {
|
||||
return Math.sin(x * Math.PI / 180);
|
||||
},
|
||||
"cosd": function(x) {
|
||||
return Math.cos(x * Math.PI / 180);
|
||||
},
|
||||
"tand": function(x) {
|
||||
return Math.tan(x * Math.PI / 180);
|
||||
},
|
||||
"asind": function(x) {
|
||||
return Math.asin(x) / Math.PI * 180;
|
||||
},
|
||||
"acosd": function(x) {
|
||||
return Math.acos(x) / Math.PI * 180;
|
||||
},
|
||||
"atand": function(x) {
|
||||
return Math.atan(x) / Math.PI * 180;
|
||||
},
|
||||
"log": Math.log,
|
||||
"exp": Math.exp
|
||||
};
|
||||
|
||||
Compiler.predefined_binary_functions = {
|
||||
"min": Math.min,
|
||||
"max": Math.max,
|
||||
"pow": Math.pow,
|
||||
"atan2": Math.atan2,
|
||||
"atan2d": function(y, x) {
|
||||
return Math.atan2(y, x) / Math.PI * 180;
|
||||
}
|
||||
};
|
||||
|
||||
Compiler.predefined_values = {
|
||||
PI: Math.PI,
|
||||
true: 1,
|
||||
false: 0
|
||||
};
|
||||
|
||||
return Compiler;
|
||||
|
||||
}).call(this);
|
||||
|
||||
this.Locals = class Locals {
|
||||
constructor(compiler, parent = null) {
|
||||
this.compiler = compiler;
|
||||
this.parent = parent;
|
||||
this.layers = [];
|
||||
this.index = 0;
|
||||
this.max_index = 0;
|
||||
this.push();
|
||||
this.imports = [];
|
||||
}
|
||||
|
||||
increment() {
|
||||
var spot;
|
||||
spot = this.index++;
|
||||
this.max_index = Math.max(this.index, this.max_index);
|
||||
return spot;
|
||||
}
|
||||
|
||||
push() {
|
||||
return this.layers.push(new LocalLayer(this));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
register(name) {
|
||||
return this.layers[this.layers.length - 1].register(name);
|
||||
}
|
||||
|
||||
allocate() {
|
||||
return this.layers[this.layers.length - 1].allocate();
|
||||
}
|
||||
|
||||
get(name) {
|
||||
var i, index, j, ref, v;
|
||||
if (name === "arguments") {
|
||||
this.arguments_used = true;
|
||||
}
|
||||
for (i = j = ref = this.layers.length - 1; j >= 0; i = j += -1) {
|
||||
v = this.layers[i].get(name);
|
||||
if (v != null) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
if (this.parent != null) {
|
||||
v = this.parent.get(name);
|
||||
if (v != null) {
|
||||
index = this.register(name);
|
||||
this.imports.push({
|
||||
name: name,
|
||||
index: index,
|
||||
source: v
|
||||
});
|
||||
return index;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
LocalLayer = class LocalLayer {
|
||||
constructor(locals1) {
|
||||
this.locals = locals1;
|
||||
this.start_index = this.locals.index;
|
||||
this.registered = {};
|
||||
}
|
||||
|
||||
register(name) {
|
||||
return this.registered[name] = this.locals.increment();
|
||||
}
|
||||
|
||||
allocate() {
|
||||
return this.locals.increment();
|
||||
}
|
||||
|
||||
get(name) {
|
||||
if (this.registered[name] != null) {
|
||||
return this.registered[name];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 594 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 913 B |
@@ -0,0 +1,467 @@
|
||||
<!DOCTYPE html><html><head><title>micro Box</title><meta http-equiv="content-type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui=1"><meta charset="UTF-8"><meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="description" content=""><link rel="manifest" href="manifest.json"><link rel="icon" type="image/png" href="icon64.png"><link rel="apple-touch-icon" sizes="180x180" href="icon180.png"><link rel="icon" type="image/png" sizes="32x32" href="icon32.png"><link rel="icon" type="image/png" sizes="16x16" href="icon16.png"><style>html,body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #000;
|
||||
overflow:hidden;
|
||||
font-family: Verdana;
|
||||
}
|
||||
.noselect {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
#canvaswrapper {
|
||||
text-align: center ;
|
||||
}
|
||||
</style><style>@font-face { font-family: "BitCell" ; src: url("fonts/BitCell.ttf") format("truetype"); }</style><style>@font-face { font-family: "Edunline" ; src: url("fonts/Edunline.ttf") format("truetype"); }</style><script>window.fonts = ["BitCell","Edunline"]</script></head><body class="noselect custom-cursor" oncontextmenu="return false;"><div id="canvaswrapper"></div><script type="text/javascript">var resources = {"images":[{"file":"arrow_left.png","version":11,"size":175,"properties":{"frames":1,"fps":5}},{"file":"arrow_right.png","version":6,"size":177,"properties":{"frames":1,"fps":5}},{"file":"exit.png","version":21,"size":152,"properties":{"frames":1,"fps":5}},{"file":"gamepad.png","version":33,"size":327,"properties":{"frames":1,"fps":5}},{"file":"icon.png","version":250,"size":748,"properties":{"frames":1,"fps":5}},{"file":"icon_transparent.png","version":19,"size":741,"properties":{"frames":1,"fps":5}},{"file":"keyboard.png","version":24,"size":272,"properties":{"frames":1,"fps":5}},{"file":"microstudio.png","version":1,"size":17652,"properties":{}},{"file":"poster.png","version":4,"size":56514,"properties":{"frames":1,"fps":5}},{"file":"rotate.png","version":47,"size":286,"properties":{"frames":1,"fps":5}},{"file":"touch.png","version":25,"size":239,"properties":{"frames":1,"fps":5}}],"assets":[],"maps":{},"sounds":[{"file":"microfxr-back.wav","version":1,"size":51772,"properties":{}},{"file":"microfxr-enter.wav","version":1,"size":51772,"properties":{}},{"file":"microfxr-switch.wav","version":1,"size":4872,"properties":{}},{"file":"microfxr-welcome.wav","version":1,"size":95192,"properties":{}}],"music":[]};
|
||||
var graphics = "M1";
|
||||
|
||||
</script><script type="text/javascript">var orientation = 'landscape' ;
|
||||
var aspect = 'free' ;
|
||||
var ms_libs = [] ;
|
||||
window.skip_service_worker = true;
|
||||
window.exported_project = true;
|
||||
window.ms_use_server = false ;
|
||||
</script><script src="compiler.js"></script><script src="parser.js"></script><script src="processor.js"></script><script src="program.js"></script><script src="routine.js"></script><script src="runner.js"></script><script src="token.js"></script><script src="tokenizer.js"></script><script src="transpiler.js"></script><script src="microengine.js"></script></body><script type="text/javascript">//
|
||||
//
|
||||
// The game is started with the code below.
|
||||
// Once you have received the "started" signal (see below),
|
||||
// you can do the following:
|
||||
// 1) Inject functions or objects into the global context of the microStudio engine, example:
|
||||
//
|
||||
// window.player.setGlobal("special_callback",function(x) { console.info(x) }) ;
|
||||
// // Your microScript code can now call the "special_callback" function
|
||||
//
|
||||
// 2) Call microScript global functions from your JavaScript code, example:
|
||||
//
|
||||
// window.player.call("call_me_from_javascript",[10,1000]) ;
|
||||
// // arguments to the function call are provided as an array
|
||||
//
|
||||
// 3) Run a microScript code snippet from your JavaScript code, example:
|
||||
//
|
||||
// window.player.exec("player.position_x = 50",function(result) { console.log(result) ; }) ;
|
||||
//
|
||||
|
||||
window.addEventListener("load",function() {
|
||||
window.player = new Player(function(event) {
|
||||
if (event.name == "started") {
|
||||
// signal that the game is started
|
||||
}
|
||||
else if (event.name == "log") {
|
||||
// console.info(event.data) ;
|
||||
}
|
||||
}) ;
|
||||
document.body.focus() ;
|
||||
}) ;
|
||||
|
||||
</script><script id="code" type="text/x-microscript">
|
||||
|
||||
|
||||
function()
|
||||
addGame = function(title,nick,slug)
|
||||
games += object
|
||||
title = title
|
||||
nick = nick
|
||||
slug = slug
|
||||
end
|
||||
end
|
||||
|
||||
addGames = function()
|
||||
games = []
|
||||
|
||||
addGame("Nameless Moth","Deleted","moth")
|
||||
addGame("Evade","HomineLudens","evade")
|
||||
addGame("Take me to Mars","JimB007","tmtm")
|
||||
addGame("The Great Wyrm","KimsGames","holiday2022")
|
||||
addGame("micro Mower","JimB007","micromower")
|
||||
addGame("Lemmy Long Legs II","Ogofkop","lemmylonglegs2")
|
||||
addGame("Panzer!","Sebastian","panzer")
|
||||
addGame("Marble Quest","HomineLudens","marblequest")
|
||||
addGame("Meowy's Adventure","mrLman","meowys_adventure")
|
||||
addGame("Energy Leak","JmeJuniper","nrgleak2")
|
||||
addGame("micro Farm","JimB007","microfarm")
|
||||
addGame("Night Drive","jaysnjj","nightdrive")
|
||||
addGame("Courage","KimsGames","courage")
|
||||
addGame("NES Fire","royerson","fire")
|
||||
addGame("micro Adventure","JimB007","micoadventure")
|
||||
addGame("Sandra and the Avocados","stonith","sandra")
|
||||
addGame("Troubles Be Gone","KimsGames","halloween")
|
||||
addGame("Reggie the Hedgie","gilles","reggie")
|
||||
addGame("Alien Blaster","jaysnjj","alien_blaster")
|
||||
addGame("Lemmy Long Legs","Ogofkop","lemmylongleg")
|
||||
addGame("Fishing Party","gilles","fishing2")
|
||||
addGame("Racing Demo","gilles","racingdemo")
|
||||
addGame("Planet Repair Squad","gilles","planetrepairsquad")
|
||||
shuffle()
|
||||
end
|
||||
|
||||
shuffle = function()
|
||||
local g = []
|
||||
while games.length > 0
|
||||
local game = games.removeAt(random.nextInt(games.length))
|
||||
g += game
|
||||
end
|
||||
games = g
|
||||
end
|
||||
|
||||
end()
|
||||
|
||||
|
||||
|
||||
system.javascript("""
|
||||
|
||||
// javascript
|
||||
|
||||
this.embed = function(url,close_button) {
|
||||
console.info(url);
|
||||
console.info("close_button = "+close_button)
|
||||
var canvas = document.querySelector("canvas") ;
|
||||
var parent = canvas.parentNode ;
|
||||
var iframe = document.createElement("iframe") ;
|
||||
iframe.src = url ;
|
||||
iframe.allow = "autoplay https://microstudio.io; gamepad https://microstudio.io; midi https://microstudio.io"
|
||||
iframe.style = "position: absolute ; top: 0 ; left: 0 ; width: 100% ; height: 100% ; border: none ; z-index: 0 ; transition-property: opacity ; transition-duration: 2s ; opacity: 0" ;
|
||||
iframe.allowFullscreen = false ;
|
||||
|
||||
canvas.style["transition-property"] = "opacity" ;
|
||||
canvas.style["transition-duration"] = "1s" ;
|
||||
parent.insertBefore(iframe,canvas)
|
||||
iframe.contentWindow.addEventListener("load",()=>{
|
||||
iframe.contentWindow.focus() ;
|
||||
iframe.style.opacity = 1 ;
|
||||
})
|
||||
|
||||
iframe.contentWindow.addEventListener('keydown', (event) => {
|
||||
console.log('Keydown event in iframe:', event);
|
||||
if (event.key == "Escape") {
|
||||
global.back_to_menu = true ;
|
||||
}
|
||||
});
|
||||
|
||||
if (close_button) {
|
||||
console.info("CLOSE BUTTON")
|
||||
var img = new Image() ;
|
||||
img.src = "sprites/exit.png" ;
|
||||
img.id = "exit-button" ;
|
||||
img.style = "width: 5vw ; position: fixed ; top: 1.5vw ; right: 1.5vw ; opacity: .5 ; image-rendering: moz-crisp-edges; image-rendering: pixelated ; z-index: 10" ;
|
||||
document.body.appendChild(img) ;
|
||||
img.addEventListener("click",()=>{global.back_to_menu = true})
|
||||
}
|
||||
|
||||
setTimeout(()=> {
|
||||
canvas.style.opacity = 0 ;
|
||||
setTimeout(()=>{
|
||||
canvas.style.display = "none" ;
|
||||
},1000)
|
||||
},0)
|
||||
|
||||
setTimeout(()=>{
|
||||
|
||||
},500)
|
||||
|
||||
global.canvas = canvas
|
||||
global.iframe = iframe
|
||||
global.window = window
|
||||
}
|
||||
|
||||
this.restore = function() {
|
||||
var iframe = document.querySelector("iframe") ;
|
||||
if (iframe) {
|
||||
iframe.parentNode.removeChild(iframe) ;
|
||||
}
|
||||
var canvas = document.querySelector("canvas") ;
|
||||
canvas.style.display = "block" ;
|
||||
setTimeout(()=>{
|
||||
canvas.style.opacity = 1 ;
|
||||
},1)
|
||||
|
||||
setTimeout(()=> { window.focus() },100)
|
||||
var exit = document.getElementById("exit-button") ;
|
||||
if (exit) {
|
||||
exit.parentNode.removeChild(exit) ;
|
||||
}
|
||||
}
|
||||
|
||||
this.loadImage = function(url,callback) {
|
||||
var img = new Image() ;
|
||||
img.src = url ;
|
||||
img.onload = ()=> { callback(new global.Image(img)) } ;
|
||||
}
|
||||
|
||||
|
||||
var fullscreendone = false ;
|
||||
|
||||
document.body.addEventListener("mouseup",()=> {
|
||||
if (! fullscreendone) {
|
||||
fullscreendone = true ;
|
||||
document.body.requestFullscreen() ;
|
||||
}
|
||||
}) ;
|
||||
|
||||
/*
|
||||
This will be needed to work cross-domain
|
||||
|
||||
window.addEventListener("message",(msg)=>{
|
||||
try {
|
||||
var data = JSON.parse(msg.data) ;
|
||||
if (data.name == "started") {
|
||||
console.info("STARTED!") ;
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
};
|
||||
}) ;*/
|
||||
|
||||
""")
|
||||
|
||||
|
||||
|
||||
function()
|
||||
CRT = function(size = 240,intensity = .5)
|
||||
if not CRT_BUFFER.type or size != CRT_BUFFER_SIZE or intensity != CRT_BUFFER_INTENSITY then
|
||||
CRT_BUFFER_SIZE = size
|
||||
size *= 2
|
||||
CRT_BUFFER_INTENSITY = intensity
|
||||
CRT_BUFFER = new Image(size,size)
|
||||
CRT_BUFFER.setRadialGradient(size/2,size/2,size/2*1.4142,"rgba(0,0,0,0)","rgba(0,0,0,"+intensity+")")
|
||||
CRT_BUFFER.fillRect(0,0,size,size)
|
||||
|
||||
CRT_BUFFER.setRadialGradient(size/2,size/2,size/2*3,"rgba(0,0,0,0)","rgba(0,0,0,"+intensity+")")
|
||||
for i=0 to size by 4
|
||||
//CRT_BUFFER.drawLine(0,0,200,200)
|
||||
CRT_BUFFER.drawLine(0,i+.5,size,i+.5)
|
||||
end
|
||||
end
|
||||
|
||||
screen.setPixelated(false)
|
||||
screen.drawImage(CRT_BUFFER,0,0,screen.width,screen.height)
|
||||
screen.setPixelated(true)
|
||||
end
|
||||
end()
|
||||
|
||||
|
||||
|
||||
function()
|
||||
init = function()
|
||||
// embed()
|
||||
addGames()
|
||||
|
||||
for game in games
|
||||
loadImage("https://microstudio.io/"+game.nick+"/"+game.slug+"/sprites/icon.png",function(img)
|
||||
game.image = img
|
||||
end)
|
||||
end
|
||||
|
||||
browse_position = 0
|
||||
browse_selected = 0
|
||||
target_position = 0
|
||||
position_speed = 0
|
||||
started = false
|
||||
back_to_menu = false
|
||||
dragging = false
|
||||
|
||||
control_modes = ["keyboard","gamepad","touch"]
|
||||
|
||||
control = object end
|
||||
clickable = []
|
||||
|
||||
mode = "browse"
|
||||
screen.setFont("Edunline")
|
||||
end
|
||||
|
||||
update = function()
|
||||
if not started then
|
||||
if mouse.press then
|
||||
started = true
|
||||
audio.playSound("microfxr/welcome",.125)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if gamepad.press.RIGHT or gamepad.press.LEFT or gamepad.A then
|
||||
control_modes = ["gamepad"]
|
||||
end
|
||||
|
||||
if keyboard.press.RIGHT or keyboard.press.LEFT or keyboard.press.ENTER or keyboard.press.SPACE then
|
||||
control_modes = ["keyboard"]
|
||||
end
|
||||
|
||||
control.LEFT = gamepad.press.LEFT or keyboard.press.LEFT
|
||||
control.RIGHT = gamepad.press.RIGHT or keyboard.press.RIGHT
|
||||
control.ACTION = gamepad.press.A or keyboard.press.ENTER or keyboard.press.SPACE
|
||||
control.BACK = back_to_menu or gamepad.press.MENU or (gamepad.X and gamepad.B)
|
||||
|
||||
if touch.press then
|
||||
control_modes = ["touch"]
|
||||
dragging = false
|
||||
if abs(touch.x+150)<10 and abs(touch.y)<25 then
|
||||
if target_position > 0 then
|
||||
target_position -= 1
|
||||
browse_selected = target_position+1
|
||||
audio.playSound("microfxr/switch",.125)
|
||||
end
|
||||
elsif abs(touch.x-150)<10 and abs(touch.y)<25 then
|
||||
if target_position < games.length-4 then
|
||||
target_position += 1
|
||||
browse_selected = target_position+1
|
||||
audio.playSound("microfxr/switch",.125)
|
||||
end
|
||||
elsif abs(touch.x)<140 and abs(touch.y)<50 then
|
||||
dragging = true
|
||||
drag_start = target_position
|
||||
drag_start_x = touch.x
|
||||
drag_moved = false
|
||||
browse_selected = round((touch.x+105)/70)+target_position
|
||||
end
|
||||
end
|
||||
|
||||
if touch.touching then
|
||||
if dragging then
|
||||
if abs(touch.x - drag_start_x) > 10 then
|
||||
drag_moved = true
|
||||
browse_selected = -1
|
||||
end
|
||||
|
||||
if drag_moved then
|
||||
target_position = max(0,min(games.length-4,drag_start+(drag_start_x-touch.x)/30))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if touch.release then
|
||||
if dragging then
|
||||
dragging = false
|
||||
if drag_moved then
|
||||
target_position = round(target_position)
|
||||
browse_selected = target_position + 1
|
||||
else
|
||||
control.ACTION = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if mode == "browse" then
|
||||
if control.RIGHT then
|
||||
if browse_selected < games.length-1 then
|
||||
browse_selected += 1
|
||||
audio.playSound("microfxr/switch",.125)
|
||||
if target_position < browse_selected-2 then
|
||||
target_position += 1
|
||||
target_position = min(games.length-4,target_position)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (control.LEFT) and browse_selected > 0 then
|
||||
browse_selected -= 1
|
||||
audio.playSound("microfxr/switch",.125)
|
||||
if target_position > browse_selected-1 and target_position > 0 then
|
||||
target_position -= 1
|
||||
end
|
||||
end
|
||||
|
||||
if control.ACTION then
|
||||
mode = "play"
|
||||
audio.playSound("microfxr/enter",.125)
|
||||
local game = games[browse_selected]
|
||||
embed("https://microstudio.io/"+game.nick+"/"+game.slug+"/",control_modes[0] == "touch")
|
||||
end
|
||||
else
|
||||
if control.BACK then
|
||||
back_to_menu = false
|
||||
restore()
|
||||
mode = "browse"
|
||||
audio.playSound("microfxr/back",.125)
|
||||
end
|
||||
end
|
||||
|
||||
position_speed += (target_position-browse_position)*.1
|
||||
position_speed *= .5
|
||||
browse_position += position_speed
|
||||
end
|
||||
|
||||
draw = function()
|
||||
local background = "rgb(5,30,43)"
|
||||
screen.clear(background)
|
||||
if screen.width < screen.height then
|
||||
screen.setAlpha(.5)
|
||||
screen.drawSprite("rotate",0,0,48)
|
||||
screen.setAlpha(1)
|
||||
return
|
||||
end
|
||||
|
||||
screen.setFont("Edunline")
|
||||
if not screen.isFontReady() then
|
||||
return
|
||||
end
|
||||
screen.drawText("micro Box",0,65,20,"rgb(65,120,147)")
|
||||
if not started then
|
||||
screen.setFont("BitCell")
|
||||
local size = sin((system.time()%500)/500*PI*2)
|
||||
screen.fillRect(0,-25,60+size,18+size*.5,"rgb(197,87,87)")
|
||||
screen.drawText("START",0,-25,10,"#FFF")
|
||||
screen.drawSprite("icon_transparent",0,20)
|
||||
screen.drawText("Powered by",0,-70,6,"rgba(255,255,255,.5)")
|
||||
screen.setPixelated(false)
|
||||
screen.drawSprite("microstudio",0,-80,50)
|
||||
screen.setPixelated(true)
|
||||
return
|
||||
end
|
||||
|
||||
// screen.drawSprite("icon",-120,65,20)
|
||||
|
||||
screen.setFont("BitCell")
|
||||
for i=0 to games.length-1 by 1
|
||||
local game = games[i]
|
||||
local x = (i-browse_position)*70-105
|
||||
if game and game.image and abs(x) <160 then
|
||||
screen.setAlpha(max(0,min(1,3-abs(x)/160*3)))
|
||||
if i == browse_selected then
|
||||
screen.fillRect(x,0,55,55,"rgb(255,142,85)")
|
||||
screen.fillRect(x,0,51,51,background)
|
||||
else
|
||||
screen.fillRect(x,0,55,55,"rgba(255,255,255,.1)")
|
||||
end
|
||||
screen.drawSprite(game.image,x,0,50,50)
|
||||
screen.drawText(game.title,x,-35,7,"rgba(255,255,255,.8)")
|
||||
end
|
||||
end
|
||||
|
||||
screen.setAlpha(.5)
|
||||
if target_position > 0 then
|
||||
screen.drawSprite("arrow_left",-150,0,8)
|
||||
end
|
||||
if target_position < games.length-4 then
|
||||
screen.drawSprite("arrow_right",150,0,8)
|
||||
end
|
||||
|
||||
local dx = -(control_modes.length-1)/2*50
|
||||
for c in control_modes
|
||||
screen.drawSprite(c,dx,-65,24)
|
||||
dx += 50
|
||||
end
|
||||
|
||||
if control_modes.length == 1 then
|
||||
if control_modes[0] == "keyboard" then
|
||||
screen.drawText("ENTER to start game - ESC to exit game",0,-90,8)
|
||||
elsif control_modes[0] == "gamepad" then
|
||||
screen.drawText("[A] to start game - [MENU] to exit game",0,-90,8)
|
||||
else
|
||||
screen.drawText("Tap to start game",-50,-90,8)
|
||||
screen.drawText("exit game with",50,-90,8)
|
||||
screen.setAlpha(1)
|
||||
screen.drawSprite("exit",85,-90)
|
||||
end
|
||||
end
|
||||
|
||||
screen.setAlpha(1)
|
||||
|
||||
// CRT()
|
||||
end
|
||||
end()
|
||||
|
||||
|
||||
</script></html>
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"name": "micro Box",
|
||||
"short_name": "micro Box",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#000000",
|
||||
"display": "fullscreen",
|
||||
"orientation": "landscape",
|
||||
"scope": "",
|
||||
"start_url": ".",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon192.png?v=0",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "icon196.png?v=0",
|
||||
"type": "image/png",
|
||||
"sizes": "196x196",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "icon512.png?v=0",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
},
|
||||
{
|
||||
"src": "icon1024.png?v=0",
|
||||
"type": "image/png",
|
||||
"sizes": "1024x1024"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,812 @@
|
||||
this.Parser = (function() {
|
||||
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;
|
||||
}
|
||||
|
||||
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("Unexpected data");
|
||||
}
|
||||
}
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//console.error err
|
||||
parseLine() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
if (first_function_call && access instanceof Program.FunctionCall) {
|
||||
return access;
|
||||
}
|
||||
expression = access;
|
||||
}
|
||||
}
|
||||
|
||||
assertExpression(filter, first_function_call = false) {
|
||||
var exp;
|
||||
exp = this.parseExpression(filter, first_function_call);
|
||||
if (exp == null) {
|
||||
throw "Expression expected";
|
||||
}
|
||||
return exp;
|
||||
}
|
||||
|
||||
parseExpressionSuffix(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);
|
||||
return expression;
|
||||
} else if (token.is_binary_operator && filter !== "noop") {
|
||||
return this.parseBinaryOperation(token, expression);
|
||||
} else {
|
||||
this.tokenizer.pushBack(token);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
parseNumberExpression(number) {
|
||||
return new Program.Value(number, Program.Value.TYPE_NUMBER, number.value);
|
||||
}
|
||||
|
||||
parseStringExpression(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);
|
||||
}
|
||||
}
|
||||
|
||||
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.tokenizer.pushBack(token);
|
||||
res.push(this.assertExpression());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 {
|
||||
res = new Program.Assignment(token, expression, this.assertExpression());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
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_CLOSED_BRACE) {
|
||||
return new Program.Braced(open, expression);
|
||||
} else {
|
||||
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 {
|
||||
this.tokenizer.pushBack(token);
|
||||
start = token.start;
|
||||
args.push(this.assertExpression());
|
||||
this.last_function_call.argslimits.push({
|
||||
start: start,
|
||||
end: this.tokenizer.index - 1
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addTerminable(token) {
|
||||
return this.not_terminated.push(token);
|
||||
}
|
||||
|
||||
endTerminable() {
|
||||
if (this.not_terminated.length > 0) {
|
||||
this.not_terminated.splice(this.not_terminated.length - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseFunctionArgs() {
|
||||
var args, exp, last, token;
|
||||
token = this.nextToken();
|
||||
args = [];
|
||||
last = null;
|
||||
if (token.type !== Token.TYPE_OPEN_BRACE) {
|
||||
return this.error("Expected opening parenthese");
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
warningAssignmentCondition(expression) {
|
||||
if (expression instanceof Program.Assignment) {
|
||||
return this.warnings.push({
|
||||
type: "assignment_as_condition",
|
||||
line: expression.token.line,
|
||||
column: expression.token.column
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(type, error) {
|
||||
var token;
|
||||
token = this.nextToken();
|
||||
if (token.type !== type) {
|
||||
throw error;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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'");
|
||||
}
|
||||
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);
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
parseWhile(whiletoken) {
|
||||
var condition;
|
||||
condition = this.assertExpression();
|
||||
return new Program.While(whiletoken, condition, this.parseSequence(whiletoken));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
parseNew(token) {
|
||||
var exp;
|
||||
exp = this.assertExpression(null, true);
|
||||
return new Program.NewCall(token, exp);
|
||||
}
|
||||
|
||||
parseAfter(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];
|
||||
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.tokenizer.pushBack(token);
|
||||
line = this.parseLine();
|
||||
if (line != null) {
|
||||
sequence.push(line);
|
||||
} else {
|
||||
this.error("Unexpected data while parsing after");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.tokenizer.pushBack(token);
|
||||
line = this.parseLine();
|
||||
if (line != null) {
|
||||
sequence.push(line);
|
||||
} else {
|
||||
this.error("Unexpected data while parsing after");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseSleep(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];
|
||||
} else {
|
||||
this.tokenizer.pushBack(token);
|
||||
}
|
||||
}
|
||||
return new Program.Sleep(sleep, delay, multiplier);
|
||||
}
|
||||
|
||||
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 {
|
||||
return new Program.Delete(del, v);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -0,0 +1,371 @@
|
||||
this.Program = class Program {
|
||||
constructor() {
|
||||
this.statements = [];
|
||||
}
|
||||
|
||||
add(statement) {
|
||||
return this.statements.push(statement);
|
||||
}
|
||||
|
||||
isAssignment() {
|
||||
return this.statements.length > 0 && this.statements[this.statements.length - 1] instanceof Program.Assignment;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Expression = class Expression {
|
||||
constructor() {}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Assignment = class Assignment {
|
||||
constructor(token1, field1, expression1, local) {
|
||||
this.token = token1;
|
||||
this.field = field1;
|
||||
this.expression = expression1;
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.SelfAssignment = class SelfAssignment {
|
||||
constructor(token1, field1, operation, expression1) {
|
||||
this.token = token1;
|
||||
this.field = field1;
|
||||
this.operation = operation;
|
||||
this.expression = expression1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Value = (function() {
|
||||
class Value {
|
||||
constructor(token1, type, value1) {
|
||||
this.token = token1;
|
||||
this.type = type;
|
||||
this.value = value1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Value.TYPE_NUMBER = 1;
|
||||
|
||||
Value.TYPE_STRING = 2;
|
||||
|
||||
Value.TYPE_ARRAY = 3;
|
||||
|
||||
Value.TYPE_OBJECT = 4;
|
||||
|
||||
Value.TYPE_FUNCTION = 5;
|
||||
|
||||
Value.TYPE_CLASS = 6;
|
||||
|
||||
return Value;
|
||||
|
||||
}).call(this);
|
||||
|
||||
this.Program.CreateFieldAccess = function(token, expression, field) {
|
||||
if (expression instanceof Program.Field) {
|
||||
expression.appendField(field);
|
||||
return expression;
|
||||
} else {
|
||||
return new Program.Field(token, expression, [field]);
|
||||
}
|
||||
};
|
||||
|
||||
this.Program.Variable = class Variable {
|
||||
constructor(token1, identifier) {
|
||||
this.token = token1;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Field = class Field {
|
||||
constructor(token1, expression1, chain) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
this.chain = chain;
|
||||
this.token = this.expression.token;
|
||||
}
|
||||
|
||||
appendField(field) {
|
||||
return this.chain.push(field);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.BuildOperations = function(ops, terms) {
|
||||
var i, o, o1, o2, prec, t1, t2;
|
||||
while (ops.length > 1) {
|
||||
i = 0;
|
||||
prec = 0;
|
||||
while (i < ops.length - 1) {
|
||||
o1 = ops[i];
|
||||
o2 = ops[i + 1];
|
||||
if (Program.Precedence[o2.operation] <= Program.Precedence[o1.operation]) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
t1 = terms[i];
|
||||
t2 = terms[i + 1];
|
||||
o = new Program.Operation(ops[i].token, ops[i].operation, t1, t2);
|
||||
terms.splice(i, 2, o);
|
||||
ops.splice(i, 1);
|
||||
}
|
||||
return new Program.Operation(ops[0].token, ops[0].operation, terms[0], terms[1]);
|
||||
};
|
||||
|
||||
this.Program.Operation = class Operation {
|
||||
constructor(token1, operation, term1, term2) {
|
||||
this.token = token1;
|
||||
this.operation = operation;
|
||||
this.term1 = term1;
|
||||
this.term2 = term2;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Negate = class Negate {
|
||||
constructor(token1, expression1) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Not = class Not {
|
||||
constructor(token1, expression1) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Braced = class Braced {
|
||||
constructor(token1, expression1) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Return = class Return {
|
||||
constructor(token1, expression1) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Condition = class Condition {
|
||||
constructor(token1, chain) {
|
||||
this.token = token1;
|
||||
this.chain = chain;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.For = class For {
|
||||
constructor(token1, iterator, range_from, range_to, range_by, sequence) {
|
||||
this.token = token1;
|
||||
this.iterator = iterator;
|
||||
this.range_from = range_from;
|
||||
this.range_to = range_to;
|
||||
this.range_by = range_by;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.ForIn = class ForIn {
|
||||
constructor(token1, iterator, list, sequence) {
|
||||
this.token = token1;
|
||||
this.iterator = iterator;
|
||||
this.list = list;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.toString = function(value, nesting = 0) {
|
||||
var i, j, k, key, len, pref, ref, s, v;
|
||||
if (value instanceof Routine) {
|
||||
if (nesting === 0) {
|
||||
return value.source || "[function]";
|
||||
} else {
|
||||
return "[function]";
|
||||
}
|
||||
} else if (typeof value === "function") {
|
||||
return "[native function]";
|
||||
} else if (typeof value === "string") {
|
||||
return `"${value}"`;
|
||||
} else if (Array.isArray(value)) {
|
||||
if (nesting >= 1) {
|
||||
return "[list]";
|
||||
}
|
||||
s = "[";
|
||||
for (i = j = 0, len = value.length; j < len; i = ++j) {
|
||||
v = value[i];
|
||||
s += Program.toString(v, nesting + 1) + (i < value.length - 1 ? "," : "");
|
||||
}
|
||||
return s + "]";
|
||||
} else if (typeof value === "object") {
|
||||
if (nesting >= 1) {
|
||||
return "[object]";
|
||||
}
|
||||
s = "object\n";
|
||||
pref = "";
|
||||
for (i = k = 1, ref = nesting; k <= ref; i = k += 1) {
|
||||
pref += " ";
|
||||
}
|
||||
for (key in value) {
|
||||
v = value[key];
|
||||
s += pref + ` ${key} = ${Program.toString(v, nesting + 1)}\n`;
|
||||
}
|
||||
return s + pref + "end";
|
||||
}
|
||||
return value || 0;
|
||||
};
|
||||
|
||||
this.Program.While = class While {
|
||||
constructor(token1, condition, sequence) {
|
||||
this.token = token1;
|
||||
this.condition = condition;
|
||||
this.sequence = sequence;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Break = class Break {
|
||||
constructor(token1) {
|
||||
this.token = token1;
|
||||
this.nopop = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Continue = class Continue {
|
||||
constructor(token1) {
|
||||
this.token = token1;
|
||||
this.nopop = true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Function = class Function {
|
||||
constructor(token1, args, sequence, end) {
|
||||
this.token = token1;
|
||||
this.args = args;
|
||||
this.sequence = sequence;
|
||||
this.source = "function" + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.FunctionCall = class FunctionCall {
|
||||
constructor(token1, expression1, args) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.CreateObject = class CreateObject {
|
||||
constructor(token1, fields) {
|
||||
this.token = token1;
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.CreateClass = class CreateClass {
|
||||
constructor(token1, ext, fields) {
|
||||
this.token = token1;
|
||||
this.ext = ext;
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.NewCall = class NewCall {
|
||||
constructor(token1, expression1) {
|
||||
this.token = token1;
|
||||
this.expression = expression1;
|
||||
if (!(this.expression instanceof Program.FunctionCall)) {
|
||||
this.expression = new Program.FunctionCall(this.token, this.expression, []);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.After = class After {
|
||||
constructor(token1, delay, sequence, end, multiplier) {
|
||||
this.token = token1;
|
||||
this.delay = delay;
|
||||
this.sequence = sequence;
|
||||
this.multiplier = multiplier;
|
||||
this.source = "after " + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Every = class Every {
|
||||
constructor(token1, delay, sequence, end, multiplier) {
|
||||
this.token = token1;
|
||||
this.delay = delay;
|
||||
this.sequence = sequence;
|
||||
this.multiplier = multiplier;
|
||||
this.source = "every " + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Do = class Do {
|
||||
constructor(token1, sequence, end) {
|
||||
this.token = token1;
|
||||
this.sequence = sequence;
|
||||
this.source = "do " + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Sleep = class Sleep {
|
||||
constructor(token1, delay, multiplier) {
|
||||
this.token = token1;
|
||||
this.delay = delay;
|
||||
this.multiplier = multiplier;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Delete = class Delete {
|
||||
constructor(token1, field1) {
|
||||
this.token = token1;
|
||||
this.field = field1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Program.Precedence = {
|
||||
"^": 21,
|
||||
"/": 20,
|
||||
"*": 19,
|
||||
"%": 18,
|
||||
"+": 17,
|
||||
"-": 17,
|
||||
"<": 16,
|
||||
"<=": 15,
|
||||
">": 14,
|
||||
">=": 13,
|
||||
"==": 12,
|
||||
"!=": 11,
|
||||
"<<": 10,
|
||||
">>": 9,
|
||||
"&": 8,
|
||||
"|": 7,
|
||||
"and": 6,
|
||||
"or": 5
|
||||
};
|
||||
@@ -0,0 +1,530 @@
|
||||
this.Routine = class Routine {
|
||||
constructor(num_args) {
|
||||
this.num_args = num_args;
|
||||
this.ops = [];
|
||||
this.opcodes = [];
|
||||
this.arg1 = [];
|
||||
this.ref = [];
|
||||
this.label_count = 0;
|
||||
this.labels = {};
|
||||
this.transpile = false;
|
||||
this.import_refs = [];
|
||||
this.import_values = [];
|
||||
this.import_self = -1;
|
||||
}
|
||||
|
||||
clone() {
|
||||
var r;
|
||||
r = new Routine(this.num_args);
|
||||
r.opcodes = this.opcodes;
|
||||
r.arg1 = this.arg1;
|
||||
r.ref = this.ref;
|
||||
r.locals_size = this.locals_size;
|
||||
r.uses_arguments = this.uses_arguments;
|
||||
return r;
|
||||
}
|
||||
|
||||
createLabel(str = "label") {
|
||||
var name;
|
||||
return name = ":" + str + "_" + this.label_count++;
|
||||
}
|
||||
|
||||
setLabel(name) {
|
||||
return this.labels[name] = this.opcodes.length;
|
||||
}
|
||||
|
||||
optimize() {
|
||||
if (this.transpile) {
|
||||
new Transpiler().transpile(this);
|
||||
}
|
||||
}
|
||||
|
||||
removeable(index) {
|
||||
var label, ref1, value;
|
||||
ref1 = this.labels;
|
||||
for (label in ref1) {
|
||||
value = ref1[label];
|
||||
if (value === index) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
remove(index) {
|
||||
var label, ref1, value;
|
||||
ref1 = this.labels;
|
||||
for (label in ref1) {
|
||||
value = ref1[label];
|
||||
if (value === index) {
|
||||
return false;
|
||||
} else if (value > index) {
|
||||
this.labels[label] -= 1;
|
||||
}
|
||||
}
|
||||
this.opcodes.splice(index, 1);
|
||||
this.arg1.splice(index, 1);
|
||||
this.ref.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
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) {
|
||||
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]]);
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
} else if ((ref3 = this.opcodes[i]) === OPCODES.FORLOOP_CONTROL || ref3 === OPCODES.FORLOOP_INIT || ref3 === OPCODES.FORIN_CONTROL || ref3 === OPCODES.FORIN_INIT) {
|
||||
if (this.labels[this.arg1[i][1]]) {
|
||||
results.push(this.arg1[i][1] = this.labels[this.arg1[i][1]]);
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
OP(code, ref, v1 = 0) {
|
||||
this.opcodes.push(code);
|
||||
this.arg1.push(v1);
|
||||
return this.ref.push(ref);
|
||||
}
|
||||
|
||||
OP_INSERT(code, ref, v1 = 0, index) {
|
||||
var label, ref1, value;
|
||||
this.opcodes.splice(index, 0, code);
|
||||
this.arg1.splice(index, 0, v1);
|
||||
this.ref.splice(index, 0, ref);
|
||||
ref1 = this.labels;
|
||||
for (label in ref1) {
|
||||
value = ref1[label];
|
||||
if (value >= index) {
|
||||
this.labels[label] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TYPE(ref) {
|
||||
return this.OP(OPCODES.TYPE, ref);
|
||||
}
|
||||
|
||||
VARIABLE_TYPE(variable, ref) {
|
||||
return this.OP(OPCODES.VARIABLE_TYPE, ref, variable);
|
||||
}
|
||||
|
||||
PROPERTY_TYPE(ref) {
|
||||
return this.OP(OPCODES.PROPERTY_TYPE, ref);
|
||||
}
|
||||
|
||||
LOAD_THIS(ref) {
|
||||
return this.OP(OPCODES.LOAD_THIS, ref);
|
||||
}
|
||||
|
||||
LOAD_GLOBAL(ref) {
|
||||
return this.OP(OPCODES.LOAD_GLOBAL, ref);
|
||||
}
|
||||
|
||||
LOAD_VALUE(value, ref) {
|
||||
return this.OP(OPCODES.LOAD_VALUE, ref, value);
|
||||
}
|
||||
|
||||
LOAD_LOCAL(index, ref) {
|
||||
return this.OP(OPCODES.LOAD_LOCAL, ref, index);
|
||||
}
|
||||
|
||||
LOAD_VARIABLE(variable, ref) {
|
||||
return this.OP(OPCODES.LOAD_VARIABLE, ref, variable);
|
||||
}
|
||||
|
||||
LOAD_LOCAL_OBJECT(index, ref) {
|
||||
return this.OP(OPCODES.LOAD_LOCAL_OBJECT, ref, index);
|
||||
}
|
||||
|
||||
LOAD_VARIABLE_OBJECT(variable, ref) {
|
||||
return this.OP(OPCODES.LOAD_VARIABLE_OBJECT, ref, variable);
|
||||
}
|
||||
|
||||
POP(ref) {
|
||||
return this.OP(OPCODES.POP, ref);
|
||||
}
|
||||
|
||||
LOAD_PROPERTY(ref) {
|
||||
return this.OP(OPCODES.LOAD_PROPERTY, ref);
|
||||
}
|
||||
|
||||
LOAD_PROPERTY_OBJECT(ref) {
|
||||
return this.OP(OPCODES.LOAD_PROPERTY_OBJECT, ref);
|
||||
}
|
||||
|
||||
CREATE_OBJECT(ref) {
|
||||
return this.OP(OPCODES.CREATE_OBJECT, ref);
|
||||
}
|
||||
|
||||
MAKE_OBJECT(ref) {
|
||||
return this.OP(OPCODES.MAKE_OBJECT, ref);
|
||||
}
|
||||
|
||||
CREATE_ARRAY(ref) {
|
||||
return this.OP(OPCODES.CREATE_ARRAY, ref);
|
||||
}
|
||||
|
||||
CREATE_CLASS(parent_var, ref) {
|
||||
return this.OP(OPCODES.CREATE_CLASS, ref, parent_var);
|
||||
}
|
||||
|
||||
UPDATE_CLASS(variable, ref) {
|
||||
return this.OP(OPCODES.UPDATE_CLASS, ref, variable);
|
||||
}
|
||||
|
||||
NEW_CALL(args, ref) {
|
||||
return this.OP(OPCODES.NEW_CALL, ref, args);
|
||||
}
|
||||
|
||||
ADD(ref, self = 0) {
|
||||
return this.OP(OPCODES.ADD, ref, self);
|
||||
}
|
||||
|
||||
SUB(ref, self = 0) {
|
||||
return this.OP(OPCODES.SUB, ref, self);
|
||||
}
|
||||
|
||||
MUL(ref) {
|
||||
return this.OP(OPCODES.MUL, ref);
|
||||
}
|
||||
|
||||
DIV(ref) {
|
||||
return this.OP(OPCODES.DIV, ref);
|
||||
}
|
||||
|
||||
MODULO(ref) {
|
||||
return this.OP(OPCODES.MODULO, ref);
|
||||
}
|
||||
|
||||
BINARY_AND(ref) {
|
||||
return this.OP(OPCODES.BINARY_AND, ref);
|
||||
}
|
||||
|
||||
BINARY_OR(ref) {
|
||||
return this.OP(OPCODES.BINARY_OR, ref);
|
||||
}
|
||||
|
||||
SHIFT_LEFT(ref) {
|
||||
return this.OP(OPCODES.SHIFT_LEFT, ref);
|
||||
}
|
||||
|
||||
SHIFT_RIGHT(ref) {
|
||||
return this.OP(OPCODES.SHIFT_RIGHT, ref);
|
||||
}
|
||||
|
||||
NEGATE(ref) {
|
||||
return this.OP(OPCODES.NEGATE, ref);
|
||||
}
|
||||
|
||||
LOAD_PROPERTY_ATOP(ref) {
|
||||
return this.OP(OPCODES.LOAD_PROPERTY_ATOP, ref);
|
||||
}
|
||||
|
||||
EQ(ref) {
|
||||
return this.OP(OPCODES.EQ, ref);
|
||||
}
|
||||
|
||||
NEQ(ref) {
|
||||
return this.OP(OPCODES.NEQ, ref);
|
||||
}
|
||||
|
||||
LT(ref) {
|
||||
return this.OP(OPCODES.LT, ref);
|
||||
}
|
||||
|
||||
GT(ref) {
|
||||
return this.OP(OPCODES.GT, ref);
|
||||
}
|
||||
|
||||
LTE(ref) {
|
||||
return this.OP(OPCODES.LTE, ref);
|
||||
}
|
||||
|
||||
GTE(ref) {
|
||||
return this.OP(OPCODES.GTE, ref);
|
||||
}
|
||||
|
||||
NOT(ref) {
|
||||
return this.OP(OPCODES.NOT, ref);
|
||||
}
|
||||
|
||||
FORLOOP_INIT(iterator, ref) {
|
||||
return this.OP(OPCODES.FORLOOP_INIT, ref, iterator);
|
||||
}
|
||||
|
||||
FORLOOP_CONTROL(args, ref) {
|
||||
return this.OP(OPCODES.FORLOOP_CONTROL, ref, args);
|
||||
}
|
||||
|
||||
FORIN_INIT(args, ref) {
|
||||
return this.OP(OPCODES.FORIN_INIT, ref, args);
|
||||
}
|
||||
|
||||
FORIN_CONTROL(args, ref) {
|
||||
return this.OP(OPCODES.FORIN_CONTROL, ref, args);
|
||||
}
|
||||
|
||||
JUMP(index, ref) {
|
||||
return this.OP(OPCODES.JUMP, ref, index);
|
||||
}
|
||||
|
||||
JUMPY(index, ref) {
|
||||
return this.OP(OPCODES.JUMPY, ref, index);
|
||||
}
|
||||
|
||||
JUMPN(index, ref) {
|
||||
return this.OP(OPCODES.JUMPN, ref, index);
|
||||
}
|
||||
|
||||
JUMPY_NOPOP(index, ref) {
|
||||
return this.OP(OPCODES.JUMPY_NOPOP, ref, index);
|
||||
}
|
||||
|
||||
JUMPN_NOPOP(index, ref) {
|
||||
return this.OP(OPCODES.JUMPN_NOPOP, ref, index);
|
||||
}
|
||||
|
||||
STORE_LOCAL(index, ref) {
|
||||
return this.OP(OPCODES.STORE_LOCAL, ref, index);
|
||||
}
|
||||
|
||||
STORE_VARIABLE(field, ref) {
|
||||
return this.OP(OPCODES.STORE_VARIABLE, ref, field);
|
||||
}
|
||||
|
||||
CREATE_PROPERTY(ref) {
|
||||
return this.OP(OPCODES.CREATE_PROPERTY, ref);
|
||||
}
|
||||
|
||||
STORE_PROPERTY(ref) {
|
||||
return this.OP(OPCODES.STORE_PROPERTY, ref);
|
||||
}
|
||||
|
||||
LOAD_ROUTINE(value, ref) {
|
||||
return this.OP(OPCODES.LOAD_ROUTINE, ref, value);
|
||||
}
|
||||
|
||||
FUNCTION_CALL(args, ref) {
|
||||
return this.OP(OPCODES.FUNCTION_CALL, ref, args);
|
||||
}
|
||||
|
||||
FUNCTION_APPLY_VARIABLE(args, ref) {
|
||||
return this.OP(OPCODES.FUNCTION_APPLY_VARIABLE, ref, args);
|
||||
}
|
||||
|
||||
FUNCTION_APPLY_PROPERTY(args, ref) {
|
||||
return this.OP(OPCODES.FUNCTION_APPLY_PROPERTY, ref, args);
|
||||
}
|
||||
|
||||
SUPER_CALL(args, ref) {
|
||||
return this.OP(OPCODES.SUPER_CALL, ref, args);
|
||||
}
|
||||
|
||||
RETURN(ref) {
|
||||
return this.OP(OPCODES.RETURN, ref);
|
||||
}
|
||||
|
||||
AFTER(ref) {
|
||||
return this.OP(OPCODES.AFTER, ref);
|
||||
}
|
||||
|
||||
EVERY(ref) {
|
||||
return this.OP(OPCODES.EVERY, ref);
|
||||
}
|
||||
|
||||
DO(ref) {
|
||||
return this.OP(OPCODES.DO, ref);
|
||||
}
|
||||
|
||||
SLEEP(ref) {
|
||||
return this.OP(OPCODES.SLEEP, ref);
|
||||
}
|
||||
|
||||
DELETE(ref) {
|
||||
return this.OP(OPCODES.DELETE, ref);
|
||||
}
|
||||
|
||||
UNARY_OP(f, ref) {
|
||||
return this.OP(OPCODES.UNARY_OP, ref, f);
|
||||
}
|
||||
|
||||
BINARY_OP(f, ref) {
|
||||
return this.OP(OPCODES.BINARY_OP, ref, f);
|
||||
}
|
||||
|
||||
toString() {
|
||||
var i, j, len, op, ref1, s;
|
||||
s = "";
|
||||
ref1 = this.opcodes;
|
||||
for (i = j = 0, len = ref1.length; j < len; i = ++j) {
|
||||
op = ref1[i];
|
||||
s += OPCODES[op];
|
||||
if (this.arg1[i] != null) {
|
||||
//if typeof @arg1[i] != "function"
|
||||
s += ` ${this.arg1[i]}`;
|
||||
}
|
||||
s += "\n";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
exportArg(arg) {
|
||||
if (arg == null) {
|
||||
return 0;
|
||||
} else if (arg instanceof Routine) {
|
||||
return arg.export();
|
||||
} else if (typeof arg === "function") {
|
||||
return arg.name;
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
export() {
|
||||
var args, i, j, ref1, res;
|
||||
args = [];
|
||||
for (i = j = 0, ref1 = this.arg1.length - 1; j <= ref1; i = j += 1) {
|
||||
args[i] = this.exportArg(this.arg1[i]);
|
||||
}
|
||||
res = {
|
||||
num_args: this.num_args,
|
||||
ops: this.opcodes,
|
||||
args: args,
|
||||
import_refs: this.import_refs,
|
||||
import_values: this.import_values,
|
||||
import_self: this.import_self,
|
||||
locals_size: this.locals_size
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
import(src) {
|
||||
var i, j, ref, ref1, token;
|
||||
this.num_args = src.num_args;
|
||||
this.opcodes = src.ops;
|
||||
this.arg1 = src.args;
|
||||
this.import_refs = src.import_refs;
|
||||
this.import_values = src.import_values;
|
||||
this.import_self = src.import_self;
|
||||
this.locals_size = src.locals_size;
|
||||
token = {
|
||||
line: 0,
|
||||
column: 0,
|
||||
start: 0,
|
||||
length: 0,
|
||||
index: 0,
|
||||
tokenizer: {
|
||||
filename: "filename",
|
||||
input: ""
|
||||
}
|
||||
};
|
||||
ref = {
|
||||
expression: {
|
||||
token: token
|
||||
},
|
||||
token: token
|
||||
};
|
||||
for (i = j = 0, ref1 = this.opcodes.length - 1; j <= ref1; i = j += 1) {
|
||||
if (this.opcodes[i] === 100) {
|
||||
this.arg1[i] = Compiler.predefined_unary_functions[this.arg1[i]];
|
||||
} else if (this.opcodes[i] === 101) {
|
||||
this.arg1[i] = Compiler.predefined_binary_functions[this.arg1[i]];
|
||||
} else if (typeof this.arg1[i] === "object" && !Array.isArray(this.arg1[i])) {
|
||||
this.arg1[i] = new Routine(0).import(this.arg1[i]);
|
||||
}
|
||||
this.ref[i] = ref;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.OPCODES_CLASS = class OPCODES_CLASS {
|
||||
constructor() {
|
||||
this.table = {};
|
||||
this.set("TYPE", 1);
|
||||
this.set("VARIABLE_TYPE", 2);
|
||||
this.set("PROPERTY_TYPE", 3);
|
||||
this.set("LOAD_IMPORT", 4);
|
||||
this.set("LOAD_THIS", 5);
|
||||
this.set("LOAD_GLOBAL", 6);
|
||||
this.set("LOAD_VALUE", 10);
|
||||
this.set("LOAD_LOCAL", 11);
|
||||
this.set("LOAD_VARIABLE", 12);
|
||||
this.set("LOAD_LOCAL_OBJECT", 13);
|
||||
this.set("LOAD_VARIABLE_OBJECT", 14);
|
||||
this.set("POP", 15);
|
||||
this.set("LOAD_PROPERTY", 16);
|
||||
this.set("LOAD_PROPERTY_OBJECT", 17);
|
||||
this.set("CREATE_OBJECT", 18);
|
||||
this.set("MAKE_OBJECT", 19);
|
||||
this.set("CREATE_ARRAY", 20);
|
||||
this.set("STORE_LOCAL", 21);
|
||||
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);
|
||||
this.set("ADD", 30);
|
||||
this.set("SUB", 31);
|
||||
this.set("MUL", 32);
|
||||
this.set("DIV", 33);
|
||||
this.set("MODULO", 34);
|
||||
this.set("BINARY_AND", 35);
|
||||
this.set("BINARY_OR", 36);
|
||||
this.set("SHIFT_LEFT", 37);
|
||||
this.set("SHIFT_RIGHT", 38);
|
||||
this.set("NEGATE", 39);
|
||||
this.set("EQ", 40);
|
||||
this.set("NEQ", 41);
|
||||
this.set("LT", 42);
|
||||
this.set("GT", 43);
|
||||
this.set("LTE", 44);
|
||||
this.set("GTE", 45);
|
||||
this.set("NOT", 50);
|
||||
this.set("LOAD_PROPERTY_ATOP", 68);
|
||||
this.set("JUMP", 80);
|
||||
this.set("JUMPY", 81);
|
||||
this.set("JUMPN", 82);
|
||||
this.set("JUMPY_NOPOP", 83);
|
||||
this.set("JUMPN_NOPOP", 84);
|
||||
this.set("LOAD_ROUTINE", 89);
|
||||
this.set("FUNCTION_CALL", 90);
|
||||
this.set("FUNCTION_APPLY_VARIABLE", 91);
|
||||
this.set("FUNCTION_APPLY_PROPERTY", 92);
|
||||
this.set("SUPER_CALL", 93);
|
||||
this.set("RETURN", 94);
|
||||
this.set("FORLOOP_INIT", 95);
|
||||
this.set("FORLOOP_CONTROL", 96);
|
||||
this.set("FORIN_INIT", 97);
|
||||
this.set("FORIN_CONTROL", 98);
|
||||
this.set("UNARY_OP", 100);
|
||||
this.set("BINARY_OP", 101);
|
||||
this.set("COMPILED", 200);
|
||||
this.set("AFTER", 110);
|
||||
this.set("EVERY", 111);
|
||||
this.set("DO", 112);
|
||||
this.set("SLEEP", 113);
|
||||
}
|
||||
|
||||
set(op, code) {
|
||||
this[op] = code;
|
||||
return this[code] = op;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.OPCODES = new this.OPCODES_CLASS;
|
||||
@@ -0,0 +1,385 @@
|
||||
this.Runner = class Runner {
|
||||
constructor(microvm) {
|
||||
this.microvm = microvm;
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initialized = true;
|
||||
this.system = this.microvm.context.global.system;
|
||||
this.system.preemptive = 1;
|
||||
this.system.threads = [];
|
||||
this.main_thread = new Thread(this);
|
||||
this.threads = [this.main_thread];
|
||||
this.current_thread = this.main_thread;
|
||||
this.thread_index = 0;
|
||||
this.microvm.context.global.print = this.microvm.context.meta.print;
|
||||
this.microvm.context.global.random = new Random(0);
|
||||
this.microvm.context.global.Function = {
|
||||
bind: function(obj) {
|
||||
var rc;
|
||||
if (this instanceof Routine) {
|
||||
rc = this.clone();
|
||||
rc.object = obj;
|
||||
return rc;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
};
|
||||
this.microvm.context.global.List = {
|
||||
sortList: (f) => {
|
||||
var funk;
|
||||
if ((f != null) && f instanceof Program.Function) {
|
||||
funk = function(a, b) {
|
||||
return f.call(this.microvm.context.global, [a, b], true);
|
||||
};
|
||||
} else if ((f != null) && typeof f === "function") {
|
||||
funk = f;
|
||||
}
|
||||
return this.sort(funk);
|
||||
},
|
||||
"+": function(a, b, self) {
|
||||
if (!self) { // not +=, clone array a
|
||||
a = [...a];
|
||||
}
|
||||
if (Array.isArray(b)) {
|
||||
return a.concat(b);
|
||||
} else {
|
||||
a.push(b);
|
||||
return a;
|
||||
}
|
||||
},
|
||||
"-": function(a, b, self) {
|
||||
var index;
|
||||
if (!self) { // not -=, clone array a
|
||||
a = [...a];
|
||||
}
|
||||
index = a.indexOf(b);
|
||||
if (index >= 0) {
|
||||
a.splice(index, 1);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
};
|
||||
this.microvm.context.global.Object = {};
|
||||
this.microvm.context.global.String = {
|
||||
fromCharCode: function(...args) { return String.fromCharCode(...args) },
|
||||
"+": function(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
};
|
||||
this.microvm.context.global.Number = {
|
||||
parse: function(s) {
|
||||
var res;
|
||||
res = Number.parseFloat(s);
|
||||
if (isFinite(res)) {
|
||||
return res;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
toString: function() {
|
||||
return this.toString();
|
||||
}
|
||||
};
|
||||
this.fps = 60;
|
||||
this.fps_max = 60;
|
||||
this.cpu_load = 0;
|
||||
this.microvm.context.meta.print("microScript 2.0");
|
||||
return this.triggers_controls_update = true;
|
||||
}
|
||||
|
||||
run(src, filename, callback) {
|
||||
var compiler, err, id, j, len, parser, program, ref, result, w;
|
||||
if (!this.initialized) {
|
||||
this.init();
|
||||
}
|
||||
parser = new Parser(src, filename);
|
||||
parser.parse();
|
||||
if (parser.error_info != null) {
|
||||
err = parser.error_info;
|
||||
err.type = "compile";
|
||||
throw err;
|
||||
}
|
||||
if (parser.warnings.length > 0) {
|
||||
ref = parser.warnings;
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
w = ref[j];
|
||||
id = filename + "-" + w.line + "-" + w.column;
|
||||
switch (w.type) {
|
||||
case "assigning_api_variable":
|
||||
if (this.microvm.context.warnings.assigning_api_variable[id] == null) {
|
||||
this.microvm.context.warnings.assigning_api_variable[id] = {
|
||||
file: filename,
|
||||
line: w.line,
|
||||
column: w.column,
|
||||
expression: w.identifier
|
||||
};
|
||||
}
|
||||
break;
|
||||
case "assignment_as_condition":
|
||||
if (this.microvm.context.warnings.assignment_as_condition[id] == null) {
|
||||
this.microvm.context.warnings.assignment_as_condition[id] = {
|
||||
file: filename,
|
||||
line: w.line,
|
||||
column: w.column
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
program = parser.program;
|
||||
compiler = new Compiler(program);
|
||||
result = null;
|
||||
compiler.routine.callback = function(res) {
|
||||
if (callback != null) {
|
||||
return callback(Program.toString(res));
|
||||
} else {
|
||||
return result = res;
|
||||
}
|
||||
};
|
||||
this.main_thread.addCall(compiler.routine);
|
||||
this.tick();
|
||||
return result;
|
||||
}
|
||||
|
||||
call(name, args) {
|
||||
var f, routine;
|
||||
if (name === "draw" || name === "update" || name === "serverUpdate") {
|
||||
if (this.microvm.context.global[name] != null) {
|
||||
this.main_thread.addCall(`${name}()`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this.microvm.context.global[name] != null) {
|
||||
if ((args == null) || !args.length) {
|
||||
return this.main_thread.addCall(`${name}()`);
|
||||
} else {
|
||||
routine = this.microvm.context.global[name];
|
||||
if (routine instanceof Routine) {
|
||||
f = this.main_thread.processor.routineAsFunction(routine, this.microvm.context);
|
||||
return f(...args);
|
||||
} else if (typeof routine === "function") {
|
||||
return routine(...args);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
toString(obj) {
|
||||
return Program.toString(obj);
|
||||
}
|
||||
|
||||
process(thread, time_limit) {
|
||||
var processor;
|
||||
processor = thread.processor;
|
||||
processor.time_limit = time_limit;
|
||||
this.current_thread = thread;
|
||||
return processor.run(this.microvm.context);
|
||||
}
|
||||
|
||||
tick() {
|
||||
var dt, frame_time, i, index, j, k, len, load, margin, processing, processor, ref, ref1, t, time, time_limit, time_out;
|
||||
if (this.system.fps != null) {
|
||||
this.fps = this.fps * .9 + this.system.fps * .1;
|
||||
}
|
||||
this.fps_max = Math.max(this.fps, this.fps_max);
|
||||
frame_time = Math.min(16, Math.floor(1000 / this.fps_max));
|
||||
if (this.fps < 59) {
|
||||
margin = 10;
|
||||
} else {
|
||||
margin = Math.floor(1000 / this.fps * .8);
|
||||
}
|
||||
time = Date.now();
|
||||
time_limit = time + 100; // allow more time to prevent interrupting main_thread in the middle of a draw()
|
||||
time_out = this.system.preemptive ? time_limit : 2e308;
|
||||
processor = this.main_thread.processor;
|
||||
if (!processor.done) {
|
||||
if (this.main_thread.sleep_until != null) {
|
||||
if (Date.now() >= this.main_thread.sleep_until) {
|
||||
delete this.main_thread.sleep_until;
|
||||
this.process(this.main_thread, time_out);
|
||||
}
|
||||
} else {
|
||||
this.process(this.main_thread, time_out);
|
||||
}
|
||||
}
|
||||
while (processor.done && Date.now() < time_out && this.main_thread.loadNext()) {
|
||||
this.process(this.main_thread, time_out);
|
||||
}
|
||||
time_limit = time + margin; // secondary threads get remaining time
|
||||
time_out = this.system.preemptive ? time_limit : 2e308;
|
||||
processing = true;
|
||||
while (processing) {
|
||||
processing = false;
|
||||
ref = this.threads;
|
||||
for (j = 0, len = ref.length; j < len; j++) {
|
||||
t = ref[j];
|
||||
if (t !== this.main_thread) {
|
||||
if (t.paused || t.terminated) {
|
||||
continue;
|
||||
}
|
||||
processor = t.processor;
|
||||
if (!processor.done) {
|
||||
if (t.sleep_until != null) {
|
||||
if (Date.now() >= t.sleep_until) {
|
||||
delete t.sleep_until;
|
||||
this.process(t, time_out);
|
||||
processing = true;
|
||||
}
|
||||
} else {
|
||||
this.process(t, time_out);
|
||||
processing = true;
|
||||
}
|
||||
} else if (t.start_time != null) {
|
||||
if (t.repeat) {
|
||||
while (time >= t.start_time && !(t.paused || t.terminated)) {
|
||||
if (time >= t.start_time + 150) {
|
||||
t.start_time = time + t.delay;
|
||||
} else {
|
||||
t.start_time += t.delay;
|
||||
}
|
||||
processor.load(t.routine);
|
||||
this.process(t, time_out);
|
||||
processing = true;
|
||||
}
|
||||
} else {
|
||||
if (time >= t.start_time) {
|
||||
delete t.start_time;
|
||||
processor.load(t.routine);
|
||||
this.process(t, time_out);
|
||||
processing = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.terminated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Date.now() > time_limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = k = ref1 = this.threads.length - 1; k >= 1; i = k += -1) {
|
||||
t = this.threads[i];
|
||||
if (t.terminated) {
|
||||
this.threads.splice(i, 1);
|
||||
index = this.system.threads.indexOf(t.interface);
|
||||
if (index >= 0) {
|
||||
this.system.threads.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
t = Date.now() - time;
|
||||
dt = time_limit - time;
|
||||
load = t / dt * 100;
|
||||
this.cpu_load = this.cpu_load * .9 + load * .1;
|
||||
this.system.cpu_load = Math.min(100, Math.round(this.cpu_load));
|
||||
}
|
||||
|
||||
createThread(routine, delay, repeat) {
|
||||
var i, j, ref, t;
|
||||
t = new Thread(this);
|
||||
t.routine = routine;
|
||||
this.threads.push(t);
|
||||
t.start_time = Date.now() + delay - 1000 / this.fps;
|
||||
if (repeat) {
|
||||
t.repeat = repeat;
|
||||
t.delay = delay;
|
||||
}
|
||||
this.system.threads.push(t.interface);
|
||||
for (i = j = 0, ref = routine.import_values.length - 1; j <= ref; i = j += 1) {
|
||||
if (routine.import_values[i] === routine) {
|
||||
routine.import_values[i] = t.interface;
|
||||
}
|
||||
}
|
||||
return t.interface;
|
||||
}
|
||||
|
||||
sleep(value) {
|
||||
if (this.current_thread != null) {
|
||||
return this.current_thread.sleep_until = Date.now() + Math.max(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Thread = class Thread {
|
||||
constructor(runner) {
|
||||
this.runner = runner;
|
||||
this.loop = false;
|
||||
this.processor = new Processor(this.runner);
|
||||
this.paused = false;
|
||||
this.terminated = false;
|
||||
this.next_calls = [];
|
||||
this.interface = {
|
||||
pause: () => {
|
||||
return this.pause();
|
||||
},
|
||||
resume: () => {
|
||||
return this.resume();
|
||||
},
|
||||
stop: () => {
|
||||
return this.stop();
|
||||
},
|
||||
status: "running"
|
||||
};
|
||||
}
|
||||
|
||||
addCall(call) {
|
||||
if (this.next_calls.indexOf(call) < 0) {
|
||||
return this.next_calls.push(call);
|
||||
}
|
||||
}
|
||||
|
||||
loadNext() {
|
||||
var compiler, f, parser, program;
|
||||
if (this.next_calls.length > 0) {
|
||||
f = this.next_calls.splice(0, 1)[0];
|
||||
if (f instanceof Routine) {
|
||||
this.processor.load(f);
|
||||
} else {
|
||||
parser = new Parser(f, "");
|
||||
parser.parse();
|
||||
program = parser.program;
|
||||
compiler = new Compiler(program);
|
||||
this.processor.load(compiler.routine);
|
||||
if ((f === "update()" || f === "serverUpdate()") && (this.runner.updateControls != null)) {
|
||||
this.runner.updateControls();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pause() {
|
||||
if (this.interface.status === "running") {
|
||||
this.interface.status = "paused";
|
||||
this.paused = true;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
resume() {
|
||||
if (this.interface.status === "paused") {
|
||||
this.interface.status = "running";
|
||||
this.paused = false;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.interface.status = "stopped";
|
||||
this.terminated = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 152 B |
|
After Width: | Height: | Size: 327 B |
|
After Width: | Height: | Size: 748 B |
|
After Width: | Height: | Size: 741 B |
|
After Width: | Height: | Size: 272 B |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 286 B |
|
After Width: | Height: | Size: 239 B |
@@ -0,0 +1,201 @@
|
||||
this.Token = class Token {
|
||||
constructor(tokenizer, type, value, string_value) {
|
||||
this.tokenizer = tokenizer;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
this.string_value = string_value;
|
||||
this.line = this.tokenizer.line;
|
||||
this.column = this.tokenizer.column;
|
||||
this.start = this.tokenizer.token_start;
|
||||
this.length = this.tokenizer.index - this.start;
|
||||
this.index = this.tokenizer.index;
|
||||
if (this.type === Token.TYPE_IDENTIFIER && Token.predefined.hasOwnProperty(this.value)) {
|
||||
this.type = Token.predefined[this.value];
|
||||
this.reserved_keyword = true;
|
||||
}
|
||||
this.is_binary_operator = (this.type >= 30 && this.type <= 39) || (this.type >= 200 && this.type <= 201) || (this.type >= 2 && this.type <= 7);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.value + " : " + this.type;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.Token.TYPE_EQUALS = 1;
|
||||
|
||||
this.Token.TYPE_DOUBLE_EQUALS = 2;
|
||||
|
||||
this.Token.TYPE_GREATER = 3;
|
||||
|
||||
this.Token.TYPE_GREATER_OR_EQUALS = 4;
|
||||
|
||||
this.Token.TYPE_LOWER = 5;
|
||||
|
||||
this.Token.TYPE_LOWER_OR_EQUALS = 6;
|
||||
|
||||
this.Token.TYPE_UNEQUALS = 7;
|
||||
|
||||
this.Token.TYPE_IDENTIFIER = 10;
|
||||
|
||||
this.Token.TYPE_NUMBER = 11;
|
||||
|
||||
this.Token.TYPE_STRING = 12;
|
||||
|
||||
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;
|
||||
|
||||
this.Token.TYPE_COMMA = 26;
|
||||
|
||||
this.Token.TYPE_DOT = 27;
|
||||
|
||||
this.Token.TYPE_PLUS = 30;
|
||||
|
||||
this.Token.TYPE_MINUS = 31;
|
||||
|
||||
this.Token.TYPE_MULTIPLY = 32;
|
||||
|
||||
this.Token.TYPE_DIVIDE = 33;
|
||||
|
||||
this.Token.TYPE_POWER = 34;
|
||||
|
||||
this.Token.TYPE_MODULO = 35;
|
||||
|
||||
this.Token.TYPE_BINARY_AND = 36;
|
||||
|
||||
this.Token.TYPE_BINARY_OR = 37;
|
||||
|
||||
this.Token.TYPE_SHIFT_LEFT = 38;
|
||||
|
||||
this.Token.TYPE_SHIFT_RIGHT = 39;
|
||||
|
||||
this.Token.TYPE_PLUS_EQUALS = 40;
|
||||
|
||||
this.Token.TYPE_MINUS_EQUALS = 41;
|
||||
|
||||
this.Token.TYPE_MULTIPLY_EQUALS = 42;
|
||||
|
||||
this.Token.TYPE_DIVIDE_EQUALS = 43;
|
||||
|
||||
this.Token.TYPE_MODULO_EQUALS = 44;
|
||||
|
||||
this.Token.TYPE_AND_EQUALS = 45;
|
||||
|
||||
this.Token.TYPE_OR_EQUALS = 46;
|
||||
|
||||
this.Token.TYPE_RETURN = 50;
|
||||
|
||||
this.Token.TYPE_BREAK = 51;
|
||||
|
||||
this.Token.TYPE_CONTINUE = 52;
|
||||
|
||||
this.Token.TYPE_FUNCTION = 60;
|
||||
|
||||
this.Token.TYPE_AFTER = 61;
|
||||
|
||||
this.Token.TYPE_EVERY = 62;
|
||||
|
||||
this.Token.TYPE_DO = 63;
|
||||
|
||||
this.Token.TYPE_SLEEP = 64;
|
||||
|
||||
this.Token.TYPE_LOCAL = 70;
|
||||
|
||||
this.Token.TYPE_OBJECT = 80;
|
||||
|
||||
this.Token.TYPE_CLASS = 90;
|
||||
|
||||
this.Token.TYPE_EXTENDS = 91;
|
||||
|
||||
this.Token.TYPE_NEW = 92;
|
||||
|
||||
this.Token.TYPE_FOR = 100;
|
||||
|
||||
this.Token.TYPE_TO = 101;
|
||||
|
||||
this.Token.TYPE_BY = 102;
|
||||
|
||||
this.Token.TYPE_IN = 103;
|
||||
|
||||
this.Token.TYPE_WHILE = 104;
|
||||
|
||||
this.Token.TYPE_IF = 105;
|
||||
|
||||
this.Token.TYPE_THEN = 106;
|
||||
|
||||
this.Token.TYPE_ELSE = 107;
|
||||
|
||||
this.Token.TYPE_ELSIF = 108;
|
||||
|
||||
this.Token.TYPE_END = 120;
|
||||
|
||||
this.Token.TYPE_AND = 200;
|
||||
|
||||
this.Token.TYPE_OR = 201;
|
||||
|
||||
this.Token.TYPE_NOT = 202;
|
||||
|
||||
this.Token.TYPE_ERROR = 404;
|
||||
|
||||
this.Token.predefined = {};
|
||||
|
||||
this.Token.predefined["return"] = this.Token.TYPE_RETURN;
|
||||
|
||||
this.Token.predefined["break"] = this.Token.TYPE_BREAK;
|
||||
|
||||
this.Token.predefined["continue"] = this.Token.TYPE_CONTINUE;
|
||||
|
||||
this.Token.predefined["function"] = this.Token.TYPE_FUNCTION;
|
||||
|
||||
this.Token.predefined["for"] = this.Token.TYPE_FOR;
|
||||
|
||||
this.Token.predefined["to"] = this.Token.TYPE_TO;
|
||||
|
||||
this.Token.predefined["by"] = this.Token.TYPE_BY;
|
||||
|
||||
this.Token.predefined["in"] = this.Token.TYPE_IN;
|
||||
|
||||
this.Token.predefined["while"] = this.Token.TYPE_WHILE;
|
||||
|
||||
this.Token.predefined["if"] = this.Token.TYPE_IF;
|
||||
|
||||
this.Token.predefined["then"] = this.Token.TYPE_THEN;
|
||||
|
||||
this.Token.predefined["else"] = this.Token.TYPE_ELSE;
|
||||
|
||||
this.Token.predefined["elsif"] = this.Token.TYPE_ELSIF;
|
||||
|
||||
this.Token.predefined["end"] = this.Token.TYPE_END;
|
||||
|
||||
this.Token.predefined["object"] = this.Token.TYPE_OBJECT;
|
||||
|
||||
this.Token.predefined["class"] = this.Token.TYPE_CLASS;
|
||||
|
||||
this.Token.predefined["extends"] = this.Token.TYPE_EXTENDS;
|
||||
|
||||
this.Token.predefined["new"] = this.Token.TYPE_NEW;
|
||||
|
||||
this.Token.predefined["and"] = this.Token.TYPE_AND;
|
||||
|
||||
this.Token.predefined["or"] = this.Token.TYPE_OR;
|
||||
|
||||
this.Token.predefined["not"] = this.Token.TYPE_NOT;
|
||||
|
||||
this.Token.predefined["after"] = this.Token.TYPE_AFTER;
|
||||
|
||||
this.Token.predefined["every"] = this.Token.TYPE_EVERY;
|
||||
|
||||
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;
|
||||
@@ -0,0 +1,343 @@
|
||||
this.Tokenizer = (function() {
|
||||
function Tokenizer(input, filename) {
|
||||
this.input = input;
|
||||
this.filename = filename;
|
||||
this.index = 0;
|
||||
this.line = 1;
|
||||
this.column = 0;
|
||||
this.last_column = 0;
|
||||
this.buffer = [];
|
||||
this.chars = {};
|
||||
this.chars["("] = Token.TYPE_OPEN_BRACE;
|
||||
this.chars[")"] = Token.TYPE_CLOSED_BRACE;
|
||||
this.chars["["] = Token.TYPE_OPEN_BRACKET;
|
||||
this.chars["]"] = Token.TYPE_CLOSED_BRACKET;
|
||||
this.chars["{"] = Token.TYPE_OPEN_CURLY_BRACE;
|
||||
this.chars["}"] = Token.TYPE_CLOSED_CURLY_BRACE;
|
||||
this.chars["^"] = Token.TYPE_POWER;
|
||||
this.chars[","] = Token.TYPE_COMMA;
|
||||
this.chars["."] = Token.TYPE_DOT;
|
||||
this.doubles = {};
|
||||
this.doubles[">"] = [Token.TYPE_GREATER, Token.TYPE_GREATER_OR_EQUALS];
|
||||
this.doubles["<"] = [Token.TYPE_LOWER, Token.TYPE_LOWER_OR_EQUALS];
|
||||
this.doubles["="] = [Token.TYPE_EQUALS, Token.TYPE_DOUBLE_EQUALS];
|
||||
this.doubles["+"] = [Token.TYPE_PLUS, Token.TYPE_PLUS_EQUALS];
|
||||
this.doubles["-"] = [Token.TYPE_MINUS, Token.TYPE_MINUS_EQUALS];
|
||||
this.doubles["*"] = [Token.TYPE_MULTIPLY, Token.TYPE_MULTIPLY_EQUALS];
|
||||
this.doubles["/"] = [Token.TYPE_DIVIDE, Token.TYPE_DIVIDE_EQUALS];
|
||||
this.doubles["%"] = [Token.TYPE_MODULO, Token.TYPE_MODULO_EQUALS];
|
||||
this.doubles["&"] = [Token.TYPE_BINARY_AND, Token.TYPE_AND_EQUALS];
|
||||
this.doubles["|"] = [Token.TYPE_BINARY_OR, Token.TYPE_OR_EQUALS];
|
||||
this.shifts = {
|
||||
"<": Token.TYPE_SHIFT_LEFT,
|
||||
">": Token.TYPE_SHIFT_RIGHT
|
||||
};
|
||||
this.letter_regex = RegExp(/^\p{L}/, 'u');
|
||||
}
|
||||
|
||||
Tokenizer.prototype.pushBack = function(token) {
|
||||
return this.buffer.splice(0, 0, token);
|
||||
};
|
||||
|
||||
Tokenizer.prototype.finished = function() {
|
||||
return this.index >= this.input.length && this.buffer.length === 0;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.nextChar = function(ignore_comments) {
|
||||
var c, endseq;
|
||||
if (ignore_comments == null) {
|
||||
ignore_comments = false;
|
||||
}
|
||||
c = this.input.charAt(this.index++);
|
||||
if (c === "\n") {
|
||||
this.line += 1;
|
||||
this.last_column = this.column;
|
||||
this.column = 0;
|
||||
} else if (c === "/" && !ignore_comments) {
|
||||
if (this.input.charAt(this.index) === "/") {
|
||||
while (true) {
|
||||
c = this.input.charAt(this.index++);
|
||||
if (c === "\n" || this.index >= this.input.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.line += 1;
|
||||
this.last_column = this.column;
|
||||
this.column = 0;
|
||||
return this.nextChar();
|
||||
} else if (this.input.charAt(this.index) === "*") {
|
||||
endseq = 0;
|
||||
while (true) {
|
||||
c = this.input.charAt(this.index++);
|
||||
if (c === "\n") {
|
||||
this.line += 1;
|
||||
this.last_column = this.column;
|
||||
this.column = 0;
|
||||
endseq = 0;
|
||||
} else if (c === "*") {
|
||||
endseq = 1;
|
||||
} else if (c === "/" && endseq === 1) {
|
||||
break;
|
||||
} else {
|
||||
endseq = 0;
|
||||
}
|
||||
if (this.index >= this.input.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this.nextChar();
|
||||
}
|
||||
} else {
|
||||
this.column += 1;
|
||||
}
|
||||
return c;
|
||||
};
|
||||
|
||||
Tokenizer.prototype.rewind = function() {
|
||||
this.index -= 1;
|
||||
this.column -= 1;
|
||||
if (this.input.charAt(this.index) === "\n") {
|
||||
this.line -= 1;
|
||||
return this.column = this.last_column;
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.next = function() {
|
||||
var c, code;
|
||||
if (this.buffer.length > 0) {
|
||||
return this.buffer.splice(0, 1)[0];
|
||||
}
|
||||
while (true) {
|
||||
if (this.index >= this.input.length) {
|
||||
return null;
|
||||
}
|
||||
c = this.nextChar();
|
||||
code = c.charCodeAt(0);
|
||||
if (code > 32 && code !== 160) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.token_start = this.index - 1;
|
||||
if (this.doubles[c] != null) {
|
||||
return this.parseDouble(c, this.doubles[c]);
|
||||
}
|
||||
if (this.chars[c] != null) {
|
||||
return new Token(this, this.chars[c], c);
|
||||
}
|
||||
if (c === "!") {
|
||||
return this.parseUnequals(c);
|
||||
} else if (code >= 48 && code <= 57) {
|
||||
return this.parseNumber(c);
|
||||
} else if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 95 || this.letter_regex.test(c)) {
|
||||
return this.parseIdentifier(c);
|
||||
} else if (c === '"') {
|
||||
return this.parseString(c, '"');
|
||||
} else if (c === "'") {
|
||||
return this.parseString(c, "'");
|
||||
} else {
|
||||
return this.error("Syntax Error");
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.changeNumberToIdentifier = function() {
|
||||
var i, j, ref, results, token, v;
|
||||
token = this.next();
|
||||
if ((token != null) && token.type === Token.TYPE_NUMBER) {
|
||||
v = token.string_value.split(".");
|
||||
results = [];
|
||||
for (i = j = ref = v.length - 1; j >= 0; i = j += -1) {
|
||||
if (v[i].length > 0) {
|
||||
this.pushBack(new Token(this, Token.TYPE_IDENTIFIER, v[i]));
|
||||
}
|
||||
if (i > 0) {
|
||||
results.push(this.pushBack(new Token(this, Token.TYPE_DOT, ".")));
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
} else if ((token != null) && token.type === Token.TYPE_STRING) {
|
||||
return this.pushBack(new Token(this, Token.TYPE_IDENTIFIER, token.value));
|
||||
} else {
|
||||
return this.pushBack(token);
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseDouble = function(c, d) {
|
||||
if ((this.shifts[c] != null) && this.index < this.input.length && this.input.charAt(this.index) === c) {
|
||||
this.nextChar();
|
||||
return new Token(this, this.shifts[c], c + c);
|
||||
} else if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
|
||||
this.nextChar();
|
||||
return new Token(this, d[1], c + "=");
|
||||
} else {
|
||||
return new Token(this, d[0], c);
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseEquals = function(c) {
|
||||
if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
|
||||
this.nextChar();
|
||||
return new Token(this, Token.TYPE_DOUBLE_EQUALS, "==");
|
||||
} else {
|
||||
return new Token(this, Token.TYPE_EQUALS, "=");
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseGreater = function(c) {
|
||||
if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
|
||||
this.nextChar();
|
||||
return new Token(this, Token.TYPE_GREATER_OR_EQUALS, ">=");
|
||||
} else {
|
||||
return new Token(this, Token.TYPE_GREATER_OR_EQUALS, ">");
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseLower = function(c) {
|
||||
if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
|
||||
this.nextChar();
|
||||
return new Token(this, Token.TYPE_LOWER_OR_EQUALS, "<=");
|
||||
} else {
|
||||
return new Token(this, Token.TYPE_LOWER, "<");
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseUnequals = function(c) {
|
||||
if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
|
||||
this.nextChar();
|
||||
return new Token(this, Token.TYPE_UNEQUALS, "!=");
|
||||
} else {
|
||||
return this.error("Expected inequality !=");
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseIdentifier = function(s) {
|
||||
var c, code;
|
||||
while (true) {
|
||||
if (this.index >= this.input.length) {
|
||||
return new Token(this, Token.TYPE_IDENTIFIER, s);
|
||||
}
|
||||
c = this.nextChar();
|
||||
code = c.charCodeAt(0);
|
||||
if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 95 || (code >= 48 && code <= 57) || this.letter_regex.test(c)) {
|
||||
s += c;
|
||||
} else {
|
||||
this.rewind();
|
||||
return new Token(this, Token.TYPE_IDENTIFIER, s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseNumber = function(s) {
|
||||
var c, code, exp, pointed;
|
||||
pointed = false;
|
||||
exp = false;
|
||||
while (true) {
|
||||
if (this.index >= this.input.length) {
|
||||
return new Token(this, Token.TYPE_NUMBER, Number.parseFloat(s), s);
|
||||
}
|
||||
c = this.nextChar();
|
||||
code = c.charCodeAt(0);
|
||||
if (c === "." && !pointed && !exp) {
|
||||
pointed = true;
|
||||
s += c;
|
||||
} else if (code >= 48 && code <= 57) {
|
||||
s += c;
|
||||
} else if ((c === "e" || c === "E") && !exp && this.index < this.input.length) {
|
||||
exp = true;
|
||||
s += c;
|
||||
c = this.nextChar();
|
||||
if (c === "+" || c === "-") {
|
||||
s += c;
|
||||
} else {
|
||||
this.rewind();
|
||||
}
|
||||
} else if ((c === "x" || c === "X") && s === "0") {
|
||||
return this.parseHexNumber("0x");
|
||||
} else {
|
||||
this.rewind();
|
||||
return new Token(this, Token.TYPE_NUMBER, Number.parseFloat(s), s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseHexNumber = function(s) {
|
||||
var c;
|
||||
while (true) {
|
||||
if (this.index >= this.input.length) {
|
||||
return new Token(this, Token.TYPE_NUMBER, Number.parseInt(s), s);
|
||||
}
|
||||
c = this.nextChar();
|
||||
if (/[a-fA-F0-9]/.test(c)) {
|
||||
s += c;
|
||||
} else {
|
||||
this.rewind();
|
||||
return new Token(this, Token.TYPE_NUMBER, Number.parseInt(s), s);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.parseString = function(s, close) {
|
||||
var c, code, count_close, n;
|
||||
if (close == null) {
|
||||
close = '"';
|
||||
}
|
||||
if (close === '"') {
|
||||
if (this.input.charAt(this.index) === '"' && this.input.charAt(this.index + 1) === '"' && this.input.charAt(this.index + 2) !== '"') {
|
||||
close = '"""';
|
||||
this.nextChar(true);
|
||||
this.nextChar(true);
|
||||
}
|
||||
}
|
||||
count_close = 0;
|
||||
while (true) {
|
||||
if (this.index >= this.input.length) {
|
||||
return this.error("Unclosed string value");
|
||||
}
|
||||
c = this.nextChar(true);
|
||||
code = c.charCodeAt(0);
|
||||
if (c === "\\") {
|
||||
n = this.nextChar(true);
|
||||
switch (n) {
|
||||
case "n":
|
||||
s += "\n";
|
||||
break;
|
||||
case "\\":
|
||||
s += "\\";
|
||||
break;
|
||||
case close:
|
||||
s += close;
|
||||
break;
|
||||
default:
|
||||
s += "\\" + n;
|
||||
}
|
||||
} else if (c === close) {
|
||||
n = this.nextChar(true);
|
||||
if (n === close) {
|
||||
s += c;
|
||||
} else {
|
||||
this.rewind();
|
||||
s += c;
|
||||
return new Token(this, Token.TYPE_STRING, s.substring(1, s.length - 1));
|
||||
}
|
||||
} else {
|
||||
if (close === '"""' && c === '"') {
|
||||
count_close += 1;
|
||||
if (count_close === 3) {
|
||||
return new Token(this, Token.TYPE_STRING, s.substring(1, s.length - 2));
|
||||
}
|
||||
} else {
|
||||
count_close = 0;
|
||||
}
|
||||
s += c;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tokenizer.prototype.error = function(s) {
|
||||
throw s;
|
||||
};
|
||||
|
||||
return Tokenizer;
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,244 @@
|
||||
var Transpiler;
|
||||
|
||||
Transpiler = (function() {
|
||||
function Transpiler() {}
|
||||
|
||||
Transpiler.prototype.transpile = function(r) {
|
||||
var i, j, l, op, ref, results;
|
||||
results = [];
|
||||
for (i = l = 0, ref = r.opcodes.length - 1; l <= ref; i = l += 1) {
|
||||
op = OPCODES[r.opcodes[i]];
|
||||
if (this.transpilable(op, r.arg1[i])) {
|
||||
j = i + 1;
|
||||
while (j < r.opcodes.length && r.removeable(j) && this.transpilable(OPCODES[r.opcodes[j]], r.arg1[j])) {
|
||||
j += 1;
|
||||
}
|
||||
j -= 1;
|
||||
if (j - i >= 2) {
|
||||
results.push(this.transpileSegment(r, i, j));
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
} else {
|
||||
results.push(void 0);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
Transpiler.prototype.transpileSegment = function(r, i, j) {
|
||||
var comp, err, index, k, l, m, ref, ref1, ref2, ref3, s;
|
||||
this.vcount = 0;
|
||||
this.stack = new Stack();
|
||||
this.locals = {};
|
||||
this.variables = {};
|
||||
s = "f = function(stack,stack_index,locals,locals_offset,object,global) {\n";
|
||||
for (k = l = ref = i, ref1 = j; l <= ref1; k = l += 1) {
|
||||
console.info(OPCODES[r.opcodes[k]] + " " + r.arg1[k]);
|
||||
comp = this[OPCODES[r.opcodes[k]]](r.arg1[k]);
|
||||
if (comp) {
|
||||
s += comp + "\n";
|
||||
}
|
||||
}
|
||||
for (index in this.stack.touched) {
|
||||
if (this.stack.touched[index]) {
|
||||
if (index < 0) {
|
||||
s += "stack[stack_index-" + (Math.abs(index)) + "] = " + this.stack.stack[index] + " ;\n";
|
||||
} else if (index > 0) {
|
||||
s += "stack[stack_index+" + index + "] = " + this.stack.stack[index] + " ;\n";
|
||||
} else {
|
||||
s += "stack[stack_index] = " + this.stack.stack[index] + " ;\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.stack.index < 0) {
|
||||
s += "stack_index -= " + (Math.abs(this.stack.index)) + " ;\n";
|
||||
} else if (this.stack.index > 0) {
|
||||
s += "stack_index += " + this.stack.index + " ;\n";
|
||||
}
|
||||
s += "return stack_index ;\n}";
|
||||
console.info(s);
|
||||
try {
|
||||
eval(s);
|
||||
} catch (error) {
|
||||
err = error;
|
||||
console.error(s);
|
||||
console.error(err);
|
||||
}
|
||||
r.opcodes[i] = 200;
|
||||
r.arg1[i] = f;
|
||||
for (k = m = ref2 = i + 1, ref3 = j; m <= ref3; k = m += 1) {
|
||||
r.remove(i + 1);
|
||||
}
|
||||
};
|
||||
|
||||
Transpiler.prototype.createVariable = function() {
|
||||
return "v" + (this.vcount++);
|
||||
};
|
||||
|
||||
Transpiler.prototype.transpilable = function(op, arg) {
|
||||
var ref;
|
||||
if (op === "LOAD_VALUE") {
|
||||
return (ref = typeof arg) === "string" || ref === "number";
|
||||
} else {
|
||||
return this[op] != null;
|
||||
}
|
||||
};
|
||||
|
||||
Transpiler.prototype.LOAD_VALUE = function(arg) {
|
||||
if (typeof arg === "string") {
|
||||
this.stack.push(" \"" + (arg.replace(/"/g, "\\\"")) + "\" ");
|
||||
} else if (typeof arg === "number") {
|
||||
this.stack.push(arg + "");
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
Transpiler.prototype.LOAD_LOCAL = function(arg) {
|
||||
var v;
|
||||
v = this.createVariable();
|
||||
this.stack.push(v);
|
||||
return "let " + v + " = locals[locals_offset+" + arg + "] ; // LOAD_LOCAL";
|
||||
};
|
||||
|
||||
Transpiler.prototype.LOAD_LOCAL_OBJECT = function(arg) {
|
||||
var res, v;
|
||||
if (this.locals[arg] != null) {
|
||||
v = this.locals[arg];
|
||||
this.stack.push(v);
|
||||
return "if (typeof " + v + " != \"object\") { " + v + " = locals[locals_offset+" + arg + "] = {} } ;";
|
||||
} else {
|
||||
v = this.createVariable();
|
||||
res = "let " + v + " = locals[locals_offset+" + arg + "] ;\nif (typeof " + v + " != \"object\") { " + v + " = locals[locals_offset+" + arg + "] = {} } ;";
|
||||
this.stack.push(v);
|
||||
this.locals[arg] = v;
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
Transpiler.prototype.STORE_LOCAL = function(arg) {
|
||||
var v;
|
||||
v = this.stack.get();
|
||||
return "locals[locals_offset+" + arg + "] = " + v + " ; // STORE_LOCAL";
|
||||
};
|
||||
|
||||
Transpiler.prototype.POP = function() {
|
||||
this.stack.pop();
|
||||
return "";
|
||||
};
|
||||
|
||||
Transpiler.prototype.CREATE_PROPERTY = function(arg) {
|
||||
var res;
|
||||
res = (this.stack.get(-2)) + "[" + (this.stack.get(-1)) + "] = " + (this.stack.get()) + " ;";
|
||||
this.stack.pop();
|
||||
this.stack.pop();
|
||||
return res;
|
||||
};
|
||||
|
||||
Transpiler.prototype.LOAD_PROPERTY = function(arg) {
|
||||
var res, v;
|
||||
v = this.createVariable();
|
||||
res = "let " + v + " = " + (this.stack.get(-1)) + "[" + (this.stack.get()) + "] ; // LOAD_PROPERTY\nif (" + v + " == null) { " + v + " = 0 ; }";
|
||||
this.stack.pop();
|
||||
this.stack.pop();
|
||||
this.stack.push(v);
|
||||
return res;
|
||||
};
|
||||
|
||||
Transpiler.prototype.LOAD_PROPERTY_ATOP = function(arg) {
|
||||
var res, v;
|
||||
v = this.createVariable();
|
||||
res = "let " + v + " = " + (this.stack.get(-1)) + "[" + (this.stack.get()) + "] ; // LOAD_PROPERTY_ATOP\nif (" + v + " == null) { " + v + " = 0 ; }";
|
||||
this.stack.push(v);
|
||||
return res;
|
||||
};
|
||||
|
||||
Transpiler.prototype.NEW_OBJECT = function() {
|
||||
var v;
|
||||
v = this.createVariable();
|
||||
this.stack.push(v);
|
||||
return "let " + v + " = {} ;";
|
||||
};
|
||||
|
||||
Transpiler.prototype.NEW_ARRAY = function() {
|
||||
var v;
|
||||
v = this.createVariable();
|
||||
this.stack.push(v);
|
||||
return "let " + v + " = [] ;";
|
||||
};
|
||||
|
||||
Transpiler.prototype.MAKE_OBJECT = function() {
|
||||
var res, v;
|
||||
v = this.createVariable();
|
||||
res = "let " + v + " = " + (this.stack.get()) + " ;\nif (typeof " + v + " != \"object\") " + v + " = {} ; ";
|
||||
this.stack.pop();
|
||||
this.stack.push(v);
|
||||
return res;
|
||||
};
|
||||
|
||||
Transpiler.prototype.STORE_VARIABLE = function(arg) {
|
||||
if (this.variables[arg] != null) {
|
||||
return this.variables[arg] + " = object[\"" + arg + "\"] = " + (this.stack.get()) + " ; // STORE_VARIABLE";
|
||||
} else {
|
||||
return "object[\"" + arg + "\"] = " + (this.stack.get()) + " ; // STORE_VARIABLE";
|
||||
}
|
||||
};
|
||||
|
||||
Transpiler.prototype.STORE_PROPERTY = function(arg) {
|
||||
var res, v;
|
||||
v = this.createVariable();
|
||||
res = "let " + v + " = " + (this.stack.get(-2)) + "[" + (this.stack.get(-1)) + "] = " + (this.stack.get(0)) + " ; // STORE_PROPERTY";
|
||||
this.stack.pop();
|
||||
this.stack.pop();
|
||||
this.stack.pop();
|
||||
this.stack.push(v);
|
||||
return res;
|
||||
};
|
||||
|
||||
return Transpiler;
|
||||
|
||||
})();
|
||||
|
||||
this.Stack = (function() {
|
||||
function Stack() {
|
||||
this.stack = ["stack[stack_index]"];
|
||||
this.index = 0;
|
||||
this.touched = {};
|
||||
}
|
||||
|
||||
Stack.prototype.push = function(value) {
|
||||
this.stack[++this.index] = value;
|
||||
return this.touched[this.index] = true;
|
||||
};
|
||||
|
||||
Stack.prototype.pop = function() {
|
||||
var res;
|
||||
if (this.index >= 0) {
|
||||
res = this.stack.splice(this.index, 1)[0];
|
||||
} else if (this.stack[this.index] != null) {
|
||||
res = this.stack[this.index];
|
||||
} else {
|
||||
res = "stack[stack_index-" + this.index + "]";
|
||||
}
|
||||
this.index -= 1;
|
||||
return res;
|
||||
};
|
||||
|
||||
Stack.prototype.get = function(index) {
|
||||
var i;
|
||||
if (index == null) {
|
||||
index = 0;
|
||||
}
|
||||
i = this.index + index;
|
||||
if (i >= 0) {
|
||||
return this.stack[i];
|
||||
} else if (this.stack[i] != null) {
|
||||
return this.stack[i];
|
||||
} else {
|
||||
return "stack[stack_index-" + (-i) + "]";
|
||||
}
|
||||
};
|
||||
|
||||
return Stack;
|
||||
|
||||
})();
|
||||
@@ -11,7 +11,14 @@
|
||||
<head>
|
||||
<a href="/WebGames-master/WebGames-master/games/cap/index.html">new test</a>
|
||||
<a href="/WebGames-master/WebGames-master/games/Gladihoppers-gh-pages/index.html">Gladihoppers-gh</a>
|
||||
<a href="/WebGames-master/WebGames-master/games/microbox/index.html">microbox</a>
|
||||
|
||||
<p>this wont look good because its beta testers eyes only</p>
|
||||
<p>tell us wen to add the to the full vr</p>
|
||||
<body><!-- begin wwww.htmlcommentbox.com -->
|
||||
<div id="HCB_comment_box"><a href="http://www.htmlcommentbox.com">Widget</a> is loading comments...</div>
|
||||
<link rel="stylesheet" type="text/css" href="https://www.htmlcommentbox.com/static/skins/bootstrap/twitter-bootstrap.css?v=0" />
|
||||
<script type="text/javascript" id="hcb"> /*<!--*/ if(!window.hcb_user){hcb_user={};} (function(){var s=document.createElement("script"), l=hcb_user.PAGE || (""+window.location).replace(/'/g,"%27"), h="https://www.htmlcommentbox.com";s.setAttribute("type","text/javascript");s.setAttribute("src", h+"/jread?page="+encodeURIComponent(l).replace("+","%2B")+"&mod=%241%24wq1rdBcg%24piEQg.u8ZJ10jZd4Ns2cl%2F"+"&opts=16798&num=10&ts=1736864483796");if (typeof s!="undefined") document.getElementsByTagName("head")[0].appendChild(s);})(); /*-->*/ </script>
|
||||
<!-- end www.htmlcommentbox.com --></body>
|
||||
</head>
|
||||
</html>
|
||||