Evaluate non-array ISeq forms (cons/concat/lazy-seq) as calls (jolt-2rx)

eval-form treated only a reader LIST (a Janet array) as a call; a runtime-built
list — a plist or lazy-seq from cons/concat/list or ~@ (list?/seq? true but
array? false) — fell through to self-eval. So (eval (cons '+ '(1 2))) returned
the list as data instead of 3, and a macro whose output contained such a subform
left it unevaluated. Add a plist?/lazy-seq? branch that coerces to the element
array via d-realize and dispatches through eval-list; an empty list self-evals.

The analyzer already punts these forms to the interpreter (analyze's :else ->
uncompilable -> interpreter fallback), so this one interpreter branch fixes the
correctness bug across the eval and macro-expansion paths; compiling them
directly (vs punting) would be a separate perf change. Verified: conformance
355/355, syntax-quote ~@ splice, list values unchanged.
This commit is contained in:
Yogthos 2026-06-15 10:27:34 -04:00
parent a2c4fe317b
commit 80aae55977
2 changed files with 27 additions and 0 deletions

View file

@ -98,4 +98,12 @@
(if (= 0 (length form))
@[]
(eval-list ctx bindings form))
# A non-array ISeq used as a form is a CALL too (jolt-2rx): cons/concat/list
# and ~@ build a plist or lazy-seq (list?/seq? true, array? false) — without
# this they fell through to self-eval, so (eval (cons '+ '(1 2))) returned the
# list as data instead of 3, and macro output containing such subforms never
# evaluated. d-realize coerces to the element array; an empty list self-evals.
(or (plist? form) (lazy-seq? form))
(let [arr (d-realize form)]
(if (= 0 (length arr)) form (eval-list ctx bindings arr)))
form)))