Skip to content
← Back

src/syntax/parsers/variables/list.ghul

1
namespace Syntax.Parsers.Variables is
2
use Source
3
use Logging
4
5
class LIST(variable_parser: Parser[Trees.Variables.VARIABLE]): Base[Trees.Variables.LIST] is
6
allow_empty: bool
7
8
super()
9
10
parse(context: CONTEXT) -> Trees.Variables.LIST is
11
let start = context.location
12
let end mut = context.location
13
let variables = Collections.LIST[Trees.Variables.VARIABLE]()
14
15
if
16
context.current_token == Lexical.TOKEN.IDENTIFIER \/
17
context.current_token == Lexical.TOKEN.PAREN_OPEN \/
18
(context.current.token == Lexical.TOKEN.OPERATOR /\ context.current.value_string =~ "..") \/
19
(context.in_formal_arguments /\ context.current_token == Lexical.TOKEN.AT) \/
20
!allow_empty
21
then
22
do
23
let variable: Trees.Variables.VARIABLE? mut
24
25
variable = variable_parser.parse(context)
26
27
if variable? /\ variable.is_variable then
28
// FIXME: parsing destructure list within an argument list probably
29
// makes this more fragile, and we don't support it anyway - should
30
// disable destructure list parsing in in the variable list parser
31
// when parsing an argument list
32
33
// A `(` straight after a variable on the same line
34
// means its name was probably absorbed from a
35
// following function declaration; recover below. A
36
// line-start `(` is not that mistake - it opens the
37
// next statement, and the variable is complete.
38
if
39
context.current.token == Lexical.TOKEN.PAREN_OPEN /\
40
!context.current.first_on_line
41
then
42
if variable.is_explicit_type then
43
// we've probably just absorbed the name of a following
44
// function declaration
45
46
// exclude the type from the variable's location
47
// to stop the error message running on into
48
// the following function declaration
49
let name_location = variable.name!.location
50
51
end = name_location
52
53
// clear the type expression so we don't report a spurious error
54
// about it being undefined
55
variable.set_type_expression(Trees.TypeExpressions.INFER(name_location))
56
57
variables.add(variable)
58
else
59
context.expect_token(Lexical.TOKEN.COLON)
60
fi
61
62
break
63
fi
64
65
end = variable.location
66
67
variables.add(variable)
68
69
// An identifier hard on the heels of a variable is
70
// probably another variable missing its comma - but
71
// only on the same line. One that opens a new line is
72
// the next statement, ended by the line break.
73
if
74
context.current.token == Lexical.TOKEN.IDENTIFIER /\
75
!context.current.first_on_line /\
76
context.location.start_column > variable.location.end_column
77
then
78
context.expect_token(Lexical.TOKEN.COMMA)
79
elif context.is_end_of_file \/ context.current.token != Lexical.TOKEN.COMMA then
80
break
81
else
82
end = context.location
83
context.next_token()
84
85
// Trailing comma: stop when what follows
86
// can't start another variable. Permits
87
// formal-argument lists, let-statement
88
// variable lists, and destructuring
89
// patterns to end with a comma.
90
if
91
context.current.token != Lexical.TOKEN.IDENTIFIER /\
92
context.current.token != Lexical.TOKEN.PAREN_OPEN /\
93
!(context.current.token == Lexical.TOKEN.OPERATOR /\ context.current.value_string =~ "..") /\
94
!(context.in_formal_arguments /\ context.current.token == Lexical.TOKEN.AT)
95
then
96
break
97
fi
98
fi
99
100
else
101
break
102
fi
103
od
104
fi
105
106
return Trees.Variables.LIST(start::end, variables)
107
si
108
si
109
si