Mercurial > repos > tabletprog
view interp.js @ 206:b4a9d4e405c5
Implemented a simple interpreter to be used for macro expansion and a driver for testing it
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 23 Oct 2013 19:10:03 -0700 |
parents | |
children | 60eff5f81d9a |
line wrap: on
line source
Number.prototype['tpmeth_+'] = function(other) { return this + other; }; Number.prototype['tpmeth_-'] = function(other) { return this - other; }; Number.prototype['tpmeth_*'] = function(other) { return this * other; }; Number.prototype['tpmeth_/'] = function(other) { return this / other; }; Number.prototype['tpmeth_='] = function(other) { return this == other ? tptrue : tpfalse; }; Number.prototype['tpmeth_>'] = function(other) { return this > other ? tptrue : tpfalse; }; Number.prototype['tpmeth_<'] = function(other) { return this < other ? tptrue : tpfalse; }; Number.prototype['tpmeth_>='] = function(other) { return this >= other ? tptrue : tpfalse; }; Number.prototype['tpmeth_<='] = function(other) { return this <= other ? tptrue : tpfalse; }; Number.prototype.tpmeth_string = function() { return '' + this; }; Number.prototype.tpmeth_print = function() { print(this); }; String.prototype['tpmeth_.'] = function(other) { return this + other; }; String.prototype['tpmeth_='] = function(other) { return this == other ? tptrue : tpfalse; }; String.prototype.tpmeth_print = function() { print(this); } var tptrue = null; var tpfalse = null; function topenv(moduledirs) { this.names = {}; this.modules = {}; for (var dirnum in moduledirs) { var results = os.system("ls", [moduledirs[dirnum]]).split('\n'); for (var i in results) { var tpidx = results[i].indexOf('.tp') if (tpidx > 0 && tpidx == results[i].length - 3) { this.names[results[i].substr(0, tpidx)] = moduledirs[dirnum] + "/" + results[i]; } } } if (!tptrue) { tptrue = this.find('true'); tptrue.valueOf = function() { return true; }; } if (!tpfalse) { tpfalse = this.find('false'); tpfalse.valueOf = function() { return false; }; } } topenv.prototype = { find: function(name) { if (name in this.modules) { return this.modules[name]; } if (name in this.names) { var parsed = parseFile(this.names[name]); this.modules[name] = parsed.eval(this); return this.modules[name]; } return null; }, findNoTop: function(name) { return null; }, findSetPresent: function(name, val) { return false; } } function environment(parent) { this.parent = parent; this.syms = {}; } environment.prototype = { find: function(name) { if (name in this.syms) { return this.syms[name]; } if (this.parent) { return this.parent.find(name); } return null; }, findNoTop: function(name) { if (name in this.syms) { return this.syms[name]; } if (this.parent) { return this.parent.findNoTop(name); } return null; }, findSet: function(name, val) { if (name in this.syms || !this.parent || !this.parent.findSetPresent(name, val)) { this.syms[name] = val; } }, findSetPresent: function(name, val) { if (name in this.syms) { this.syms[name] = val; return true; } if (this.parent) { return this.parent.findSetPresent(name, val); } return false; } }; op.prototype.eval = function(env) { var l = this.left.eval(env); var r = this.right.eval(env); var name = this.op; var fun = env.findNoTop(name); var ret; if (fun) { ret = fun(l,r) } else { ret = l['tpmeth_'+name](r); } return ret; }; symbol.prototype.eval = function(env) { return env.find(this.name); }; intlit.prototype.eval = floatlit.prototype.eval = strlit.prototype.eval = arraylit.prototype.eval = function(env) { return this.val; }; funcall.prototype.eval = function(env) { var args = []; var name = this.name; if (name[name.length-1] == ":") { name = name.substr(0, name.length-1); } if (this.receiver) { args.push(this.receiver.eval(env)); } for (var i = 0; i < this.args.length; i++) { args.push(this.args[i].eval(env)); } var fun = env.findNoTop(name); if (fun) { return fun.apply(null, args); } else { return args[0]['tpmeth_'+name].apply(args[0], args.slice(1)); } }; object.prototype.eval = function(parentenv) { var env = new environment(parentenv); var obj = {env: env}; for (var i = 0; i < this.messages.length; i++) { var msg = this.messages[i]; if (msg instanceof assignment) { if (msg.expression instanceof lambda) { obj['tpmeth_' + msg.symbol.name] = msg.expression.eval(env); (function(name) { env.syms[name] = function() { return obj['tpmeth_' + name].apply(obj, arguments); }; })(msg.symbol.name); } else { var makeProp = function(obj, name) { obj['tprop_' + name] = msg.expression.eval(env); name = 'tpmeth_' + name; obj[name] = function() { return this[name]; }; var setname = name+'!'; obj[setname] = function(val) { this[setname] = val; return this; }; }; makeProp(obj, msg.symbol.name); } } else { throw new Error('pseudo function calls in object definitions not implemented yet'); } } return obj; }; lambda.prototype.eval = function(parentenv) { var args = this.args; var exprs = this.expressions; return function() { var env = new environment(parentenv); for (var i = 0, j = 0; i < arguments.length && j < args.length; i++, j++) { while (j < args.length && args[j].cleanName() == 'self') { j++; } env.syms[args[j].cleanName()] = arguments[i]; } if (this != null && (args.length == 0 || args[0].cleanName() != 'self')) { env.syms['self'] = this; } var res = null; for (var i = 0; i < exprs.length; i++) { res = exprs[i].eval(env); } return res; }; }; assignment.prototype.eval = function(env) { var val = this.expression.eval(env); env.findSet(this.symbol.name, val); return val; };