Skip to content
← Back

src/syntax/parsers/definitions/variant_list.ghul

1
namespace Syntax.Parsers.Definitions is
2
use Source
3
use Logging
4
use Ghul.Disposable
5
6
class VARIANT_LIST(variant_parser: Parser[Trees.Definitions.VARIANT]): Base[Trees.Definitions.LIST] is
7
super()
8
9
parse(context: CONTEXT) -> Trees.Definitions.LIST is
10
let start = context.location
11
let should_poison mut = false
12
13
/*
14
parse a list of typed-union variants using the supplied variant parser
15
16
union_definition ::= "union" identifier type_parameters? modifiers? "is" variant_definition+ "si"
17
^ we're here
18
*/
19
20
try
21
let variants = Collections.LIST[Trees.Definitions.Definition]()
22
23
let start = context.location
24
let end mut = context.location
25
26
while context.current_token != Lexical.TOKEN.SI /\ context.current_token != Lexical.TOKEN.END_OF_INPUT do
27
let variant_start = context.location
28
29
let variant = variant_parser.parse(context)
30
31
if variant? then
32
variants.add(variant)
33
end = variant.location
34
else
35
end = context.location
36
fi
37
38
if !variant? \/ variant.is_poisoned then
39
should_poison = true
40
41
if variant_start.start_column <= context.member_indent \/ context.current_token != Lexical.TOKEN.IDENTIFIER then
42
// either indent is less than the member indent or we're not looking at an idenfier
43
// either way we've likely fallen off the end of the union definition:
44
45
if context.current_token == Lexical.TOKEN.SI then
46
context.next_token()
47
else
48
context.expect_closer(Lexical.TOKEN.SI)
49
fi
50
51
break
52
fi
53
fi
54
od
55
56
let result = Trees.Definitions.LIST(
57
start::end,
58
variants
59
)
60
61
62
result.poison(should_poison)
63
64
return result
65
finally
66
context.in_classy = false
67
yrt
68
si
69
70
lookahead_for_body(context: CONTEXT) -> bool is
71
let want_backtrack = true
72
73
let line = context.current.location.start_line
74
75
let use diagnostics_snapshot = context.diagnostics_speculate_then_backtrack()
76
77
// search on the current line for an 'is'
78
while context.current.location.start_line == line /\ context.current.location.start_column >= context.global_indent do
79
if context.current.token == Lexical.TOKEN.IS then
80
diagnostics_snapshot.commit()
81
82
context.next_token()
83
84
// is on the same line as the start of the class definition means it's likely the block is associated with the
85
// class, and we should parse it as such, even if the first part of the class definition is invalid
86
return true
87
fi
88
89
context.next_token()
90
od
91
92
if context.current_token == Lexical.TOKEN.IS /\ context.current.location.start_column >= context.global_indent then
93
diagnostics_snapshot.commit()
94
context.next_token()
95
96
// again, if the `is` is on the line immediately following the class definition, and it's properly indented,
97
// it's likely the block is associated with the class, and we should parse it as such, even if the first part of
98
// the class definition is invalid
99
return true
100
fi
101
102
return false
103
si
104
si
105
si