Phase 7A: add try-catch codegen + 8 tests
ober
57995702ac2529f511160800ca6eb131b6f2449b
--- a/lib/jerboa/wasm/codegen.sls +++ b/lib/jerboa/wasm/codegen.sls @@ -1113,6 +1113,29 @@ (bv-concat-list (map (lambda (a) (compile-expr a ctx)) (cdr args))) (bytevector wasm-opcode-throw) (encode-u32-leb128 (car args)))] + ;; (try-catch tag-idx body catch-var handler) + ;; Emits legacy exceptions try/catch: evaluates body; if an exception + ;; with tag-idx is thrown, binds the first payload value to catch-var + ;; and evaluates handler. Both branches must produce an i32 result. + [(try-catch) + (let* ([tag-idx (car args)] + [body (cadr args)] + [cvar (caddr args)] + [handler (cadddr args)] + ;; Allocate a local for the caught value + [cvar-idx (context-add-local! ctx cvar)]) + (bv-concat + ;; try block returning i32 + (bytevector wasm-opcode-try wasm-type-i32) + (compile-expr body ctx) + ;; catch: pops the payload (first i32) into local cvar + (bytevector wasm-opcode-catch) + (encode-u32-leb128 tag-idx) + (bytevector wasm-opcode-local-set) + (encode-u32-leb128 cvar-idx) + (compile-expr handler ctx) + (bytevector wasm-opcode-end)))] + ;; -- GC: struct operations -- ;; (struct.new type-idx field-exprs...) [(struct.new) --- a/tests/test-slang-wasm.ss +++ b/tests/test-slang-wasm.ss @@ -710,6 +710,88 @@ (check-pred bytevector? wasm) (check (> (bytevector-length wasm) 30) => #t)) +;; Helper: check whether a bytevector contains a given byte value +(define (bv-contains? bv byte) + (let loop ([i 0]) + (cond + [(>= i (bytevector-length bv)) #f] + [(= (bytevector-u8-ref bv i) byte) #t] + [else (loop (+ i 1))]))) + +;; try-catch compiles to a valid WASM bytevector +(let ([wasm (compile-program + (append + value-memory-forms + value-global-forms + value-tag-forms + '((define-tag 0) + (define (safe-add a b) + (try-catch 0 + (if (= b 0) (throw 0 0) (+ a b)) + exn + -1)))))]) + (check-pred bytevector? wasm) + (check (> (bytevector-length wasm) 30) => #t)) + +;; try-catch binary contains the try opcode (#x06) +(let ([wasm (compile-program + (append + value-memory-forms + value-global-forms + value-tag-forms + '((define-tag 0) + (define (safe-add a b) + (try-catch 0 + (if (= b 0) (throw 0 0) (+ a b)) + exn + -1)))))]) + (check (bv-contains? wasm #x06) => #t)) + +;; try-catch binary contains the catch opcode (#x07) +(let ([wasm (compile-program + (append + value-memory-forms + value-global-forms + value-tag-forms + '((define-tag 0) + (define (safe-add a b) + (try-catch 0 + (if (= b 0) (throw 0 0) (+ a b)) + exn + -1)))))]) + (check (bv-contains? wasm #x07) => #t)) + +;; try-catch with constant handler compiles (minimal form) +(let ([wasm (compile-program + (append + value-memory-forms + value-global-forms + value-tag-forms + '((define-tag 0) + (define (try-const x) + (try-catch 0 + x + _err + 0)))))]) + (check-pred bytevector? wasm) + (check (bv-contains? wasm #x06) => #t)) + +;; try-catch catch-var is accessible in handler expression +;; (handler uses the caught value — compiles without error) +(let ([wasm (compile-program + (append + value-memory-forms + value-global-forms + value-tag-forms + '((define-tag 0) + (define (recover x) + (try-catch 0 + (throw 0 x) + caught + caught)))))]) + (check-pred bytevector? wasm) + (check (bv-contains? wasm #x07) => #t)) + ;; ================================================================ ;; Tail Call Patterns ;; ================================================================