Mercurial > repos > tabletprog
comparison interp.js @ 208:a1b4a2bc8d72
Initial work on pattern match macrosfor the new parser
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Fri, 22 Nov 2013 19:37:25 -0800 |
parents | 60eff5f81d9a |
children | 4b3b57f39f10 |
comparison
equal
deleted
inserted
replaced
207:60eff5f81d9a | 208:a1b4a2bc8d72 |
---|---|
23 return this >= other ? tptrue : tpfalse; | 23 return this >= other ? tptrue : tpfalse; |
24 }; | 24 }; |
25 Number.prototype['tpmeth_<='] = function(other) { | 25 Number.prototype['tpmeth_<='] = function(other) { |
26 return this <= other ? tptrue : tpfalse; | 26 return this <= other ? tptrue : tpfalse; |
27 }; | 27 }; |
28 Number.prototype.tpmeth_asStringChar = function() { | |
29 return String.fromCharCode(this); | |
30 }; | |
28 Number.prototype.tpmeth_string = function() { | 31 Number.prototype.tpmeth_string = function() { |
29 return '' + this; | 32 return '' + this; |
30 }; | 33 }; |
31 Number.prototype.tpmeth_print = function() { | 34 Number.prototype.tpmeth_print = function() { |
32 print(this); | 35 print(this); |
36 return this + other; | 39 return this + other; |
37 }; | 40 }; |
38 String.prototype['tpmeth_='] = function(other) { | 41 String.prototype['tpmeth_='] = function(other) { |
39 return this == other ? tptrue : tpfalse; | 42 return this == other ? tptrue : tpfalse; |
40 }; | 43 }; |
44 String.prototype.tpmeth_length = function() { | |
45 return this.length; | |
46 }; | |
47 String.prototype.tpmeth_byte_length = function() { | |
48 return this.length; | |
49 }; | |
50 String.prototype.tpmeth_byte = function(index) { | |
51 return this.charCodeAt(index); | |
52 }; | |
53 String.prototype['tpmeth_from:withLength'] = function(pos, length) { | |
54 return this.substr(pos, length); | |
55 }; | |
41 String.prototype.tpmeth_print = function() { | 56 String.prototype.tpmeth_print = function() { |
42 print(this); | 57 print(this); |
43 } | 58 }; |
59 | |
60 Function.prototype['tpmeth_while:do'] = function(body) { | |
61 var ret = null; | |
62 for (;;) { | |
63 var res = this.call(null); | |
64 if (res != tptrue) { | |
65 break; | |
66 } | |
67 ret = body.call(null); | |
68 } | |
69 return ret; | |
70 }; | |
44 | 71 |
45 var tptrue = null; | 72 var tptrue = null; |
46 var tpfalse = null; | 73 var tpfalse = null; |
47 | 74 |
48 function topenv(moduledirs) | 75 function topenv(moduledirs) |
91 return false; | 118 return false; |
92 }, | 119 }, |
93 findMacro: function(name) { | 120 findMacro: function(name) { |
94 return null; | 121 return null; |
95 }, | 122 }, |
123 findQuoteTrans: function(name) { | |
124 return null; | |
125 } | |
96 } | 126 } |
97 | 127 |
98 function environment(parent) | 128 function environment(parent) |
99 { | 129 { |
100 this.parent = parent; | 130 this.parent = parent; |
101 this.syms = {}; | 131 this.syms = {}; |
102 this.macros = {}; | 132 this.macros = {}; |
133 this.quotetrans = {}; | |
103 } | 134 } |
104 | 135 |
105 environment.prototype = { | 136 environment.prototype = { |
106 find: function(name) { | 137 find: function(name) { |
107 if (name in this.syms) { | 138 if (name in this.syms) { |
148 if (this.parent) { | 179 if (this.parent) { |
149 return this.parent.findMacro(name); | 180 return this.parent.findMacro(name); |
150 } | 181 } |
151 return null; | 182 return null; |
152 }, | 183 }, |
184 findQuoteTrans: function(name) { | |
185 if (name in this.quotetrans) { | |
186 return this.quotetrans[name]; | |
187 } | |
188 if (this.parent) { | |
189 return this.parent.findQuoteTrans(name); | |
190 } | |
191 return null; | |
192 }, | |
153 defMacro: function(name, def) { | 193 defMacro: function(name, def) { |
154 this.syms[name] = def; | 194 this.syms[name] = def; |
155 this.macros[name] = true; | 195 this.macros[name] = true; |
156 } | 196 } |
157 }; | 197 }; |
160 { | 200 { |
161 if (typeof val == 'number') { | 201 if (typeof val == 'number') { |
162 return new intlit(val); | 202 return new intlit(val); |
163 } | 203 } |
164 if (typeof val == 'string') { | 204 if (typeof val == 'string') { |
165 return new stringlit(val); | 205 return new strlit(val); |
166 } | 206 } |
167 if (val instanceof Array) { | 207 if (val instanceof Array) { |
168 return new arraylit(val); | 208 return new arraylit(val); |
169 } | 209 } |
170 if (val == tptrue) { | 210 if (val == tptrue) { |
194 this.left = this.left.macroexpand(env); | 234 this.left = this.left.macroexpand(env); |
195 this.right = this.right.macroexpand(env); | 235 this.right = this.right.macroexpand(env); |
196 return this; | 236 return this; |
197 }; | 237 }; |
198 | 238 |
239 op.prototype.quote = function(env) { | |
240 var left = this.left.quote(env); | |
241 var right = this.right.quote(env); | |
242 return new op(left, this.op, right); | |
243 }; | |
244 | |
245 var quote_prefix = 0; | |
246 | |
199 symbol.prototype.eval = function(env) { | 247 symbol.prototype.eval = function(env) { |
200 return env.find(this.name); | 248 var res = env.find(this.name); |
249 if (res === null) { | |
250 throw new Error('Symbol ' + this.name + ' is not bound'); | |
251 } | |
252 return res; | |
253 }; | |
254 | |
255 symbol.prototype.quote = function(env) { | |
256 var val = env.find(this.name); | |
257 if (val) { | |
258 return makeASTNode(val); | |
259 } else { | |
260 var hygenic = env.findQuoteTrans(this.name); | |
261 return hygenic ? new symbol(hygenic, this.symbols) : this; | |
262 } | |
201 }; | 263 }; |
202 | 264 |
203 intlit.prototype.eval = | 265 intlit.prototype.eval = |
204 floatlit.prototype.eval = | 266 floatlit.prototype.eval = |
205 strlit.prototype.eval = | 267 strlit.prototype.eval = |
214 arraylit.prototype.macroexpand = | 276 arraylit.prototype.macroexpand = |
215 listlit.prototype.macroexpand = function(env) { | 277 listlit.prototype.macroexpand = function(env) { |
216 return this; | 278 return this; |
217 }; | 279 }; |
218 | 280 |
281 intlit.prototype.quote = | |
282 floatlit.prototype.quote = | |
283 strlit.prototype.quote = | |
284 arraylit.prototype.quote = | |
285 listlit.prototype.quote = function(env) { | |
286 return this; | |
287 }; | |
288 | |
219 funcall.prototype.eval = function(env) { | 289 funcall.prototype.eval = function(env) { |
220 var args = []; | 290 var args = []; |
221 var name = this.name; | 291 var name = this.name; |
222 if (name[name.length-1] == ":") { | 292 if (name[name.length-1] == ":") { |
223 name = name.substr(0, name.length-1); | 293 name = name.substr(0, name.length-1); |
224 } | 294 } |
225 if (name == 'quote') { | 295 if (name == 'quote') { |
226 if (this.receiver) { | 296 if (this.receiver) { |
227 return this.receiver; | 297 return this.receiver.quote(env); |
228 } | 298 } |
229 if (this.args.length) { | 299 if (this.args.length) { |
230 return this.args[0]; | 300 return this.args[0].quote(env); |
231 } | 301 } |
232 throw new Error('quote takes an argument'); | 302 throw new Error('quote takes an argument'); |
233 } | 303 } |
234 if (name == 'macro') { | 304 if (name == 'macro') { |
235 return null; | 305 return null; |
251 var fun = env.findNoTop(name); | 321 var fun = env.findNoTop(name); |
252 if (fun) { | 322 if (fun) { |
253 return fun.apply(null, args); | 323 return fun.apply(null, args); |
254 } else { | 324 } else { |
255 //if (typeof args[0]'tpmeth_'+name in args[0]) { | 325 //if (typeof args[0]'tpmeth_'+name in args[0]) { |
256 //try { | 326 try { |
257 return args[0]['tpmeth_'+name].apply(args[0], args.slice(1)); | 327 return args[0]['tpmeth_'+name].apply(args[0], args.slice(1)); |
258 /*} catch(e) { | 328 } catch(e) { |
259 throw new Error('Error, \n\t' + e.message.split('\n').join('\n\t') + '\ninvoking method ' + name + ' on object ' + args[0] + ' ' + JSON.stringify(Object.keys(args[0]))); | 329 throw new Error('Error, \n\t' + e.message.split('\n').join('\n\t') + '\ninvoking method ' + name + ' on object ' + args[0]); |
260 }*/ | 330 } |
261 /*} else {JSON.stringify | 331 /*} else {JSON.stringify |
262 throw new Error('No method named ' + name + ' on object ' + JSON.stringify(args[0])); | 332 throw new Error('No method named ' + name + ' on object ' + JSON.stringify(args[0])); |
263 }*/ | 333 }*/ |
264 } | 334 } |
265 }; | 335 }; |
285 } | 355 } |
286 for (var i = 0; i < this.args.length; i++) { | 356 for (var i = 0; i < this.args.length; i++) { |
287 args.push(this.args[i]); | 357 args.push(this.args[i]); |
288 } | 358 } |
289 return makeASTNode(macro.apply(null, args)); | 359 return makeASTNode(macro.apply(null, args)); |
360 }; | |
361 | |
362 funcall.prototype.quote = function(env) { | |
363 var receiver = this.receiver ? this.receiver.quote(env) : null; | |
364 var args = []; | |
365 for (var i = 0; i < this.args.length; i++) { | |
366 args.push(this.args[i].quote(env)); | |
367 } | |
368 var name = env.findQuoteTrans(this.name); | |
369 if (!name) { | |
370 name = this.name; | |
371 } | |
372 var ret = new funcall(name, args); | |
373 ret.receiver = receiver; | |
374 return ret; | |
290 }; | 375 }; |
291 | 376 |
292 object.prototype.eval = function(parentenv) { | 377 object.prototype.eval = function(parentenv) { |
293 var env = new environment(parentenv); | 378 var env = new environment(parentenv); |
294 var obj = {env: env}; | 379 var obj = {env: env}; |
367 } | 452 } |
368 this.messages = outmessages; | 453 this.messages = outmessages; |
369 return this; | 454 return this; |
370 }; | 455 }; |
371 | 456 |
457 object.prototype.quote = function(parentenv) { | |
458 var env = new environment(parentenv); | |
459 var outmessages = []; | |
460 for (var i = 0; i < this.messages.length; i++) { | |
461 var msg = this.messages[i]; | |
462 if (msg instanceof assignment) { | |
463 //Make sure method names don't get renamed for hygene | |
464 env.syms[msg.symbol.name] = null; | |
465 env.quotetrans[msg.symbol.name] = msg.symbol.name; | |
466 if (msg.expression instanceof lambda) { | |
467 env.syms[msg.symbol.name + '!'] = null; | |
468 env.quotetrans[msg.symbol.name + '!'] = msg.symbol.name + '!'; | |
469 } | |
470 } | |
471 } | |
472 for (var i = 0; i < this.messages.length; i++) { | |
473 var msg = this.messages[i]; | |
474 if (msg instanceof assignment) { | |
475 outmessages.push(new assignment(msg.symbol, msg.expression.quote(env))); | |
476 } else { | |
477 outmessages.push(msg.quote(env)); | |
478 } | |
479 } | |
480 return new object(outmessages); | |
481 }; | |
482 | |
372 lambda.prototype.eval = function(parentenv) { | 483 lambda.prototype.eval = function(parentenv) { |
373 var args = this.args; | 484 var args = this.args; |
374 var exprs = this.expressions; | 485 var exprs = this.expressions; |
375 return function() { | 486 return function() { |
376 var env = new environment(parentenv); | 487 var env = new environment(parentenv); |
378 while (j < args.length && args[j].cleanName() == 'self') { | 489 while (j < args.length && args[j].cleanName() == 'self') { |
379 j++; | 490 j++; |
380 } | 491 } |
381 env.syms[args[j].cleanName()] = arguments[i]; | 492 env.syms[args[j].cleanName()] = arguments[i]; |
382 } | 493 } |
383 if (this != null && (args.length == 0 || args[0].cleanName() != 'self')) { | 494 if (this != null && !(args.length == 0 || args[0].cleanName() != 'self')) { |
384 env.syms['self'] = this; | 495 env.syms['self'] = this; |
385 } | 496 } |
386 var res = null; | 497 var res = null; |
387 for (var i = 0; i < exprs.length; i++) { | 498 for (var i = 0; i < exprs.length; i++) { |
388 res = exprs[i].eval(env); | 499 res = exprs[i].eval(env); |
410 } | 521 } |
411 } | 522 } |
412 return this; | 523 return this; |
413 }; | 524 }; |
414 | 525 |
526 lambda.prototype.quote = function(parentenv) { | |
527 var args = []; | |
528 var expressions = []; | |
529 var env = new environment(parentenv); | |
530 for (var i = 0; i < this.args.length; i++) { | |
531 env.syms[this.args[i].cleanName()] = null; | |
532 var hygenic = '' + quote_prefix + this.args[i].cleanName(); | |
533 env.quotetrans[this.args[i].cleanName()] = hygenic; | |
534 args.push(new symbol(hygenic, this.args[i].symbols)); | |
535 } | |
536 for (var i = 0; i < this.expressions.length; i++) { | |
537 expressions.push(this.expressions[i].quote(env)); | |
538 } | |
539 return new lambda(args, expressions); | |
540 }; | |
541 | |
415 assignment.prototype.eval = function(env) { | 542 assignment.prototype.eval = function(env) { |
416 var val = this.expression.eval(env); | 543 var val = this.expression.eval(env); |
417 env.findSet(this.symbol.name, val); | 544 env.findSet(this.symbol.name, val); |
418 return val; | 545 return val; |
419 }; | 546 }; |
420 | 547 |
421 assignment.prototype.macroexpand = function(env) { | 548 assignment.prototype.macroexpand = function(env) { |
422 this.expression = this.expression.macroexpand(env); | 549 this.expression = this.expression.macroexpand(env); |
423 return this; | 550 return this; |
424 }; | 551 }; |
552 | |
553 assignment.prototype.quote = function(env) { | |
554 var name = this.symbol.cleanName(); | |
555 env.syms[name] = null; | |
556 var hygenic = '' + quote_prefix + name; | |
557 env.quotetrans[name] = hygenic; | |
558 return new assignment(new symbol(hygenic, this.symbol.symbols), this.expression.quote(env)); | |
559 }; |