Socket
Socket
Sign inDemoInstall

jester

Package Overview
Dependencies
1
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.2.2 to 0.2.3

examples/free_vars.jester

4

index.js
module.exports = {
createContext : require('./lib/context').createContext,
createVM : require('./lib/vm').createVM
createVM : require('./lib/vm').createVM,
constants : require('./lib/constants'),
opcodeMeta : require('./lib/vm').opcodeMeta
};

@@ -7,3 +7,4 @@ "use strict";

[ 'DEF',
[ 'MODULE',
'DEF',
'IF',

@@ -18,6 +19,8 @@ 'WHILE',

'IDENT',
'GLOBAL_IDENT',
'CALL',
'BIN_OP',
'UN_OP',
'SPAWN'
'SPAWN',
'EVAL'
].forEach(function(ast) {

@@ -28,2 +31,2 @@ var astNodeId = nextAstNode++;

module.exports = AST_NODES;
module.exports = AST_NODES;
"use strict";
var T = require('./tokens').tokens,
A = require('./ast_nodes'),
ops = require('./opcodes'),
makeFunction = require('./types').makeFunction,
makeColor = require('./types').makeColor;
var T = require('./tokens').tokens,
A = require('./ast_nodes'),
ops = require('./opcodes'),
makeFunction = require('./types').makeFunction,
makeColor = require('./types').makeColor;
function assert(condition, message) {
if (!condition) throw (message || "assertion failed");
if (!condition) throw (message || "assertion failed");
}

@@ -26,296 +26,349 @@

function Compiler() {
this._fn = null;
this._fn = null;
}
Compiler.prototype = {
emit: function(opcode, line) {
this._fn.code.push(opcode);
this._fn.sourceMap.push(line || 0);
},
compileFnDef: function(ast) {
var oldFn = this._fn;
var newFn = makeFunction();
newFn.name = ast.name;
this._fn = newFn;
var params = ast.parameters;
for (var i = 0; i < params.length; ++i) {
newFn.slotForLocal(params[i]);
newFn.minArgs++;
newFn.maxArgs++;
}
this.compileFunctionBody(ast.body);
this._env[ast.name] = newFn;
this._fn = oldFn;
return newFn;
},
compileAssign: function(ast) {
var slot = this._fn.slotForLocal(ast.left.name);
this.compileExpression(ast.right);
this.emit(ops.SETL | (slot << 8), ast.line);
},
compileIf: function(ast) {
var ix = 0,
firstAbs = null,
lastAbs = null,
clauses = ast.clauses;
while (ix < clauses.length) {
var clause = clauses[ix];
if (typeof clause.condition !== 'undefined') {
this.compileExpression(clause.condition);
var failJump = this._fn.code.length;
this.emit(ops.JMPF);
this.compileStatements(clause.body);
if (firstAbs === null) {
firstAbs = this._fn.code.length;
lastAbs = this._fn.code.length;
this.emit(0);
} else {
var tmp = this._fn.code.length;
this.emit(lastAbs); // hack - stash pointer to last jump point so we can backtrack
lastAbs = tmp;
}
this._fn.code[failJump] = ops.JMPF | ((this._fn.code.length - failJump - 1) << 8);
} else {
this.compileStatements(clause.body);
}
ix++;
}
var jmpOp = ops.JMPA | (this._fn.code.length << 8),
currAbs = lastAbs;
do {
var tmp = this._fn.code[currAbs];
this._fn.code[currAbs] = jmpOp;
if (currAbs == firstAbs) {
break;
} else {
currAbs = tmp;
}
} while (true);
},
compileWhile: function(ast) {
var loopStart = this._fn.code.length;
this.compileExpression(ast.condition);
var failJump = this._fn.code.length;
this.emit(ops.JMPF);
this.compileStatements(ast.body);
this.emit(ops.JMPA | (loopStart << 8));
this._fn.code[failJump] = ops.JMPF | ((this._fn.code.length - failJump - 1) << 8);
emit: function(opcode, line) {
this._fn.code.push(opcode);
this._fn.sourceMap.push(line || 0);
},
compileFnDef: function(ast) {
var oldFn = this._fn;
var newFn = makeFunction();
newFn.name = ast.name;
this._fn = newFn;
var params = ast.parameters;
for (var i = 0; i < params.length; ++i) {
newFn.slotForLocal(params[i]);
newFn.minArgs++;
newFn.maxArgs++;
}
this.compileFunctionBody(ast.body);
this._env[ast.name] = newFn;
this._fn = oldFn;
return newFn;
},
compileAssign: function(ast) {
},
compileLoop: function(ast) {
var loopStart = this._fn.code.length;
this.compileStatements(ast.body);
this.emit(ops.YIELD, ast.line);
this.emit(ops.JMPA | (loopStart << 8));
},
compileReturn: function(ast) {
if (typeof ast.returnValue !== 'undefined') {
this.compileExpression(ast.returnValue);
} else {
this.emit(ops.PUSHF); // TODO: should probably push undefined/null or whatever
}
this.emit(ops.RET, ast.line);
},
compileYield: function(ast) {
this.emit(ops.YIELD, ast.line);
},
compileCall: function(ast) {
var args = ast.args;
if (args.length > 255) {
throw "compile error - max args per function call (255) exceeded";
}
for (var i = 0; i < args.length; ++i) {
this.compileExpression(args[i]);
}
this.emit(ops.CALL | (args.length << 8) | (this._fn.slotForFunctionCall(ast.fn.name) << 16), ast.line);
},
if (ast.left.type === A.IDENT) {
compileSpawn: function(ast) {
var slot = this._fn.slotForLocal(ast.left.name);
this.compileExpression(ast.right);
this.emit(ops.SETL | (slot << 8), ast.line);
} else if (ast.left.type === A.GLOBAL_IDENT) {
var args = ast.args;
if (args.length > 255) {
throw "compile error - max args per spawn (255) exceeded";
}
var slot = this._fn.slotForName(ast.left.name);
this.compileExpression(ast.right);
this.emit(ops.SETG | (slot << 16), ast.line);
for (var i = 0; i < args.length; ++i) {
this.compileExpression(args[i]);
}
} else {
this.emit(ops.SPAWN | (args.length << 8) | (this._fn.slotForFunctionCall(ast.fn.name) << 16), ast.line);
throw "compile error: invalid left hand in assignment";
},
compileLogicalAnd: function(ast) {
this.compileExpression(ast.left);
var bailJump = this._fn.code.length;
this.emit(0);
this.compileExpression(ast.right);
this._fn.code[bailJump] = ops.JMPF_OP | ((this._fn.code.length - bailJump - 1) << 8);
}
},
compileLogicalOr: function(ast) {
this.compileExpression(ast.left);
var bailJump = this._fn.code.length;
this.emit(0);
this.compileExpression(ast.right);
this._fn.code[bailJump] = ops.JMPT_OP | ((this._fn.code.length - bailJump - 1) << 8);
},
compileExpression: function(ast) {
if (ast === true) {
this.emit(ops.PUSHT, ast.line);
} else if (ast === false) {
this.emit(ops.PUSHF, ast.line);
} else if (typeof ast == 'number' || typeof ast == 'string') {
this.emit(ops.PUSHC | (this._fn.slotForConstant(ast) << 8), ast.line);
} else {
switch (ast.type) {
case A.COLOR:
var color = makeColor(ast.r, ast.g, ast.b, ast.a);
this.emit(ops.PUSHC | (this._fn.slotForConstant(color) << 8), ast.line);
break;
case A.ASSIGN:
this.compileAssign(ast);
break;
case A.TRACE:
this.emit(ops.TRACE, ast.line);
break;
case A.IDENT:
this.emit(ops.PUSHL | (this._fn.slotForLocal(ast.name) << 8), ast.line);
break;
case A.CALL:
this.compileCall(ast);
break;
case A.BIN_OP:
if (ast.op === T.LAND) {
this.compileLogicalAnd(ast);
} else if (ast.op === T.LOR) {
this.compileLogicalOr(ast);
} else if (ast.op in BIN_OPS) {
this.compileExpression(ast.left);
this.compileExpression(ast.right);
this.emit(BIN_OPS[ast.op], ast.line);
} else {
throw "unknown binary operator!";
}
break;
case A.SPAWN:
this.compileSpawn(ast);
break;
default:
throw "unknown/unimplemented AST node type: " + ast.type;
}
}
},
compileStatement: function(ast) {
if (ast.type) {
switch (ast.type) {
case A.DEF:
this.compileFnDef(ast);
break;
case A.IF:
this.compileIf(ast);
break;
case A.WHILE:
this.compileWhile(ast);
break;
case A.LOOP:
this.compileLoop(ast);
break;
case A.RETURN:
this.compileReturn(ast);
break;
case A.YIELD:
this.compileYield(ast);
break;
default:
this.compileExpression(ast);
this.emit(ops.SETZ);
break;
}
} else {
this.compileExpression(ast);
this.emit(ops.SETZ);
}
},
compileStatements: function(statements) {
for (var i = 0; i < statements.length; ++i) {
this.compileStatement(statements[i]);
}
},
compileFunctionBody: function(statements) {
this.compileStatements(statements);
this.emit(ops.PUSHZ);
this.emit(ops.RET);
},
compile: function(ast) {
this._env = {};
this._fn = makeFunction();
this.compileFunctionBody(ast);
return {
topLevelFn : this._fn,
symbols : this._env
};
}
},
compileIf: function(ast) {
var ix = 0,
firstAbs = null,
lastAbs = null,
clauses = ast.clauses;
while (ix < clauses.length) {
var clause = clauses[ix];
if (typeof clause.condition !== 'undefined') {
this.compileExpression(clause.condition);
var failJump = this._fn.code.length;
this.emit(ops.JMPF);
this.compileStatements(clause.body);
if (firstAbs === null) {
firstAbs = this._fn.code.length;
lastAbs = this._fn.code.length;
this.emit(0);
} else {
var tmp = this._fn.code.length;
this.emit(lastAbs); // hack - stash pointer to last jump point so we can backtrack
lastAbs = tmp;
}
this._fn.code[failJump] = ops.JMPF | ((this._fn.code.length - failJump - 1) << 8);
} else {
this.compileStatements(clause.body);
}
ix++;
}
var jmpOp = ops.JMPA | (this._fn.code.length << 8),
currAbs = lastAbs;
do {
var tmp = this._fn.code[currAbs];
this._fn.code[currAbs] = jmpOp;
if (currAbs == firstAbs) {
break;
} else {
currAbs = tmp;
}
} while (true);
},
compileWhile: function(ast) {
var loopStart = this._fn.code.length;
this.compileExpression(ast.condition);
var failJump = this._fn.code.length;
this.emit(ops.JMPF);
this.compileStatements(ast.body);
this.emit(ops.JMPA | (loopStart << 8));
this._fn.code[failJump] = ops.JMPF | ((this._fn.code.length - failJump - 1) << 8);
},
compileLoop: function(ast) {
var loopStart = this._fn.code.length;
this.compileStatements(ast.body);
this.emit(ops.YIELD, ast.line);
this.emit(ops.JMPA | (loopStart << 8));
},
compileReturn: function(ast) {
if (typeof ast.returnValue !== 'undefined') {
this.compileExpression(ast.returnValue);
} else {
this.emit(ops.PUSHF); // TODO: should probably push undefined/null or whatever
}
this.emit(ops.RET, ast.line);
},
compileYield: function(ast) {
this.emit(ops.YIELD, ast.line);
},
compileCall: function(ast) {
var args = ast.args;
if (args.length > 255) {
throw "compile error - max args per function call (255) exceeded";
}
for (var i = 0; i < args.length; ++i) {
this.compileExpression(args[i]);
}
this.emit(ops.CALL | (args.length << 8) | (this._fn.slotForFunctionCall(ast.fn.name) << 16), ast.line);
},
compileSpawn: function(ast) {
var args = ast.args;
if (args.length > 255) {
throw "compile error - max args per spawn (255) exceeded";
}
for (var i = 0; i < args.length; ++i) {
this.compileExpression(args[i]);
}
this.emit(ops.SPAWN | (args.length << 8) | (this._fn.slotForFunctionCall(ast.fn.name) << 16), ast.line);
},
compileEval: function(ast) {
this.compileExpression(ast.code);
this.emit(ops.EVAL, ast.line);
},
compileLogicalAnd: function(ast) {
this.compileExpression(ast.left);
var bailJump = this._fn.code.length;
this.emit(0);
this.compileExpression(ast.right);
this._fn.code[bailJump] = ops.JMPF_OP | ((this._fn.code.length - bailJump - 1) << 8);
},
compileLogicalOr: function(ast) {
this.compileExpression(ast.left);
var bailJump = this._fn.code.length;
this.emit(0);
this.compileExpression(ast.right);
this._fn.code[bailJump] = ops.JMPT_OP | ((this._fn.code.length - bailJump - 1) << 8);
},
compileExpression: function(ast) {
// FIXME: ast.line will be undefined for true and false. Is this intentional?
if (ast === true) {
this.emit(ops.PUSHT, ast.line);
} else if (ast === false) {
this.emit(ops.PUSHF, ast.line);
} else if (typeof ast == 'number' || typeof ast == 'string') {
this.emit(ops.PUSHC | (this._fn.slotForConstant(ast) << 8), ast.line);
} else {
switch (ast.type) {
case A.COLOR:
var color = makeColor(ast.r, ast.g, ast.b, ast.a);
this.emit(ops.PUSHC | (this._fn.slotForConstant(color) << 8), ast.line);
break;
case A.ASSIGN:
this.compileAssign(ast);
break;
case A.TRACE:
this.emit(ops.TRACE, ast.line);
break;
case A.IDENT:
this.emit(ops.PUSHL | (this._fn.slotForLocal(ast.name) << 8), ast.line);
break;
case A.GLOBAL_IDENT:
this.emit(ops.PUSHG | (this._fn.slotForName(ast.name) << 16), ast.line);
break;
case A.CALL:
this.compileCall(ast);
break;
case A.BIN_OP:
if (ast.op === T.LAND) {
this.compileLogicalAnd(ast);
} else if (ast.op === T.LOR) {
this.compileLogicalOr(ast);
} else if (ast.op in BIN_OPS) {
this.compileExpression(ast.left);
this.compileExpression(ast.right);
this.emit(BIN_OPS[ast.op], ast.line);
} else {
throw "unknown binary operator!";
}
break;
case A.SPAWN:
this.compileSpawn(ast);
break;
case A.EVAL:
this.compileEval(ast);
break;
case A.NULL:
this.emit(ops.PUSHN, ast.line);
break;
default:
throw "unknown/unimplemented AST node type: " + ast.type;
}
}
},
compileStatement: function(ast) {
if (ast.type) {
switch (ast.type) {
case A.DEF:
this.compileFnDef(ast);
break;
case A.IF:
this.compileIf(ast);
break;
case A.WHILE:
this.compileWhile(ast);
break;
case A.LOOP:
this.compileLoop(ast);
break;
case A.RETURN:
this.compileReturn(ast);
break;
case A.YIELD:
this.compileYield(ast);
break;
default:
this.compileExpression(ast);
this.emit(ops.SETZ);
break;
}
} else {
this.compileExpression(ast);
this.emit(ops.SETZ);
}
},
compileStatements: function(statements) {
for (var i = 0; i < statements.length; ++i) {
this.compileStatement(statements[i]);
}
},
compileFunctionBody: function(statements) {
this.compileStatements(statements);
this.emit(ops.PUSHZ);
this.emit(ops.RET);
},
compile: function(ast) {
this._env = {};
this._fn = makeFunction();
this.compileFunctionBody(ast);
return {
topLevelFn : this._fn,
symbols : this._env
};
},
compileForEval: function(ast, fn) {
this._env = {};
this._fn = fn;
var code = fn.code;
this._fn.code = [];
this.compileStatements(ast);
this.emit(ops.PUSHZ);
var retVal = {
code : this._fn.code,
symbols : this._env
};
this._fn.code = code;
return retVal;
}
};
exports.createCompiler = function() {
return new Compiler();
}
return new Compiler();
}
"use strict";
var createVM = require('./vm').createVM,
createLexer = require('./lexer').createLexer,
createParser = require('./parser').createParser,
createCompiler = require('./compiler').createCompiler,
taskStates = require('./task_states'),
types = require('./types');
var createVM = require('./vm').createVM,
createLexer = require('./lexer').createLexer,
createParser = require('./parser').createParser,
createCompiler = require('./compiler').createCompiler,
taskStates = require('./task_states'),
types = require('./types'),
readline = require('readline');
function createContext(vm) {
vm = vm || createVM();
//
// Ghetto stdlib
vm.trace = function(vm, task, frame) {
console.log("tracin'", task, frame);
console.log(frame.dirtyLocals());
}
vm.env['random'] = function() {
return Math.floor(Math.random() * 1000);
}
vm.env['delay'] = function(args, task, env, vm) {
if (task.state === taskStates.RESUMED) {
task.state = taskStates.RUNNABLE;
return null;
}
task.state = taskStates.BLOCKED;
setTimeout(function() { vm.resumeTask(task); }, args[0]);
};
vm.env['print'] = function(args) {
var val = args[0];
if (typeof val !== 'object') {
console.log(args[0]);
} else {
switch (val.__type__) {
case types.T_FN:
console.log("<Function>");
break;
case types.T_TASK:
console.log("<Task id=" + val.id + ">");
break;
default:
console.log("<Unknown>");
}
}
};
function start() {
vm.start();
}
function run(source, filename) {
try {
var lexer = createLexer(source),
parser = createParser(lexer),
ast = parser.parseTopLevel(),
compiler = createCompiler(),
result = compiler.compile(ast);
vm = vm || createVM();
//
// Ghetto stdlib
vm.trace = function(vm, task, frame) {
console.log("tracin'", task, frame);
console.log(frame.dirtyLocals());
}
vm.env['random'] = function() {
return Math.floor(Math.random() * 1000);
}
vm.env['delay'] = function(args, task, env, vm) {
vm.merge(result.symbols);
vm.spawn(result.topLevelFn);
} catch (e) {
console.log(e);
}
}
return {
start : start,
run : run
};
if (task.state === taskStates.RESUMED) {
task.state = taskStates.RUNNABLE;
return null;
}
task.state = taskStates.BLOCKED;
setTimeout(function() {
if (task.state !== taskStates.DEAD) {
vm.resumeTask(task);
}
}, args[0]);
};
vm.env['print'] = function(args) {
var val = args[0];
if (typeof val !== 'object') {
console.log(args[0]);
} else {
switch (val.__type__) {
case types.T_FN:
console.log("<Function>");
break;
case types.T_TASK:
console.log("<Task id=" + val.id + ">");
break;
default:
console.log("<Unknown>");
}
}
};
vm.env['prompt'] = function(args) {
var prompt = args[0] || "> ";
process.stdout.write(prompt);
};
vm.env['input'] = function(args, task, env, vm) {
var frame = task.frames[task.fp];
if (task.state == taskStates.RESUMED) {
task.state = taskStates.RUNNABLE;
return frame.z;
}
task.state = taskStates.BLOCKED;
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
frame.z = null;
rl.once("line", function(input) {
frame.z = input;
rl.close();
}).once("close", function() {
vm.resumeTask(task);
});
};
function start() {
vm.start();
}
function spawn(fun) {
return vm.spawn(fun);
}
function compile(source, filename) {
try {
var lexer = createLexer(source),
parser = createParser(lexer),
ast = parser.parseTopLevel(),
compiler = createCompiler(),
result = compiler.compile(ast);
vm.merge(result.symbols);
return result.topLevelFn;
} catch (e) {
console.log(e);
return null;
}
}
function run(source, filename) {
var fun = compile(source, filename);
if (!fun)
return null;
return vm.spawn(fun);
}
function killTask(task) {
vm.killTask(task);
}
return {
compile : compile,
start : start,
run : run,
spawn : spawn,
killTask : killTask,
env : vm.env
};
}
exports.createContext = createContext;
exports.createContext = createContext;

@@ -15,3 +15,5 @@ "use strict";

'false' : T.FALSE,
'spawn' : T.SPAWN
'null' : T.NULL,
'spawn' : T.SPAWN,
'eval' : T.EVAL
};

@@ -188,2 +190,15 @@

break;
case '$':
if (more() && ident_start_p(src[p+1])) {
start = ++p;
while (more() && ident_rest_p(src[p+1]))
adv();
text = src.substring(start, p + 1);
tok = T.GLOBAL_IDENT;
} else {
error = "expected: global variable name";
tok = T.ERROR;
}
break;
case '\r':

@@ -315,2 +330,2 @@ if (more() && src[p+1] === '\n') {

};
};

