Added a lot of comments to the interpreter, clearing up a confusion in my mind.
This commit is contained in:
parent
40a4d5ca19
commit
74579b9fa0
|
@ -4,17 +4,23 @@ print = require "../chapter1/print"
|
||||||
# Debugging tool.
|
# Debugging tool.
|
||||||
{inspect} = require "util"
|
{inspect} = require "util"
|
||||||
|
|
||||||
|
|
||||||
env_init = nil
|
env_init = nil
|
||||||
env_global = env_init
|
env_global = env_init
|
||||||
|
|
||||||
ntype = (node) -> car node
|
ntype = (node) -> car node
|
||||||
nvalu = (node) -> cadr node
|
nvalu = (node) -> cadr node
|
||||||
|
|
||||||
|
# Takes a name and a value and pushes those onto the global environment.
|
||||||
|
|
||||||
definitial = (name, value = nil) ->
|
definitial = (name, value = nil) ->
|
||||||
env_global = (cons (cons name, value), env_global)
|
env_global = (cons (cons name, value), env_global)
|
||||||
name
|
name
|
||||||
|
|
||||||
|
# Takes a name, a native function, and the expected arity of that
|
||||||
|
# function, and returns the global environment with new a (native)
|
||||||
|
# function perpared to unpack any (interpreter) variable pairs and
|
||||||
|
# apply the (native) function with them.
|
||||||
|
|
||||||
defprimitive = (name, nativ, arity) ->
|
defprimitive = (name, nativ, arity) ->
|
||||||
definitial name, ((args) ->
|
definitial name, ((args) ->
|
||||||
vmargs = listToVector(args)
|
vmargs = listToVector(args)
|
||||||
|
@ -33,12 +39,16 @@ definitial "bar"
|
||||||
definitial "fib"
|
definitial "fib"
|
||||||
definitial "fact"
|
definitial "fact"
|
||||||
|
|
||||||
|
# Wraps a native predicate in function to ensure the interpreter's
|
||||||
|
# notion of falsity is preserved.
|
||||||
|
|
||||||
defpredicate = (name, nativ, arity) ->
|
defpredicate = (name, nativ, arity) ->
|
||||||
defprimitive name, ((a, b) -> if nativ.call(null, a, b) then true else the_false_value), arity
|
defprimitive name, ((a, b) -> if nativ.call(null, a, b) then true else the_false_value), arity
|
||||||
|
|
||||||
defprimitive "cons", cons, 2
|
defprimitive "cons", cons, 2
|
||||||
defprimitive "car", car, 2
|
defprimitive "car", car, 2
|
||||||
defprimitive "set-cdr!", setcdr, 2
|
defprimitive "set-cdr!", setcdr, 2
|
||||||
|
defprimitive "log", ((a) -> console.log a), 1
|
||||||
defprimitive "+", ((a, b) -> a + b), 2
|
defprimitive "+", ((a, b) -> a + b), 2
|
||||||
defprimitive "*", ((a, b) -> a * b), 2
|
defprimitive "*", ((a, b) -> a * b), 2
|
||||||
defprimitive "-", ((a, b) -> a - b), 2
|
defprimitive "-", ((a, b) -> a - b), 2
|
||||||
|
@ -46,6 +56,10 @@ defprimitive "/", ((a, b) -> a / b), 2
|
||||||
defpredicate "lt", ((a, b) -> a < b), 2
|
defpredicate "lt", ((a, b) -> a < b), 2
|
||||||
defpredicate "eq?", ((a, b) -> a == b), 2
|
defpredicate "eq?", ((a, b) -> a == b), 2
|
||||||
|
|
||||||
|
# Takes an environment, a list of names and a list of values, and for
|
||||||
|
# each name and value pair pushes that pair onto the list, adding them
|
||||||
|
# to the environment.
|
||||||
|
|
||||||
extend = (env, variables, values) ->
|
extend = (env, variables, values) ->
|
||||||
if (pairp variables)
|
if (pairp variables)
|
||||||
if (pairp values)
|
if (pairp values)
|
||||||
|
@ -61,16 +75,24 @@ extend = (env, variables, values) ->
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
# Takes a list of variable names, a function body, and an environment
|
||||||
|
# at the time of evaluation, and returns:
|
||||||
|
# a (native) function that takes a list of values, applies them to the
|
||||||
|
# environment, and evaluates the body, returning the resulting value.
|
||||||
|
|
||||||
make_function = (variables, body, env) ->
|
make_function = (variables, body, env) ->
|
||||||
(values) -> eprogn body, (extend env, variables, values)
|
(values) -> eprogn body, (extend env, variables, values)
|
||||||
|
|
||||||
invoke = (fn, args) ->
|
# Evaluates a (native) function with of one arg with the arg provided.
|
||||||
(fn args)
|
# Invoke runs the functions created by make_function, and is unrelated
|
||||||
|
# to the native functions of defprimitive()
|
||||||
|
|
||||||
|
invoke = (fn, arg) -> (fn arg)
|
||||||
|
|
||||||
# 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 macro
|
||||||
# macros, "->"
|
# often named "->"
|
||||||
|
|
||||||
eprogn = (exps, env) ->
|
eprogn = (exps, env) ->
|
||||||
if (pairp exps)
|
if (pairp exps)
|
||||||
|
@ -82,12 +104,17 @@ eprogn = (exps, env) ->
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
# Evaluates a list of expressions and returns a list of resolved
|
||||||
|
# values.
|
||||||
|
|
||||||
evlis = (exps, env) ->
|
evlis = (exps, env) ->
|
||||||
if (pairp exps)
|
if (pairp exps)
|
||||||
(cons (evaluate (car exps), env), (evlis (cdr exps), env))
|
(cons (evaluate (car exps), env), (evlis (cdr exps), env))
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
# Locates a named reference in the environment and returns its value.
|
||||||
|
|
||||||
lookup = (id, env) ->
|
lookup = (id, env) ->
|
||||||
if (pairp env)
|
if (pairp env)
|
||||||
if (caar env) == id
|
if (caar env) == id
|
||||||
|
@ -97,6 +124,9 @@ lookup = (id, env) ->
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
|
|
||||||
|
# Locates a named reference in the environment and replaces its value
|
||||||
|
# with a new value.
|
||||||
|
|
||||||
update = (id, env, value) ->
|
update = (id, env, value) ->
|
||||||
if (pairp env)
|
if (pairp env)
|
||||||
if (caar env) == id
|
if (caar env) == id
|
||||||
|
@ -120,8 +150,9 @@ astSymbolsToLispSymbols = (node) ->
|
||||||
handler(nvalu node)
|
handler(nvalu node)
|
||||||
|
|
||||||
|
|
||||||
# Takes an AST node and evaluates it and its contents. A node may be
|
# Takes an AST node and evaluates it and its contents, returning the
|
||||||
# ("list" (... contents ...)) or ("number" 42) or ("symbol" x), etc.
|
# final value of the calculation. A node may be ("list" (... contents
|
||||||
|
# ...)) or ("number" 42) or ("symbol" x), etc.
|
||||||
|
|
||||||
cadddr = metacadr('cadddr')
|
cadddr = metacadr('cadddr')
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ lisp = require './interpreter.coffee'
|
||||||
{read, readForms} = require '../chapter1/reader'
|
{read, readForms} = require '../chapter1/reader'
|
||||||
{inspect} = require 'util'
|
{inspect} = require 'util'
|
||||||
|
|
||||||
ast = read("(begin (set! fact (lambda (x) (if (eq? x 0) 1 (* x (fact (- x 1)))))) (fact 5))")
|
ast = read("(log (begin (set! fact (lambda (x) (if (eq? x 0) 1 (* x (fact (- x 1)))))) (fact 5)))")
|
||||||
|
|
||||||
# ast = read("(begin (if (lt 4 2) (+ 4 1) (+ 2 1)))")
|
# ast = read("(begin (if (lt 4 2) (+ 4 1) (+ 2 1)))")
|
||||||
# ast = read("(begin (set! fact 4) fact)")
|
# ast = read("(begin (set! fact 4) fact)")
|
||||||
|
@ -11,4 +11,4 @@ ast = read("(begin (set! fact (lambda (x) (if (eq? x 0) 1 (* x (fact (- x 1)))))
|
||||||
# ast = read("(begin (set! fact (lambda (x) (+ x x))) (fact 5))")
|
# ast = read("(begin (set! fact (lambda (x) (+ x x))) (fact 5))")
|
||||||
# ast = read("(begin (set! fact (lambda (x) (- x 4))) (fact 5))")
|
# ast = read("(begin (set! fact (lambda (x) (- x 4))) (fact 5))")
|
||||||
|
|
||||||
console.log "Result:", (lisp ast)
|
(lisp ast)
|
||||||
|
|
Loading…
Reference in New Issue