Skip to content
← Back

src/syntax/parsers/expressions/primary.ghul

1
namespace Syntax.Parsers.Expressions is
2
use IO.Std;
3
4
use Source;
5
6
use Logging;
7
8
class PRIMARY(
9
identifier_parser: Parser[Trees.Identifiers.Identifier],
10
type_parser: Parser[Trees.TypeExpressions.TypeExpression],
11
expression_parser: Parser[Trees.Expressions.Expression],
12
expression_list_parser: Parser[Trees.Expressions.LIST],
13
expression_tuple_parser: Parser[Trees.Expressions.TUPLE],
14
statement_parser: Parser[Trees.Statements.Statement],
15
statement_list_parser: Parser[Trees.Statements.LIST],
16
variable_list_parser: Parser[Trees.Variables.LIST],
17
pragma_parser: Parser[Trees.Pragmas.PRAGMA]
18
): Base[Trees.Expressions.Expression] is
19
description: string => "primary expression";
20
21
super();
22
23
init(..) is
24
add_parsers();
25
si
26
27
// `@Foo() name: T` — an attribute pragma on a lambda-literal
28
// parameter. Recognised only where a tuple element (and so
29
// potentially a lambda parameter) can start — everywhere else
30
// `@` falls through to the base dispatch and its ordinary
31
// "unexpected token" error, so it never shows up as a spurious
32
// option in an unrelated "expected ..." diagnostic. Whether
33
// this position genuinely turns out to be a lambda parameter
34
// (as opposed to an element of a value tuple that was never
35
// rewritten into one) is checked once the enclosing construct
36
// is known — see COMPILE_TUPLES.visit_tuple and
37
// TUPLE_ELEMENT.rewrite_as_expression.
38
parse(context: CONTEXT) -> Trees.Expressions.Expression? is
39
if context.current.token == Lexical.TOKEN.AT /\ context.allow_tuple_element then
40
return _parse_pragma_variable(context);
41
fi
42
43
return super.parse(context);
44
si
45
46
_parse_pragma_variable(context: CONTEXT) -> Trees.Expressions.Expression is
47
let start = context.location;
48
49
let pragmas = Collections.LIST[Trees.Pragmas.PRAGMA]();
50
51
while context.current.token == Lexical.TOKEN.AT do
52
let pragma = pragma_parser.parse(context);
53
54
if !pragma? then
55
break;
56
fi
57
58
pragmas.add(pragma);
59
od
60
61
context.allow_tuple_element = false;
62
63
let identifier = identifier_parser.parse(context)!;
64
65
if identifier.is_qualified then
66
context.error(identifier.location, "expected a simple parameter name here");
67
fi
68
69
let end mut = identifier.location;
70
let type_expression: Trees.TypeExpressions.TypeExpression mut = Trees.TypeExpressions.INFER(identifier.location);
71
let initializer: Trees.Expressions.Expression? mut = null;
72
73
if context.current.token == Lexical.TOKEN.COLON then
74
context.next_token();
75
let parsed_type = type_parser.parse(context);
76
77
if parsed_type? then
78
type_expression = parsed_type;
79
end = parsed_type.location;
80
fi
81
fi
82
83
if context.current.token == Lexical.TOKEN.ASSIGN then
84
context.next_token();
85
initializer = expression_parser.parse(context);
86
87
if initializer? then
88
end = initializer.location;
89
fi
90
fi
91
92
let result = Trees.Expressions.VARIABLE(start::end, identifier, type_expression, initializer);
93
result.set_pragmas(pragmas);
94
95
return result;
96
si
97
98
add_parsers() is
99
add_parser(
100
(context) -> Trees.Expressions.Expression is
101
let start = context.location;
102
let identifier = identifier_parser.parse(context)!;
103
104
// A bare unqualified `_` in a value position is the
105
// default-value expression. The `: T` and `= init`
106
// guards keep the typed-discard formal `_: T` on the
107
// identifier path. Binding and pattern positions
108
// (`let _ =`, destructure leaves, `for _`, `if let`)
109
// never reach this parser — they parse identifiers
110
// directly — so the discard meanings don't collide
111
// with the value meaning. Inside a `(...)` group the
112
// speculative tuple/pattern rewrite converts a `_`
113
// element back to a discard leaf via DEFAULT's
114
// try_copy_as_*.
115
if
116
identifier.name =~ "_" /\
117
!identifier.is_qualified /\
118
context.current.token != Lexical.TOKEN.COLON /\
119
context.current.token != Lexical.TOKEN.ASSIGN
120
then
121
// `_[T]` pins the type explicitly. `_` is
122
// never indexable, so a `[` here is the type
123
// argument, not an indexer.
124
let type_expression: Trees.TypeExpressions.TypeExpression? mut = null;
125
126
if context.current_token == Lexical.TOKEN.SQUARE_OPEN then
127
context.next_token();
128
type_expression = type_parser.parse(context);
129
context.next_token(Lexical.TOKEN.SQUARE_CLOSE);
130
fi
131
132
return Trees.Expressions.DEFAULT(start::context.location, type_expression);
133
fi
134
135
if context.allow_tuple_element /\ !identifier.is_qualified then
136
context.allow_tuple_element = false;
137
let end mut = identifier.location;
138
let type_expression: Trees.TypeExpressions.TypeExpression? mut = null;
139
let initializer: Trees.Expressions.Expression? mut = null;
140
141
if context.current.token == Lexical.TOKEN.COLON then
142
context.next_token();
143
type_expression = type_parser.parse(context);
144
end = type_expression!.location;
145
fi
146
147
if context.current.token == Lexical.TOKEN.ASSIGN then
148
context.next_token();
149
initializer = expression_parser.parse(context);
150
end = initializer!.location;
151
fi
152
153
if initializer? then
154
if type_expression == null then
155
type_expression = Trees.TypeExpressions.INFER(context.location);
156
fi
157
fi
158
159
if type_expression? then
160
return Trees.Expressions.VARIABLE(start::end, identifier, type_expression, initializer);
161
fi
162
fi
163
164
return Trees.Expressions.IDENTIFIER(identifier.location, identifier);
165
si, Lexical.TOKEN.IDENTIFIER
166
);
167
168
add_parser(
169
(context) is
170
let start = context.location;
171
context.next_token();
172
173
// `[ ]` with the brackets tokenized separately is the
174
// empty list literal, the same as the `[]` single token;
175
// its element type comes from the surrounding context.
176
let elements =
177
if context.current.token == Lexical.TOKEN.SQUARE_CLOSE then
178
Trees.Expressions.LIST(context.location, Collections.LIST[Trees.Expressions.Expression]())
179
else
180
expression_list_parser.parse(context)!
181
fi;
182
183
let end mut = context.location;
184
context.next_token(Lexical.TOKEN.SQUARE_CLOSE);
185
let type_expression: Trees.TypeExpressions.TypeExpression =
186
if context.current.token == Lexical.TOKEN.COLON then
187
context.next_token();
188
let parsed = type_parser.parse(context)!;
189
end = parsed.location;
190
parsed
191
else
192
Trees.TypeExpressions.INFER(start::end)
193
fi;
194
195
return Trees.Expressions.SEQUENCE(start::end, elements, type_expression);
196
si,
197
Lexical.TOKEN.SQUARE_OPEN
198
);
199
200
add_parser(
201
(context) is
202
// `[]` is a single token. As a value it is the empty
203
// list literal: the element type can't come from the
204
// (absent) elements, so it relies on a constraint pushed
205
// down by the surrounding context — a typed initializer,
206
// a call argument with a known formal type, and so on.
207
// With no such constraint compile_tuples reports
208
// "cannot infer type of list literal with no elements".
209
let location = context.location;
210
211
context.next_token();
212
213
return Trees.Expressions.SEQUENCE(
214
location,
215
Trees.Expressions.LIST(location, Collections.LIST[Trees.Expressions.Expression]()),
216
Trees.TypeExpressions.INFER(location)
217
);
218
si,
219
Lexical.TOKEN.ARRAY_DEF
220
);
221
222
add_parser(
223
(context) is
224
return expression_tuple_parser.parse(context)!;
225
si,
226
Lexical.TOKEN.PAREN_OPEN
227
);
228
229
add_parser(
230
(context) is
231
let start = context.location;
232
233
context.next_token(Lexical.TOKEN.NEW);
234
235
// `new(args)` form: no explicit type, the type
236
// is taken from the surrounding constraint
237
// (LHS of an assignment / typed initializer /
238
// call argument with a known formal type).
239
// Distinguished from `new TYPE(args)` by an
240
// immediately-following `(`.
241
let type_expression: Trees.TypeExpressions.TypeExpression? mut = null;
242
243
if context.current.token != Lexical.TOKEN.PAREN_OPEN then
244
type_expression = type_parser.parse(context);
245
fi
246
247
let arguments: Trees.Expressions.LIST? mut = null;
248
249
if context.next_token(Lexical.TOKEN.PAREN_OPEN) then
250
if context.current.token != Lexical.TOKEN.PAREN_CLOSE then
251
arguments = expression_list_parser.parse(context);
252
fi
253
context.next_token(Lexical.TOKEN.PAREN_CLOSE, syntax_error_message);
254
fi
255
256
if !arguments? then
257
arguments = Trees.Expressions.LIST(context.location, Collections.LIST[Trees.Expressions.Expression]());
258
fi
259
260
return Trees.Expressions.NEW(start::arguments.location, type_expression, arguments);
261
si,
262
Lexical.TOKEN.NEW
263
);
264
265
add_parser(
266
(context) is
267
let start = context.location;
268
269
context.next_token(Lexical.TOKEN.CAST);
270
271
let type_expression = type_parser.parse(context)!;
272
273
context.next_token(Lexical.TOKEN.PAREN_OPEN);
274
275
let value = expression_parser.parse(context)!;
276
let result = Trees.Expressions.CAST(start::context.location, type_expression, value);
277
278
context.next_token(Lexical.TOKEN.PAREN_CLOSE);
279
return result;
280
si,
281
Lexical.TOKEN.CAST
282
);
283
284
add_parser(
285
(context) is
286
let start = context.location;
287
context.next_token(Lexical.TOKEN.ISA);
288
let type_expression = type_parser.parse(context)!;
289
context.next_token(Lexical.TOKEN.PAREN_OPEN);
290
let value = expression_parser.parse(context)!;
291
let result = Trees.Expressions.ISA(start::context.location, type_expression, value);
292
context.next_token(Lexical.TOKEN.PAREN_CLOSE);
293
return result;
294
si,
295
Lexical.TOKEN.ISA
296
);
297
298
add_parser(
299
(context) is
300
let start = context.location;
301
context.next_token(Lexical.TOKEN.TYPEOF);
302
let type_expression = type_parser.parse(context)!;
303
let result = Trees.Expressions.TYPEOF(start::context.location, type_expression);
304
return result;
305
si,
306
Lexical.TOKEN.TYPEOF
307
);
308
309
add_parser(
310
(context) is
311
let location = context.location;
312
let value_string = context.current.value_string;
313
context.next_token();
314
return Trees.Expressions.Literals.INTEGER(location, value_string);
315
si,
316
Lexical.TOKEN.INT_LITERAL
317
);
318
319
add_parser(
320
(context) is
321
let location = context.location;
322
let value_string = context.current.value_string;
323
context.next_token();
324
return Trees.Expressions.Literals.FLOAT(location, value_string);
325
si,
326
Lexical.TOKEN.FLOAT_LITERAL
327
);
328
329
add_parser(
330
(context) is
331
let location = context.location;
332
let value_string = context.current.value_string;
333
context.next_token();
334
return Trees.Expressions.Literals.STRING(location, value_string);
335
si,
336
Lexical.TOKEN.STRING_LITERAL
337
);
338
339
add_parser(
340
(context) is
341
let location = context.location;
342
let value_string = context.current.value_string;
343
context.next_token();
344
return Trees.Expressions.Literals.CHARACTER(location, value_string);
345
si,
346
Lexical.TOKEN.CHAR_LITERAL
347
);
348
349
add_parser(
350
(context) => parse_string_with_interpolations(context),
351
Lexical.TOKEN.ENTER_STRING
352
);
353
354
add_parser(
355
(context) is
356
let location = context.location;
357
let value_string = context.current.value_string;
358
context.next_token();
359
return Trees.Expressions.Literals.BOOLEAN(location, value_string);
360
si,
361
[Lexical.TOKEN.TRUE, Lexical.TOKEN.FALSE]
362
);
363
364
add_parser(
365
(context) is
366
let location = context.location;
367
context.next_token();
368
return Trees.Expressions.NULL(location);
369
si,
370
Lexical.TOKEN.NULL
371
);
372
373
add_parser(
374
(context) is
375
let location = context.location;
376
context.next_token();
377
return Trees.Expressions.SELF(location);
378
si,
379
Lexical.TOKEN.SELF
380
);
381
382
add_parser(
383
(context) is
384
let location = context.location;
385
context.next_token();
386
return Trees.Expressions.SUPER(location);
387
si, Lexical.TOKEN.SUPER
388
);
389
390
add_parser(
391
(context) is
392
let location = context.location;
393
context.next_token();
394
return Trees.Expressions.RECURSE(location);
395
si, Lexical.TOKEN.REC
396
);
397
398
add_parser(
399
(context) -> Trees.Expressions.Expression is
400
let statement = statement_parser.parse(context)!;
401
402
return Trees.Expressions.STATEMENT(statement.location, statement);
403
si, Lexical.TOKEN.IF
404
);
405
406
add_parser(
407
(context) -> Trees.Expressions.Expression is
408
let statement = statement_parser.parse(context)!;
409
410
return Trees.Expressions.STATEMENT(statement.location, statement);
411
si, Lexical.TOKEN.CASE
412
);
413
414
// `val ... lav` — a value-producing block. The block's
415
// value is the LUB of its tail expression (if it provides
416
// one) and every `return E` whose target is this block;
417
// `return E` inside a `val ... lav` exits the innermost
418
// enclosing val-block rather than the enclosing function.
419
add_parser(
420
(context) -> Trees.Expressions.Expression is
421
let start = context.location;
422
context.next_token(Lexical.TOKEN.VAL);
423
let statements = statement_list_parser.parse(context)!;
424
let end = context.location;
425
context.next_token(Lexical.TOKEN.LAV, syntax_error_message);
426
return Trees.Expressions.VAL_BLOCK(start::end, statements);
427
si, Lexical.TOKEN.VAL
428
);
429
430
add_parser(
431
(context) is
432
let start = context.location;
433
context.next_token();
434
let want_dispose = false;
435
if context.current_token == Lexical.TOKEN.USE then
436
// TODO it's not totally clear what the scope of the
437
// use should be - just the expression? There may not
438
// be a clear statement block given that we're in an
439
// expression context
440
context.error(context.location, "use is not supported in this context");
441
442
context.next_token();
443
444
// want_dispose = true;
445
fi
446
447
let variable_list = variable_list_parser.parse(context)!;
448
449
let expression =
450
if context.next_token(Lexical.TOKEN.IN) then
451
expression_parser.parse(context)!
452
else
453
Trees.Expressions.Literals.NONE(start::variable_list.location)
454
fi;
455
456
let location = start::expression.location;
457
458
return Trees.Expressions.LET_IN(
459
location,
460
want_dispose,
461
variable_list,
462
expression
463
);
464
si,
465
Lexical.TOKEN.LET
466
);
467
468
add_parser(
469
(context) is
470
let start = context.location;
471
context.next_token();
472
473
let condition = expression_parser.parse(context)!;
474
475
let message: Trees.Expressions.Expression? mut = null;
476
477
if context.current_token == Lexical.TOKEN.ELSE then
478
context.next_token();
479
message = expression_parser.parse(context);
480
fi
481
482
let expression =
483
if context.next_token(Lexical.TOKEN.IN, syntax_error_message) then
484
expression_parser.parse(context)!
485
else
486
Trees.Expressions.Literals.NONE(start::condition.location)
487
fi;
488
489
let location = start::expression.location;
490
491
return Trees.Expressions.ASSERT_IN(
492
location,
493
condition,
494
message,
495
expression
496
);
497
si,
498
Lexical.TOKEN.ASSERT
499
);
500
si
501
502
parse_string_with_interpolations(context: CONTEXT) -> Trees.Expressions.Expression is
503
// ENTER_STRING expression (':' FORMAT_STRING)? (CONTINUE_STRING expression (':' FORMAT_STRING)? )* (EXIT_STRING | CANCEL_STRING)
504
// ^ we're here
505
506
let start = context.location;
507
508
let fragments = Collections.LIST[Trees.Expressions.INTERPOLATION_FRAGMENT]();
509
510
let is_first mut = true;
511
let success mut = false;
512
let line mut = start.start_line;
513
514
while
515
context.current_token != Lexical.TOKEN.EXIT_STRING
516
do
517
// a newline in the string part will result in a CANCEL_STRING token
518
// we should stop parsing the string and return immediately
519
// TODO: return the interpolation that we've assembled so far
520
521
if context.current_token == Lexical.TOKEN.CANCEL_STRING then
522
// TODO might want to skip to end of line, as the input could be garbled
523
context.next_token();
524
return Trees.Expressions.Literals.STRING(start::context.location, "");
525
fi
526
527
// we've either just entered a string interpolation, or we've just passed a closing curly bracket
528
// either way we're expecting a string fragment
529
530
line = context.location.start_line;
531
532
let success_line = parse_single_interpolated_string_fragment(context, is_first, fragments);
533
success = success_line.success;
534
line = success_line.line;
535
536
if !success then
537
skip_to_end_of_string_with_interpolations(context, line);
538
539
return Trees.Expressions.Literals.STRING(start::context.location, "");
540
fi
541
542
if context.current_token == Lexical.TOKEN.CANCEL_STRING then
543
// TODO might want to skip to end of line, as the input could be garbled
544
context.next_token();
545
return Trees.Expressions.Literals.STRING(start::context.location, "");
546
fi
547
548
(success, line) = parse_single_interpolated_expression(context, fragments);
549
550
if !success then
551
skip_to_end_of_string_with_interpolations(context, line);
552
553
return Trees.Expressions.Literals.STRING(start::context.location, "");
554
fi
555
556
is_first = false;
557
od
558
559
if context.current_token == Lexical.TOKEN.CANCEL_STRING then
560
context.next_token();
561
elif context.current_token != Lexical.TOKEN.EXIT_STRING then
562
context.error(context.location, "unexpected token in string interpolation");
563
564
if context.location.start_line == start.start_line then
565
skip_to_end_of_string_with_interpolations(context, line);
566
fi
567
else
568
parse_single_interpolated_string_fragment(context, is_first, fragments);
569
fi
570
571
let end = context.location;
572
573
let expression_count mut = 0;
574
let should_poison mut = false;
575
let total_fragment_length mut = 0;
576
577
for e in fragments do
578
if e.is_expression then
579
expression_count = expression_count + 1;
580
if e.expression.is_poisoned then
581
should_poison = true;
582
fi
583
else
584
let fragment = cast Trees.Expressions.Literals.STRING?(e.expression)!;
585
let fragment_length = fragment.value_string.length;
586
587
total_fragment_length = total_fragment_length + fragment_length;
588
fi
589
od
590
591
let result = Trees.Expressions.STRING_INTERPOLATION(start::end, fragments, total_fragment_length, expression_count);
592
593
return result;
594
si
595
596
skip_to_end_of_string_with_interpolations(context: CONTEXT, line: int) is
597
let retries mut = 50;
598
599
while
600
context.current_token != Lexical.TOKEN.EXIT_STRING /\
601
context.current_token != Lexical.TOKEN.CANCEL_STRING /\
602
context.location.start_line == line /\
603
!context.is_end_of_file /\
604
retries > 0
605
do
606
context.next_token();
607
retries = retries - 1;
608
od
609
si
610
611
parse_single_interpolated_string_fragment(
612
context: CONTEXT,
613
is_first: bool,
614
into: Collections.MutableList[Trees.Expressions.INTERPOLATION_FRAGMENT]
615
) ->
616
(success: bool, line: int)
617
is
618
// ENTER_STRING expression (':' FORMAT_STRING)? (CONTINUE_STRING expression (':' FORMAT_STRING)? )* (EXIT_STRING | CANCEL_STRING)
619
// ^ we're here ^ or here ^ or here
620
621
// we've either just entered a string interpolation, or we've just passed a closing curly bracket
622
// either way we're expecting a string fragment
623
624
if is_first then
625
if !context.expect_token(Lexical.TOKEN.ENTER_STRING) then
626
return (false, 0);
627
fi
628
else
629
if
630
context.current_token != Lexical.TOKEN.CONTINUE_STRING /\
631
context.current_token != Lexical.TOKEN.EXIT_STRING
632
then
633
context.logger.error(context.location, "syntax error: expected }} but found {context.current_token_name}");
634
635
return (false, 0);
636
fi
637
fi
638
639
into.add(
640
Trees.Expressions.INTERPOLATION_FRAGMENT(
641
false,
642
Trees.Expressions.Literals.STRING(context.location, context.current_string!),
643
null,
644
null
645
)
646
);
647
648
let line = context.location.start_line;
649
650
context.next_token();
651
652
return (true, line);
653
si
654
655
parse_single_interpolated_expression(context: CONTEXT, into: Collections.MutableList[Trees.Expressions.INTERPOLATION_FRAGMENT]) -> (success: bool, line: int) is
656
// ENTER_STRING expression (':' FORMAT_STRING)? (CONTINUE_STRING expression (':' FORMAT_STRING)? )* (EXIT_STRING | CANCEL_STRING)
657
// ^ we're here ^ or here
658
659
let start = context.location;
660
661
let expression: Trees.Expressions.Expression mut;
662
663
// Neither an interpolated expression nor the alignment
664
// after it is ever a formal-argument list, and the `:` that
665
// can follow either opens a format specifier rather than a
666
// type. Clear the flag the enclosing expression list may
667
// have left set for the whole fragment, so nothing inside
668
// it consumes that `:`.
669
let previous_allow_tuple_element = context.allow_tuple_element;
670
context.allow_tuple_element = false;
671
672
if context.current_token != Lexical.TOKEN.CONTINUE_STRING then
673
expression = expression_parser.parse(context)!;
674
else
675
expression = Trees.Expressions.Literals.STRING(context.location, "");
676
context.logger.error(context.location, "expected an expression");
677
context.next_token();
678
fi
679
680
if expression.is_poisoned then
681
if
682
context.current_token != Lexical.TOKEN.COMMA /\
683
context.current_token != Lexical.TOKEN.COLON /\
684
context.current_token != Lexical.TOKEN.CONTINUE_STRING /\
685
context.current_token != Lexical.TOKEN.EXIT_STRING
686
then
687
context.allow_tuple_element = previous_allow_tuple_element;
688
return (false, 0);
689
fi
690
fi
691
692
let alignment: Trees.Expressions.Expression? mut = null;
693
let format: string? mut = null;
694
695
let line mut = 0;
696
697
if context.current_token == Lexical.TOKEN.COMMA then
698
context.next_token();
699
700
alignment = expression_parser.parse(context)!;
701
702
if alignment.is_poisoned then
703
if
704
context.current_token != Lexical.TOKEN.COLON /\
705
context.current_token != Lexical.TOKEN.CONTINUE_STRING /\
706
context.current_token != Lexical.TOKEN.EXIT_STRING
707
then
708
context.allow_tuple_element = previous_allow_tuple_element;
709
return (false, 0);
710
fi
711
fi
712
713
line = alignment.location.end_line;
714
fi
715
716
if context.current_token == Lexical.TOKEN.COLON then
717
context.expect_format_specifier();
718
719
context.next_token();
720
721
if context.expect_token(Lexical.TOKEN.FORMAT_STRING) then
722
format = context.current_string;
723
line = context.location.end_line;
724
725
context.next_token();
726
fi
727
fi
728
729
context.allow_tuple_element = previous_allow_tuple_element;
730
731
into.add(Trees.Expressions.INTERPOLATION_FRAGMENT(true, expression, alignment, format));
732
733
return (true, line);
734
si
735
736
other_token(context: CONTEXT) -> Trees.Expressions.Expression is
737
super.other_token(context);
738
739
let result = Trees.Expressions.Literals.NONE(context.location);
740
741
result.poison();
742
743
return result;
744
si
745
746
si
747
si