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.ReaderExp)
(import kiss.ReaderExp.ReaderExpDef)
(import kiss.ReaderExp.ReaderExpDef.Symbol)
(import kiss.ReaderExp.ReaderExpDef.FieldExp)
(import kiss.Stream)
(prop &mut :ReadTable readTable (Reader.builtins))
@@ -20,7 +22,7 @@
(method :Map<String,(Array<ReaderExp>,Dynamic->Void)->Void> _specialForms [] [
=>"if"
->[args cc]
(evalCC (first ~args)
(evalCC (first args)
->val
(if val
(evalCC (second args) cc)
@@ -42,14 +44,35 @@
(throw "Couldn't read valid expression from $s")))
([:ReaderExpDef def]
(case def
// Special form call
((when (specialForms.exists form) (CallExp (object def (Symbol form)) args))
((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)
// Check for numbers
(let [f (Std.parseFloat ident)]
(unless (Math.isNaN f)
(cc f)
(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)
(let [scope (nth localScopes (- localScopes.length i 1))]
(when (scope.exists ident)

View File

@@ -19,4 +19,7 @@ class KissInterp2TestCase extends Test {
function 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 []
(let [interp (new Interp)]
(dictSet interp.globals "a" 5)
(interp.evalCC "a" ->v (Assert.equals 5 v))))
(assertEval 5 "a")))
(function _testIf []
(let [interp (new Interp)]
(interp.evalCC "(if true 5 3)" ->v (Assert.equals 5 v))
(interp.evalCC "(if false 5 3)" ->v (Assert.equals 3 v))))
(assertEval 5 "(if true 5 3)")
(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")))