errdefer and try/defer fix

This commit is contained in:
2026-07-13 19:20:22 +02:00
parent 9e75549d02
commit 6de4d9f9f3
23 changed files with 113190 additions and 105482 deletions
+31 -5
View File
@@ -1410,18 +1410,44 @@ parse_block_statement :: proc(parser: ^Parser, label := symbol.INVALID) -> ast.S
return id
}
// `defer <statement>` runs the statement when the enclosing scope exits. The
// statement may be a block (`defer { ... }`). The checker rejects deferring a
// `return`/`break`/`continue`/`defer`.
// `defer <statement>` runs whenever the enclosing scope exits; `errdefer`
// runs only when it exits through a function error and may capture that error.
parse_defer :: proc(parser: ^Parser) -> ast.Stmt_Id {
marker := advance(parser) // consume 'defer'
marker := advance(parser)
error_only := marker.kind == .Keyword_Errdefer
skip_newlines(parser)
captures: []symbol.Id
if error_only {
if _, ok := allow(parser, .Pipe); ok {
capture := current(parser)
if capture.kind != .Identifier && capture.kind != .Underscore {
source.add(parser.diagnostics, capture.span, "expected an errdefer capture name")
} else {
advance(parser)
captures = make([]symbol.Id, 1, parser.module.allocator)
captures[0] = capture.symbol
}
if current(parser).kind == .Comma {
source.add(parser.diagnostics, current(parser).span, "'errdefer' accepts exactly one capture")
for current(parser).kind != .Pipe && current(parser).kind != .Newline &&
current(parser).kind != .Eof {
advance(parser)
}
}
if _, close_ok := allow(parser, .Pipe); !close_ok {
source.add(parser.diagnostics, current(parser).span, "expected '|' after errdefer capture")
}
skip_newlines(parser)
}
}
inner := parse_statement(parser)
id := ast.stmt_id(len(parser.module.statements))
append(&parser.module.statements, ast.Stmt{
kind=.Defer,
span=marker.span,
update=inner,
error_only=error_only,
captures=captures,
expr=ast.INVALID_EXPR,
diagnostic=source.INVALID_DIAGNOSTIC,
})
@@ -1486,7 +1512,7 @@ parse_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
if current(parser).kind == .Keyword_Continue {
return parse_loop_control(parser, .Continue)
}
if current(parser).kind == .Keyword_Defer {
if current(parser).kind == .Keyword_Defer || current(parser).kind == .Keyword_Errdefer {
return parse_defer(parser)
}
if current(parser).kind == .Keyword_Yield {