@@ -12,13 +12,14 @@ "use strict";

var EXP_START_TOKENS = {};
EXP_START_TOKENS[T.BANG] = true;
EXP_START_TOKENS[T.TILDE] = true;
EXP_START_TOKENS[T.TRUE] = true;
EXP_START_TOKENS[T.FALSE] = true;
EXP_START_TOKENS[T.INTEGER] = true;
EXP_START_TOKENS[T.HEX] = true;
EXP_START_TOKENS[T.FLOAT] = true;
EXP_START_TOKENS[T.STRING] = true;
EXP_START_TOKENS[T.TRACE] = true;
EXP_START_TOKENS[T.IDENT] = true;
EXP_START_TOKENS[T.COLOR] = true;
EXP_START_TOKENS[T.BANG] = true;
EXP_START_TOKENS[T.TILDE] = true;
EXP_START_TOKENS[T.TRUE] = true;
EXP_START_TOKENS[T.FALSE] = true;
EXP_START_TOKENS[T.INTEGER] = true;
EXP_START_TOKENS[T.HEX] = true;
EXP_START_TOKENS[T.FLOAT] = true;
EXP_START_TOKENS[T.STRING] = true;
EXP_START_TOKENS[T.TRACE] = true;
EXP_START_TOKENS[T.IDENT] = true;
EXP_START_TOKENS[T.GLOBAL_IDENT] = true;
EXP_START_TOKENS[T.COLOR] = true;

