Fixed test pass. Almost have CPS running.
This commit is contained in:
parent
df6f3f17ae
commit
9d9624632a
|
@ -10,4 +10,4 @@ bin/_mocha
|
||||||
bin/mocha
|
bin/mocha
|
||||||
bin/coffee
|
bin/coffee
|
||||||
bin/cake
|
bin/cake
|
||||||
|
./test-reports.xml
|
||||||
|
|
4
Makefile
4
Makefile
|
@ -21,7 +21,9 @@ node_modules: package.json
|
||||||
test: clean node_modules
|
test: clean node_modules
|
||||||
@JUNIT_REPORT_PATH=test-reports.xml JUNIT_REPORT_STACK=1 ./node_modules/.bin/mocha \
|
@JUNIT_REPORT_PATH=test-reports.xml JUNIT_REPORT_STACK=1 ./node_modules/.bin/mocha \
|
||||||
--reporter mocha-jenkins-reporter --compilers coffee:coffee-script/register || true
|
--reporter mocha-jenkins-reporter --compilers coffee:coffee-script/register || true
|
||||||
# @node_modules/.bin/mocha
|
|
||||||
|
ltest: node_modules
|
||||||
|
@node_modules/.bin/mocha --compilers coffee:coffee-script/register
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f report.xml test-reports.xml
|
rm -f report.xml test-reports.xml
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
{car, cdr, cons, nil, nilp, pairp, vectorToList} = require 'cons-lists/lists'
|
{car, cdr, cons, nil, nilp, pairp, vectorToList, list} = require 'cons-lists/lists'
|
||||||
|
{inspect} = require "util"
|
||||||
|
|
||||||
|
|
||||||
NEWLINES = ["\n", "\r", "\x0B", "\x0C"]
|
NEWLINES = ["\n", "\r", "\x0B", "\x0C"]
|
||||||
WHITESPACE = [" ", "\t"].concat(NEWLINES)
|
WHITESPACE = [" ", "\t"].concat(NEWLINES)
|
||||||
|
@ -32,7 +34,7 @@ skipWS = (inStream) ->
|
||||||
|
|
||||||
# (type, value, line, column) -> (node {type, value, line, column)}
|
# (type, value, line, column) -> (node {type, value, line, column)}
|
||||||
makeObj = (type, value, line, column) ->
|
makeObj = (type, value, line, column) ->
|
||||||
cons(type, cons(value, cons(line, cons(column, nil))))
|
list(type, value, line, column)
|
||||||
|
|
||||||
# msg -> (IO -> Node => Error)
|
# msg -> (IO -> Node => Error)
|
||||||
handleError = (message) ->
|
handleError = (message) ->
|
||||||
|
|
|
@ -3,7 +3,6 @@ readline = require "readline"
|
||||||
{inspect} = require "util"
|
{inspect} = require "util"
|
||||||
print = require "../chapter1/print"
|
print = require "../chapter1/print"
|
||||||
|
|
||||||
|
|
||||||
env_init = nil
|
env_init = nil
|
||||||
env_global = env_init
|
env_global = env_init
|
||||||
|
|
||||||
|
@ -15,10 +14,10 @@ definitial = (name, value = nil) ->
|
||||||
name
|
name
|
||||||
|
|
||||||
defprimitive = (name, nativ, arity) ->
|
defprimitive = (name, nativ, arity) ->
|
||||||
definitial name, ((args) ->
|
definitial name, ((args, callback) ->
|
||||||
vmargs = listToVector(args)
|
vmargs = listToVector(args)
|
||||||
if (vmargs.length == arity)
|
if (vmargs.length == arity)
|
||||||
nativ.apply null, vmargs
|
callback nativ.apply null, vmargs
|
||||||
else
|
else
|
||||||
throw "Incorrect arity")
|
throw "Incorrect arity")
|
||||||
|
|
||||||
|
@ -60,43 +59,43 @@ extend = (env, variables, values) ->
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
|
|
||||||
make_function = (variables, body, env, continuation) ->
|
make_function = (variables, body, env, callback) ->
|
||||||
continuation (values, cb) -> eprogn body, (extend env, variables, values), cb
|
callback (values) -> eprogn body, (extend env, variables, values)
|
||||||
|
|
||||||
invoke = (fn, args, cb) ->
|
invoke = (fn, args, callback) ->
|
||||||
fn args, cb
|
fn args, callback
|
||||||
|
|
||||||
# Takes a list of nodes and calls evaluate on each one, returning the
|
# Takes a list of nodes and calls evaluate on each one, returning the
|
||||||
# last one as the value of the total expression. In this example, we
|
# last one as the value of the total expression. In this example, we
|
||||||
# are hard-coding what ought to be a macro, namely the threading
|
# are hard-coding what ought to be a macro, namely the threading
|
||||||
# macros, "->"
|
# macros, "->"
|
||||||
|
|
||||||
eprogn = (exps, env, cb) ->
|
eprogn = (exps, env, callback) ->
|
||||||
if (pairp exps)
|
if (pairp exps)
|
||||||
if pairp (cdr exps)
|
if pairp (cdr exps)
|
||||||
evaluate (car exps), env, (next) ->
|
evaluate (car exps), env, (next) ->
|
||||||
eprogn (cdr exps), env, cb
|
eprogn (cdr exps), env, callback
|
||||||
else
|
else
|
||||||
evaluate (car exps), env, cb
|
evaluate (car exps), env, callback
|
||||||
else
|
else
|
||||||
cb nil
|
callback nil
|
||||||
|
|
||||||
evlis = (exps, env, cb) ->
|
evlis = (exps, env, callback) ->
|
||||||
if (pairp exps)
|
if (pairp exps)
|
||||||
evaluate (car exps), env, (stepv) ->
|
evlis (cdr exps), env, (rest) ->
|
||||||
evlis (cdr exps), env, (next) ->
|
evaluate (car exps), env, (calc) ->
|
||||||
cb cons stepv, next
|
callback cons calc, rest
|
||||||
else
|
else
|
||||||
cb(nil)
|
callback nil
|
||||||
|
|
||||||
lookup = (id, env, continuation) ->
|
lookup = (id, env) ->
|
||||||
if (pairp env)
|
if (pairp env)
|
||||||
if (caar env) == id
|
if (caar env) == id
|
||||||
continuation (cdar env)
|
cdar env
|
||||||
else
|
else
|
||||||
lookup id, (cdr env), continuation
|
lookup id, (cdr env)
|
||||||
else
|
else
|
||||||
continuation nil
|
nil
|
||||||
|
|
||||||
update = (id, env, value, callback) ->
|
update = (id, env, value, callback) ->
|
||||||
if (pairp env)
|
if (pairp env)
|
||||||
|
@ -106,7 +105,7 @@ update = (id, env, value, callback) ->
|
||||||
else
|
else
|
||||||
update id, (cdr env), value, callback
|
update id, (cdr env), value, callback
|
||||||
else
|
else
|
||||||
nil
|
callback nil
|
||||||
|
|
||||||
# This really ought to be the only place where the AST meets the
|
# This really ought to be the only place where the AST meets the
|
||||||
# interpreter core. I can't help but think that this design precludes
|
# interpreter core. I can't help but think that this design precludes
|
||||||
|
@ -126,37 +125,38 @@ astSymbolsToLispSymbols = (node) ->
|
||||||
|
|
||||||
cadddr = metacadr('cadddr')
|
cadddr = metacadr('cadddr')
|
||||||
|
|
||||||
evaluate = (e, env, continuation) ->
|
evaluate = (e, env, callback) ->
|
||||||
[type, exp] = [(ntype e), (nvalu e)]
|
[type, exp] = [(ntype e), (nvalu e)]
|
||||||
if type in ["number", "string", "boolean", "vector"]
|
if type == "symbol"
|
||||||
return continuation exp
|
return callback lookup exp, env
|
||||||
else if type == "symbol"
|
else if type in ["number", "string", "boolean", "vector"]
|
||||||
return lookup exp, env, continuation
|
return callback exp
|
||||||
else if type == "list"
|
else if type == "list"
|
||||||
head = car exp
|
head = car exp
|
||||||
if (ntype head) == 'symbol'
|
if (ntype head) == 'symbol'
|
||||||
switch (nvalu head)
|
return switch (nvalu head)
|
||||||
when "quote" then continuation cdr exp
|
when "quote"
|
||||||
|
callback cdr exp
|
||||||
when "if"
|
when "if"
|
||||||
evaluate (cadr exp), env, (result) ->
|
evaluate (cadr exp), env, (res) ->
|
||||||
unless result == the_false_value
|
w = unless res == the_false_value then caddr else cadddr
|
||||||
evaluate (caddr exp), env, continuation
|
evaluate (w exp), env, callback
|
||||||
else
|
when "begin"
|
||||||
evaluate (cadddr exp), env, continuation
|
eprogn (cdr exp), env, callback
|
||||||
when "begin" then eprogn (cdr exp), env, continuation
|
when "set!"
|
||||||
when "set!" then evaluate (caddr exp), env, (value) ->
|
evaluate (caddr exp), env, (newvalue) ->
|
||||||
update (nvalu cadr exp), env, value, continuation
|
update (nvalu cadr exp), env, newvalue, callback
|
||||||
when "lambda"
|
when "lambda"
|
||||||
make_function (astSymbolsToLispSymbols cadr exp), (cddr exp), env, continuation
|
make_function (astSymbolsToLispSymbols cadr exp), (cddr exp), env, callback
|
||||||
else
|
else
|
||||||
evlis (cdr exp), env, (args) ->
|
|
||||||
evaluate (car exp), env, (fn) ->
|
evaluate (car exp), env, (fn) ->
|
||||||
invoke fn, args, continuation
|
evlis (cdr exp), env, (args) ->
|
||||||
|
invoke fn, args, callback
|
||||||
else
|
else
|
||||||
evlis (cdr exp), env, (args) ->
|
|
||||||
evaluate (car exp), env, (fn) ->
|
evaluate (car exp), env, (fn) ->
|
||||||
invoke fn, args, continuation
|
evlis (cdr exp), env, (args) ->
|
||||||
|
invoke fn, args, callback
|
||||||
else
|
else
|
||||||
throw new Error("Can't handle a #{type}")
|
throw new Error("Can't handle a #{type}")
|
||||||
|
|
||||||
module.exports = (c, continuation) -> evaluate c, env_global, continuation
|
module.exports = (c, cb) -> evaluate c, env_global, cb
|
||||||
|
|
139
test-reports.xml
139
test-reports.xml
|
@ -1,139 +0,0 @@
|
||||||
<testsuites name="Mocha Tests">
|
|
||||||
<testsuite name="Core interpreter" tests="13" failures="2" skipped="0" timestamp="Wed, 17 Jun 2015 22:28:41 GMT" time="0.1">
|
|
||||||
<testcase classname="Core interpreter" name="Should handle true statements" time="0.004"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle false statements" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle return strings" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle return strings when false" time="0"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle equivalent objects that are not intrinsically truthy" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle inequivalent objects that are not intrinsically truthy" time="0"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle basic arithmetic" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle some algebra" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a basic setting" time="0"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a zero arity thunk" time="0.001">
|
|
||||||
<failure message="Cannot read property '1' of undefined">
|
|
||||||
at nvalu (chapter1/interpreter.coffee:11:19)
|
|
||||||
at handler (chapter1/interpreter.coffee:118:11)
|
|
||||||
at astSymbolsToLispSymbols (chapter1/interpreter.coffee:119:3)
|
|
||||||
at evaluate (chapter1/interpreter.coffee:145:43)
|
|
||||||
at evaluate (chapter1/interpreter.coffee:144:57)
|
|
||||||
at eprogn (chapter1/interpreter.coffee:77:7)
|
|
||||||
at evaluate (chapter1/interpreter.coffee:143:27)
|
|
||||||
at module.exports (chapter1/interpreter.coffee:152:25)
|
|
||||||
at Context.<anonymous> (test/test_chapter1.coffee:38:12)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a two arity thunk" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a recursive function" time="0.001"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle an IIFE" time="0">
|
|
||||||
<failure message="Cannot read property '1' of undefined">
|
|
||||||
at nvalu (chapter1/interpreter.coffee:11:19)
|
|
||||||
at handler (chapter1/interpreter.coffee:118:11)
|
|
||||||
at astSymbolsToLispSymbols (chapter1/interpreter.coffee:119:3)
|
|
||||||
at evaluate (chapter1/interpreter.coffee:145:43)
|
|
||||||
at evaluate (chapter1/interpreter.coffee:148:15)
|
|
||||||
at eprogn (chapter1/interpreter.coffee:80:7)
|
|
||||||
at evaluate (chapter1/interpreter.coffee:143:27)
|
|
||||||
at module.exports (chapter1/interpreter.coffee:152:25)
|
|
||||||
at Context.<anonymous> (test/test_chapter1.coffee:47:12)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
</testsuite>
|
|
||||||
<testsuite name="Core interpreter" tests="8" failures="6" skipped="0" timestamp="Wed, 17 Jun 2015 22:28:41 GMT" time="0.103">
|
|
||||||
<testcase classname="Core interpreter" name="Should handle if statements" time="0.003">
|
|
||||||
<failure message="expected [ 'false', 'boolean', __list: true ] to equal false">
|
|
||||||
at Context.<anonymous> (test/test_chapter3.coffee:11:56)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle basic arithmetic" time="0"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle some algebra" time="0">
|
|
||||||
<failure message="Can't handle a e">
|
|
||||||
at evaluate (chapter3/interpreter.coffee:160:15)
|
|
||||||
at eprogn (chapter3/interpreter.coffee:77:7)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:146:27)
|
|
||||||
at module.exports (chapter3/interpreter.coffee:162:39)
|
|
||||||
at Context.<anonymous> (test/test_chapter3.coffee:24:12)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a basic setting" time="0.001">
|
|
||||||
<failure message="continuation is not a function">
|
|
||||||
at lookup (chapter3/interpreter.coffee:95:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at lookup (chapter3/interpreter.coffee:97:7)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:134:12)
|
|
||||||
at eprogn (chapter3/interpreter.coffee:80:7)
|
|
||||||
at chapter3/interpreter.coffee:78:9
|
|
||||||
at update (chapter3/interpreter.coffee:105:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at update (chapter3/interpreter.coffee:107:7)
|
|
||||||
at chapter3/interpreter.coffee:148:11
|
|
||||||
at evaluate (chapter3/interpreter.coffee:132:12)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:147:26)
|
|
||||||
at eprogn (chapter3/interpreter.coffee:77:7)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:146:27)
|
|
||||||
at module.exports (chapter3/interpreter.coffee:162:39)
|
|
||||||
at Context.<anonymous> (test/test_chapter3.coffee:27:12)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a zero arity thunk" time="0.001">
|
|
||||||
<failure message="Cannot read property '1' of undefined">
|
|
||||||
at nvalu (chapter3/interpreter.coffee:11:19)
|
|
||||||
at handler (chapter3/interpreter.coffee:120:11)
|
|
||||||
at astSymbolsToLispSymbols (chapter3/interpreter.coffee:121:3)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:150:26)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:147:26)
|
|
||||||
at eprogn (chapter3/interpreter.coffee:77:7)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:146:27)
|
|
||||||
at module.exports (chapter3/interpreter.coffee:162:39)
|
|
||||||
at Context.<anonymous> (test/test_chapter3.coffee:30:12)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a two arity thunk" time="0"/>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle a recursive function" time="0.001">
|
|
||||||
<failure message="expected [ 'false', 'boolean', __list: true ] to equal 120">
|
|
||||||
Index: string
|
|
||||||
===================================================================
|
|
||||||
--- string
|
|
||||||
+++ string
|
|
||||||
|
|
||||||
at Context.<anonymous> (test/test_chapter3.coffee:36:108)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
<testcase classname="Core interpreter" name="Should handle an IIFE" time="0">
|
|
||||||
<failure message="Cannot read property '1' of undefined">
|
|
||||||
at nvalu (chapter3/interpreter.coffee:11:19)
|
|
||||||
at handler (chapter3/interpreter.coffee:120:11)
|
|
||||||
at astSymbolsToLispSymbols (chapter3/interpreter.coffee:121:3)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:150:26)
|
|
||||||
at chapter3/interpreter.coffee:157:9
|
|
||||||
at evlis (chapter3/interpreter.coffee:90:5)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:156:7)
|
|
||||||
at eprogn (chapter3/interpreter.coffee:80:7)
|
|
||||||
at evaluate (chapter3/interpreter.coffee:146:27)
|
|
||||||
at module.exports (chapter3/interpreter.coffee:162:39)
|
|
||||||
at Context.<anonymous> (test/test_chapter3.coffee:39:12)
|
|
||||||
|
|
||||||
</failure>
|
|
||||||
</testcase>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
|
@ -2,17 +2,31 @@ chai = require 'chai'
|
||||||
chai.should()
|
chai.should()
|
||||||
expect = chai.expect
|
expect = chai.expect
|
||||||
|
|
||||||
lisp = require '../chapter3/interpreter'
|
{cons} = require "cons-lists/lists"
|
||||||
|
olisp = require '../chapter3/interpreter'
|
||||||
{read, readForms} = require '../chapter1/reader'
|
{read, readForms} = require '../chapter1/reader'
|
||||||
|
|
||||||
|
the_false_value = (cons "false", "boolean")
|
||||||
|
|
||||||
|
lisp = (ast) ->
|
||||||
|
ret = undefined
|
||||||
|
olisp ast, (i) -> ret = i
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
describe "Core interpreter #3", ->
|
describe "Core interpreter #3", ->
|
||||||
it "Should handle if statements", ->
|
it "Should handle true statements", ->
|
||||||
expect(lisp read "(begin (if (lt 0 1) #t #f))").to.equal(true)
|
expect(lisp read "(begin (if (lt 0 1) #t #f))").to.equal(true)
|
||||||
expect(lisp read "(begin (if (lt 1 0) #t #f))").to.equal(false)
|
it "Should handle false statements", ->
|
||||||
expect(lisp read '(begin (if (lt 1 0) "y" "n"))').to.equal("n")
|
expect(lisp read "(begin (if (lt 1 0) #t #f))").to.deep.equal(the_false_value)
|
||||||
|
it "Should handle return strings", ->
|
||||||
expect(lisp read '(begin (if (lt 0 1) "y" "n"))').to.equal("y")
|
expect(lisp read '(begin (if (lt 0 1) "y" "n"))').to.equal("y")
|
||||||
expect(lisp read '(begin (if (eq "y" "y") "y" "n"))').to.equal("y")
|
it "Should handle return strings when false", ->
|
||||||
expect(lisp read '(begin (if (eq "y" "x") "y" "n"))').to.equal("n")
|
expect(lisp read '(begin (if (lt 1 0) "y" "n"))').to.equal("n")
|
||||||
|
it "Should handle equivalent objects that are not intrinsically truthy", ->
|
||||||
|
expect(lisp read '(begin (if (eq? "y" "y") "y" "n"))').to.equal("y")
|
||||||
|
it "Should handle inequivalent objects that are not intrinsically truthy", ->
|
||||||
|
expect(lisp read '(begin (if (eq? "y" "x") "y" "n"))').to.equal("n")
|
||||||
|
|
||||||
it "Should handle basic arithmetic", ->
|
it "Should handle basic arithmetic", ->
|
||||||
expect(lisp read '(begin (+ 5 5))').to.equal(10)
|
expect(lisp read '(begin (+ 5 5))').to.equal(10)
|
||||||
|
@ -21,7 +35,7 @@ describe "Core interpreter #3", ->
|
||||||
expect(lisp read '(begin (- 9 5))').to.equal(4)
|
expect(lisp read '(begin (- 9 5))').to.equal(4)
|
||||||
|
|
||||||
it "Should handle some algebra", ->
|
it "Should handle some algebra", ->
|
||||||
expect(lisp read '(begin (* (+ 5 5) (* 2 3))').to.equal(60)
|
expect(lisp read '(begin (* (+ 5 5) (* 2 3)))').to.equal(60)
|
||||||
|
|
||||||
it "Should handle a basic setting", ->
|
it "Should handle a basic setting", ->
|
||||||
expect(lisp read '(begin (set! fact 4) fact)').to.equal(4)
|
expect(lisp read '(begin (set! fact 4) fact)').to.equal(4)
|
||||||
|
|
Loading…
Reference in New Issue