implement field access

This commit is contained in:
2025-09-12 20:27:32 -05:00
parent 4670a8bd4e
commit 269156dd09
3 changed files with 39 additions and 4 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,35 @@
(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))
// 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)

View File

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

View File

@@ -1,9 +1,18 @@
(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")))