@@ -228,3 +229,3 @@ function ParseError(message, line, column, expectedToken, actualToken) {

}
function parseStatements() {

@@ -372,5 +373,23 @@ var statements = [];

}
curr.exp = parseCall();
curr.exp = parseEval();
return root;
} else {
return parseEval();
}
}
function parseEval() {
if (at(T.EVAL)) {
var line = lexer.line();
var node = { type: A.EVAL, line: line, code: undefined };
next();
if (atBlockTerminator() || atStatementTerminator()) {
error("expected: expression");
} else {
node.code = parseExpression();
}
return node;
} else {
return parseCall();

@@ -413,2 +432,5 @@ }

next();
} else if (at(T.NULL)) {
exp = { type: A.NULL, line: line };
next();
} else if (at(T.INTEGER)) {

@@ -438,2 +460,5 @@ exp = parseInt(text(), 10);

next();
} else if (at(T.GLOBAL_IDENT)) {
exp = { type: A.GLOBAL_IDENT, line: line, name: text() };
next();
} else if (at(T.SPAWN)) {

@@ -469,2 +494,2 @@ next();

};
}
}

@@ -35,2 +35,3 @@ "use strict";

'FALSE', // false
'NULL', // null
'IF', // if

@@ -44,4 +45,6 @@ 'ELSE', // else

