Mercurial > repos > tabletprog
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) { |