spec/ now contains only the language definition (5 files): evaluator.sx, parser.sx, primitives.sx, render.sx, special-forms.sx lib/ contains code written IN the language (8 files): stdlib.sx, types.sx, freeze.sx, content.sx, bytecode.sx, compiler.sx, vm.sx, callcc.sx Test files follow source: spec/tests/ for core language tests, lib/tests/ for library tests (continuations, freeze, types, vm). Updated all consumers: - JS/Python/OCaml bootstrappers: added lib/ to source search paths - OCaml bridge: spec_dir for parser/render, lib_dir for compiler/freeze - JS test runner: scans spec/tests/ (always) + lib/tests/ (--full) - OCaml test runner: scans spec/tests/, lib tests via explicit request - Docker dev mounts: added ./lib:/app/lib:ro Tests: 1041 JS standard, 1322 JS full, 1101 OCaml — all pass Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
118 lines
4.9 KiB
Plaintext
118 lines
4.9 KiB
Plaintext
;; vm-inline.sx — Tests for inline VM opcodes (OP_ADD, OP_EQ, etc.)
|
|
;;
|
|
;; These verify that the JIT-compiled inline opcodes produce
|
|
;; identical results to the CALL_PRIM fallback.
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Arithmetic
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(test "inline + integers" (= (+ 3 4) 7))
|
|
(test "inline + floats" (= (+ 1.5 2.5) 4.0))
|
|
(test "inline + string concat" (= (+ "hello" " world") "hello world"))
|
|
(test "inline - integers" (= (- 10 3) 7))
|
|
(test "inline - negative" (= (- 3 10) -7))
|
|
(test "inline * integers" (= (* 6 7) 42))
|
|
(test "inline * float" (= (* 2.5 4.0) 10.0))
|
|
(test "inline / integers" (= (/ 10 2) 5))
|
|
(test "inline / float" (= (/ 7.0 2.0) 3.5))
|
|
(test "inline inc" (= (inc 5) 6))
|
|
(test "inline dec" (= (dec 5) 4))
|
|
(test "inline inc float" (= (inc 2.5) 3.5))
|
|
(test "inline dec zero" (= (dec 0) -1))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Comparison
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(test "inline = numbers" (= 5 5))
|
|
(test "inline = strings" (= "hello" "hello"))
|
|
(test "inline = false" (not (= 5 6)))
|
|
(test "inline = nil" (= nil nil))
|
|
(test "inline = mixed false" (not (= 5 "5")))
|
|
(test "inline < numbers" (< 3 5))
|
|
(test "inline < false" (not (< 5 3)))
|
|
(test "inline < equal" (not (< 5 5)))
|
|
(test "inline < strings" (< "abc" "def"))
|
|
(test "inline > numbers" (> 5 3))
|
|
(test "inline > false" (not (> 3 5)))
|
|
(test "inline > equal" (not (> 5 5)))
|
|
(test "inline not true" (= (not true) false))
|
|
(test "inline not false" (= (not false) true))
|
|
(test "inline not nil" (= (not nil) true))
|
|
(test "inline not number" (= (not 0) true))
|
|
(test "inline not string" (= (not "") true))
|
|
(test "inline not nonempty" (= (not "x") false))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Collection ops
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(test "inline len list" (= (len (list 1 2 3)) 3))
|
|
(test "inline len string" (= (len "hello") 5))
|
|
(test "inline len empty" (= (len (list)) 0))
|
|
(test "inline len nil" (= (len nil) 0))
|
|
(test "inline first" (= (first (list 10 20 30)) 10))
|
|
(test "inline first empty" (= (first (list)) nil))
|
|
(test "inline rest" (= (rest (list 1 2 3)) (list 2 3)))
|
|
(test "inline rest single" (= (rest (list 1)) (list)))
|
|
(test "inline nth" (= (nth (list 10 20 30) 1) 20))
|
|
(test "inline nth zero" (= (nth (list 10 20 30) 0) 10))
|
|
(test "inline nth out of bounds" (= (nth (list 1 2) 5) nil))
|
|
(test "inline cons" (= (cons 1 (list 2 3)) (list 1 2 3)))
|
|
(test "inline cons to empty" (= (cons 1 (list)) (list 1)))
|
|
(test "inline cons to nil" (= (cons 1 nil) (list 1)))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Composition — inline ops in expressions
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(test "nested arithmetic" (= (+ (* 3 4) (- 10 5)) 17))
|
|
(test "comparison in if" (if (< 3 5) "yes" "no") (= "yes"))
|
|
(test "len in condition" (if (> (len (list 1 2 3)) 2) true false))
|
|
(test "inc in loop" (= (let ((x 0)) (for-each (fn (_) (set! x (inc x))) (list 1 2 3)) x) 3))
|
|
(test "first + rest roundtrip" (= (cons (first (list 1 2 3)) (rest (list 1 2 3))) (list 1 2 3)))
|
|
(test "nested comparison" (= (and (< 1 2) (> 3 0) (= 5 5)) true))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Edge cases
|
|
;; --------------------------------------------------------------------------
|
|
|
|
(test "+ with nil" (= (+ 5 nil) 5))
|
|
(test "len of dict" (= (len {:a 1 :b 2}) 2))
|
|
(test "= with booleans" (= (= true true) true))
|
|
(test "= with keywords" (= (= :foo :foo) true))
|
|
(test "not with list" (= (not (list 1)) false))
|
|
|
|
;; --------------------------------------------------------------------------
|
|
;; Recursive mutation — VM closure capture must preserve mutable state
|
|
;; --------------------------------------------------------------------------
|
|
;;
|
|
;; Regression: recursive functions that append! to a shared mutable list
|
|
;; lost mutations after the first call under JIT. The VM closure capture
|
|
;; was copying the list value instead of sharing the mutable reference.
|
|
|
|
(test "recursive append! to shared list"
|
|
(let ((walk (fn (items result)
|
|
(when (not (empty? items))
|
|
(append! result (first items))
|
|
(walk (rest items) result)))))
|
|
(let ((result (list)))
|
|
(walk (list "a" "b" "c") result)
|
|
(= (len result) 3))))
|
|
|
|
(test "recursive tree walk with append!"
|
|
(let ((walk (fn (expr result)
|
|
(cond
|
|
(not (list? expr))
|
|
(append! result "leaf")
|
|
(empty? expr) nil
|
|
:else
|
|
(do (append! result "open")
|
|
(for-each (fn (c) (walk c result)) (rest expr))
|
|
(append! result "close"))))))
|
|
(let ((tree (first (sx-parse "(div \"a\" (span \"b\") \"c\")")))
|
|
(result (list)))
|
|
(walk tree result)
|
|
(= (len result) 7))))
|