Successful conversion to lists. Yay.

This commit is contained in:
Elf M. Sternberg 2015-04-04 16:26:51 -07:00
parent 6558843e9b
commit 4089f80770
9 changed files with 50 additions and 74 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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]+

View File

@ -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

View File

@ -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) ->

View File

@ -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

View File

@ -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