This commit is contained in:
2026-06-23 17:22:41 +02:00
parent f16f352d1e
commit 2f68fc966a
16 changed files with 809 additions and 38 deletions
+131
View File
@@ -588,6 +588,21 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
})
case .Left_Bracket:
return parse_array_literal(parser, nesting)
case .Dot:
start := advance(parser)
member := current(parser)
if member.kind != .Identifier {
return invalid_expr(parser, member.span, "expected an enum member after '.'")
}
advance(parser)
return add_expr(parser, ast.Expr{
kind=.Enum_Literal,
span=span_from(start.span, member.span),
name=member.symbol,
left=ast.INVALID_EXPR,
right=ast.INVALID_EXPR,
diagnostic=source.INVALID_DIAGNOSTIC,
})
case .Identifier:
first := advance(parser)
name := first
@@ -1490,6 +1505,118 @@ parse_distinct :: proc(parser: ^Parser, name: token.Token) {
_ = finish_statement(parser)
}
parse_enum :: proc(parser: ^Parser, name: token.Token) {
start := advance(parser)
explicit_backing := false
backing := types.INVALID
if _, ok := allow(parser, .Left_Paren); ok {
explicit_backing = true
backing = parse_type(parser)
if _, close_ok := allow(parser, .Right_Paren); !close_ok {
source.add(parser.diagnostics, current(parser).span, "expected ')' after enum backing type")
}
}
skip_newlines(parser)
if _, ok := allow(parser, .Left_Brace); !ok {
source.add(parser.diagnostics, current(parser).span, "expected '{' after enum declaration")
_ = finish_statement(parser)
return
}
members: [dynamic]types.Enum_Member
members.allocator = parser.module.allocator
defer delete(members)
next_value: i128
previous_value: i128
has_previous := false
skip_newlines(parser)
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
if current(parser).kind != .Identifier {
source.add(parser.diagnostics, current(parser).span, "expected an enum member name")
for current(parser).kind != .Newline &&
current(parser).kind != .Right_Brace &&
current(parser).kind != .Eof {
advance(parser)
}
skip_newlines(parser)
continue
}
member := advance(parser)
duplicate := false
for existing in members {
if existing.name == u32(member.symbol) {
duplicate = true
break
}
}
if duplicate {
source.addf(parser.diagnostics, member.span, "duplicate enum member '%s'", token_text(parser, member))
}
value := next_value
if _, ok := allow(parser, .Equal); ok {
if !explicit_backing {
source.add(parser.diagnostics, member.span, "explicit enum values require a backing type")
}
negative := false
if _, minus_ok := allow(parser, .Minus); minus_ok {
negative = true
}
literal := current(parser)
if literal.kind != .Integer {
source.add(parser.diagnostics, literal.span, "expected a decimal integer literal for enum value")
} else {
advance(parser)
magnitude, magnitude_ok := parse_integer_magnitude(token_text(parser, literal))
if !magnitude_ok {
source.add(parser.diagnostics, literal.span, "enum value magnitude does not fit in u64")
} else {
value = i128(magnitude)
if negative {
value = -value
}
}
}
}
if has_previous && value <= previous_value {
source.add(parser.diagnostics, member.span, "enum values must be strictly increasing")
}
if !duplicate {
append(&members, types.Enum_Member{name=u32(member.symbol), value=value})
}
previous_value = value
has_previous = true
next_value = value+1
if _, ok := allow(parser, .Comma); ok {
skip_newlines(parser)
} else {
_ = finish_statement(parser, true)
}
}
if _, ok := allow(parser, .Right_Brace); !ok {
source.add(parser.diagnostics, current(parser).span, "expected '}' after enum members")
}
if len(members) == 0 {
source.add(parser.diagnostics, start.span, "enum declarations require at least one member")
}
if !explicit_backing {
max_value := u64(max(len(members)-1, 0))
backing = types.U8
if max_value > 0xff {
backing = types.U16
}
if max_value > 0xffff {
backing = types.U32
}
if max_value > 0xffff_ffff {
backing = types.U64
}
}
id := types.named(&parser.module.type_store, u32(parser.pkg), u32(name.symbol))
if !types.define_enum(&parser.module.type_store, id, backing, members[:], explicit_backing) {
source.addf(parser.diagnostics, name.span, "duplicate type declaration '%s'", token_text(parser, name))
}
_ = finish_statement(parser)
}
decode_import_path :: proc(parser: ^Parser, tok: token.Token) -> string {
text := token_text(parser, tok)
if len(text) < 2 {
@@ -1601,6 +1728,10 @@ parse_top_level :: proc(parser: ^Parser) {
parse_struct(parser, name, current(parser).kind == .Keyword_C_Struct)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Enum {
parse_enum(parser, name)
return
}
if operator.kind == .Colon_Colon && current(parser).kind == .Keyword_Distinct {
parse_distinct(parser, name)
return