Successful conversion to lists. Yay.
This commit is contained in:
parent
6558843e9b
commit
4089f80770
5
Makefile
5
Makefile
|
@ -1,7 +1,4 @@
|
|||
lib/lisp_parser.js: lib/lisp_parser.peg
|
||||
node_modules/.bin/pegjs $< $@
|
||||
|
||||
tests: lib/lisp_parser.js
|
||||
tests:
|
||||
node_modules/.bin/coffee bin/lisp test.scm
|
||||
|
||||
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
lookup = require './lookup'
|
||||
{car, cdr} = require './lists'
|
||||
{car, cdr, cadr, caadr, cdadr} = require './lists'
|
||||
|
||||
lispeval = (element, scope) ->
|
||||
|
||||
switch element.type
|
||||
when 'number' then parseInt(element.value, 10)
|
||||
when 'symbol'
|
||||
lookup(scope, element.value)
|
||||
switch (car element)
|
||||
when 'number' then parseInt (cadr element), 10
|
||||
when 'symbol' then lookup scope, (cadr element)
|
||||
when 'list'
|
||||
proc = lispeval((car element.value), scope)
|
||||
args = (cdr element.value)
|
||||
proc = lispeval (caadr element), scope
|
||||
args = cdadr element
|
||||
proc args, scope
|
||||
else throw new Error ("Unrecognized type in parse: #{element.type}")
|
||||
else throw new Error ("Unrecognized type in parse: #{(car element)}")
|
||||
|
||||
module.exports = lispeval
|
||||
|
||||
|
|
|
@ -4,19 +4,33 @@ lispeval = require './eval'
|
|||
module.exports =
|
||||
create_vm_expression_evaluator: (defining_scope, params, body) ->
|
||||
(cells, scope) ->
|
||||
args = listToVector(cells).map (i) -> lispeval i, scope
|
||||
args = (amap = (cells, accum) ->
|
||||
return accum if nilp cells
|
||||
amap((cdr cells), accum.concat(lispeval (car cells), scope)))(cells, [])
|
||||
body.apply null, args
|
||||
|
||||
create_lisp_expression_evaluator: (defining_scope, params, body) ->
|
||||
(cells, scope) ->
|
||||
|
||||
# Takes the current scope, which has been passed in during the
|
||||
# execution phase, and evaluate the contents of the parameters
|
||||
# in the context in which this call is made (i.e. when the
|
||||
# function is *called*, rather than defined.
|
||||
|
||||
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)
|
||||
|
||||
# Execute and evaluate the body, creating an inner scope that
|
||||
# consists of all the bound variables (the parameters) evaluated
|
||||
# in the context of the function call, and all of free variables
|
||||
# evaluated in the context of the defining scope.
|
||||
|
||||
inner_scope = cons(new_scope, defining_scope)
|
||||
(nval = (body, memo) ->
|
||||
return memo if nilp body
|
||||
nval((cdr body), lispeval((car body), inner)))(body)
|
||||
nval((cdr body), lispeval((car body), inner_scope)))(body)
|
||||
|
||||
create_special_form_evaluator: (defining_scope, params, body) ->
|
||||
(cells, scope) -> body(cells, scope)
|
||||
|
|
|
@ -2,16 +2,15 @@ fs = require 'fs'
|
|||
{readForms} = require './reader'
|
||||
lispeval = require './eval'
|
||||
scope = require './scope'
|
||||
{car, cdr, nilp} = require './lists'
|
||||
{car, cdr, nilp, cadr} = require './lists'
|
||||
|
||||
module.exports =
|
||||
run: (pathname) ->
|
||||
text = fs.readFileSync(pathname, 'utf8')
|
||||
root = scope
|
||||
ast = readForms(text)
|
||||
(nval = (body, memo) ->
|
||||
return memo if nilp body
|
||||
nval((cdr body), lispeval((car body), root)))(ast.value)
|
||||
nval((cdr body), lispeval((car body), scope)))(cadr ast)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
lisp
|
||||
= cell*
|
||||
|
||||
cell
|
||||
= _* datum:datum _*
|
||||
{ return datum }
|
||||
|
||||
datum
|
||||
= list / boolean / number / symbol
|
||||
|
||||
list
|
||||
= "(" items:cell* ")"
|
||||
{ return { type: "list", value: items } }
|
||||
|
||||
boolean
|
||||
= b:("#t" / "#f")
|
||||
{ return { type: 'boolean', value: b } }
|
||||
|
||||
delim
|
||||
= paren / _
|
||||
|
||||
number
|
||||
= b:( [0-9]+ )
|
||||
{ return { type: 'number', value: b.join("") } }
|
||||
|
||||
symbol
|
||||
= b:(!delim c:. { return c })+
|
||||
{ return { type: 'symbol', value: b.join("") } }
|
||||
|
||||
paren
|
||||
= "(" / ")"
|
||||
|
||||
_
|
||||
= w:[ \t\n\r]+
|
|
@ -1,6 +1,8 @@
|
|||
vectorp = (a) -> toString.call(a) == '[object Array]'
|
||||
|
||||
listp = (a) -> vectorp(a) and a.__list == true
|
||||
pairp = (a) -> vectorp(a) and a.__list == true
|
||||
|
||||
listp = (a) -> (pairp a) and (pairp cdr a)
|
||||
|
||||
recordp = (a) -> Object.prototype.toString.call(a) == '[object Object]'
|
||||
|
||||
|
@ -16,7 +18,7 @@ car = (a) -> a[0]
|
|||
|
||||
cdr = (a) -> a[1]
|
||||
|
||||
nilp = (a) -> listp(a) and a.length == 0
|
||||
nilp = (a) -> pairp(a) and a.length == 0
|
||||
|
||||
vectorToList = (v, p) ->
|
||||
p = if p? then p else 0
|
||||
|
@ -25,14 +27,17 @@ vectorToList = (v, p) ->
|
|||
# have to be intercepted first. The use of duck-typing here is
|
||||
# frustrating, but I suppose the eventual runtime will be doing
|
||||
# something like this anyway for base types.
|
||||
item = if listp(v[p]) then v[p] else if vectorp(v[p]) then vectorToList(v[p]) else v[p]
|
||||
item = if pairp(v[p]) then v[p] else if vectorp(v[p]) then vectorToList(v[p]) else v[p]
|
||||
cons(item, vectorToList(v, p + 1))
|
||||
|
||||
list = (v...) -> vectorToList v
|
||||
list = (v...) ->
|
||||
ln = v.length;
|
||||
(nl = (a) ->
|
||||
cons(v[a], if (a < ln) then (nl(a + 1)) else nil))(0)
|
||||
|
||||
listToVector = (l, v = []) ->
|
||||
return v if nilp l
|
||||
v.push if listp (car l) then listToVector(car l) else (car l)
|
||||
v.push if pairp (car l) then listToVector(car l) else (car l)
|
||||
listToVector (cdr l), v
|
||||
|
||||
# This is the simplified version. It can't be used stock with reader,
|
||||
|
@ -41,7 +46,7 @@ listToVector = (l, v = []) ->
|
|||
|
||||
listToString = (l) ->
|
||||
return "" if nilp l
|
||||
if listp (car l)
|
||||
if pairp (car l)
|
||||
"(" + (listToString(car l)).replace(/\ *$/, "") + ") " + listToString(cdr l)
|
||||
else
|
||||
p = if typeof (car l) == 'string' then '"' else ''
|
||||
|
@ -54,7 +59,7 @@ module.exports =
|
|||
cdr: cdr
|
||||
list: list
|
||||
nilp: nilp
|
||||
listp: listp
|
||||
pairp: pairp
|
||||
vectorp: vectorp
|
||||
recordp: recordp
|
||||
vectorToList: vectorToList
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{car, cdr, cons, nil, nilp, listp} = require './lists'
|
||||
{car, cdr, cons, nil, nilp, pairp, vectorToList} = require './lists'
|
||||
|
||||
NEWLINES = ["\n", "\r", "\x0B", "\x0C"]
|
||||
WHITESPACE = [" ", "\t"].concat(NEWLINES)
|
||||
|
@ -32,10 +32,7 @@ skipWS = (inStream) ->
|
|||
|
||||
# (type, value, line, column) -> (node {type, value, line, column)}
|
||||
makeObj = (type, value, line, column) ->
|
||||
'type': type
|
||||
'value': value
|
||||
'line': line
|
||||
'column': column
|
||||
vectorToList([type, value, line, column])
|
||||
|
||||
# msg -> (IO -> Node => Error)
|
||||
handleError = (message) ->
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{car, cdr, cons, listp, nilp, nil, list, listToString} = require './lists'
|
||||
{car, cdr, cons, pairp, nilp, nil, list, listToString} = require './lists'
|
||||
|
||||
reduce = (lst, iteratee, memo, context) ->
|
||||
count = 0
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
lispeval = require './eval'
|
||||
{cons, car, cdr, nilp, nil} = require './lists'
|
||||
{cons, car, cdr, nilp, nil, cadar, cadr, caddr} = require './lists'
|
||||
{create_lisp_expression_evaluator, create_vm_expression_evaluator, create_special_form_evaluator} = require './fn'
|
||||
|
||||
scope = cons
|
||||
|
@ -13,20 +13,19 @@ scope = cons
|
|||
|
||||
'define': create_special_form_evaluator scope, [], (nodes, scope) ->
|
||||
current = (car scope)
|
||||
current[(car nodes).value] = lispeval((car cdr nodes), scope)
|
||||
current[(cadar nodes)] = lispeval((cadr nodes), scope)
|
||||
|
||||
'lambda': create_special_form_evaluator scope, [], (nodes, scope) ->
|
||||
param_nodes = (car nodes).value
|
||||
param_nodes = cadar nodes
|
||||
reducer = (l) ->
|
||||
if (nilp l) then nil else cons((car l).value, reducer(cdr l))
|
||||
if (nilp l) then nil else cons (cadar l), reducer(cdr l)
|
||||
param_names = reducer(param_nodes)
|
||||
|
||||
create_lisp_expression_evaluator(scope, param_names, (cdr nodes))
|
||||
create_lisp_expression_evaluator scope, param_names, (cdr nodes)
|
||||
|
||||
'if': create_special_form_evaluator scope, [], (nodes, scope) ->
|
||||
if lispeval((car nodes), scope)
|
||||
lispeval((car cdr nodes), scope)
|
||||
if lispeval (car nodes), scope
|
||||
lispeval (cadr nodes), scope
|
||||
else
|
||||
lispeval((car cdr cdr nodes), scope)
|
||||
lispeval (caddr nodes), scope
|
||||
|
||||
module.exports = scope
|
||||
|
|
Loading…
Reference in New Issue