From 6558843e9be0689e0fbe5099f5ebba3a6b2d387c Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Fri, 3 Apr 2015 20:30:02 -0700 Subject: [PATCH] First pass. Grief. Works with cons cells for tree structure. --- .gitignore | 1 + bin/lisp | 2 +- lib/eval.coffee | 11 ++++++----- lib/fn.coffee | 31 +++++++++++++++++-------------- lib/lisp.coffee | 17 +++++++++++------ lib/parser.coffee | 8 -------- lib/reader.coffee | 7 +++++-- lib/scope.coffee | 44 ++++++++++++++++++++++++-------------------- test/t.scm | 1 - 9 files changed, 65 insertions(+), 57 deletions(-) delete mode 100644 lib/parser.coffee delete mode 100644 test/t.scm diff --git a/.gitignore b/.gitignore index 19cc150..9a389e0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ npm-debug.log node_modules/* lib/lisp_parser.js tmp/ +test/ diff --git a/bin/lisp b/bin/lisp index 1ac1e94..4b5a342 100644 --- a/bin/lisp +++ b/bin/lisp @@ -2,4 +2,4 @@ lisp = require '../lib/lisp' fs = require 'fs' {inspect} = require 'util' -console.log inspect((lisp.run process.argv[2]), true, null, false) +console.log lisp.run process.argv[2] diff --git a/lib/eval.coffee b/lib/eval.coffee index 405a6e4..35bdf14 100644 --- a/lib/eval.coffee +++ b/lib/eval.coffee @@ -1,16 +1,17 @@ lookup = require './lookup' +{car, cdr} = require './lists' lispeval = (element, scope) -> + switch element.type - when 'boolean' then element.value == '#t' when 'number' then parseInt(element.value, 10) when 'symbol' lookup(scope, element.value) when 'list' - proc = lispeval(element.value[0], scope) - args = element.value.slice(1) + proc = lispeval((car element.value), scope) + args = (cdr element.value) proc args, scope - - else throw new Error ("Unrecognized type in parse") + else throw new Error ("Unrecognized type in parse: #{element.type}") module.exports = lispeval + diff --git a/lib/fn.coffee b/lib/fn.coffee index 230d559..b98c7cf 100644 --- a/lib/fn.coffee +++ b/lib/fn.coffee @@ -1,20 +1,23 @@ lispeval = require './eval' -{cons} = require './lists' +{cons, nil, nilp, car, cdr, listToVector} = require './lists' module.exports = - create_expression_evaluator: (defining_scope, params, body) -> - if body instanceof Function - (cells, scope) -> - args = cells.map (i) -> lispeval i, scope - body.apply null, args - else - (cells, scope) -> - args = cells.map (i) -> lispeval i, scope - new_scope = {} - params.forEach (name, i) -> new_scope[name] = args[i] - inner = cons(new_scope, defining_scope) - body.map((i) -> lispeval i, inner).pop() - + create_vm_expression_evaluator: (defining_scope, params, body) -> + (cells, scope) -> + args = listToVector(cells).map (i) -> lispeval i, scope + body.apply null, args + + create_lisp_expression_evaluator: (defining_scope, params, body) -> + (cells, scope) -> + new_scope = (cmap = (cells, params, nscope) -> + return nscope if (nilp cells) or (nilp params) + nscope[(car params)] = lispeval (car cells), scope + cmap((cdr cells), (cdr params), nscope))(cells, params, {}) + inner = cons(new_scope, defining_scope) + (nval = (body, memo) -> + return memo if nilp body + nval((cdr body), lispeval((car body), inner)))(body) + create_special_form_evaluator: (defining_scope, params, body) -> (cells, scope) -> body(cells, scope) diff --git a/lib/lisp.coffee b/lib/lisp.coffee index e041ba1..3123878 100644 --- a/lib/lisp.coffee +++ b/lib/lisp.coffee @@ -1,12 +1,17 @@ fs = require 'fs' -{parse} = require './lisp_parser' -lisp = require './parser' -{scope} = require './scope' -{inspect} = require 'util' +{readForms} = require './reader' +lispeval = require './eval' +scope = require './scope' +{car, cdr, nilp} = require './lists' module.exports = run: (pathname) -> text = fs.readFileSync(pathname, 'utf8') - ast = parse(text) - return lisp(ast, scope) + root = scope + ast = readForms(text) + (nval = (body, memo) -> + return memo if nilp body + nval((cdr body), lispeval((car body), root)))(ast.value) + + diff --git a/lib/parser.coffee b/lib/parser.coffee deleted file mode 100644 index ed527b3..0000000 --- a/lib/parser.coffee +++ /dev/null @@ -1,8 +0,0 @@ -lispeval = require './eval' - -lisp = (ast, scope) -> - ast.map((e) -> lispeval(e, scope)).pop() - -module.exports = lisp - - diff --git a/lib/reader.coffee b/lib/reader.coffee index 3c60dc7..7fc816b 100644 --- a/lib/reader.coffee +++ b/lib/reader.coffee @@ -31,8 +31,11 @@ skipWS = (inStream) -> while inStream.peek() in WHITESPACE then inStream.next() # (type, value, line, column) -> (node {type, value, line, column)} -makeObj = (type, value, line, column) -> - cons type, (cons value, (cons line, (cons column))) +makeObj = (type, value, line, column) -> + 'type': type + 'value': value + 'line': line + 'column': column # msg -> (IO -> Node => Error) handleError = (message) -> diff --git a/lib/scope.coffee b/lib/scope.coffee index 416802e..ed185dc 100644 --- a/lib/scope.coffee +++ b/lib/scope.coffee @@ -1,28 +1,32 @@ -parser = require './parser' lispeval = require './eval' -{cons, car, cdr, nilp} = require './lists' -{create_expression_evaluator, create_special_form_evaluator} = require './fn' -lookup = require './lookup' +{cons, car, cdr, nilp, nil} = require './lists' +{create_lisp_expression_evaluator, create_vm_expression_evaluator, create_special_form_evaluator} = require './fn' scope = cons - '+': create_expression_evaluator scope, [], (a, b) -> a + b - '-': create_expression_evaluator scope, [], (a, b) -> a - b - '*': create_expression_evaluator scope, [], (a, b) -> a * b - '/': create_expression_evaluator scope, [], (a, b) -> a / b - '==': create_expression_evaluator scope, [], (a, b) -> a == b + '+': create_vm_expression_evaluator scope, [], (a, b) -> a + b + '-': create_vm_expression_evaluator scope, [], (a, b) -> a - b + '*': create_vm_expression_evaluator scope, [], (a, b) -> a * b + '/': create_vm_expression_evaluator scope, [], (a, b) -> a / b + '==': create_vm_expression_evaluator scope, [], (a, b) -> a == b + '#t': true + '#f': false - 'define': create_special_form_evaluator scope, [], (list, scope) -> + 'define': create_special_form_evaluator scope, [], (nodes, scope) -> current = (car scope) - current[list[0].value] = lispeval(list[1], scope) + current[(car nodes).value] = lispeval((car cdr nodes), scope) - 'lambda': create_special_form_evaluator scope, [], (list, scope) -> - params = list[0].value.map (n) -> return n.value - create_expression_evaluator(scope, params, list.slice(1)) + 'lambda': create_special_form_evaluator scope, [], (nodes, scope) -> + param_nodes = (car nodes).value + reducer = (l) -> + if (nilp l) then nil else cons((car l).value, reducer(cdr l)) + param_names = reducer(param_nodes) + + create_lisp_expression_evaluator(scope, param_names, (cdr nodes)) - 'if': create_special_form_evaluator scope, [], (list, scope) -> - lispeval(list[if lispeval(list[0], scope) then 1 else 2], scope) + 'if': create_special_form_evaluator scope, [], (nodes, scope) -> + if lispeval((car nodes), scope) + lispeval((car cdr nodes), scope) + else + lispeval((car cdr cdr nodes), scope) - -module.exports = - lookup: lookup - scope: scope +module.exports = scope diff --git a/test/t.scm b/test/t.scm deleted file mode 100644 index 27ba77d..0000000 --- a/test/t.scm +++ /dev/null @@ -1 +0,0 @@ -true