# Jolt Compiler Tests — Phase 2 # Tests for source-to-source Clojure→Janet compilation. # Core ops: const, do, if, def, fn, let, invoke # Phase 2 adds: symbol classification with binding awareness (use ../../src/jolt/compiler) (use ../../src/jolt/reader) (defn compile-str [s] (let [form (parse-string s)] (compile-form form))) # ============================================================ # 1. Literals (const) # ============================================================ (print "1: literal constants...") (assert (= "42" (compile-str "42")) "integer") (assert (= "nil" (compile-str "nil")) "nil") (assert (= "true" (compile-str "true")) "true") (assert (= "false" (compile-str "false")) "false") (assert (= "\"hello\"" (compile-str "\"hello\"")) "string") (assert (= ":foo" (compile-str ":foo")) "keyword") (print " passed") # ============================================================ # 2. do # ============================================================ (print "2: do...") (assert (= "(do 1 2)" (compile-str "(do 1 2)")) "do two exprs") (assert (= "(do 42)" (compile-str "(do 42)")) "do single expr") (assert (= "(do (core-inc 1) (core-inc 2))" (compile-str "(do (inc 1) (inc 2))")) "do with fn calls") (print " passed") # ============================================================ # 3. if # ============================================================ (print "3: if...") (assert (= "(if true 1 2)" (compile-str "(if true 1 2)")) "if three-arg") (assert (= "(if false 1 nil)" (compile-str "(if false 1)")) "if two-arg") (print " passed") # ============================================================ # 4. def # ============================================================ (print "4: def...") (assert (= "(def x 42)" (compile-str "(def x 42)")) "def constant") (assert (= "(def f (fn [x] (core-inc x)))" (compile-str "(def f (fn* [x] (inc x)))")) "def with fn") (print " passed") # ============================================================ # 5. fn # ============================================================ (print "5: fn...") (assert (= "(fn [x] (core-inc x))" (compile-str "(fn* [x] (inc x))")) "fn single arity") (assert (= "(fn [] 42)" (compile-str "(fn* [] 42)")) "fn no args") (assert (= "(fn [x] (do (core-print x) (core-inc x)))" (compile-str "(fn* [x] (print x) (inc x))")) "fn multi-expr body") (print " passed") # ============================================================ # 6. let # ============================================================ (print "6: let...") (assert (= "(let [x 1] (core-inc x))" (compile-str "(let* [x 1] (inc x))")) "let single binding") (assert (= "(let [x 1 y 2] (core-+ x y))" (compile-str "(let* [x 1 y 2] (+ x y))")) "let two bindings") (assert (= "(let [x (core-inc 1)] (core-inc x))" (compile-str "(let* [x (inc 1)] (inc x))")) "let with fn in binding") (print " passed") # ============================================================ # 7. invoke (function calls) # ============================================================ (print "7: invoke...") (assert (= "(core-inc 1)" (compile-str "(inc 1)")) "inc call") (assert (= "(core-+ 1 2)" (compile-str "(+ 1 2)")) "+ call") (assert (= "(core-+ (core-inc 1) 2)" (compile-str "(+ (inc 1) 2)")) "nested calls") (assert (= "(core-map core-inc (core-vec 1 2 3))" (compile-str "(map inc (vec 1 2 3))")) "multi-arg call") (print " passed") # ============================================================ # 8. Local symbol classification (Phase 2) # ============================================================ (print "8: local classification...") # Shadowing: local inc should NOT be rewritten to core-inc (assert (= "(let [inc 5] (inc inc))" (compile-str "(let* [inc 5] (inc inc))")) "local shadows core fn") # fn params are locals, not core symbols (assert (= "(fn [map] (core-vec map))" (compile-str "(fn* [map] (vec map))")) "fn param shadows core map") # nested let with shadowing (assert (= "(let [x 1] (let [inc x] (inc x)))" (compile-str "(let* [x 1] (let* [inc x] (inc x)))")) "nested let local") (print " passed") (print "\nAll compiler Phase 2 tests passed!") # ============================================================ # 9. Compile-and-eval round-trip (Phase 3) # ============================================================ (print "9: compile-and-eval...") (use ../../src/jolt/core) # need core fns in scope for eval (defn compile-eval-str [s] (let [form (parse-string s)] (compile-and-eval form nil))) (assert (= 42 (compile-eval-str "42")) "eval literal") (assert (= 2 (compile-eval-str "(inc 1)")) "eval inc") (assert (= 3 (compile-eval-str "(+ 1 2)")) "eval +") (assert (= 6 (compile-eval-str "(+ (inc 1) (inc 3))")) "eval nested") (assert (= 2 (compile-eval-str "(do 1 2)")) "eval do") (assert (= 1 (compile-eval-str "(if true 1 2)")) "eval if true") (assert (= 2 (compile-eval-str "(if false 1 2)")) "eval if false") (assert (= 2 (compile-eval-str "(let* [x 1] (inc x))")) "eval let") (let [f (compile-eval-str "(fn* [x] (inc x))")] (assert (function? f) "eval fn returns fn") (assert (= 6 (f 5)) "eval fn works")) (print " passed") # ============================================================ # 10. Compile flag in context (Phase 3) # ============================================================ (print "10: compile flag...") (use ../../src/jolt/api) # Without compile flag (let [ctx (init)] (assert (= 2 (eval-string ctx "(inc 1)")) "no-compile flag: inc works")) # With compile flag: pure expressions use compile-and-eval (let [ctx (init {:compile? true})] (assert (= 2 (eval-string ctx "(inc 1)")) "compile flag: inc works") (assert (= 3 (eval-string ctx "(+ 1 2)")) "compile flag: + works") (assert (= 6 (eval-string ctx "(+ (inc 1) (inc 3))")) "compile flag: nested works")) # With compile flag: stateful forms fall back to interpreter (let [ctx (init {:compile? true})] (eval-string ctx "(def foo 99)") (assert (= 99 (eval-string ctx "foo")) "compile flag: def works")) (print " passed") (print "\nAll compiler Phase 3 tests passed!") # ============================================================ # 11. Macro expansion (Phase 4) # ============================================================ (print "11: macro expansion...") (use ../../src/jolt/api) (let [ctx (init {:compile? true})] # defn expands via compiler, produces Janet def (eval-string ctx "(defn square [n] (* n n))") (assert (= 25 (eval-string ctx "(square 5)")) "defn via compiler") # when macro (assert (= 42 (eval-string ctx "(when true 42)")) "when true") (assert (= nil (eval-string ctx "(when false 42)")) "when false") # let macro (assert (= 30 (eval-string ctx "(let [x 10 y 20] (+ x y))")) "let macro") # fn macro (assert (= 49 (eval-string ctx "((fn [x] (* x x)) 7)")) "fn macro") # and/or (assert (= 3 (eval-string ctx "(and 1 2 3)")) "and") (assert (= 99 (eval-string ctx "(or nil false 99)")) "or")) (print " passed") (print "\nAll compiler Phase 4 tests passed!") # ============================================================ # 12. throw, try, loop*/recur (Phase 5) # ============================================================ (print "12: throw/try/loop...") (use ../../src/jolt/api) (let [ctx (init {:compile? true})] # throw/catch via compiler (assert (= "caught" (eval-string ctx "(try (throw 42) (catch Exception e \"caught\"))")) "try/catch") # try without catch returns body (assert (= 1 (eval-string ctx "(try 1 (catch Exception e 2))")) "try no throw") # throw in nested context (assert (= "ok" (eval-string ctx "(try (do (throw 99) 1) (catch Exception e \"ok\"))")) "throw in do") # loop*/recur (assert (= 3 (eval-string ctx "(loop* [x 0] (if (< x 3) (recur (inc x)) x))")) "loop count up") (assert (= 3 (eval-string ctx "(loop* [i 0 acc 0] (if (< i 3) (recur (inc i) (+ acc i)) acc))")) "loop with acc")) (print " passed") (print "\nAll compiler Phase 5 tests passed!") # ============================================================ # 13. defn/def integration (Phase 0 fix) # ============================================================ (print "13: defn/def integration...") (use ../../src/jolt/api) (let [ctx (init {:compile? true})] # defn produces a resolvable var (eval-string ctx "(defn identity-fn [x] x)") (assert (= 1 (eval-string ctx "(identity-fn 1)")) "defn works") (let [f (eval-string ctx "identity-fn")] (assert (function? f) "bare defn symbol returns fn")) # def produces a resolvable var (eval-string ctx "(def answer 42)") (assert (= 42 (eval-string ctx "answer")) "def bare symbol") (assert (= 43 (eval-string ctx "(inc answer)")) "def in call")) (print " passed") (print "\nAll compiler tests passed!") # ============================================================ # 14. Phase 1: ns accessors + ns form extensions # ============================================================ (print "14: ns accessors...") (use ../../src/jolt/api) (let [ctx (init)] (eval-string ctx "(ns mytest.core)") (def ns-list (eval-string ctx "(all-ns)")) (assert (> (length ns-list) 0) "all-ns returns namespaces") # create-ns (eval-string ctx "(create-ns mytest.extra)") (def all (eval-string ctx "(all-ns)")) (assert (> (length all) 1) "create-ns adds namespace")) (print " passed") (print "15: ns form extensions...") (let [ctx (init)] # ns with :require + :refer (eval-string ctx "(ns test.ns-ext (:require [clojure.core :refer [inc +]]))") (assert (= 2 (eval-string ctx "(inc 1)")) "refer inc works")) (print " passed") (print "\nAll Phase 1 tests passed!") # ============================================================ # 17. Phase 3: Var system completion # ============================================================ (print "17: var system...") (use ../../src/jolt/api) (let [ctx (init)] (eval-string ctx "(def x-var-test 42)") (assert (= true (eval-string ctx "(var? (var x-var-test))")) "var?") (eval-string ctx "(def y-var-test 99)") (assert (= 99 (eval-string ctx "(var-get (var y-var-test))")) "var-get") (eval-string ctx "(def z-var-test 10)") (assert (= 20 (eval-string ctx "(do (var-set (var z-var-test) 20) (var-get (var z-var-test)))")) "var-set") (eval-string ctx "(def a-var-test 1)") (assert (= 2 (eval-string ctx "(do (alter-var-root (var a-var-test) inc) (var-get (var a-var-test)))")) "alter-var-root") (eval-string ctx "(def fv-var-test :found)") (assert (= :found (eval-string ctx "(var-get (find-var 'fv-var-test))")) "find-var") (eval-string ctx "(intern (the-ns) 'iv-var-test 77)") (assert (= 77 (eval-string ctx "iv-var-test")) "intern") (eval-string ctx "(def ^:dynamic *dv* 1)") (assert (= 99 (eval-string ctx "(binding [*dv* 99] *dv*)")) "dynamic binding")) (print " passed") # ============================================================ # 18. Phase 3: Var metadata # ============================================================ (print "18: var metadata...") (let [ctx (init)] (eval-string ctx "(def mvar 42)") (eval-string ctx "(alter-meta! (var mvar) assoc :doc \"the answer\")") (assert (= "the answer" (eval-string ctx "(:doc (meta (var mvar)))")) "alter-meta!") (eval-string ctx "(reset-meta! (var mvar) {:a 1})") (assert (= 1 (eval-string ctx "(:a (meta (var mvar)))")) "reset-meta!")) (print " passed") (print "\nAll Phase 3 tests passed!") # ============================================================ # 19. Phase 4: deftype # ============================================================ (print "19: deftype...") (use ../../src/jolt/api) (let [ctx (init)] (eval-string ctx "(deftype Point [x y])") (assert (not (nil? (eval-string ctx "(Point. 3 4)"))) "deftype constructs") (assert (= 3 (eval-string ctx "(. (Point. 3 4) x)")) ".x access") (assert (= 4 (eval-string ctx "(. (Point. 3 4) y)")) ".y access") (assert (= 10 (eval-string ctx "(let [p (Point. 3 4)] (set! (.-x p) 10) (. p x))")) "set! field") (assert (= true (eval-string ctx "(instance? Point (Point. 1 2))")) "instance?") (assert (= false (eval-string ctx "(instance? Point {:x 1})")) "instance? false") (assert (= 5 (eval-string ctx "(. (->Point 5 6) x)")) "arrow factory")) (print " passed") # ============================================================ # 20. Phase 4: defrecord # ============================================================ (print "20: defrecord...") (let [ctx (init)] (eval-string ctx "(defrecord Person [name age])") (assert (not (nil? (eval-string ctx "(Person. \"Alice\" 30)"))) "record constructs") (assert (= true (eval-string ctx "(map? (Person. \"Alice\" 30))")) "record is map?") (assert (= "Alice" (eval-string ctx "(:name (Person. \"Alice\" 30))")) "keyword access") (assert (= 30 (eval-string ctx "(get (Person. \"Alice\" 30) :age)")) "get access") (assert (= "Alice" (eval-string ctx "(. (Person. \"Alice\" 30) name)")) ".name access") (assert (= 30 (eval-string ctx "(. (Person. \"Alice\" 30) age)")) ".age access") (assert (= 2 (eval-string ctx "(count (Person. \"Alice\" 30))")) "count") (assert (= "Bob" (eval-string ctx "(:name (->Person \"Bob\" 25))")) "arrow factory")) (print " passed") # ============================================================ # 21. Phase 4: record equality # ============================================================ (print "21: record equality...") (let [ctx (init)] (eval-string ctx "(defrecord Point3D [x y z])") (assert (= true (eval-string ctx "(= (Point3D. 1 2 3) (Point3D. 1 2 3))")) "same values") (assert (= false (eval-string ctx "(= (Point3D. 1 2 3) (Point3D. 4 5 6))")) "different values")) (print " passed") (print "\nAll Phase 4 tests passed!")