comparison 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
comparison
equal deleted inserted replaced
205:6fe9343b1400 206:b4a9d4e405c5
1 Number.prototype['tpmeth_+'] = function(other) {
2 return this + other;
3 };
4 Number.prototype['tpmeth_-'] = function(other) {
5 return this - other;
6 };
7 Number.prototype['tpmeth_*'] = function(other) {
8 return this * other;
9 };
10 Number.prototype['tpmeth_/'] = function(other) {
11 return this / other;
12 };
13 Number.prototype['tpmeth_='] = function(other) {
14 return this == other ? tptrue : tpfalse;
15 };
16 Number.prototype['tpmeth_>'] = function(other) {
17 return this > other ? tptrue : tpfalse;
18 };
19 Number.prototype['tpmeth_<'] = function(other) {
20 return this < other ? tptrue : tpfalse;
21 };
22 Number.prototype['tpmeth_>='] = function(other) {
23 return this >= other ? tptrue : tpfalse;
24 };
25 Number.prototype['tpmeth_<='] = function(other) {
26 return this <= other ? tptrue : tpfalse;
27 };
28 Number.prototype.tpmeth_string = function() {
29 return '' + this;
30 };
31 Number.prototype.tpmeth_print = function() {
32 print(this);
33 };
34
35 String.prototype['tpmeth_.'] = function(other) {
36 return this + other;
37 };
38 String.prototype['tpmeth_='] = function(other) {
39 return this == other ? tptrue : tpfalse;
40 };
41 String.prototype.tpmeth_print = function() {
42 print(this);
43 }
44
45 var tptrue = null;
46 var tpfalse = null;
47
48 function topenv(moduledirs)
49 {
50 this.names = {};
51 this.modules = {};
52 for (var dirnum in moduledirs) {
53 var results = os.system("ls", [moduledirs[dirnum]]).split('\n');
54 for (var i in results) {
55 var tpidx = results[i].indexOf('.tp')
56 if (tpidx > 0 && tpidx == results[i].length - 3) {
57 this.names[results[i].substr(0, tpidx)] = moduledirs[dirnum] + "/" + results[i];
58 }
59 }
60 }
61 if (!tptrue) {
62 tptrue = this.find('true');
63 tptrue.valueOf = function() {
64 return true;
65 };
66 }
67 if (!tpfalse) {
68 tpfalse = this.find('false');
69 tpfalse.valueOf = function() {
70 return false;
71 };
72 }
73 }
74
75 topenv.prototype = {
76 find: function(name) {
77 if (name in this.modules) {
78 return this.modules[name];
79 }
80 if (name in this.names) {
81 var parsed = parseFile(this.names[name]);
82 this.modules[name] = parsed.eval(this);
83 return this.modules[name];
84 }
85 return null;
86 },
87 findNoTop: function(name) {
88 return null;
89 },
90 findSetPresent: function(name, val) {
91 return false;
92 }
93 }
94
95 function environment(parent)
96 {
97 this.parent = parent;
98 this.syms = {};
99 }
100
101 environment.prototype = {
102 find: function(name) {
103 if (name in this.syms) {
104 return this.syms[name];
105 }
106 if (this.parent) {
107 return this.parent.find(name);
108 }
109 return null;
110 },
111 findNoTop: function(name) {
112 if (name in this.syms) {
113 return this.syms[name];
114 }
115 if (this.parent) {
116 return this.parent.findNoTop(name);
117 }
118 return null;
119 },
120 findSet: function(name, val) {
121 if (name in this.syms
122 || !this.parent
123 || !this.parent.findSetPresent(name, val)) {
124 this.syms[name] = val;
125 }
126 },
127 findSetPresent: function(name, val) {
128 if (name in this.syms) {
129 this.syms[name] = val;
130 return true;
131 }
132 if (this.parent) {
133 return this.parent.findSetPresent(name, val);
134 }
135 return false;
136 }
137 };
138
139 op.prototype.eval = function(env) {
140 var l = this.left.eval(env);
141 var r = this.right.eval(env);
142 var name = this.op;
143 var fun = env.findNoTop(name);
144 var ret;
145 if (fun) {
146 ret = fun(l,r)
147 } else {
148 ret = l['tpmeth_'+name](r);
149 }
150 return ret;
151 };
152
153 symbol.prototype.eval = function(env) {
154 return env.find(this.name);
155 };
156
157 intlit.prototype.eval =
158 floatlit.prototype.eval =
159 strlit.prototype.eval =
160 arraylit.prototype.eval = function(env) {
161 return this.val;
162 };
163
164 funcall.prototype.eval = function(env) {
165 var args = [];
166 var name = this.name;
167 if (name[name.length-1] == ":") {
168 name = name.substr(0, name.length-1);
169 }
170 if (this.receiver) {
171 args.push(this.receiver.eval(env));
172 }
173 for (var i = 0; i < this.args.length; i++) {
174 args.push(this.args[i].eval(env));
175 }
176 var fun = env.findNoTop(name);
177 if (fun) {
178 return fun.apply(null, args);
179 } else {
180 return args[0]['tpmeth_'+name].apply(args[0], args.slice(1));
181 }
182 };
183
184 object.prototype.eval = function(parentenv) {
185 var env = new environment(parentenv);
186 var obj = {env: env};
187 for (var i = 0; i < this.messages.length; i++) {
188 var msg = this.messages[i];
189 if (msg instanceof assignment) {
190 if (msg.expression instanceof lambda) {
191 obj['tpmeth_' + msg.symbol.name] = msg.expression.eval(env);
192 (function(name) {
193 env.syms[name] = function() {
194 return obj['tpmeth_' + name].apply(obj, arguments);
195 };
196 })(msg.symbol.name);
197 } else {
198 var makeProp = function(obj, name) {
199 obj['tprop_' + name] = msg.expression.eval(env);
200 name = 'tpmeth_' + name;
201 obj[name] = function() {
202 return this[name];
203 };
204 var setname = name+'!';
205 obj[setname] = function(val) {
206 this[setname] = val;
207 return this;
208 };
209 };
210 makeProp(obj, msg.symbol.name);
211 }
212 } else {
213 throw new Error('pseudo function calls in object definitions not implemented yet');
214 }
215 }
216 return obj;
217 };
218
219 lambda.prototype.eval = function(parentenv) {
220 var args = this.args;
221 var exprs = this.expressions;
222 return function() {
223 var env = new environment(parentenv);
224 for (var i = 0, j = 0; i < arguments.length && j < args.length; i++, j++) {
225 while (j < args.length && args[j].cleanName() == 'self') {
226 j++;
227 }
228 env.syms[args[j].cleanName()] = arguments[i];
229 }
230 if (this != null && (args.length == 0 || args[0].cleanName() != 'self')) {
231 env.syms['self'] = this;
232 }
233 var res = null;
234 for (var i = 0; i < exprs.length; i++) {
235 res = exprs[i].eval(env);
236 }
237 return res;
238 };
239 };
240
241 assignment.prototype.eval = function(env) {
242 var val = this.expression.eval(env);
243 env.findSet(this.symbol.name, val);
244 return val;
245 };