comparison interp.js @ 210:d0848563f25d

Fix some bugs and allow proper access to list literals in interpreter/macro expander
author Mike Pavone <pavone@retrodev.com>
date Sat, 30 Nov 2013 15:03:47 -0800
parents 4b3b57f39f10
children e00a8bc6361b
comparison
equal deleted inserted replaced
209:4b3b57f39f10 210:d0848563f25d
75 return ret; 75 return ret;
76 }; 76 };
77 77
78 var tptrue = null; 78 var tptrue = null;
79 var tpfalse = null; 79 var tpfalse = null;
80 var tplist = null;
80 81
81 function topenv(moduledirs) 82 function topenv(moduledirs)
82 { 83 {
83 this.names = {}; 84 this.names = {};
84 this.modules = {}; 85 this.modules = {};
101 tpfalse = this.find('false'); 102 tpfalse = this.find('false');
102 tpfalse.valueOf = function() { 103 tpfalse.valueOf = function() {
103 return false; 104 return false;
104 }; 105 };
105 } 106 }
107 if (!tplist) {
108 tplist = this.find('list');
109 if (tplist instanceof Function) {
110 tplist = tplist.call(null);
111 }
112 }
106 } 113 }
107 114
108 topenv.prototype = { 115 topenv.prototype = {
109 find: function(name) { 116 find: function(name) {
110 if (name in this.modules) { 117 if (name in this.modules) {
313 }; 320 };
314 321
315 symbol.prototype.macroexpand = 322 symbol.prototype.macroexpand =
316 intlit.prototype.macroexpand = 323 intlit.prototype.macroexpand =
317 floatlit.prototype.macroexpand = 324 floatlit.prototype.macroexpand =
318 strlit.prototype.macroexpand = 325 strlit.prototype.macroexpand = function(env) {
319 arraylit.prototype.macroexpand = 326 return this;
327 };
328
329
330 arraylit.prototype.macroexpand =
320 listlit.prototype.macroexpand = function(env) { 331 listlit.prototype.macroexpand = function(env) {
332 for (var i = 0; i < this.val.length; i++) {
333 this.val[i] = this.val[i].macroexpand(env);
334 }
321 return this; 335 return this;
322 }; 336 };
323 337
324 intlit.prototype.quote = 338 intlit.prototype.quote =
325 floatlit.prototype.quote = 339 floatlit.prototype.quote =
350 }; 364 };
351 365
352 intlit.prototype.tpmeth_value = 366 intlit.prototype.tpmeth_value =
353 floatlit.prototype.tpmeth_value = 367 floatlit.prototype.tpmeth_value =
354 strlit.prototype.tpmeth_value = 368 strlit.prototype.tpmeth_value =
355 arraylit.prototype.tpmeth_value = 369 arraylit.prototype.tpmeth_value = function() {
356 listlit.prototype.tpmeth_value = function() {
357 return this.val; 370 return this.val;
358 } 371 };
372
373 listlit.prototype.tpmeth_value = function() {
374 var cur = tplist.tpmeth_empty();
375 for (var idx = this.val.length - 1; idx >= 0; --idx) {
376 cur = tplist['tpmeth_node:withTail'](this.val[idx], cur);
377 }
378 return cur;
379 };
359 380
360 funcall.prototype.eval = function(env) { 381 funcall.prototype.eval = function(env) {
361 var args = []; 382 var args = [];
362 var name = this.name; 383 var name = this.name;
363 if (name[name.length-1] == ":") { 384 if (name[name.length-1] == ":") {
389 return args[2].call(null); 410 return args[2].call(null);
390 } 411 }
391 return args[1].call(null, res); 412 return args[1].call(null, res);
392 } 413 }
393 var fun = env.findNoTop(name); 414 var fun = env.findNoTop(name);
394 if (fun) { 415 if (fun && (fun.numargs === undefined || fun.numargs == args.length)) {
395 return fun.apply(null, args); 416 return fun.apply(null, args);
396 } else { 417 } else {
397 //if (typeof args[0]'tpmeth_'+name in args[0]) { 418 //if (typeof args[0]'tpmeth_'+name in args[0]) {
398 try { 419 try {
399 return args[0]['tpmeth_'+name].apply(args[0], args.slice(1)); 420 return args[0]['tpmeth_'+name].apply(args[0], args.slice(1));
400 } catch(e) { 421 } catch(e) {
401 throw new Error('Error, \n\t' + e.message.split('\n').join('\n\t') + '\ninvoking method ' + name + ' on object ' + args[0]); 422 var msg = 'Error, \n\t' + e.message.split('\n').join('\n\t') + '\ninvoking method ' + name + ' on object ' + args[0];
423 if (typeof args[0] == 'object') {
424 msg += ' with keys ' + JSON.stringify(Object.keys(args[0]) + ' and constructor ' + args[0].constructor.name);
425 }
426 throw new Error(msg);
402 } 427 }
403 /*} else {JSON.stringify 428 /*} else {JSON.stringify
404 throw new Error('No method named ' + name + ' on object ' + JSON.stringify(args[0])); 429 throw new Error('No method named ' + name + ' on object ' + JSON.stringify(args[0]));
405 }*/ 430 }*/
406 } 431 }
472 if (msg instanceof assignment) { 497 if (msg instanceof assignment) {
473 if (msg.expression instanceof lambda) { 498 if (msg.expression instanceof lambda) {
474 obj['tpmeth_' + msg.symbol.name] = msg.expression.eval(env); 499 obj['tpmeth_' + msg.symbol.name] = msg.expression.eval(env);
475 (function(name) { 500 (function(name) {
476 env.syms[name] = function() { 501 env.syms[name] = function() {
477 return obj['tpmeth_' + name].apply(obj, arguments); 502 var ret = obj['tpmeth_' + name].apply(obj, arguments);
503 return ret;
478 }; 504 };
505 env.syms[name].numargs = msg.expression.numArgs();
479 })(msg.symbol.name); 506 })(msg.symbol.name);
480 } else { 507 } else {
481 var makeProp = function(obj, name) { 508 var makeProp = function(obj, name) {
482 obj['tprop_' + name] = msg.expression.eval(env); 509 obj['tprop_' + name] = msg.expression.eval(env);
483 name = 'tpmeth_' + name; 510 obj['tpmeth_' + name] = function() {
484 obj[name] = function() { 511 return this['tprop_'+name];
485 return this[name];
486 }; 512 };
487 var setname = name+'!'; 513 var setname = name+'!';
488 obj[setname] = function(val) { 514 obj['tpmeth_' + setname] = function(val) {
489 this[setname] = val; 515 this['tprop_'+name] = val;
490 return this; 516 return this;
491 }; 517 };
492 }; 518 };
493 makeProp(obj, msg.symbol.name); 519 makeProp(obj, msg.symbol.name);
494 } 520 }
512 if (!obj['tpmeth_' + name]) { 538 if (!obj['tpmeth_' + name]) {
513 obj['tpmeth_' + name] = expr.eval(env); 539 obj['tpmeth_' + name] = expr.eval(env);
514 } 540 }
515 return obj['tpmeth_' + name].apply(obj, arguments); 541 return obj['tpmeth_' + name].apply(obj, arguments);
516 }; 542 };
543 env.syms[name].numargs = expr.numArgs();
517 })(msg.symbol.name, msg.expression); 544 })(msg.symbol.name, msg.expression);
518 outmessages.push(msg); 545 outmessages.push(msg);
519 } else if (msg.expression instanceof funcall && msg.expression.name == 'macro:') { 546 } else if (msg.expression instanceof funcall && msg.expression.name == 'macro:') {
520 env.defMacro(msg.symbol.name, msg.expression.args[0].eval(env)); 547 env.defMacro(msg.symbol.name, msg.expression.args[0].eval(env));
521 } else { 548 } else {
583 while (j < args.length && args[j].cleanName() == 'self') { 610 while (j < args.length && args[j].cleanName() == 'self') {
584 j++; 611 j++;
585 } 612 }
586 env.syms[args[j].cleanName()] = arguments[i]; 613 env.syms[args[j].cleanName()] = arguments[i];
587 } 614 }
588 if (this != null && !(args.length == 0 || args[0].cleanName() != 'self')) { 615 if (this != null) {
589 env.syms['self'] = this; 616 env.syms['self'] = this;
590 } 617 }
591 var res = null; 618 var res = null;
592 for (var i = 0; i < exprs.length; i++) { 619 for (var i = 0; i < exprs.length; i++) {
593 res = exprs[i].eval(env); 620 res = exprs[i].eval(env);
631 expressions.push(this.expressions[i].quote(env)); 658 expressions.push(this.expressions[i].quote(env));
632 } 659 }
633 return new lambda(args, expressions); 660 return new lambda(args, expressions);
634 }; 661 };
635 662
663 lambda.prototype.numArgs = function() {
664 var num = this.args.length;
665 if (num && (this.args[0].cleanName() == 'self')) {
666 --num;
667 }
668 return num;
669 };
670
636 lambda.prototype.tpmeth_nodeType = function() { 671 lambda.prototype.tpmeth_nodeType = function() {
637 return "lambda"; 672 return "lambda";
638 }; 673 };
639 674
640 assignment.prototype.eval = function(env) { 675 assignment.prototype.eval = function(env) {