2 Commits

Author SHA1 Message Date
95780bd06c implement method/function call
Some checks failed
CI / test-core (14, ubuntu-latest, 3.x, js) (push) Successful in 48s
CI / test-core (14, ubuntu-latest, 3.x, interp) (push) Successful in 1m2s
CI / test-core (14, ubuntu-latest, 3.x, nodejs) (push) Successful in 57s
CI / test-core (14, ubuntu-latest, 3.x, cpp) (push) Successful in 1m49s
CI / test-core (14, ubuntu-latest, 3.x, py) (push) Failing after 1m19s
2025-09-12 20:51:44 -05:00
269156dd09 implement field access 2025-09-12 20:35:00 -05:00
3 changed files with 70 additions and 5 deletions

View File

@@ -4,6 +4,8 @@
(import kiss.Reader.ReadTable) (import kiss.Reader.ReadTable)
(import kiss.ReaderExp) (import kiss.ReaderExp)
(import kiss.ReaderExp.ReaderExpDef) (import kiss.ReaderExp.ReaderExpDef)
(import kiss.ReaderExp.ReaderExpDef.Symbol)
(import kiss.ReaderExp.ReaderExpDef.FieldExp)
(import kiss.Stream) (import kiss.Stream)
(prop &mut :ReadTable readTable (Reader.builtins)) (prop &mut :ReadTable readTable (Reader.builtins))
@@ -20,7 +22,7 @@
(method :Map<String,(Array<ReaderExp>,Dynamic->Void)->Void> _specialForms [] [ (method :Map<String,(Array<ReaderExp>,Dynamic->Void)->Void> _specialForms [] [
=>"if" =>"if"
->[args cc] ->[args cc]
(evalCC (first ~args) (evalCC (first args)
->val ->val
(if val (if val
(evalCC (second args) cc) (evalCC (second args) cc)
@@ -42,14 +44,46 @@
(throw "Couldn't read valid expression from $s"))) (throw "Couldn't read valid expression from $s")))
([:ReaderExpDef def] ([:ReaderExpDef def]
(case def (case def
// Special form call
((when (specialForms.exists form) (CallExp (object def (Symbol form)) args)) ((when (specialForms.exists form) (CallExp (object def (Symbol form)) args))
((dictGet specialForms form) args cc)) ((dictGet specialForms form) args cc))
// Method/function call
((CallExp callable args)
(evalCC callable ->f
(_evalAllCC args ->values
(case callable
// Method call
((object def (FieldExp field obj safe))
(evalCC obj ->o
(cc (Reflect.callMethod o f values))))
// Function call
(otherwise (cc (Reflect.callMethod null f values)))))))
// Field access
((FieldExp field obj safe)
(evalCC obj ->v
(if v
(cc (Reflect.getProperty v field))
(if safe
(cc null)
(throw "field access on null! $(Reader.toString obj.def)")))))
// Symbol
((Symbol ident) ((Symbol ident)
// Check for numbers // Check for numbers
(let [f (Std.parseFloat ident)] (let [f (Std.parseFloat ident)]
(unless (Math.isNaN f) (unless (Math.isNaN f)
(cc f) (cc f)
(return))) (return)))
// Check for field access
(let [idx (ident.indexOf ".")]
(unless (= -1 idx)
(let [parts (ident.split ".")
&mut exp (object pos null def (Symbol (first parts)))]
(doFor part (parts.slice 1)
(let [safe (StringTools.startsWith part "?")]
(when safe (set part (part.substr 1)))
(set exp (object pos null def (FieldExp part exp safe)))))
(evalCC exp cc)
(return))))
(doFor i (range localScopes.length) (doFor i (range localScopes.length)
(let [scope (nth localScopes (- localScopes.length i 1))] (let [scope (nth localScopes (- localScopes.length i 1))]
(when (scope.exists ident) (when (scope.exists ident)
@@ -57,4 +91,13 @@
(return)))) (return))))
(cc (dictGet globals ident))) (cc (dictGet globals ident)))
(never otherwise))) (never otherwise)))
(otherwise (throw "Can't interpret ${input}")))) (otherwise (throw "Can't interpret ${input}"))))
(method :Void _evalAllCC [:Array<Dynamic> inputs :Array<Dynamic>->Void cc &opt :Array<Dynamic> outputs]
(unless outputs (set outputs []))
(if inputs
(evalCC (inputs.shift) ->v {
(outputs.push v)
(_evalAllCC inputs cc outputs)
})
(cc outputs)))

View File

@@ -19,4 +19,10 @@ class KissInterp2TestCase extends Test {
function testIf() { function testIf() {
_testIf(); _testIf();
} }
function testField() {
_testField();
}
function testCallMethod() {
_testCallMethod();
}
} }

View File

@@ -1,9 +1,25 @@
(defMacro assertEval [expected exp]
`(interp.evalCC ,exp ->v (Assert.equals ,expected v)))
(function _testEvalGlobal [] (function _testEvalGlobal []
(let [interp (new Interp)] (let [interp (new Interp)]
(dictSet interp.globals "a" 5) (dictSet interp.globals "a" 5)
(interp.evalCC "a" ->v (Assert.equals 5 v)))) (assertEval 5 "a")))
(function _testIf [] (function _testIf []
(let [interp (new Interp)] (let [interp (new Interp)]
(interp.evalCC "(if true 5 3)" ->v (Assert.equals 5 v)) (assertEval 5 "(if true 5 3)")
(interp.evalCC "(if false 5 3)" ->v (Assert.equals 3 v)))) (assertEval 3 "(if false 5 3)")))
(function _testField []
(let [interp (new Interp)]
(dictSet interp.globals "obj" (object a 5 b (object c 3)))
(assertEval 5 "obj.a")
(assertEval 3 "obj.b.c")))
(function _testCallMethod []
(let [interp (new Interp)]
(dictSet interp.globals "f" ->[a b] (+ a b))
(dictSet interp.globals "o" (object f ->[a b] (- a b)))
(assertEval 2 "(f -1 3)")
(assertEval 2 "(o.f 5 3)")))