Error Handling
Trap / Evade (try / catch)
Section titled “Trap / Evade (try / catch)”The Trap/Evade block catches runtime errors and prevents them from crashing your program.
Trap begins Countstone result is 10 / 0; Chant("This line never runs.");Evade (err) Chant("Caught: " + err);end of TrapOutput:
Caught: division by zero - the void consumes allThe error variable (err in the example above) contains the error message as a Runestone (string). You can name it whatever you want.
What gets caught
Section titled “What gets caught”Trap/Evade catches all runtime errors, including:
- Division by zero
- Index out of bounds
- Type mismatches
- Undefined variable access
- Explicitly thrown errors (via
Forfeit)
Execution flow
Section titled “Execution flow”When an error occurs inside Trap:
- Execution immediately jumps to the
Evadeblock - The error message is bound to the named variable
- After the
Evadeblock, execution continues normally
Chant("Before trap");
Trap begins Chant("Inside trap - before error"); Countstone bad is 10 / 0; Chant("Inside trap - after error (never reached)");Evade (err) Chant("Caught: " + err);end of Trap
Chant("After trap - program continues");Output:
Before trapInside trap - before errorCaught: division by zero - the void consumes allAfter trap - program continuesForfeit (throw)
Section titled “Forfeit (throw)”Use Forfeit to throw a custom error:
Ritual withdraw(Mutable Countstone balance, Countstone amount) begins Quest begins when (amount > balance) Forfeit "insufficient gold! Need " + amount + " but only have " + balance; end of Quest balance is written as balance - amount; returneth balance;end of RitualForfeit takes any expression that evaluates to a value. That value becomes the error message.
Catching custom errors
Section titled “Catching custom errors”Custom errors thrown with Forfeit are caught by Trap/Evade just like built-in errors:
Trap begins Mutable Countstone gold is 50; withdraw(gold, 100);Evade (err) Chant("Transaction failed: " + err);end of TrapOutput:
Transaction failed: insufficient gold! Need 100 but only have 50Assert
Section titled “Assert”The Assert built-in function throws an error if a condition is false:
Assert(1 + 1 == 2); // passes silentlyAssert(player.health > 0); // passes if player is aliveAssert(Falsehood); // ERROR: assertion failedUse Assert for debugging and validating assumptions during development.
Patterns
Section titled “Patterns”Guard clauses
Section titled “Guard clauses”Use Forfeit at the top of a Ritual to validate inputs early:
Ritual set_level(Mutable Familiar player, Countstone level) begins Quest begins when (level < 1) Forfeit "level must be at least 1"; end of Quest Quest begins when (level > 100) Forfeit "level cannot exceed 100"; end of Quest player.level is written as level;end of RitualWrapping risky operations
Section titled “Wrapping risky operations”Ritual safe_divide(Countstone a, Countstone b) begins Trap begins returneth a / b; Evade (err) Chant("Warning: " + err); returneth 0; end of Trapend of RitualError messages
Section titled “Error messages”RuneLang’s built-in errors are themed to match the fantasy setting:
| Error | Message style |
|---|---|
| Division by zero | division by zero - the void consumes all |
| Undefined variable | unknown rune 'x' - it has not been inscribed |
| Type mismatch | Hex Mismatch (Type): ... |
| Immutable reassignment | cannot reassign enchanted (immutable) rune 'x' |
| Index out of bounds | scroll index out of bounds |