Reject a malformed catch clause with a clean error in both modes

jolt's catch is (catch class binding body*); the binding (3rd element) must be
a symbol. Neither the analyzer nor the interpreter validated it, so a non-symbol
binding crashed with an internal Janet error (expected integer key for array...)
and, in the interpreter, a malformed clause whose body never threw was silently
swallowed (returned the try value). Clojure rejects a non-class/non-symbol catch
clause; match that with an up-front error in analyze-try and eval-try.

Surfaced building the Chez try/throw emit. Regression rows in exceptions-spec
(runs x3 modes) plus a unit test asserting the clean message in interpret and
compile. jolt-kg6p.
This commit is contained in:
Yogthos 2026-06-17 17:25:14 -04:00
parent ffa122440a
commit d35783bf1b
4 changed files with 67 additions and 1 deletions

View file

@ -435,6 +435,13 @@
(when (and (struct? head) (= :symbol (head :jolt/type)))
(match (head :name)
"catch" (do
# (catch class binding body*) — binding (3rd elem) must
# be a symbol. Validate up front (even when the body
# never throws) so a malformed clause is a clean error,
# not a silent nil or an internal crash when caught.
(let [b (when (>= (length clause) 3) (in clause 2))]
(unless (and b (struct? b) (= :symbol (b :jolt/type)))
(error "Unable to parse catch clause; expected (catch class binding body*)")))
(set catch-sym (in clause 2))
(set catch-body (tuple/slice clause 3)))
"finally" (set finally-body (tuple/slice clause 1)))))))