enum, union
This commit is contained in:
@@ -160,7 +160,7 @@ pub const Parser = struct {
|
||||
return self.parseStructDecl(name, start_pos);
|
||||
}
|
||||
|
||||
// Union declaration
|
||||
// C-style union declaration
|
||||
if (self.current.tag == .kw_union) {
|
||||
return self.parseUnionDecl(name, start_pos);
|
||||
}
|
||||
@@ -368,7 +368,7 @@ pub const Parser = struct {
|
||||
if (self.current.tag == .kw_struct) {
|
||||
return try self.parseStructDecl("__anon", start);
|
||||
}
|
||||
// Inline union type in type position: union { ... }
|
||||
// Inline C-style union in type position: union { ... }
|
||||
if (self.current.tag == .kw_union) {
|
||||
return try self.parseUnionDecl("__anon", start);
|
||||
}
|
||||
@@ -382,30 +382,13 @@ pub const Parser = struct {
|
||||
fn parseEnumDecl(self: *Parser, name: []const u8, start_pos: u32) anyerror!*Node {
|
||||
self.advance(); // skip 'enum'
|
||||
try self.expect(.l_brace);
|
||||
var variants = std.ArrayList([]const u8).empty;
|
||||
var variant_names = std.ArrayList([]const u8).empty;
|
||||
var variant_types = std.ArrayList(?*Node).empty;
|
||||
var has_any_type = false;
|
||||
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
||||
if (self.current.tag != .identifier) {
|
||||
return self.fail("expected variant name");
|
||||
}
|
||||
try variants.append(self.allocator, self.tokenSlice(self.current));
|
||||
self.advance();
|
||||
if (self.current.tag == .semicolon) {
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
try self.expect(.r_brace);
|
||||
return try self.createNode(start_pos, .{ .enum_decl = .{ .name = name, .variants = try variants.toOwnedSlice(self.allocator) } });
|
||||
}
|
||||
|
||||
fn parseUnionDecl(self: *Parser, name: []const u8, start_pos: u32) anyerror!*Node {
|
||||
self.advance(); // skip 'union'
|
||||
try self.expect(.l_brace);
|
||||
var variant_names = std.ArrayList([]const u8).empty;
|
||||
var variant_types = std.ArrayList(?*Node).empty;
|
||||
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
||||
if (self.current.tag != .identifier) {
|
||||
return self.fail("expected variant name in union");
|
||||
}
|
||||
try variant_names.append(self.allocator, self.tokenSlice(self.current));
|
||||
self.advance();
|
||||
if (self.current.tag == .colon) {
|
||||
@@ -413,6 +396,7 @@ pub const Parser = struct {
|
||||
self.advance();
|
||||
const vtype = try self.parseTypeExpr();
|
||||
try variant_types.append(self.allocator, vtype);
|
||||
has_any_type = true;
|
||||
} else {
|
||||
// Void variant: name;
|
||||
try variant_types.append(self.allocator, null);
|
||||
@@ -422,10 +406,54 @@ pub const Parser = struct {
|
||||
}
|
||||
}
|
||||
try self.expect(.r_brace);
|
||||
return try self.createNode(start_pos, .{ .union_decl = .{
|
||||
// Always produce enum_decl; variant_types distinguishes payload-less from tagged
|
||||
return try self.createNode(start_pos, .{ .enum_decl = .{
|
||||
.name = name,
|
||||
.variant_names = try variant_names.toOwnedSlice(self.allocator),
|
||||
.variant_types = try variant_types.toOwnedSlice(self.allocator),
|
||||
.variant_types = if (has_any_type) try variant_types.toOwnedSlice(self.allocator) else &.{},
|
||||
} });
|
||||
}
|
||||
|
||||
fn parseUnionDecl(self: *Parser, name: []const u8, start_pos: u32) anyerror!*Node {
|
||||
self.advance(); // skip 'union'
|
||||
try self.expect(.l_brace);
|
||||
var field_names = std.ArrayList([]const u8).empty;
|
||||
var field_types = std.ArrayList(*Node).empty;
|
||||
var anon_idx: u32 = 0;
|
||||
while (self.current.tag != .r_brace and self.current.tag != .eof) {
|
||||
// Anonymous struct field: struct { x, y: f32; };
|
||||
if (self.current.tag == .kw_struct) {
|
||||
const anon_field = try std.fmt.allocPrint(self.allocator, "__anon_{d}", .{anon_idx});
|
||||
anon_idx += 1;
|
||||
const anon_struct_name = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{ name, anon_field });
|
||||
const struct_node = try self.parseStructDecl(anon_struct_name, self.current.loc.start);
|
||||
try field_names.append(self.allocator, anon_field);
|
||||
try field_types.append(self.allocator, struct_node);
|
||||
if (self.current.tag == .semicolon) {
|
||||
self.advance();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (self.current.tag != .identifier) {
|
||||
return self.fail("expected field name or 'struct'");
|
||||
}
|
||||
try field_names.append(self.allocator, self.tokenSlice(self.current));
|
||||
self.advance();
|
||||
if (self.current.tag != .colon) {
|
||||
return self.fail("union fields must have a type");
|
||||
}
|
||||
self.advance();
|
||||
const ftype = try self.parseTypeExpr();
|
||||
try field_types.append(self.allocator, ftype);
|
||||
if (self.current.tag == .semicolon) {
|
||||
self.advance();
|
||||
}
|
||||
}
|
||||
try self.expect(.r_brace);
|
||||
return try self.createNode(start_pos, .{ .union_decl = .{
|
||||
.name = name,
|
||||
.field_names = try field_names.toOwnedSlice(self.allocator),
|
||||
.field_types = try field_types.toOwnedSlice(self.allocator),
|
||||
} });
|
||||
}
|
||||
|
||||
@@ -1141,14 +1169,13 @@ pub const Parser = struct {
|
||||
}
|
||||
const name = self.tokenSlice(self.current);
|
||||
self.advance();
|
||||
// Union literal: .variant(payload)
|
||||
// Enum literal with payload: .variant(payload) — tagged enum (formerly union literal)
|
||||
if (self.current.tag == .l_paren) {
|
||||
self.advance(); // skip '('
|
||||
const payload = try self.parseExpr();
|
||||
try self.expect(.r_paren);
|
||||
return try self.createNode(start, .{ .union_literal = .{
|
||||
.union_name = null,
|
||||
.variant_name = name,
|
||||
return try self.createNode(start, .{ .enum_literal = .{
|
||||
.name = name,
|
||||
.payload = payload,
|
||||
} });
|
||||
}
|
||||
@@ -1175,8 +1202,12 @@ pub const Parser = struct {
|
||||
// Anonymous struct expression: struct { value: T; count: u32; }
|
||||
return try self.parseStructDecl("__anon", start);
|
||||
},
|
||||
.kw_enum => {
|
||||
// Anonymous enum expression: enum { variant: T; other: u32; }
|
||||
return try self.parseEnumDecl("__anon", start);
|
||||
},
|
||||
.kw_union => {
|
||||
// Anonymous union expression: union { variant: T; other: u32; }
|
||||
// Anonymous C-style union expression: union { f: f32; i: s32; }
|
||||
return try self.parseUnionDecl("__anon", start);
|
||||
},
|
||||
.kw_if => {
|
||||
|
||||
Reference in New Issue
Block a user