allow keywords as values in enums (and tagged unions)
This commit is contained in:
@@ -105,6 +105,7 @@ lex :: proc(
|
||||
) -> token.Stream {
|
||||
stream: token.Stream
|
||||
stream.items.allocator = allocator
|
||||
stream.symbols = symbols
|
||||
bytes := transmute([]byte)source_file.text
|
||||
cursor := 0
|
||||
|
||||
|
||||
+34
-17
@@ -86,6 +86,18 @@ allow :: proc(parser: ^Parser, kind: token.Kind) -> (token.Token, bool) {
|
||||
return current(parser), false
|
||||
}
|
||||
|
||||
parse_member_name :: proc(parser: ^Parser, allow_keyword := true) -> (token.Token, bool) {
|
||||
name := current(parser)
|
||||
if name.kind != .Identifier && (!allow_keyword || !token.is_keyword(name.kind)) {
|
||||
return name, false
|
||||
}
|
||||
advance(parser)
|
||||
if name.kind != .Identifier {
|
||||
name.symbol = symbol.intern(parser.tokens.symbols, token_text(parser, name))
|
||||
}
|
||||
return name, true
|
||||
}
|
||||
|
||||
skip_newlines :: proc(parser: ^Parser) {
|
||||
for current(parser).kind == .Newline {
|
||||
advance(parser)
|
||||
@@ -539,12 +551,11 @@ parse_keyed_initializers :: proc(
|
||||
args.allocator = parser.module.allocator
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
|
||||
field := current(parser)
|
||||
if field.kind != .Identifier {
|
||||
field, field_ok := parse_member_name(parser)
|
||||
if !field_ok {
|
||||
source.add(parser.diagnostics, field.span, "expected a keyed struct field initializer")
|
||||
break
|
||||
}
|
||||
advance(parser)
|
||||
// A bare key (`T{ variant }`, no `= value`) constructs a void-payload union
|
||||
// variant; the checker validates that the field actually has a void type.
|
||||
value := ast.INVALID_EXPR
|
||||
@@ -804,11 +815,10 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
return parse_array_literal(parser, nesting)
|
||||
case .Dot:
|
||||
start := advance(parser)
|
||||
member := current(parser)
|
||||
if member.kind != .Identifier {
|
||||
member, member_ok := parse_member_name(parser)
|
||||
if !member_ok {
|
||||
return invalid_expr(parser, member.span, "expected an enum member after '.'")
|
||||
}
|
||||
advance(parser)
|
||||
payload := ast.INVALID_EXPR
|
||||
end := member.span
|
||||
if left_brace, ok := allow(parser, .Left_Brace); ok {
|
||||
@@ -868,11 +878,12 @@ parse_primary :: proc(parser: ^Parser, nesting: int) -> ast.Expr_Id {
|
||||
name := first
|
||||
qualifier := symbol.INVALID
|
||||
if _, ok := allow(parser, .Dot); ok {
|
||||
if current(parser).kind != .Identifier {
|
||||
member, member_ok := parse_member_name(parser)
|
||||
if !member_ok {
|
||||
return invalid_expr(parser, current(parser).span, "expected a package member after '.'")
|
||||
}
|
||||
qualifier = first.symbol
|
||||
name = advance(parser)
|
||||
name = member
|
||||
}
|
||||
if current(parser).kind == .Left_Paren {
|
||||
call := parse_call(parser, qualifier, first, name, nesting)
|
||||
@@ -1074,12 +1085,11 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
}
|
||||
if current(parser).kind == .Dot {
|
||||
advance(parser)
|
||||
field := current(parser)
|
||||
if field.kind != .Identifier {
|
||||
field, field_ok := parse_member_name(parser)
|
||||
if !field_ok {
|
||||
left = invalid_expr(parser, field.span, "expected a field name after '.'")
|
||||
continue
|
||||
}
|
||||
advance(parser)
|
||||
left_expr := parser.module.exprs[left]
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Field,
|
||||
@@ -2252,6 +2262,7 @@ parse_record_body :: proc(
|
||||
fields: ^[dynamic]types.Field,
|
||||
expected_open: string,
|
||||
allow_anonymous_struct_payload := false,
|
||||
allow_keyword_names := false,
|
||||
) -> bool {
|
||||
if _, ok := allow(parser, .Left_Brace); !ok {
|
||||
source.add(parser.diagnostics, current(parser).span, expected_open)
|
||||
@@ -2259,7 +2270,8 @@ parse_record_body :: proc(
|
||||
}
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
|
||||
if current(parser).kind != .Identifier {
|
||||
field_name, field_ok := parse_member_name(parser, allow_keyword_names)
|
||||
if !field_ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected a struct field name")
|
||||
for current(parser).kind != .Newline &&
|
||||
current(parser).kind != .Right_Brace &&
|
||||
@@ -2269,7 +2281,6 @@ parse_record_body :: proc(
|
||||
skip_newlines(parser)
|
||||
continue
|
||||
}
|
||||
field_name := advance(parser)
|
||||
field_type := parse_record_field_type(parser, allow_anonymous_struct_payload)
|
||||
append(fields, types.Field{name=u32(field_name.symbol), type=field_type})
|
||||
if _, ok := allow(parser, .Comma); ok {
|
||||
@@ -2317,7 +2328,7 @@ parse_inline_union_type :: proc(parser: ^Parser) -> types.Type {
|
||||
fields: [dynamic]types.Field
|
||||
fields.allocator = parser.module.allocator
|
||||
defer delete(fields)
|
||||
if !parse_record_body(parser, &fields, "expected '{' after inline union error type", true) || !valid {
|
||||
if !parse_record_body(parser, &fields, "expected '{' after inline union error type", true, true) || !valid {
|
||||
return types.INVALID
|
||||
}
|
||||
tag := synthesize_union_tag(parser, fields[:])
|
||||
@@ -2372,7 +2383,13 @@ parse_struct :: proc(parser: ^Parser, name: token.Token, c_layout: bool, is_unio
|
||||
fields.allocator = parser.module.allocator
|
||||
defer delete(fields)
|
||||
allow_anonymous_struct_payload := is_union && (inferred_tag || types.is_valid(declared_tag))
|
||||
_ = parse_record_body(parser, &fields, "expected '{' after struct fields", allow_anonymous_struct_payload)
|
||||
_ = parse_record_body(
|
||||
parser,
|
||||
&fields,
|
||||
"expected '{' after struct fields",
|
||||
allow_anonymous_struct_payload,
|
||||
allow_anonymous_struct_payload,
|
||||
)
|
||||
if is_union && (inferred_tag || types.is_valid(declared_tag)) {
|
||||
tag = synthesize_union_tag(parser, fields[:])
|
||||
}
|
||||
@@ -2479,7 +2496,8 @@ parse_enum_body :: proc(
|
||||
has_previous := false
|
||||
skip_newlines(parser)
|
||||
for current(parser).kind != .Right_Brace && current(parser).kind != .Eof {
|
||||
if current(parser).kind != .Identifier {
|
||||
member, member_ok := parse_member_name(parser)
|
||||
if !member_ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected an enum member name")
|
||||
for current(parser).kind != .Newline &&
|
||||
current(parser).kind != .Right_Brace &&
|
||||
@@ -2489,7 +2507,6 @@ parse_enum_body :: proc(
|
||||
skip_newlines(parser)
|
||||
continue
|
||||
}
|
||||
member := advance(parser)
|
||||
duplicate := false
|
||||
for existing in members^ {
|
||||
if existing.name == u32(member.symbol) {
|
||||
|
||||
@@ -114,6 +114,10 @@ Kind :: enum u8 {
|
||||
Keyword_C_Longdouble,
|
||||
}
|
||||
|
||||
is_keyword :: proc(kind: Kind) -> bool {
|
||||
return kind >= .Keyword_Func && kind <= .Keyword_C_Longdouble
|
||||
}
|
||||
|
||||
Token :: struct {
|
||||
span: source.Span,
|
||||
symbol: symbol.Id,
|
||||
@@ -122,5 +126,6 @@ Token :: struct {
|
||||
}
|
||||
|
||||
Stream :: struct {
|
||||
items: [dynamic]Token,
|
||||
items: [dynamic]Token,
|
||||
symbols: ^symbol.Table,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user