Mercurial > repos > tabletprog
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 }; |