ERR/E0.2: raise / try / catch / onfail + precedence + consumer-aware pipe (parser)
Parser-only second step of the error-handling stream. No sema/codegen.
- token: 4 keywords — `raise`, `try`, `catch`, `onfail`.
- ast: RaiseStmt, TryExpr, CatchExpr {operand, binding?, body, is_match_body},
OnFailStmt {binding?, body}.
- parser:
- `try` is a unary prefix (binds tighter than `or`; right-recursive so it
stacks under `xx`/`@`/etc).
- `or` is already left-associative (precedence-climbing loop) — no change.
- `catch` is a postfix with four body shapes (no-binding block / block /
bare-expr / `== { case }` match-body, the latter reusing parseMatchBody
with the binding as subject).
- `raise EXPR;` and `onfail [e] { } | onfail EXPR;` statements; `error`
parses in expression position so `raise error.X` works; raise rejected
in expression position and inside an onfail body (in_onfail_body flag).
- consumer-aware `|>`: pipes the LHS into the head call through a
try/catch/or wrapper, preserving the wrapper.
- print: printExpr + match-arm printing for round-trips (anyerror!void to
break the printExpr<->printMatchArms inferred-error-set loop).
- sema/lsp: exhaustive switch arms for the 4 nodes + 4 keyword tokens.
- tests: ~22 inline parser tests (precedence, all catch forms, both
rejections, pipe cases, round-trip prints incl. match-body).
zig build, zig build test (264), and 254/254 examples green.
This commit is contained in:
38
src/ast.zig
38
src/ast.zig
@@ -58,6 +58,10 @@ pub const Node = struct {
|
||||
many_pointer_type_expr: ManyPointerTypeExpr,
|
||||
optional_type_expr: OptionalTypeExpr,
|
||||
error_type_expr: ErrorTypeExpr,
|
||||
raise_stmt: RaiseStmt,
|
||||
try_expr: TryExpr,
|
||||
catch_expr: CatchExpr,
|
||||
onfail_stmt: OnFailStmt,
|
||||
pack_index_type_expr: PackIndexTypeExpr,
|
||||
comptime_pack_ref: ComptimePackRef,
|
||||
force_unwrap: ForceUnwrap,
|
||||
@@ -407,6 +411,40 @@ pub const DeferStmt = struct {
|
||||
expr: *Node,
|
||||
};
|
||||
|
||||
// ── Error handling (ERR stream) ──────────────────────────────────────────
|
||||
|
||||
/// `raise EXPR;` — terminates control flow like `return`, populating the
|
||||
/// error channel. `tag` is a tag-typed expression: `error.X` (a field
|
||||
/// access on the `error` keyword) or a tag-bound variable (`raise e`).
|
||||
pub const RaiseStmt = struct {
|
||||
tag: *Node,
|
||||
};
|
||||
|
||||
/// `try X` — a failable attempt. Unary prefix, binds tighter than any
|
||||
/// binary operator. Sema (E1.4) rejects a non-failable operand.
|
||||
pub const TryExpr = struct {
|
||||
operand: *Node,
|
||||
};
|
||||
|
||||
/// `X catch [e] BODY` — inline failure handler (postfix). The binding is a
|
||||
/// bare name (no parens) and optional. Body is a block, a bare expression,
|
||||
/// or — when `is_match_body` — a `match_expr` from the `== { case ... }`
|
||||
/// sugar (whose subject is the binding).
|
||||
pub const CatchExpr = struct {
|
||||
operand: *Node,
|
||||
binding: ?[]const u8 = null,
|
||||
body: *Node,
|
||||
is_match_body: bool = false,
|
||||
};
|
||||
|
||||
/// `onfail [e] BODY` — cleanup run on error-exit of the enclosing block.
|
||||
/// Binding optional (bare name). Body is a block (`onfail [e] { ... }`) or
|
||||
/// a bare expression (`onfail EXPR;`).
|
||||
pub const OnFailStmt = struct {
|
||||
binding: ?[]const u8 = null,
|
||||
body: *Node,
|
||||
};
|
||||
|
||||
pub const PushStmt = struct {
|
||||
context_expr: *Node,
|
||||
body: *Node,
|
||||
|
||||
Reference in New Issue
Block a user