try..except
Use try..except to intercept a script-runtime exception raised while executing a protected statement sequence and run recovery code.
Syntax
try
ProtectedStatements;
except
HandlerStatements;
end;
The current Velox PascalScript grammar supports a general handler statement list. It does not implement Delphi's typed on E: ExceptionType do handler syntax.
How it works
TPSPascalCompiler.ProcessTry emits a PascalScript exception-handler frame around the protected statements. At runtime:
- If the protected sequence finishes normally, the handler is removed and the
exceptsequence is skipped. - If a VM operation or registered call raises an exception recognised by the script runtime, control transfers to the
exceptoffset and statements after the failing operation are skipped. - The handler sequence runs once. Reaching its end marks the exception handled and execution continues after the final
end(or through a following combinedfinallyclause). - An exception raised by the handler itself leaves this handler and propagates outward.
PascalScript registers ExceptionType, ExceptionParam, ExceptionProc, ExceptionPos, ExceptionToString and RaiseLastException for inspecting or re-raising the current VM exception. These describe PascalScript's TIFException/TPSError model, not a Delphi exception-object variable.
Example
procedure ScriptEvent(var Value: Variant);
var
Divisor: Integer;
begin
Divisor := 0;
try
Value := 100 div Divisor;
except
Value := ExceptionParam;
end;
end;
The example handles the runtime division failure and exposes the runtime's exception parameter as the event result. In production logic, prefer validating an expected zero divisor before calculating; exception handling is for failures that cannot be handled more directly.
Inspecting and re-raising
Within the handler, the registered functions provide diagnostic fields:
ExceptionTypereturns the currentTIFExceptionenumeration value.ExceptionParamreturns the associated text parameter/message.ExceptionProcreturns the PascalScript procedure index attached to the active handler frame.ExceptionPosis registered as a position function, but the current runtime returns the active frame'sExceptOffset. Once control has transferred into the handler, that field is changed to the internalInvalidVal - 1sentinel.ExceptionToStringformats a type/parameter pair.RaiseLastExceptionre-raises the saved current exception when one is available.
The ExceptionProc/ExceptionPos pair is therefore not a dependable original-failure location from inside an active handler: the procedure can be the enclosing handler procedure rather than a called procedure where the error arose, and the position is normally the sentinel rather than the failing bytecode offset. Treat both as low-level diagnostics and use the host compilation/runtime log for actionable source location information.
Do not expose internal exception text to an external party without considering whether it contains data values supplied to the failed operation.
Common mistakes
- Copying a Delphi typed handler (
on E: Exception do) into a Velox script. The modifiedProcessTrypath does not parse typedonclauses. - Swallowing every failure without setting a clear result, logging through an approved host facility or re-raising. A bare handler marks the exception handled.
- Using exceptions as ordinary branching for expected Null, empty or zero values. Test predictable conditions explicitly.
- Assuming the handler rolls back dataset edits, file activity or module side effects completed before the failure. It changes control flow only.
Edge cases and quirks
- The modified grammar accepts
try ... except ... finally ... endand eventry ... finally ... except ... endas one combined construct. These are PascalScript extensions, not normal Delphi syntax. Prefer conventional nestedtry..exceptandtry..finallyblocks for portability and an unambiguous recovery/cleanup order. breakandcontinuecompiled inside protected regions emit exception-handler unwind operations before leaving the region. Invalid jumps across structured regions are rejected by compiler checks.- The handler catches script-runtime errors routed through the VM. Host code may catch, log or transform errors outside the script at an event boundary; this page does not promise that every process-level failure is recoverable inside a script.
- A handler can read the last VM exception metadata, but there is no typed Delphi exception object scoped to the handler.
ExceptionPosexposing the handler sentinel is a current runtime diagnostic quirk, not a source line/column contract.- If a conventional outer
try..finallyencloses this statement, its cleanup runs after the handler or during propagation as appropriate.
Errors and side effects
Missing except/finally or end, invalid handler syntax and unsafe cross-region jumps cause compilation errors. Runtime side effects completed before the exception remain unless the called API itself supplies a rollback contract. An exception in the handler propagates; use RaiseLastException when deliberately preserving the original VM failure.
Performance and concurrency
Installing a handler has runtime and bytecode overhead, so use it around a coherent failure boundary rather than every simple operation. It does not serialise shared objects or make a non-thread-safe API safe.
Related reference
try..finally— guarantees cleanup while preserving an unhandled exception.Compilation errors— compile-time failures are reported before an event runs and are not caught by scripttry..except.Testing values— explicit guards for expected Variant states.