Fixed test pass. Almost have CPS running.

This commit is contained in:
Elf M. Sternberg 2015-06-30 08:05:58 -07:00
parent df6f3f17ae
commit 9d9624632a
6 changed files with 73 additions and 194 deletions

2
.gitignore vendored
View File

@ -10,4 +10,4 @@ bin/_mocha
bin/mocha bin/mocha
bin/coffee bin/coffee
bin/cake bin/cake
./test-reports.xml

View File

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

View File

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

View File

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

View File

@ -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 &#39;1&#39; 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.&lt;anonymous&gt; (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 &#39;1&#39; 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.&lt;anonymous&gt; (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 [ &#39;false&#39;, &#39;boolean&#39;, __list: true ] to equal false">
at Context.&lt;anonymous&gt; (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&#39;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.&lt;anonymous&gt; (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.&lt;anonymous&gt; (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 &#39;1&#39; 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.&lt;anonymous&gt; (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 [ &#39;false&#39;, &#39;boolean&#39;, __list: true ] to equal 120">
Index: string
===================================================================
--- string
+++ string
at Context.&lt;anonymous&gt; (test/test_chapter3.coffee:36:108)
</failure>
</testcase>
<testcase classname="Core interpreter" name="Should handle an IIFE" time="0">
<failure message="Cannot read property &#39;1&#39; 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.&lt;anonymous&gt; (test/test_chapter3.coffee:39:12)
</failure>
</testcase>
</testsuite>
</testsuites>

View File

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