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 };