Error Handling Patterns
How to implement error handling, result types, and setjmp/longjmp in SBBE IR.
SBBE has no exception mechanism. Error handling is implemented by the frontend using return values, tagged unions, or extern calls to runtime support functions.
Result types (return codes)
The simplest approach: functions return an error code (0 = success, nonzero = error). This is how C and Go handle most errors.
func $parse_int(ptr) -> i32 {
// Returns 0 on success (result in a global), -1 on error
entry:
ldl 0
ldm.u8 // load first byte
dup
// Check if it's a digit (0x30-0x39)
ldi 0x30
lt.u i32
jmp.if error
// ... parsing logic ...
ldi 0 // success
ret
error:
drop
ldi -1 // error code
ret
}
Result/Either types (tagged return)
For richer error handling, return a tagged union (see the unions guide) where tag 0 = success with a value and tag 1 = error with an error code or message.
// Result layout:
// offset 0: i32 tag (0 = Ok, 1 = Err)
// offset 4: i32 value_or_error
func $divide(i32, i32, ptr) -> i32 {
// params: a=0, b=1, result_ptr=2
// Returns 0 on success, 1 on error. Writes to result_ptr.
entry:
ldl 1
eqz i32
jmp.if div_by_zero
// Success: write tag=0, value=a/b
ldl 2
ldi 0
stm i32 // tag = 0 (Ok)
ldl 2
ldi 4
add.s i64
ldl 0
ldl 1
div.s i32
stm i32 // value = a / b
ldi 0 // return success
ret
div_by_zero:
// Error: write tag=1, error_code=1
ldl 2
ldi 1
stm i32 // tag = 1 (Err)
ldl 2
ldi 4
add.s i64
ldi 1
stm i32 // error_code = 1 (division by zero)
ldi 1 // return error
ret
}
setjmp / longjmp (non-local return)
For languages with exceptions or setjmp/longjmp, the frontend can use extern functions to interface with the C runtime:
extern func $setjmp(ptr) -> i32
extern func $longjmp(ptr, i32)
func $try_something(ptr) -> i32 {
// param 0: jmp_buf pointer
entry:
ldl 0
call $setjmp // returns 0 on first call, nonzero on longjmp
dup
eqz i32
jmp.if try_body
jmp catch
try_body:
drop // discard the 0 from setjmp
// ... do risky work ...
// If something goes wrong:
ldl 0
ldi 1 // error code
call $longjmp // jumps back to setjmp, which returns 1
ret // unreachable
catch:
// setjmp returned nonzero — an error occurred
// error code is on the stack
ret
}
Key takeaways
- Error codes are the simplest pattern and impose no overhead
- Tagged result types give rich error information at the cost of a branch per call site
setjmp/longjmpare available via extern bindings for languages that need non-local returns- SBBE does not add hidden control flow paths; all error handling is explicit in the IR