'SPAWN', // spawn
'EVAL', // eval
'IDENT',
'GLOBAL_IDENT',
'INTEGER',

@@ -64,2 +67,2 @@ 'HEX',

exports.tokens = TOKENS;
exports.names = TOKEN_NAMES;
exports.names = TOKEN_NAMES;

@@ -23,3 +23,3 @@ "use strict";

this.fnNames = [];
this.fnCache = [];
this.names = [];
};

@@ -58,4 +58,13 @@

this.fnNames.push(name);
this.fnCache.push(null);
return this.fnNames.length - 1;
},
slotForName: function(name) {
for (var i = 0; i < this.names.length; ++i) {
if (name === this.names[i]) {
return i;
}
}
this.names.push(name);
return this.names.length - 1;
}

@@ -78,2 +87,10 @@ };

Task.prototype.stop = function() {
}
Task.prototype.start = function() {
}
exports.makeFunction = function() {

@@ -80,0 +97,0 @@ return new Fn();

@@ -105,7 +105,10 @@ "use strict";

OP_PUSHL = t('PUSHL', 'Push local', [31, 8, 'local']),
OP_PUSHG = t('PUSHG', 'Push global', [31, 16, 'name']),
OP_PUSHT = t('PUSHT', 'Push true'),
OP_PUSHF = t('PUSHF', 'Push false'),
OP_PUSHN = t('PUSHN', 'Push null'),
OP_PUSHZ = t('PUSHZ', 'Push last evaluated value'),
OP_SETZ = t('SETZ', 'Set last evaluated value'),
OP_SETL = t('SETL', 'Set local', [31, 8, 'local']),
OP_SETG = t('SETG', 'Set global', [31, 16, 'name']),
OP_CALL = t('CALL', 'Call function', [31, 16, 'fn', 15, 8, 'nargs']),

@@ -133,2 +136,3 @@ OP_SPAWN = t('SPAWN', 'Spawn new thread', [31, 16, 'fn', 15, 8, 'nargs']),

OP_YIELD = t('YIELD', 'Yield'),
OP_EVAL = t('EVAL', 'Evaluate code'),
OP_EXIT = t('EXIT', 'Exit task');

@@ -157,3 +161,4 @@

blocked: new TaskList(),
env: {}
env: {},
globals: {}
};

