This commit is contained in:
agra
2026-02-14 19:33:33 +02:00
parent d61c6488f3
commit 0e777e9d2e
7 changed files with 957 additions and 72 deletions

View File

@@ -408,15 +408,23 @@ pub const Parser = struct {
try variant_names.append(self.allocator, self.tokenSlice(self.current));
self.advance();
if (self.current.tag == .colon_colon) {
// Explicit value: name :: expr;
if (!is_flags) {
return self.fail("explicit enum values require 'enum flags'");
}
// Explicit value: name :: expr; or name :: expr: type;
self.advance();
const val_expr = try self.parseExpr();
try variant_values.append(self.allocator, val_expr);
try variant_types.append(self.allocator, null);
has_any_value = true;
// Check for payload type after value: name :: 0x300: KeyData
if (self.current.tag == .colon) {
if (is_flags) {
return self.fail("flags enum variants cannot have payloads");
}
self.advance();
const vtype = try self.parseTypeExpr();
try variant_types.append(self.allocator, vtype);
has_any_type = true;
} else {
try variant_types.append(self.allocator, null);
}
} else if (self.current.tag == .colon) {
// Typed variant: name: type;
if (is_flags) {
@@ -553,7 +561,12 @@ pub const Parser = struct {
// All names in the group share the same type and default
for (group_names.items) |fname| {
try field_names.append(self.allocator, fname);
// `_` is an ignore identifier — auto-rename to unique internal name
const actual_name = if (std.mem.eql(u8, fname, "_"))
try std.fmt.allocPrint(self.allocator, "_{d}", .{field_names.items.len})
else
fname;
try field_names.append(self.allocator, actual_name);
try field_types.append(self.allocator, field_type);
try field_defaults.append(self.allocator, default_val);
}
@@ -892,6 +905,24 @@ pub const Parser = struct {
return try self.createNode(start, .{ .insert_expr = .{ .expr = inner } });
}
// Block-form if/while/for as statements — parse directly to prevent
// postfix chaining (e.g. `if cond { ... }.field` being misparsed)
if (self.current.tag == .kw_if) {
const expr = try self.parseIfExpr();
try self.expectSemicolonAfter(expr);
return expr;
}
if (self.current.tag == .kw_while) {
const expr = try self.parsePrimary();
try self.expectSemicolonAfter(expr);
return expr;
}
if (self.current.tag == .kw_for) {
const expr = try self.parsePrimary();
try self.expectSemicolonAfter(expr);
return expr;
}
// Expression statement
const expr = try self.parseExpr();
@@ -1427,11 +1458,28 @@ pub const Parser = struct {
} else try self.parsePrimary(); // .variant
try self.expect(.colon);
// Optional payload capture: (ident)
var capture: ?[]const u8 = null;
if (self.current.tag == .l_paren) {
self.advance();
if (self.current.tag != .identifier) return self.fail("expected capture name");
capture = self.tokenSlice(self.current);
self.advance();
try self.expect(.r_paren);
}
if (self.current.tag == .kw_break) {
self.advance();
try self.expect(.semicolon);
const body = try self.createNode(arm_start, .{ .block = .{ .stmts = &.{} } });
try arms.append(self.allocator, .{ .pattern = pattern, .body = body, .is_break = true });
try arms.append(self.allocator, .{ .pattern = pattern, .body = body, .is_break = true, .capture = capture });
} else if (self.current.tag == .fat_arrow) {
// Short form: (ident) => expr;
self.advance();
const expr = try self.parseExpr();
try self.expect(.semicolon);
const body = try self.createNode(arm_start, .{ .block = .{ .stmts = try self.allocator.dupe(*Node, &.{expr}) } });
try arms.append(self.allocator, .{ .pattern = pattern, .body = body, .is_break = false, .capture = capture });
} else {
const stmts_start = self.current.loc.start;
var stmts = std.ArrayList(*Node).empty;
@@ -1439,7 +1487,7 @@ pub const Parser = struct {
try stmts.append(self.allocator, try self.parseStmt());
}
const body = try self.createNode(stmts_start, .{ .block = .{ .stmts = try stmts.toOwnedSlice(self.allocator) } });
try arms.append(self.allocator, .{ .pattern = pattern, .body = body, .is_break = false });
try arms.append(self.allocator, .{ .pattern = pattern, .body = body, .is_break = false, .capture = capture });
}
}
// Optional else arm (default)