Skip to content
← Back

src/syntax/parsers/definitions/variant.ghul

1
namespace Syntax.Parsers.Definitions is
2
use Source
3
use Logging
4
5
class VARIANT(
6
identifier_parser: Parser[Trees.Identifiers.Identifier],
7
variable_list_parser: Parser[Trees.Variables.LIST],
8
modifier_parser: Parser[Trees.Modifiers.LIST]
9
): Base[Trees.Definitions.VARIANT] is
10
super()
11
12
parse(context: CONTEXT) -> Trees.Definitions.VARIANT? is
13
let start = context.location
14
context.in_classy = true
15
context.global_indent = start.start_column
16
17
/*
18
parse a typed-union variant, which is of the form
19
20
variant_definition ::= identifier variant_fields? "default"? ";"
21
variant_fields ::= "(" variant_field ("," variant_field)* ")"
22
variant_field ::= identifier ":" type_expression
23
24
A trailing `default` nominates this variant as the union's
25
default variant — the one `?` and `!` test and unwrap.
26
*/
27
28
try
29
let identifier = identifier_parser.parse(context)
30
31
let should_poison mut = false
32
33
if !identifier? then
34
return null
35
fi
36
37
should_poison = identifier.is_poisoned
38
39
let members: Trees.Variables.LIST mut = Trees.Variables.LIST(start::context.location, System.Array.empty`[Trees.Variables.VARIABLE]())
40
41
if context.current_token == Lexical.TOKEN.PAREN_OPEN then
42
context.next_token()
43
44
let previous_in_init_arguments = context.in_init_arguments
45
context.in_init_arguments = true
46
try
47
members = variable_list_parser.parse(context)!
48
finally
49
context.in_init_arguments = previous_in_init_arguments
50
yrt
51
52
should_poison = should_poison \/ members.is_poisoned
53
54
if !should_poison \/ context.current_token == Lexical.TOKEN.PAREN_CLOSE then
55
context.next_token(Lexical.TOKEN.PAREN_CLOSE)
56
fi
57
else
58
59
for m in members do
60
if !m.is_explicit_type then
61
context.error(m.location, "variant field must have an explicit type")
62
should_poison = true
63
fi
64
od
65
fi
66
67
let modifiers = Trees.Modifiers.LIST(
68
context.location,
69
Trees.Modifiers.PUBLIC(context.location),
70
Trees.Modifiers.FIELD(context.location)
71
)
72
73
let is_default mut = false
74
75
if context.current_token == Lexical.TOKEN.DEFAULT then
76
is_default = true
77
context.next_token()
78
fi
79
80
if !should_poison \/ context.current_token == Lexical.TOKEN.SEMICOLON then
81
context.accept_terminator()
82
fi
83
84
// Read once the variant is parsed, so the extent ends at the
85
// variant's own last token rather than at whatever follows it.
86
let semicolon_end = context.previous_end
87
88
let result = Trees.Definitions.VARIANT(
89
start::semicolon_end,
90
identifier!,
91
members,
92
modifiers
93
)
94
95
result.is_default = is_default
96
result.poison(should_poison)
97
98
return result
99
finally
100
context.in_classy = false
101
yrt
102
si
103
si
104
si