From 4f2bdf0f7f76041c5f6acb6d5cb36d3249a804a5 Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Tue, 11 Nov 2025 18:58:11 -0600 Subject: [PATCH] KissInterp2 lambda/localFunction/function --- src/kiss/KissInterp2.kiss | 60 ++++++++++++++++++++++++- src/test/cases/KissInterp2TestCase.hx | 4 ++ src/test/cases/KissInterp2TestCase.kiss | 4 ++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/kiss/KissInterp2.kiss b/src/kiss/KissInterp2.kiss index 64d3240..1008a50 100644 --- a/src/kiss/KissInterp2.kiss +++ b/src/kiss/KissInterp2.kiss @@ -16,7 +16,7 @@ (prop &mut :Map callAliases (new Map)) (prop :Map globals [=>"false" false =>"true" true =>"null" null]) -(prop :kiss.List> localScopes []) +(prop &mut :kiss.List> localScopes []) (prop :Map,Dynamic->Void)->Void> specialForms) @@ -28,6 +28,47 @@ (let [name (symbolNameValue (first args))] (evalCC (second args) ->val {(dictSet scope name val) (cc val)}))) +(method makeFunction [:Array argExps :Array bodyExps] + (let [capture (localScopes.copy) + argNames [] + &mut hasOpt false + &mut minArgs 0] + (doFor arg argExps + (case arg.def + ((MetaExp "rest" arg) + (throw "KissInterp2 does not support &rest args")) + ((MetaExp "opt" arg) + (set hasOpt true) + (argNames.push (symbolNameValue arg))) + ((Symbol argName) + (argNames.push argName) + (unless hasOpt + ++minArgs)) + (never otherwise))) + (let [f_ (lambda [:Array args] + (let [currentLocals (localScopes.copy) + innerCapture (capture.copy) + // Oof -- everything needs to be synchronous + &mut :Dynamic returnValue null] + (set localScopes innerCapture) + (localScopes.push (new Map)) + (doFor [idx argName] (enumerate argNames) + (dictSet (last localScopes) argName + (if (< idx argNames.length) + (nth args idx) + (if hasOpt + null + (throw "not enough arguments! need $argName"))))) + (evalCC (ReaderExpDef.CallExp (object pos null def (ReaderExpDef.Symbol "begin")) bodyExps) + ->v + { + (set localScopes currentLocals) + (set returnValue v) + }) + returnValue)) + f (Reflect.makeVarArgs f_)] + f))) + (method :Map,Dynamic->Void)->Void> _specialForms [] [ =>"if" ->[args cc] @@ -36,6 +77,7 @@ (if val (evalCC (second args) cc) (evalCC (third args) cc))) + // TODO handle early return =>"begin" ->[args cc] (_evalAllCC args ->values @@ -87,6 +129,22 @@ (evalCC (second args) ->key (cc (container.get key)))) + =>"lambda" + ->[args cc] + (let [argExps (Prelude.argList (first args) "lambda") bodyExps (rest args)] + (cc (makeFunction argExps bodyExps))) + =>"localFunction" + ->[args cc] + (let [name (symbolNameValue (first args)) argExps (Prelude.argList (second args) "lambda") bodyExps (args.slice 2) + func (makeFunction argExps bodyExps)] + (dictSet (last localScopes) name func) + (cc func)) + =>"function" + ->[args cc] + (let [name (symbolNameValue (first args)) argExps (Prelude.argList (second args) "lambda") bodyExps (args.slice 2) + func (makeFunction argExps bodyExps)] + (dictSet globals name func) + (cc func)) ]) (method :ReaderExp read [:Dynamic input] diff --git a/src/test/cases/KissInterp2TestCase.hx b/src/test/cases/KissInterp2TestCase.hx index afb2f13..7b51223 100644 --- a/src/test/cases/KissInterp2TestCase.hx +++ b/src/test/cases/KissInterp2TestCase.hx @@ -37,4 +37,8 @@ class KissInterp2TestCase extends Test { function testNth() { _testNth(); } + function testLambda() { + _testLambda(); + } + } \ No newline at end of file diff --git a/src/test/cases/KissInterp2TestCase.kiss b/src/test/cases/KissInterp2TestCase.kiss index 77756fd..d58d28a 100644 --- a/src/test/cases/KissInterp2TestCase.kiss +++ b/src/test/cases/KissInterp2TestCase.kiss @@ -44,3 +44,7 @@ (let [interp (new Interp)] (assertEval 2 "(nth [1 2 3] 1)") (assertEval 9 #"(dictGet [=>"a" 2 =>"b" 9 =>"c" 3] "b")"#))) + +(function _testLambda [] + (let [interp (new Interp)] + (assertEval 6 "(let [add ->[a b] (+ a b)] (add 2 4))")))