@@ -163,3 +168,3 @@

var env = vm.env;
var env = vm.env, globals = vm.globals;

@@ -191,6 +196,10 @@ function runtimeError(task, message) {

fn = frame.fn,
code = fn.code;
code = fn.code,
fetch = function () { return code[frame.ip++]; },
next_op = fetch;
for (;;) {
var op = code[frame.ip++];
var op = next_op();
// console.log(opcodeMeta[op & 0xFF].name);

@@ -207,2 +216,6 @@ switch (op & 0x000000FF) {

break;
case OP_PUSHG:
var gname = fn.names[op >> 16];
task.stack[frame.sp++] = (gname in globals) ? globals[gname] : null;
break;
case OP_PUSHT:

@@ -214,2 +227,5 @@ task.stack[frame.sp++] = true;

break;
case OP_PUSHN:
task.stack[frame.sp++] = null;
break;
case OP_PUSHZ:

@@ -230,2 +246,6 @@ task.stack[frame.sp++] = frame.z;

break;
case OP_SETG:
// Again, stack is not popped
globals[fn.names[op >> 16]] = task.stack[frame.sp-1];
break;
case OP_CALL:

@@ -315,2 +335,36 @@

break;
case OP_EVAL:
var value = task.stack[frame.sp-1],
eval_ip = 0,
eval_code = [];
try {
var lexer = require('./lexer').createLexer(value),
parser = require('./parser').createParser(lexer),
ast = parser.parseTopLevel(),
compiler = require('./compiler').createCompiler(),
result = compiler.compileForEval(ast, frame.fn);
vm.merge(result.symbols);
eval_code = result.code;
} catch (e) {
return runtimeError(task, "Could not evaluate code '" + value + "': " + e);
}
next_op = function () {
if (eval_ip < eval_code.length) {
return eval_code[eval_ip++];
} else {
next_op = fetch;
return next_op();
}
}
break;
case OP_POP:

@@ -481,3 +535,3 @@ --frame.sp;

setTimeout(resume, 0);
return task;

@@ -546,2 +600,11 @@ }

}
function killTask(task) {
if (task.state === TASK_RUNNABLE || task.state === TASK_RESUMED) {
tasklist_remove(vm.runnable, task);
} else if (task.state === TASK_BLOCKED) {
tasklist_remove(vm.blocked, task);
}
task.state = TASK_DEAD;
}

@@ -581,2 +644,3 @@ function gcTask(task) {

vm.resumeTask = resumeTask;
vm.killTask = killTask;
vm.merge = merge;

@@ -589,2 +653,2 @@

exports.opcodes = opcodes;
exports.opcodeMeta = opcodeMeta;
exports.opcodeMeta = opcodeMeta;
{
"name": "jester",
"version": "0.2.2",
"version": "0.2.3",
"description": "Simple language designed for teaching",

@@ -5,0 +5,0 @@ "main": "index.js",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc