[chore] Lint-picked versions that pass all unit tests.
This commit is contained in:
parent
111ad5d8dc
commit
abf6c4ec50
|
@ -1,7 +1,11 @@
|
|||
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr} = require "cons-lists/lists"
|
||||
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar,
|
||||
cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr} = require "cons-lists/lists"
|
||||
readline = require "readline"
|
||||
{inspect} = require "util"
|
||||
print = require "../chapter1/print"
|
||||
|
||||
class LispInterpreterError extends Error
|
||||
name: 'LispInterpreterError'
|
||||
constructor: (@message) ->
|
||||
|
||||
env_init = nil
|
||||
env_global = env_init
|
||||
|
@ -19,7 +23,7 @@ defprimitive = (name, nativ, arity) ->
|
|||
if (vmargs.length == arity)
|
||||
callback nativ.apply null, vmargs
|
||||
else
|
||||
throw "Incorrect arity")
|
||||
throw new LispInterpreterError "Incorrect arity")
|
||||
|
||||
the_false_value = (cons "false", "boolean")
|
||||
|
||||
|
@ -50,9 +54,9 @@ extend = (env, variables, values) ->
|
|||
(cons (cons (car variables), (car values)),
|
||||
(extend env, (cdr variables), (cdr values)))
|
||||
else
|
||||
throw "Too few values"
|
||||
throw new LispInterpreterError "Too few values"
|
||||
else if (nilp variables)
|
||||
if (nilp values) then env else throw "Too many values"
|
||||
if (nilp values) then env else throw new LispInterpreterError "Too many values"
|
||||
else
|
||||
if (symbolp variables)
|
||||
(cons (cons variables, values), env)
|
||||
|
@ -87,7 +91,7 @@ evlis = (exps, env, callback) ->
|
|||
callback cons calc, rest
|
||||
else
|
||||
callback nil
|
||||
|
||||
|
||||
lookup = (id, env) ->
|
||||
if (pairp env)
|
||||
if (caar env) == id
|
||||
|
@ -113,12 +117,12 @@ update = (id, env, value, callback) ->
|
|||
|
||||
astSymbolsToLispSymbols = (node) ->
|
||||
return nil if nilp node
|
||||
throw "Not a list of variable names" if not (ntype(node) is 'list')
|
||||
throw (new LispInterpreterError "Not a list of variable names") if not (ntype(node) is 'list')
|
||||
handler = (node) ->
|
||||
return nil if nilp node
|
||||
cons (nvalu car node), (handler cdr node)
|
||||
handler(nvalu node)
|
||||
|
||||
|
||||
|
||||
# Takes an AST node and evaluates it and its contents. A node may be
|
||||
# ("list" (... contents ...)) or ("number" 42) or ("symbol" x), etc.
|
||||
|
@ -157,6 +161,6 @@ evaluate = (e, env, callback) ->
|
|||
evlis (cdr exp), env, (args) ->
|
||||
invoke fn, args, callback
|
||||
else
|
||||
throw new Error("Can't handle a #{type}")
|
||||
throw new LispInterpreterError ("Can't handle a #{type}")
|
||||
|
||||
module.exports = (c, cb) -> evaluate c, env_global, cb
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{car, cdr, cons, listp, nilp, nil, list, pairp, listToString} = require 'cons-lists/lists'
|
||||
{car, cdr, cons, listp, nilp, nil,
|
||||
list, pairp, listToString} = require 'cons-lists/lists'
|
||||
{aSymbol, aValue, astObject} = require './astAccessors'
|
||||
|
||||
# RICH_AST -> LISP_AST
|
||||
|
@ -12,13 +13,13 @@ normalizeForm = (form) ->
|
|||
l = cdr cdr l
|
||||
null
|
||||
o
|
||||
|
||||
|
||||
listToVector1 = (l) ->
|
||||
while(l != nil) then p = normalizeForm(car l); l = cdr l; p
|
||||
|
||||
id = (a) -> a
|
||||
|
||||
methods =
|
||||
methods =
|
||||
'list': normalizeForms
|
||||
'vector': (atom) -> listToVector1(atom)
|
||||
'record': (atom) -> listToRecord1(atom)
|
||||
|
@ -28,7 +29,7 @@ normalizeForm = (form) ->
|
|||
'number': id
|
||||
'string': (atom) -> atom
|
||||
'nil': (atom) -> nil
|
||||
|
||||
|
||||
# Values inherited from the VM.
|
||||
'true': (atom) -> true
|
||||
'false': (atom) -> false
|
||||
|
@ -47,10 +48,8 @@ normalizeForms = (forms) ->
|
|||
if (astObject forms)
|
||||
return normalizeForm(forms)
|
||||
cons(normalizeForm(car forms), normalizeForms(cdr forms))
|
||||
|
||||
|
||||
module.exports =
|
||||
normalizeForm: normalizeForm
|
||||
normalizeForms: normalizeForms
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr} = require "cons-lists/lists"
|
||||
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr,
|
||||
cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr} = require "cons-lists/lists"
|
||||
readline = require "readline"
|
||||
{inspect} = require "util"
|
||||
print = require "./print"
|
||||
|
||||
class LispInterpreterError extends Error
|
||||
name: 'LispInterpreterError'
|
||||
constructor: (@message) ->
|
||||
|
||||
env_init = nil
|
||||
env_global = env_init
|
||||
|
@ -20,7 +23,7 @@ defprimitive = (name, nativ, arity) ->
|
|||
if (vmargs.length == arity)
|
||||
nativ.apply null, vmargs
|
||||
else
|
||||
throw "Incorrect arity")
|
||||
throw (new LispInterpreterError "Incorrect arity"))
|
||||
|
||||
the_false_value = (cons "false", "boolean")
|
||||
|
||||
|
@ -51,9 +54,9 @@ extend = (env, variables, values) ->
|
|||
(cons (cons (car variables), (car values)),
|
||||
(extend env, (cdr variables), (cdr values)))
|
||||
else
|
||||
throw "Too few values"
|
||||
throw new LispInterpreterError "Too few values"
|
||||
else if (nilp variables)
|
||||
if (nilp values) then env else throw "Too many values"
|
||||
if (nilp values) then env else throw new LispInterpreterError "Too many values"
|
||||
else
|
||||
if (symbolp variables)
|
||||
(cons (cons variables, values), env)
|
||||
|
@ -112,7 +115,7 @@ update = (id, env, value) ->
|
|||
|
||||
astSymbolsToLispSymbols = (node) ->
|
||||
return nil if nilp node
|
||||
throw "Not a list of variable names" if not (ntype(node) is 'list')
|
||||
throw (new LispInterpreterError "Not a list of variable names") if not (ntype(node) is 'list')
|
||||
handler = (node) ->
|
||||
return nil if nilp node
|
||||
cons (nvalu car node), (handler cdr node)
|
||||
|
@ -147,6 +150,6 @@ evaluate = (e, env) ->
|
|||
else
|
||||
invoke (evaluate (car exp), env), (evlis (cdr exp), env)
|
||||
else
|
||||
throw new Error("Can't handle a #{type}")
|
||||
throw new LispInterpreterError "Can't handle a #{type}"
|
||||
|
||||
module.exports = (c) -> evaluate c, env_global
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
NEWLINES = ["\n", "\r", "\x0B", "\x0C"]
|
||||
WHITESPACE = [" ", "\t"].concat(NEWLINES)
|
||||
|
||||
EOF = new (class)
|
||||
EOO = new (class)
|
||||
EOF = new (class Eof)()
|
||||
EOO = new (class Eoo)()
|
||||
|
||||
class Source
|
||||
constructor: (@inStream) ->
|
||||
|
@ -29,7 +29,7 @@ class Source
|
|||
done: -> @index > @max
|
||||
|
||||
# IO -> IO
|
||||
skipWS = (inStream) ->
|
||||
skipWS = (inStream) ->
|
||||
while inStream.peek() in WHITESPACE then inStream.next()
|
||||
|
||||
# (type, value, line, column) -> (node {type, value, line, column)}
|
||||
|
@ -88,7 +88,7 @@ readSymbol = (inStream, tableKeys) ->
|
|||
if number?
|
||||
return makeObj 'number', number, line, column
|
||||
makeObj 'symbol', symbol, line, column
|
||||
|
||||
|
||||
|
||||
# (Delim, TypeName) -> IO -> (IO, node) | Error
|
||||
makeReadPair = (delim, type) ->
|
||||
|
@ -143,7 +143,7 @@ readMacros =
|
|||
'[': makeReadPair ']', 'vector'
|
||||
']': handleError "Closing bracket encountered"
|
||||
'{': makeReadPair('}', 'record', (res) ->
|
||||
res.length % 2 == 0 and true or mkerr "record key without value")
|
||||
res.length % 2 == 0 and true or mkerr "record key without value")
|
||||
'}': handleError "Closing curly without corresponding opening."
|
||||
"`": prefixReader 'back-quote'
|
||||
"'": prefixReader 'quote'
|
||||
|
@ -188,19 +188,19 @@ read = (inStream, eofErrorP = false, eofError = EOF, recursiveP = false, inReadM
|
|||
|
||||
# IO -> (Form* | Error)
|
||||
readForms = (inStream) ->
|
||||
inStream = if inStream instanceof Source then inStream else new Source inStream
|
||||
return nil if inStream.done()
|
||||
inStream = if inStream instanceof Source then inStream else new Source inStream
|
||||
return nil if inStream.done()
|
||||
|
||||
# IO -> (FORM*, IO) | Error
|
||||
[line, column] = inStream.position()
|
||||
readEach = (inStream) ->
|
||||
obj = read inStream, true, null, false
|
||||
return nil if (nilp obj)
|
||||
return obj if (car obj) == 'error'
|
||||
cons obj, readEach inStream
|
||||
# IO -> (FORM*, IO) | Error
|
||||
[line, column] = inStream.position()
|
||||
readEach = (inStream) ->
|
||||
obj = read inStream, true, null, false
|
||||
return nil if (nilp obj)
|
||||
return obj if (car obj) == 'error'
|
||||
cons obj, readEach inStream
|
||||
|
||||
obj = readEach inStream
|
||||
if (car obj) == 'error' then obj else makeObj "list", obj, line, column
|
||||
obj = readEach inStream
|
||||
if (car obj) == 'error' then obj else makeObj "list", obj, line, column
|
||||
|
||||
exports.read = read
|
||||
exports.readForms = readForms
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar, cadr, caadr, cadar, caddr, nilp, nil, setcdr, metacadr, setcar} = require "cons-lists/lists"
|
||||
{listToString, listToVector, pairp, cons, car, cdr, caar, cddr, cdar,
|
||||
cadr, caadr, cadar, caddr, nilp, nil, setcdr,
|
||||
metacadr, setcar} = require "cons-lists/lists"
|
||||
readline = require "readline"
|
||||
{inspect} = require "util"
|
||||
|
||||
class LispInterpreterError extends Error
|
||||
name: 'LispInterpreterError'
|
||||
constructor: (@message) ->
|
||||
|
||||
ntype = (node) -> car node
|
||||
nvalu = (node) -> cadr node
|
||||
|
||||
|
@ -12,33 +18,33 @@ class Value
|
|||
# Represents the base class of a continuation. Calls to invoke resume
|
||||
# the contained continuation, which is typecast to one of the specific
|
||||
# continuation needs of conditional, sequence, etc...
|
||||
|
||||
|
||||
class Continuation
|
||||
constructor: (@k) ->
|
||||
invoke: (v, env, kont) ->
|
||||
if nilp cdr v
|
||||
@k.resume (car v)
|
||||
else
|
||||
throw "Continuations expect one argument"
|
||||
throw new LispInterpreterError "Continuations expect one argument"
|
||||
|
||||
# Abstract class representing the environment
|
||||
|
||||
class Environment
|
||||
lookup: -> throw "Nonspecific invocation"
|
||||
update: -> throw "Nonspecific invocation"
|
||||
lookup: -> throw new LispInterpreterError "Nonspecific invocation"
|
||||
update: -> throw new LispInterpreterError "Nonspecific invocation"
|
||||
|
||||
# Base of the environment stack. If you hit this, your variable was
|
||||
# never found for lookup/update. Note that at this time in the
|
||||
# class, you have not
|
||||
# class, you have not
|
||||
|
||||
class NullEnv extends Environment
|
||||
lookup: (e) -> throw "Unknown variable #{e}"
|
||||
update: (e) -> throw "Unknown variable #{e}"
|
||||
lookup: (e) -> throw new LispInterpreterError "Unknown variable #{e}"
|
||||
update: (e) -> throw new LispInterpreterError "Unknown variable #{e}"
|
||||
|
||||
# This appears to be an easy and vaguely abstract handle to the
|
||||
# environment. The book is not clear on the distinction between the
|
||||
# FullEnv and the VariableEnv.
|
||||
|
||||
|
||||
class FullEnv extends Environment
|
||||
constructor: (@others, @name) ->
|
||||
@_type = "FullEnv"
|
||||
|
@ -116,7 +122,7 @@ evaluateVariable = (name, env, kont) ->
|
|||
# called after an update has been performed.
|
||||
|
||||
evaluateSet = (name, exp, env, kont) ->
|
||||
evaluate exp, env, (new SetCont(kont, name, env))
|
||||
evaluate exp, env, (new SetCont(kont, name, env))
|
||||
|
||||
class SetCont extends Continuation
|
||||
constructor: (@k, @name, @env) ->
|
||||
|
@ -149,7 +155,7 @@ extend = (env, names, values) ->
|
|||
if (pairp names) and (pairp values)
|
||||
new VariableEnv (extend env, (cdr names), (cdr values)), (car names), (car values)
|
||||
else if (nilp names)
|
||||
if (nilp values) then env else throw "Arity mismatch"
|
||||
if (nilp values) then env else throw new LispInterpreterError "Arity mismatch"
|
||||
else
|
||||
new VariableEnv env, names, values
|
||||
|
||||
|
@ -195,7 +201,7 @@ class GatherCont extends Continuation
|
|||
@k.resume (cons @v, v)
|
||||
|
||||
# Upon resumption, invoke the function.
|
||||
|
||||
|
||||
class ApplyCont extends Continuation
|
||||
constructor: (@k, @fn, @env) ->
|
||||
@_type = "ApplyCont"
|
||||
|
@ -205,13 +211,13 @@ class ApplyCont extends Continuation
|
|||
|
||||
# A special continuation that represents what we want the interpreter
|
||||
# to do when it's done processing.
|
||||
|
||||
|
||||
class BottomCont extends Continuation
|
||||
constructor: (@k, @f) ->
|
||||
@_type = "BottomCont"
|
||||
resume: (v) ->
|
||||
@f(v)
|
||||
|
||||
|
||||
class Primitive extends Value
|
||||
constructor: (@name, @nativ) ->
|
||||
@_type = "Primitive"
|
||||
|
@ -220,7 +226,7 @@ class Primitive extends Value
|
|||
|
||||
astSymbolsToLispSymbols = (node) ->
|
||||
return nil if nilp node
|
||||
throw "Not a list of variable names" if not (ntype(node) is 'list')
|
||||
throw (new LispInterpreterError "Not a list of variable names") if not (ntype(node) is 'list')
|
||||
handler = (node) ->
|
||||
return nil if nilp node
|
||||
cons (nvalu car node), (handler cdr node)
|
||||
|
@ -245,7 +251,7 @@ evaluate = (e, env, kont) ->
|
|||
else
|
||||
evaluateApplication (car exp), (cdr exp), env, kont
|
||||
else
|
||||
throw new Error("Can't handle a '#{type}'")
|
||||
throw new LispInterpreterError("Can't handle a '#{type}'")
|
||||
|
||||
env_init = new NullEnv()
|
||||
|
||||
|
@ -259,7 +265,7 @@ defprimitive = (name, nativ, arity) ->
|
|||
if (vmargs.length == arity)
|
||||
kont.resume (nativ.apply null, vmargs)
|
||||
else
|
||||
throw "Incorrect arity"
|
||||
throw new LispInterpreterError "Incorrect arity"
|
||||
|
||||
defpredicate = (name, nativ, arity) ->
|
||||
defprimitive name, ((a, b) -> if nativ.call(null, a, b) then true else the_false_value), arity
|
||||
|
@ -294,7 +300,7 @@ definitial "call/cc", new Primitive "call/cc", (values, env, kont) ->
|
|||
if nilp cdr values
|
||||
(car values).invoke (cons kont), env, kont
|
||||
else
|
||||
throw ["Incorrect arity for call/cc", [r, k]]
|
||||
throw new LispInterpreterError "Incorrect arity for call/cc"
|
||||
|
||||
definitial "apply", new Primitive "apply", (values, env, kont) ->
|
||||
if pairp cdr values
|
||||
|
@ -309,5 +315,5 @@ definitial "list", new Primitive "list", (values, env, kont) ->
|
|||
|
||||
interpreter = (ast, kont) ->
|
||||
evaluate ast, env_init, new BottomCont null, kont
|
||||
|
||||
|
||||
module.exports = interpreter
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
chai = require 'chai'
|
||||
chai.should()
|
||||
expect = chai.expect
|
||||
expect = chai.expect
|
||||
|
||||
{cons} = require "cons-lists/lists"
|
||||
olisp = require '../chapter-lambda-1/interpreter'
|
||||
|
@ -27,7 +27,7 @@ describe "Core interpreter #3", ->
|
|||
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", ->
|
||||
expect(lisp read '(begin (+ 5 5))').to.equal(10)
|
||||
expect(lisp read '(begin (* 5 5))').to.equal(25)
|
||||
|
@ -51,4 +51,4 @@ describe "Core interpreter #3", ->
|
|||
|
||||
it "Should handle an IIFE", ->
|
||||
expect(lisp read '(begin ((lambda () (+ 5 5))))').to.equal(10)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
chai = require 'chai'
|
||||
chai.should()
|
||||
expect = chai.expect
|
||||
expect = chai.expect
|
||||
|
||||
{cons} = require "cons-lists/lists"
|
||||
lisp = require '../chapter1/interpreter'
|
||||
|
@ -21,7 +21,7 @@ describe "Core interpreter #1", ->
|
|||
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", ->
|
||||
expect(lisp read '(begin (+ 5 5))').to.equal(10)
|
||||
expect(lisp read '(begin (* 5 5))').to.equal(25)
|
||||
|
@ -45,4 +45,4 @@ describe "Core interpreter #1", ->
|
|||
|
||||
it "Should handle an IIFE", ->
|
||||
expect(lisp read '(begin ((lambda () (+ 5 5))))').to.equal(10)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
chai = require 'chai'
|
||||
chai.should()
|
||||
expect = chai.expect
|
||||
expect = chai.expect
|
||||
|
||||
{cons} = require "cons-lists/lists"
|
||||
olisp = require '../chapter3/interpreter'
|
||||
|
@ -27,7 +27,7 @@ describe "Core interpreter #3", ->
|
|||
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", ->
|
||||
expect(lisp read '(begin (+ 5 5))').to.equal(10)
|
||||
expect(lisp read '(begin (* 5 5))').to.equal(25)
|
||||
|
@ -51,5 +51,5 @@ describe "Core interpreter #3", ->
|
|||
|
||||
it "Should handle an IIFE", ->
|
||||
expect(lisp read '(begin ((lambda () (+ 5 5))))').to.equal(10)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
chai = require 'chai'
|
||||
chai.should()
|
||||
expect = chai.expect
|
||||
expect = chai.expect
|
||||
|
||||
{cons, nil, nilp} = require "cons-lists/lists"
|
||||
{read, readForms} = require '../chapter1/reader'
|
||||
|
|
Loading…
Reference in New Issue