continue, break in KissInterp2
Some checks failed
CI / test (push) Failing after 53s
CI / test-core (14, ubuntu-latest, 3.x, py) (push) Failing after 1m46s
CI / test-core (14, ubuntu-latest, 3.x, cpp) (push) Failing after 1m43s
CI / test-core (14, ubuntu-latest, 3.x, js) (push) Failing after 2m1s
CI / test-core (14, ubuntu-latest, 3.x, interp) (push) Failing after 2m8s
CI / test-core (14, ubuntu-latest, 3.x, nodejs) (push) Failing after 2m2s
Some checks failed
CI / test (push) Failing after 53s
CI / test-core (14, ubuntu-latest, 3.x, py) (push) Failing after 1m46s
CI / test-core (14, ubuntu-latest, 3.x, cpp) (push) Failing after 1m43s
CI / test-core (14, ubuntu-latest, 3.x, js) (push) Failing after 2m1s
CI / test-core (14, ubuntu-latest, 3.x, interp) (push) Failing after 2m8s
CI / test-core (14, ubuntu-latest, 3.x, nodejs) (push) Failing after 2m2s
This commit is contained in:
@@ -53,4 +53,10 @@ class KissInterp2 {
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
#end
|
||||
#end
|
||||
|
||||
enum ControlFlow {
|
||||
Continue;
|
||||
Break;
|
||||
Return(v:Dynamic);
|
||||
}
|
||||
@@ -60,9 +60,17 @@
|
||||
(localScopes.pop)
|
||||
(cc results)
|
||||
(return))
|
||||
(evalCC (callSymbol "let" (.concat [(listExp [varName (callSymbol "__iter__.next" [])])] body))
|
||||
->v (when collect
|
||||
(results.push v)))
|
||||
(try
|
||||
(handleLet (.concat [(listExp [varName (callSymbol "__iter__.next" [])])] body)
|
||||
->v
|
||||
(when collect
|
||||
(results.push v)) true)
|
||||
(catch [:kiss.KissInterp2.ControlFlow control]
|
||||
(case control
|
||||
(Break (localScopes.pop)
|
||||
(cc results))
|
||||
(Continue 0)
|
||||
(otherwise (throw control)))))
|
||||
(run))
|
||||
(run)))))
|
||||
|
||||
@@ -97,16 +105,56 @@
|
||||
(if hasOpt
|
||||
null
|
||||
(throw "not enough arguments! need $argName")))))
|
||||
(evalCC (callSymbol "begin" bodyExps)
|
||||
->v
|
||||
{
|
||||
(set localScopes currentLocals)
|
||||
(set returnValue v)
|
||||
})
|
||||
(handleBegin bodyExps ->v (set returnValue v) false true)
|
||||
returnValue))
|
||||
f (Reflect.makeVarArgs f_)]
|
||||
f)))
|
||||
|
||||
(method handleBegin [:Array<ReaderExp> args :Dynamic->Void cc &opt :Bool pushScope :Bool handleReturn :Bool handleLoopFlow]
|
||||
(when pushScope (localScopes.push (new Map<String,Dynamic>)))
|
||||
(when handleReturn (dictSet (last localScopes) "return" ->v (throw (kiss.KissInterp2.ControlFlow.Return v))))
|
||||
(when handleLoopFlow
|
||||
(dictSet (last localScopes) "continue" ->[] (throw kiss.KissInterp2.ControlFlow.Continue))
|
||||
(dictSet (last localScopes) "break" ->(throw kiss.KissInterp2.ControlFlow.Break)))
|
||||
(try
|
||||
(_evalAllCC args ->values {
|
||||
(when pushScope (localScopes.pop))
|
||||
(cc (values.pop))
|
||||
})
|
||||
(catch [:kiss.KissInterp2.ControlFlow control]
|
||||
(when pushScope (localScopes.pop)) // Not needed if it's a return, but also not a problem
|
||||
(case control
|
||||
((when handleReturn (Return v))
|
||||
(cc v))
|
||||
(otherwise (throw control))))))
|
||||
|
||||
(method handleLet [:Array<ReaderExp> args :Dynamic->Void cc &opt :Bool forLoop]
|
||||
(let [bindings (first args)
|
||||
bindings (.copy (Prelude.bindingList bindings "let"))
|
||||
body (rest args)
|
||||
scope (new Map<String,Dynamic>)]
|
||||
(localScopes.push scope)
|
||||
|
||||
(withFunctions [
|
||||
(nextVar []
|
||||
(if bindings
|
||||
(let [v (bindings.shift)
|
||||
val (bindings.shift)]
|
||||
(evalCC val ->val
|
||||
(case v.def
|
||||
((Symbol vName)
|
||||
(dictSet scope vName val))
|
||||
((ListExp names)
|
||||
(doFor [i s] (enumerate names)
|
||||
(dictSet scope (symbolNameValue s) (nth val i))))
|
||||
(never otherwise)))
|
||||
(nextVar))
|
||||
(handleBegin body ->result {
|
||||
(localScopes.pop)
|
||||
(cc result)
|
||||
} false false ?forLoop)))
|
||||
] (nextVar))))
|
||||
|
||||
(method :Map<String,(Array<ReaderExp>,Dynamic->Void)->Void> _specialForms [] [
|
||||
=>"if"
|
||||
->[args cc]
|
||||
@@ -115,49 +163,29 @@
|
||||
(if val
|
||||
(evalCC (second args) cc)
|
||||
(evalCC (third args) cc)))
|
||||
// TODO handle early return, loop break/continue
|
||||
// TODO this should make a local scope!
|
||||
=>"begin"
|
||||
->[args cc]
|
||||
(_evalAllCC args ->values
|
||||
(cc (values.pop)))
|
||||
->[args cc] (handleBegin args cc true) // push scope
|
||||
=>"var"
|
||||
(declareInScope globals)
|
||||
=>"localVar"
|
||||
(declareInScope (nth localScopes -1))
|
||||
=>"let"
|
||||
->[args cc]
|
||||
(let [bindings (first args)
|
||||
bindings (.copy (Prelude.bindingList bindings "let"))
|
||||
body (rest args)
|
||||
scope (new Map<String,Dynamic>)]
|
||||
(localScopes.push scope)
|
||||
|
||||
(withFunctions [
|
||||
(nextVar []
|
||||
(if bindings
|
||||
(let [v (bindings.shift)
|
||||
val (bindings.shift)]
|
||||
(evalCC val ->val
|
||||
(case v.def
|
||||
((Symbol vName)
|
||||
(dictSet scope vName val))
|
||||
((ListExp names)
|
||||
(doFor [i s] (enumerate names)
|
||||
(dictSet scope (symbolNameValue s) (nth val i))))
|
||||
(never otherwise)))
|
||||
(nextVar))
|
||||
(evalCC (callSymbol "begin" body) ->result {
|
||||
(localScopes.pop)
|
||||
(cc result)
|
||||
})))
|
||||
] (nextVar)))
|
||||
(handleLet args cc)
|
||||
|
||||
=>"new"
|
||||
->[args cc]
|
||||
// TODO hscript tries to resolve types by name using Type.resolveClass before trying to resolve them with class objects
|
||||
// in the interp variables. That might be nice.
|
||||
(_evalAllCC args ->vals
|
||||
(cc (Type.createInstance (first vals) (rest vals))))
|
||||
// Special case: Types that can't be stored as values and constructed with reflection
|
||||
(case .def (first args)
|
||||
((Symbol "Map")
|
||||
(cc (new Map<String,Dynamic>)))
|
||||
(otherwise
|
||||
// TODO hscript tries to resolve types by name using Type.resolveClass before trying to resolve them with class objects
|
||||
// in the interp variables. That might be nice. Right now they have to be in globals
|
||||
(_evalAllCC args ->vals
|
||||
(cc (Type.createInstance (first vals) (rest vals))))))
|
||||
// TODO nth, dictGet, setNth, dictSet would all be more DRY as functions.
|
||||
// Should they be?
|
||||
=>"nth"
|
||||
->[args cc]
|
||||
(evalCC (first args)
|
||||
@@ -172,6 +200,29 @@
|
||||
(evalCC (second args)
|
||||
->key
|
||||
(cc (.get (cast container Map<String,Dynamic>) key))))
|
||||
=>"setNth"
|
||||
->[args cc]
|
||||
(evalCC (first args)
|
||||
->container
|
||||
(evalCC (second args)
|
||||
->index
|
||||
(evalCC (third args)
|
||||
->value
|
||||
{
|
||||
(setNth container index value)
|
||||
(cc value)
|
||||
})))
|
||||
=>"dictSet"
|
||||
->[args cc]
|
||||
(evalCC (first args)
|
||||
->container
|
||||
(evalCC (second args)
|
||||
->key
|
||||
(evalCC (third args)
|
||||
->value {
|
||||
(.set (cast container Map<String,Dynamic>) key value)
|
||||
(cc value)
|
||||
})))
|
||||
=>"lambda"
|
||||
->[args cc]
|
||||
(let [argExps (Prelude.argList (first args) "lambda") bodyExps (rest args)]
|
||||
@@ -199,7 +250,15 @@
|
||||
(evalCC condition
|
||||
->v
|
||||
(if v
|
||||
(evalCC (callSymbol "begin" body) ->_ (run))
|
||||
(try
|
||||
(handleBegin body ->_ (run) true false true)
|
||||
(catch [:kiss.KissInterp2.ControlFlow control]
|
||||
(case control
|
||||
(Continue
|
||||
(run))
|
||||
(Break
|
||||
(cc null))
|
||||
(otherwise (throw control)))))
|
||||
(cc null))))
|
||||
(run))
|
||||
=>"set"
|
||||
|
||||
@@ -52,5 +52,14 @@ class KissInterp2TestCase extends Test {
|
||||
function testListDestructure() {
|
||||
_testListDestructure();
|
||||
}
|
||||
function testEarlyReturn() {
|
||||
_testEarlyReturn();
|
||||
}
|
||||
function testBreak() {
|
||||
_testBreak();
|
||||
}
|
||||
function testContinue() {
|
||||
_testContinue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -70,3 +70,15 @@
|
||||
(function _testListDestructure []
|
||||
(let [interp (new Interp)]
|
||||
(assertEval [5 6 7] "(let [[a b c] [5 6 7]] [a b c])")))
|
||||
|
||||
(function _testEarlyReturn []
|
||||
(let [interp (new Interp)]
|
||||
(assertEval 5 "(let [f ->{(return 5) 6}] (f))")))
|
||||
|
||||
(function _testBreak []
|
||||
(let [interp (new Interp)]
|
||||
(assertEval [0 1 2 3] "(for i (range 10) (if (< i 4) i (break)))")))
|
||||
|
||||
(function _testContinue []
|
||||
(let [interp (new Interp)]
|
||||
(assertEval [0 2 4 6 8] "(for i (range 10) (if (= 0 (% i 2)) i (continue)))")))
|
||||
|
||||
Reference in New Issue
Block a user