All docsErrors

Errors

How Venutian reports a problem in your source, and how attempt and rescue catch a fault while a program runs.

Every failure in Venutian gets one of two treatments: a diagnostic if the toolchain caught the problem before your program ran, or a catchable fault if it happened while your program was running. Neither ever shows you a raw interpreter traceback.

Toolchain diagnostics

venutian run, venutian build, venutian check and every other command that reads your source report a problem the same way, whether it is a lexing, parsing, or semantic analysis error. A diagnostic carries the message, the file, the line and column, and, where the toolchain has one, a suggestion. When it can, it prints the offending source line with a ^ under the exact column:

output
VENUTIAN ERROR V2001
'use "does_not_exist.ven"' could not find that file.
source: bad_use.ven
line: 1
column: 1
Checked: /full/resolved/path/to/does_not_exist.ven

Run any command with --diagnostics-format json to get the same information as structured JSON, for an editor or a script to read directly.

attempt and rescue

Inside a running program, attempt and rescue catch a fault. A raise inside the attempt block, or a fault the runtime itself raises (dividing by zero, indexing past the end of a List, and the like), unwinds to the nearest matching rescue:

venutian
shape ValidationError
    message: Text

shape TimeoutError
    seconds: Integer

make risky(n)
    when n < 0
        raise ValidationError("must be positive")
    when n > 100
        raise TimeoutError(30)
    give n * 2

make try_it(n)
    attempt
        give risky(n)
    rescue err: ValidationError
        give "validation: " + err.message
    rescue err: TimeoutError
        give "timeout after " + as_text(err.seconds) + "s"
    rescue err
        give "unknown: " + as_text(err)

print try_it(5)
print try_it(-1)
print try_it(200)
output
10
validation: must be positive
timeout after 30s

A rescue clause with a : Type filter only catches a value of that shape, or of a shape it inherits from, exactly the way choose's is name: Type pattern matches (see types and shapes). Only the last rescue clause in an attempt may skip the type filter; an earlier untyped rescue would catch everything and make every clause after it unreachable, so the compiler refuses to build a program written that way.

A raised value keeps its real runtime type through the catch, so rescue err: Animal matches a raised Dog. The stack is restored to the exact depth it had when the attempt was entered, even when the raise happens in the middle of an expression, so no stale value from before the fault is left for code after the rescue to trip over.

What raise takes

raise takes any Venutian value: a shape instance built for the purpose, as above, or plain Text. A built in runtime fault, like dividing by zero, raises Text carrying the fault's message, so your own raise and a built in fault land in exactly the same rescue.

What stays uncaught

An attempt/rescue block only ever sees a raise from code that runs inside it, directly or through a function it calls. A toolchain diagnostic never reaches a rescue: your program has not started running yet when one of those is reported, so there is nothing an attempt block could be wrapped around. An uncaught runtime fault ends the program and renders through the same diagnostic format as a toolchain error, so you see one consistent shape of error message no matter when the problem was actually found.