[feat] labeled 'block' and 'return' added! Woot!
This commit is contained in:
parent
07a800cfbf
commit
5e8172d233
|
@ -20,18 +20,21 @@ class Value
|
||||||
# continuation needs of conditional, sequence, etc...
|
# continuation needs of conditional, sequence, etc...
|
||||||
|
|
||||||
class Continuation
|
class Continuation
|
||||||
constructor: (@k) ->
|
constructor: (@kont) ->
|
||||||
invoke: (v, env, kont) ->
|
invoke: (value, env, kont) ->
|
||||||
if nilp cdr v
|
if nilp cdr value
|
||||||
@k.resume (car v)
|
@kont.resume (car value)
|
||||||
else
|
else
|
||||||
throw new LispInterpreterError "Continuations expect one argument"
|
throw new LispInterpreterError "Continuations expect one argument"
|
||||||
|
unwind: (value, ktarget) ->
|
||||||
|
if (@kont == ktarget) then (@kont.resume value) else (@kont.unwind value, ktarget)
|
||||||
|
|
||||||
# Abstract class representing the environment
|
# Abstract class representing the environment
|
||||||
|
|
||||||
class Environment
|
class Environment
|
||||||
lookup: -> throw new LispInterpreterError "Nonspecific invocation"
|
lookup: -> throw new LispInterpreterError "Nonspecific invocation"
|
||||||
update: -> throw new LispInterpreterError "Nonspecific invocation"
|
update: -> throw new LispInterpreterError "Nonspecific invocation"
|
||||||
|
blockLookup: -> throw new LispInterpreterError "Not an Environment"
|
||||||
|
|
||||||
# Base of the environment stack. If you hit this, your variable was
|
# Base of the environment stack. If you hit this, your variable was
|
||||||
# never found for lookup/update. Note that at this time in the
|
# never found for lookup/update. Note that at this time in the
|
||||||
|
@ -40,6 +43,7 @@ class Environment
|
||||||
class NullEnv extends Environment
|
class NullEnv extends Environment
|
||||||
lookup: (e) -> throw new LispInterpreterError "Unknown variable #{e}"
|
lookup: (e) -> throw new LispInterpreterError "Unknown variable #{e}"
|
||||||
update: (e) -> throw new LispInterpreterError "Unknown variable #{e}"
|
update: (e) -> throw new LispInterpreterError "Unknown variable #{e}"
|
||||||
|
blockLookup: (name) -> throw new LispInterpreterError "Unknown block label #{name}"
|
||||||
|
|
||||||
# This appears to be an easy and vaguely abstract handle to the
|
# This appears to be an easy and vaguely abstract handle to the
|
||||||
# environment. The book is not clear on the distinction between the
|
# environment. The book is not clear on the distinction between the
|
||||||
|
@ -52,6 +56,8 @@ class FullEnv extends Environment
|
||||||
@others.lookup name, kont
|
@others.lookup name, kont
|
||||||
update: (name, kont, value) ->
|
update: (name, kont, value) ->
|
||||||
@others.update name, kont, value
|
@others.update name, kont, value
|
||||||
|
blockLookup: (name, kont, value) ->
|
||||||
|
@others.blockLookup(name, kont, value)
|
||||||
|
|
||||||
# This is the classic environment pair; either it's *this*
|
# This is the classic environment pair; either it's *this*
|
||||||
# environment, or it's a parent environment, until you hit the
|
# environment, or it's a parent environment, until you hit the
|
||||||
|
@ -88,10 +94,10 @@ evaluateIf = (exps, env, kont) ->
|
||||||
evaluate (car exps), env, new IfCont(kont, (cadr exps), (caddr exps), env)
|
evaluate (car exps), env, new IfCont(kont, (cadr exps), (caddr exps), env)
|
||||||
|
|
||||||
class IfCont extends Continuation
|
class IfCont extends Continuation
|
||||||
constructor: (@k, @ift, @iff, @env) ->
|
constructor: (@kont, @ift, @iff, @env) ->
|
||||||
@_type = "IfCont"
|
@_type = "IfCont"
|
||||||
resume: (value) ->
|
resume: (value) ->
|
||||||
evaluate (if value == the_false_value then @iff else @ift), @env, @k
|
evaluate (if value == the_false_value then @iff else @ift), @env, @kont
|
||||||
|
|
||||||
# Sequences: evaluates the current expression with a continuation that
|
# Sequences: evaluates the current expression with a continuation that
|
||||||
# represents "the next expression" in the sequence. Upon resumption,
|
# represents "the next expression" in the sequence. Upon resumption,
|
||||||
|
@ -107,9 +113,9 @@ evaluateBegin = (exps, env, kont) ->
|
||||||
kont.resume("Begin empty value")
|
kont.resume("Begin empty value")
|
||||||
|
|
||||||
class BeginCont extends Continuation
|
class BeginCont extends Continuation
|
||||||
constructor: (@k, @exps, @env) ->
|
constructor: (@kont, @exps, @env) ->
|
||||||
@_type = "BeginCont"
|
@_type = "BeginCont"
|
||||||
resume: (v) -> evaluateBegin (cdr @exps), @env, @k
|
resume: (v) -> evaluateBegin (cdr @exps), @env, @kont
|
||||||
|
|
||||||
# In this continuation, we simply pass the continuation and the name
|
# In this continuation, we simply pass the continuation and the name
|
||||||
# to the environment to look up. The environment knows to call the
|
# to the environment to look up. The environment knows to call the
|
||||||
|
@ -125,10 +131,10 @@ 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
|
class SetCont extends Continuation
|
||||||
constructor: (@k, @name, @env) ->
|
constructor: (@kont, @name, @env) ->
|
||||||
@_type = "SetCont"
|
@_type = "SetCont"
|
||||||
resume: (value) ->
|
resume: (value) ->
|
||||||
@env.update @name, @k, value
|
@env.update @name, @kont, value
|
||||||
|
|
||||||
# Calls the current contunation, passing it a new function wrapper.
|
# Calls the current contunation, passing it a new function wrapper.
|
||||||
|
|
||||||
|
@ -171,10 +177,10 @@ evaluateApplication = (exp, exps, env, kont) ->
|
||||||
evaluate exp, env, (new EvFunCont kont, exps, env)
|
evaluate exp, env, (new EvFunCont kont, exps, env)
|
||||||
|
|
||||||
class EvFunCont extends Continuation
|
class EvFunCont extends Continuation
|
||||||
constructor: (@k, @exp, @env) ->
|
constructor: (@kont, @exp, @env) ->
|
||||||
@_type = "EvFunCont"
|
@_type = "EvFunCont"
|
||||||
resume: (f) ->
|
resume: (f) ->
|
||||||
evaluateArguments @exp, @env, (new ApplyCont(@k, f, @env))
|
evaluateArguments @exp, @env, (new ApplyCont(@kont, f, @env))
|
||||||
|
|
||||||
# Evaluate the first list, creating a new list of the arguments. Upon
|
# Evaluate the first list, creating a new list of the arguments. Upon
|
||||||
# completion, resume the continuation with the gather phase
|
# completion, resume the continuation with the gather phase
|
||||||
|
@ -186,37 +192,64 @@ evaluateArguments = (exp, env, kont) ->
|
||||||
kont.resume(nil)
|
kont.resume(nil)
|
||||||
|
|
||||||
class ArgumentCont extends Continuation
|
class ArgumentCont extends Continuation
|
||||||
constructor: (@k, @exp, @env) ->
|
constructor: (@kont, @exp, @env) ->
|
||||||
@_type = "ArgumentCont"
|
@_type = "ArgumentCont"
|
||||||
resume: (v) ->
|
resume: (v) ->
|
||||||
evaluateArguments (cdr @exp), @env, (new GatherCont @k, v)
|
evaluateArguments (cdr @exp), @env, (new GatherCont @kont, v)
|
||||||
|
|
||||||
# Gather the arguments as each ArgumentCont is resumed into a list to
|
# Gather the arguments as each ArgumentCont is resumed into a list to
|
||||||
# be passed to our next step.
|
# be passed to our next step.
|
||||||
|
|
||||||
class GatherCont extends Continuation
|
class GatherCont extends Continuation
|
||||||
constructor: (@k, @v) ->
|
constructor: (@kont, @value) ->
|
||||||
@_type = "GatherCont"
|
@_type = "GatherCont"
|
||||||
resume: (v) ->
|
resume: (value) ->
|
||||||
@k.resume (cons @v, v)
|
@kont.resume (cons @value, value)
|
||||||
|
|
||||||
# Upon resumption, invoke the function.
|
# Upon resumption, invoke the function.
|
||||||
|
|
||||||
class ApplyCont extends Continuation
|
class ApplyCont extends Continuation
|
||||||
constructor: (@k, @fn, @env) ->
|
constructor: (@kont, @fn, @env) ->
|
||||||
@_type = "ApplyCont"
|
@_type = "ApplyCont"
|
||||||
resume: (v) ->
|
resume: (value) ->
|
||||||
console.log
|
@fn.invoke value, @env, @kont
|
||||||
@fn.invoke v, @env, @k
|
|
||||||
|
|
||||||
# A special continuation that represents what we want the interpreter
|
# A special continuation that represents what we want the interpreter
|
||||||
# to do when it's done processing.
|
# to do when it's done processing.
|
||||||
|
|
||||||
class BottomCont extends Continuation
|
class BottomCont extends Continuation
|
||||||
constructor: (@k, @f) ->
|
constructor: (@kont, @func) ->
|
||||||
@_type = "BottomCont"
|
@_type = "BottomCont"
|
||||||
|
resume: (value) ->
|
||||||
|
@func(value)
|
||||||
|
unwind: (value, ktarget) ->
|
||||||
|
throw new LispInterpreterError "Obsolete continuation"
|
||||||
|
|
||||||
|
evaluateBlock = (label, body, env, kont) ->
|
||||||
|
k = new BlockCont(kont, label)
|
||||||
|
evaluateBegin body, (new BlockEnv env, label, kont), k
|
||||||
|
|
||||||
|
class BlockCont extends Continuation
|
||||||
|
constructor: (@kont, @label) ->
|
||||||
|
@_type = "BlockCont"
|
||||||
|
resume: (value) ->
|
||||||
|
@kont.resume value
|
||||||
|
|
||||||
|
class BlockEnv extends FullEnv
|
||||||
|
constructor: (@others, @name, @kont) ->
|
||||||
|
blockLookup: (name, kont, value) ->
|
||||||
|
if (name == @name)
|
||||||
|
kont.unwind value, @kont
|
||||||
|
else
|
||||||
|
@others.blockLookup(name, kont, value)
|
||||||
|
|
||||||
|
evaluateReturnFrom = (label, form, env, kont) ->
|
||||||
|
evaluate form, env, (new ReturnFromCont kont, env, label)
|
||||||
|
|
||||||
|
class ReturnFromCont extends Continuation
|
||||||
|
constructor: (@kont, @env, @label) ->
|
||||||
resume: (v) ->
|
resume: (v) ->
|
||||||
@f(v)
|
@env.blockLookup @label, @kont, v
|
||||||
|
|
||||||
class Primitive extends Value
|
class Primitive extends Value
|
||||||
constructor: (@name, @nativ) ->
|
constructor: (@name, @nativ) ->
|
||||||
|
@ -247,6 +280,11 @@ evaluate = (e, env, kont) ->
|
||||||
when "begin" then evaluateBegin (cdr exp), env, kont
|
when "begin" then evaluateBegin (cdr exp), env, kont
|
||||||
when "set!" then evaluateSet (nvalu cadr exp), (caddr exp), env, kont
|
when "set!" then evaluateSet (nvalu cadr exp), (caddr exp), env, kont
|
||||||
when "lambda" then evaluateLambda (astSymbolsToLispSymbols cadr exp), (cddr exp), env, kont
|
when "lambda" then evaluateLambda (astSymbolsToLispSymbols cadr exp), (cddr exp), env, kont
|
||||||
|
when "block" then evaluateBlock (nvalu cadr exp), (cddr exp), env, kont
|
||||||
|
when "return-from" then evaluateReturnFrom (nvalu cadr exp), (caddr exp), env, kont
|
||||||
|
when "catch" then evaluateCatch (cadr exp), (cddr exp), env, kont
|
||||||
|
when "throw" then evaluateThrow (cadr exp), (caddr exp), env, kont
|
||||||
|
when "unwind-protect" then evaluateUnwindProtect (cadr exp), (cddr exp), env, kont
|
||||||
else evaluateApplication (car exp), (cdr exp), env, kont
|
else evaluateApplication (car exp), (cdr exp), env, kont
|
||||||
else
|
else
|
||||||
evaluateApplication (car exp), (cdr exp), env, kont
|
evaluateApplication (car exp), (cdr exp), env, kont
|
||||||
|
|
Loading…
Reference in New Issue