add defer

This commit is contained in:
2026-06-27 03:36:47 +02:00
parent 81ae939bf0
commit b4ce2c2117
8 changed files with 375 additions and 13 deletions
+43 -1
View File
@@ -1001,6 +1001,41 @@ parse_loop_control :: proc(parser: ^Parser, kind: ast.Stmt_Kind) -> ast.Stmt_Id
return id
}
// A bare `{ ... }` introduces a nested scope. Locals declared inside are not
// visible after it, and any `defer`s inside it run at the closing brace.
parse_block_statement :: proc(parser: ^Parser) -> ast.Stmt_Id {
start := current(parser).span // the '{'
body := parse_block(parser)
id := ast.stmt_id(len(parser.module.statements))
append(&parser.module.statements, ast.Stmt{
kind=.Block,
span=start,
body=body,
expr=ast.INVALID_EXPR,
update=ast.INVALID_STMT,
diagnostic=source.INVALID_DIAGNOSTIC,
})
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`.
parse_defer :: proc(parser: ^Parser) -> ast.Stmt_Id {
marker := advance(parser) // consume 'defer'
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,
expr=ast.INVALID_EXPR,
diagnostic=source.INVALID_DIAGNOSTIC,
})
return id
}
starts_declared_type :: proc(parser: ^Parser) -> bool {
if current(parser).kind != .Left_Bracket {
return is_type_token(current(parser).kind)
@@ -1045,6 +1080,13 @@ 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 {
return parse_defer(parser)
}
// A leading `{` opens a bare block scope (struct literals are postfix only).
if current(parser).kind == .Left_Brace {
return parse_block_statement(parser)
}
if current(parser).kind == .Identifier || current(parser).kind == .Underscore {
start_cursor := parser.cursor
@@ -1333,7 +1375,7 @@ parse_while_update :: proc(parser: ^Parser) -> ast.Stmt_Id {
statement := &parser.module.statements[update]
switch statement.kind {
case .Assignment, .Expression:
case .Invalid, .Declaration, .Return, .If, .While, .For, .Break, .Continue:
case .Invalid, .Declaration, .Return, .If, .While, .For, .Break, .Continue, .Block, .Defer:
diagnostic := source.add(
parser.diagnostics,
statement.span,