Skip to content
← Back

src/syntax/parsers/expressions/primary.ghul

1
namespace Syntax.Parsers.Expressions is
2
use IO.Std
3
use Ghul.Disposable
4
5
use Source
6
7
use Logging
8
9
class PRIMARY(
10
identifier_parser: Parser[Trees.Identifiers.Identifier],
11
type_parser: Parser[Trees.TypeExpressions.TypeExpression],
12
expression_parser: Parser[Trees.Expressions.Expression],
13
expression_list_parser: Parser[Trees.Expressions.LIST],
14
expression_tuple_parser: Parser[Trees.Expressions.Expression],
15
statement_parser: Parser[Trees.Statements.Statement],
16
statement_list_parser: Parser[Trees.Statements.LIST],
17
variable_list_parser: Parser[Trees.Variables.LIST],
18
pragma_parser: Parser[Trees.Pragmas.PRAGMA]
19
): Base[Trees.Expressions.Expression] is
20
description: string => "primary expression"
21
22
super()
23
24
init(..) is
25
add_parsers()
26
si
27
28
// `@Foo() name: T` — an attribute pragma on a lambda-literal
29
// parameter. Recognised only where a tuple element (and so
30
// potentially a lambda parameter) can start — everywhere else
31
// `@` falls through to the base dispatch and its ordinary
32
// "unexpected token" error, so it never shows up as a spurious
33
// option in an unrelated "expected ..." diagnostic. Whether
34
// this position genuinely turns out to be a lambda parameter
35
// (as opposed to an element of a value tuple that was never
36
// rewritten into one) is checked once the enclosing construct
37
// is known — see COMPILE_TUPLES.visit_tuple and
38
// TUPLE_ELEMENT.rewrite_as_expression.
39
parse(context: CONTEXT) -> Trees.Expressions.Expression? is
40
if context.current.token == Lexical.TOKEN.AT /\ context.allow_tuple_element then
41
return _parse_pragma_variable(context)
42
fi
43
44
return super.parse(context)
45
si
46
47
_parse_pragma_variable(context: CONTEXT) -> Trees.Expressions.Expression is
48
let start = context.location
49
50
let pragmas = Collections.LIST[Trees.Pragmas.PRAGMA]()
51
52
while context.current.token == Lexical.TOKEN.AT do
53
let pragma = pragma_parser.parse(context)
54
55
if !pragma? then
56
break
57
fi
58
59
pragmas.add(pragma)
60
od
61
62
context.allow_tuple_element = false
63
64
let identifier = identifier_parser.parse(context)!
65
66
if identifier.is_qualified then
67
context.error(identifier.location, "expected a simple parameter name here")
68
fi
69
70
let end mut = identifier.location
71
let type_expression: Trees.TypeExpressions.TypeExpression mut = Trees.TypeExpressions.INFER(identifier.location)
72
let initializer: Trees.Expressions.Expression? mut = null
73
74
if context.current.token == Lexical.TOKEN.COLON then
75
context.next_token()
76
let parsed_type = type_parser.parse(context)
77
78
if parsed_type? then
79
type_expression = parsed_type
80
end = parsed_type.location
81
fi
82
fi
83
84
if context.current.token == Lexical.TOKEN.ASSIGN then
85
context.next_token()
86
initializer = expression_parser.parse(context)
87
88
if initializer? then
89
end = initializer.location
90
fi
91
fi
92
93
let result = Trees.Expressions.VARIABLE(start::end, identifier, type_expression, initializer)
94
result.set_pragmas(pragmas)
95
96
return result
97
si
98
99
// The target type of a `cast`, or null when it is elided and
100
// comes from the context instead. Tuple types are
101
// parenthesised, so `cast (int, string)(v)` opens with the same
102
// token as `cast(v)`: a type is only taken as the target when
103
// one parses cleanly *and* the argument list's `(` follows it.
104
// Cleanly is what separates the two - `cast(f(3))` reaches a
105
// `(` where the type expression wanted a `)`, and taking the
106
// half-parsed `f` as the target loses the call and leaves the
107
// type parse's own errors behind. `cast (f)(x)` still reads as
108
// a cast to the parenthesised type `(f)`, as it did before the
109
// elided form existed.
110
_try_parse_cast_type(context: CONTEXT) -> Trees.TypeExpressions.TypeExpression? is
111
if context.current.token != Lexical.TOKEN.PAREN_OPEN then
112
return type_parser.parse(context)!
113
fi
114
115
let use diagnostics_snapshot = context.diagnostics_speculate_then_backtrack()
116
let use snapshot = context.tokenizer_speculate_then_backtrack()
117
118
let errors_before = context.logger.error_count
119
120
let type_expression = type_parser.parse(context)
121
122
if
123
type_expression? /\
124
!type_expression.is_poisoned /\
125
context.logger.error_count == errors_before /\
126
context.current.token == Lexical.TOKEN.PAREN_OPEN
127
then
128
snapshot.commit()
129
diagnostics_snapshot.commit()
130
131
return type_expression
132
fi
133
134
return null
135
si
136
137
add_parsers() is
138
add_parser(
139
(context) -> Trees.Expressions.Expression is
140
let start = context.location
141
let identifier = identifier_parser.parse(context)!
142
143
// A bare unqualified `_` in a value position is the
144
// default-value expression. The `: T` and `= init`
145
// guards keep the typed-discard formal `_: T` on the
146
// identifier path. Binding and pattern positions
147
// (`let _ =`, destructure leaves, `for _`, `if let`)
148
// never reach this parser — they parse identifiers
149
// directly — so the discard meanings don't collide
150
// with the value meaning. Inside a `(...)` group the
151
// speculative tuple/pattern rewrite converts a `_`
152
// element back to a discard leaf via DEFAULT's
153
// try_copy_as_*.
154
if
155
identifier.name =~ "_" /\
156
!identifier.is_qualified /\
157
context.current.token != Lexical.TOKEN.COLON /\
158
context.current.token != Lexical.TOKEN.ASSIGN
159
then
160
// `_(args)` constructs the type the context
161
// expects. `_` is never callable, so a `(` here
162
// opens a constructor argument list, by the same
163
// reasoning that makes `[` a type argument below.
164
if context.current_token == Lexical.TOKEN.PAREN_OPEN then
165
context.next_token()
166
167
let arguments: Trees.Expressions.LIST? mut = null
168
169
if context.current.token != Lexical.TOKEN.PAREN_CLOSE then
170
arguments = expression_list_parser.parse(context)
171
fi
172
173
context.next_token(Lexical.TOKEN.PAREN_CLOSE, syntax_error_message)
174
175
if !arguments? then
176
arguments =
177
Trees.Expressions.LIST(
178
context.location,
179
Collections.LIST[Trees.Expressions.Expression]()
180
)
181
fi
182
183
return Trees.Expressions.CONSTRUCT(start::arguments.location, arguments)
184
fi
185
186
// `_[T]` pins the type explicitly. `_` is
187
// never indexable, so a `[` here is the type
188
// argument, not an indexer.
189
let type_expression: Trees.TypeExpressions.TypeExpression? mut = null
190
191
if context.current_token == Lexical.TOKEN.SQUARE_OPEN then
192
context.next_token()
193
type_expression = type_parser.parse(context)
194
context.next_token(Lexical.TOKEN.SQUARE_CLOSE)
195
fi
196
197
return Trees.Expressions.DEFAULT(start::context.location, type_expression)
198
fi
199
200
if context.allow_tuple_element /\ !identifier.is_qualified then
201
context.allow_tuple_element = false
202
let end mut = identifier.location
203
let type_expression: Trees.TypeExpressions.TypeExpression? mut = null
204
let initializer: Trees.Expressions.Expression? mut = null
205
206
if context.current.token == Lexical.TOKEN.COLON then
207
context.next_token()
208
type_expression = type_parser.parse(context)
209
end = type_expression!.location
210
fi
211
212
if context.current.token == Lexical.TOKEN.ASSIGN then
213
context.next_token()
214
initializer = expression_parser.parse(context)
215
end = initializer!.location
216
fi
217
218
if initializer? then
219
if type_expression == null then
220
type_expression = Trees.TypeExpressions.INFER(context.location)
221
fi
222
fi
223
224
if type_expression? then
225
return Trees.Expressions.VARIABLE(start::end, identifier, type_expression, initializer)
226
fi
227
fi
228
229
return Trees.Expressions.IDENTIFIER(identifier.location, identifier)
230
si, Lexical.TOKEN.IDENTIFIER
231
)
232
233
add_parser(
234
(context) is
235
let start = context.location
236
context.next_token()
237
238
// `[ ]` with the brackets tokenized separately is the
239
// empty list literal, the same as the `[]` single token;
240
// its element type comes from the surrounding context.
241
let elements =
242
if context.current.token == Lexical.TOKEN.SQUARE_CLOSE then
243
Trees.Expressions.LIST(context.location, Collections.LIST[Trees.Expressions.Expression]())
244
else
245
expression_list_parser.parse(context)!
246
fi
247
248
let end mut = context.location
249
context.next_token(Lexical.TOKEN.SQUARE_CLOSE)
250
let type_expression: Trees.TypeExpressions.TypeExpression =
251
if context.current.token == Lexical.TOKEN.COLON then
252
context.next_token()
253
let parsed = type_parser.parse(context)!
254
end = parsed.location
255
parsed
256
else
257
Trees.TypeExpressions.INFER(start::end)
258
fi
259
260
return Trees.Expressions.SEQUENCE(start::end, elements, type_expression)
261
si,
262
Lexical.TOKEN.SQUARE_OPEN
263
)
264
265
add_parser(
266
(context) is
267
// `[]` is a single token. As a value it is the empty
268
// list literal: the element type can't come from the
269
// (absent) elements, so it relies on a constraint pushed
270
// down by the surrounding context — a typed initializer,
271
// a call argument with a known formal type, and so on.
272
// With no such constraint compile_tuples reports
273
// "cannot infer type of list literal with no elements".
274
let location = context.location
275
276
context.next_token()
277
278
return Trees.Expressions.SEQUENCE(
279
location,
280
Trees.Expressions.LIST(location, Collections.LIST[Trees.Expressions.Expression]()),
281
Trees.TypeExpressions.INFER(location)
282
)
283
si,
284
Lexical.TOKEN.ARRAY_DEF
285
)
286
287
add_parser(
288
(context) is
289
return expression_tuple_parser.parse(context)!
290
si,
291
Lexical.TOKEN.PAREN_OPEN
292
)
293
294
// `new` is no longer part of the language, but it stays a
295
// reserved token so that reaching one here can say so. Freed
296
// as an identifier it would instead report a symbol that does
297
// not exist, which says nothing about what to write instead.
298
// Consuming just the keyword and parsing on leaves
299
// `TYPE(args)`, which is what the construction should have
300
// been written as, so the rest of the expression analyses
301
// normally and the reader gets this error alone rather than a
302
// cascade behind it.
303
add_parser(
304
(context) is
305
let location = context.location
306
307
context.next_token(Lexical.TOKEN.NEW)
308
309
context.logger.error(
310
location,
311
"new is not supported",
312
location,
313
"help: construct by calling the type, as in TYPE(arguments)"
314
)
315
316
let expression = parse(context)
317
318
if !expression? then
319
return Trees.Expressions.Literals.STRING(location, "")
320
fi
321
322
return expression
323
si,
324
Lexical.TOKEN.NEW
325
)
326
327
add_parser(
328
(context) -> Trees.Expressions.Expression is
329
let start = context.location
330
331
context.next_token(Lexical.TOKEN.CAST)
332
333
let opens_with_group = context.current.token == Lexical.TOKEN.PAREN_OPEN
334
335
let type_expression = _try_parse_cast_type(context)
336
337
context.next_token(Lexical.TOKEN.PAREN_OPEN)
338
339
// A parenthesised target reads two ways whenever it
340
// is also a value: as the cast's target type with
341
// the parentheses that follow holding its value, or
342
// as the cast's value with those parentheses
343
// calling the result. Both readings are carried to
344
// resolve-type-expressions, which can ask the scope
345
// which of the two the name is. A target that only
346
// reads as a type - a tuple, a function type - is
347
// unambiguous: its value reading could not be
348
// called. A name is the only target shape whose
349
// value reading is callable, so it is the only one
350
// taken as ambiguous.
351
let called_value =
352
if
353
opens_with_group /\
354
isa Trees.TypeExpressions.NAMED(type_expression)
355
then
356
type_expression.try_copy_as_value_expression()
357
else
358
null
359
fi
360
361
if called_value? /\ type_expression? then
362
let arguments =
363
if context.current.token != Lexical.TOKEN.PAREN_CLOSE then
364
expression_list_parser.parse(context)!
365
else
366
Trees.Expressions.LIST(
367
context.location,
368
Collections.LIST[Trees.Expressions.Expression]()
369
)
370
fi
371
372
let end = context.location
373
374
context.next_token(Lexical.TOKEN.PAREN_CLOSE)
375
376
// A cast takes one value, so an argument list of
377
// any other length settles the reading here: only
378
// the call can be meant, and it is built as one.
379
if arguments.expressions.count != 1 then
380
return Trees.Expressions.CALL(
381
start::end,
382
Trees.Expressions.CAST(start::end, null, called_value, true),
383
arguments
384
)
385
fi
386
387
let result =
388
Trees.Expressions.CAST(
389
start::end,
390
type_expression,
391
arguments.expressions[0],
392
true
393
)
394
395
result.set_ambiguous_readings(
396
Trees.Expressions.CALL(
397
start::end,
398
Trees.Expressions.CAST(start::end, null, called_value, true),
399
arguments
400
),
401
arguments
402
)
403
404
return result
405
fi
406
407
let value = expression_parser.parse(context)!
408
let result = Trees.Expressions.CAST(start::context.location, type_expression, value, true)
409
410
context.next_token(Lexical.TOKEN.PAREN_CLOSE)
411
return result
412
si,
413
Lexical.TOKEN.CAST
414
)
415
416
add_parser(
417
(context) is
418
let start = context.location
419
context.next_token(Lexical.TOKEN.ISA)
420
let type_expression = type_parser.parse(context)!
421
context.next_token(Lexical.TOKEN.PAREN_OPEN)
422
let value = expression_parser.parse(context)!
423
let result = Trees.Expressions.ISA(start::context.location, type_expression, value)
424
context.next_token(Lexical.TOKEN.PAREN_CLOSE)
425
return result
426
si,
427
Lexical.TOKEN.ISA
428
)
429
430
add_parser(
431
(context) is
432
let start = context.location
433
context.next_token(Lexical.TOKEN.TYPEOF)
434
let type_expression = type_parser.parse(context)!
435
let result = Trees.Expressions.TYPEOF(start::context.location, type_expression)
436
return result
437
si,
438
Lexical.TOKEN.TYPEOF
439
)
440
441
add_parser(
442
(context) is
443
let location = context.location
444
let value_string = context.current.value_string
445
context.next_token()
446
return Trees.Expressions.Literals.INTEGER(location, value_string)
447
si,
448
Lexical.TOKEN.INT_LITERAL
449
)
450
451
add_parser(
452
(context) is
453
let location = context.location
454
let value_string = context.current.value_string
455
context.next_token()
456
return Trees.Expressions.Literals.FLOAT(location, value_string)
457
si,
458
Lexical.TOKEN.FLOAT_LITERAL
459
)
460
461
add_parser(
462
(context) is
463
let location = context.location
464
let value_string = context.current.value_string
465
context.next_token()
466
return Trees.Expressions.Literals.STRING(location, value_string)
467
si,
468
Lexical.TOKEN.STRING_LITERAL
469
)
470
471
add_parser(
472
(context) is
473
let location = context.location
474
let value_string = context.current.value_string
475
context.next_token()
476
return Trees.Expressions.Literals.CHARACTER(location, value_string)
477
si,
478
Lexical.TOKEN.CHAR_LITERAL
479
)
480
481
add_parser(
482
(context) => parse_string_with_interpolations(context),
483
Lexical.TOKEN.ENTER_STRING
484
)
485
486
add_parser(
487
(context) is
488
let location = context.location
489
let value_string = context.current.value_string
490
context.next_token()
491
return Trees.Expressions.Literals.BOOLEAN(location, value_string)
492
si,
493
[Lexical.TOKEN.TRUE, Lexical.TOKEN.FALSE]
494
)
495
496
add_parser(
497
(context) is
498
let location = context.location
499
context.next_token()
500
return Trees.Expressions.NULL(location)
501
si,
502
Lexical.TOKEN.NULL
503
)
504
505
add_parser(
506
(context) is
507
let location = context.location
508
context.next_token()
509
return Trees.Expressions.SELF(location)
510
si,
511
Lexical.TOKEN.SELF
512
)
513
514
add_parser(
515
(context) is
516
let location = context.location
517
context.next_token()
518
return Trees.Expressions.SUPER(location)
519
si, Lexical.TOKEN.SUPER
520
)
521
522
add_parser(
523
(context) is
524
let location = context.location
525
context.next_token()
526
return Trees.Expressions.RECURSE(location)
527
si, Lexical.TOKEN.REC
528
)
529
530
add_parser(
531
(context) -> Trees.Expressions.Expression is
532
// A compound statement in element position settles
533
// the element: it is never a lambda's formal
534
// parameter. The flag has to be cleared before the
535
// body is parsed, not merely when the element is
536
// complete - inside the body, `name = e` is an
537
// assignment statement, while the flag says to read
538
// it as a named element, which declares a local
539
// shadowing the one being assigned.
540
context.allow_tuple_element = false
541
542
let statement = statement_parser.parse(context)!
543
544
return Trees.Expressions.STATEMENT(statement.location, statement)
545
si, Lexical.TOKEN.IF
546
)
547
548
add_parser(
549
(context) -> Trees.Expressions.Expression is
550
context.allow_tuple_element = false
551
552
let statement = statement_parser.parse(context)!
553
554
return Trees.Expressions.STATEMENT(statement.location, statement)
555
si, Lexical.TOKEN.CASE
556
)
557
558
// Loops in expression position: same delegation as `if` /
559
// `case`. The wrapped statement produces a value only when a
560
// valued `break` targets it; compile-expressions reports the
561
// value-less forms.
562
add_parser(
563
(context) -> Trees.Expressions.Expression is
564
context.allow_tuple_element = false
565
566
let statement = statement_parser.parse(context)!
567
568
return Trees.Expressions.STATEMENT(statement.location, statement)
569
si, Lexical.TOKEN.DO
570
)
571
572
add_parser(
573
(context) -> Trees.Expressions.Expression is
574
context.allow_tuple_element = false
575
576
let statement = statement_parser.parse(context)!
577
578
return Trees.Expressions.STATEMENT(statement.location, statement)
579
si, Lexical.TOKEN.FOR
580
)
581
582
add_parser(
583
(context) -> Trees.Expressions.Expression is
584
context.allow_tuple_element = false
585
586
let statement = statement_parser.parse(context)!
587
588
return Trees.Expressions.STATEMENT(statement.location, statement)
589
si, Lexical.TOKEN.WHILE
590
)
591
592
// `val ... lav` — a value-producing block. The block's
593
// value is the LUB of its tail expression (if it provides
594
// one) and every `return E` whose target is this block;
595
// `return E` inside a `val ... lav` exits the innermost
596
// enclosing val-block rather than the enclosing function.
597
add_parser(
598
(context) -> Trees.Expressions.Expression is
599
let start = context.location
600
context.next_token(Lexical.TOKEN.VAL)
601
602
let use open = context.open_construct(Lexical.TOKEN.LAV)
603
let statements = statement_list_parser.parse(context)!
604
let end = context.location
605
context.expect_closer(Lexical.TOKEN.LAV, syntax_error_message)
606
return Trees.Expressions.VAL_BLOCK(start::end, statements)
607
si, Lexical.TOKEN.VAL
608
)
609
610
add_parser(
611
(context) is
612
let start = context.location
613
context.next_token()
614
let want_dispose = false
615
if context.current_token == Lexical.TOKEN.USE then
616
// TODO it's not totally clear what the scope of the
617
// use should be - just the expression? There may not
618
// be a clear statement block given that we're in an
619
// expression context
620
context.error(context.location, "use is not supported in this context")
621
622
context.next_token()
623
624
// want_dispose = true;
625
fi
626
627
let variable_list = variable_list_parser.parse(context)!
628
629
let expression =
630
if context.next_token(Lexical.TOKEN.IN) then
631
expression_parser.parse(context)!
632
else
633
Trees.Expressions.Literals.NONE(start::variable_list.location)
634
fi
635
636
let location = start::expression.location
637
638
return Trees.Expressions.LET_IN(
639
location,
640
want_dispose,
641
variable_list,
642
expression
643
)
644
si,
645
Lexical.TOKEN.LET
646
)
647
648
add_parser(
649
(context) is
650
let start = context.location
651
context.next_token()
652
653
let condition = expression_parser.parse(context)!
654
655
let message: Trees.Expressions.Expression? mut = null
656
657
if context.current_token == Lexical.TOKEN.ELSE /\ context.continues(start) then
658
context.next_token()
659
message = expression_parser.parse(context)
660
fi
661
662
let expression =
663
if context.next_token(Lexical.TOKEN.IN, syntax_error_message) then
664
expression_parser.parse(context)!
665
else
666
Trees.Expressions.Literals.NONE(start::condition.location)
667
fi
668
669
let location = start::expression.location
670
671
return Trees.Expressions.ASSERT_IN(
672
location,
673
condition,
674
message,
675
expression
676
)
677
si,
678
Lexical.TOKEN.ASSERT
679
)
680
si
681
682
parse_string_with_interpolations(context: CONTEXT) -> Trees.Expressions.Expression is
683
// ENTER_STRING expression (':' FORMAT_STRING)? (CONTINUE_STRING expression (':' FORMAT_STRING)? )* (EXIT_STRING | CANCEL_STRING)
684
// ^ we're here
685
686
let start = context.location
687
688
let fragments = Collections.LIST[Trees.Expressions.INTERPOLATION_FRAGMENT]()
689
690
let is_first mut = true
691
let success mut = false
692
let line mut = start.start_line
693
694
while
695
context.current_token != Lexical.TOKEN.EXIT_STRING
696
do
697
// a newline in the string part will result in a CANCEL_STRING token
698
// we should stop parsing the string and return immediately
699
// TODO: return the interpolation that we've assembled so far
700
701
if context.current_token == Lexical.TOKEN.CANCEL_STRING then
702
// TODO might want to skip to end of line, as the input could be garbled
703
context.next_token()
704
return Trees.Expressions.Literals.STRING(start::context.location, "")
705
fi
706
707
// we've either just entered a string interpolation, or we've just passed a closing curly bracket
708
// either way we're expecting a string fragment
709
710
line = context.location.start_line
711
712
let success_line = parse_single_interpolated_string_fragment(context, is_first, fragments)
713
success = success_line.success
714
line = success_line.line
715
716
if !success then
717
skip_to_end_of_string_with_interpolations(context, line)
718
719
return Trees.Expressions.Literals.STRING(start::context.location, "")
720
fi
721
722
if context.current_token == Lexical.TOKEN.CANCEL_STRING then
723
// TODO might want to skip to end of line, as the input could be garbled
724
context.next_token()
725
return Trees.Expressions.Literals.STRING(start::context.location, "")
726
fi
727
728
(success, line) = parse_single_interpolated_expression(context, fragments)
729
730
if !success then
731
skip_to_end_of_string_with_interpolations(context, line)
732
733
return Trees.Expressions.Literals.STRING(start::context.location, "")
734
fi
735
736
is_first = false
737
od
738
739
if context.current_token == Lexical.TOKEN.CANCEL_STRING then
740
context.next_token()
741
elif context.current_token != Lexical.TOKEN.EXIT_STRING then
742
context.error(context.location, "unexpected token in string interpolation")
743
744
if context.location.start_line == start.start_line then
745
skip_to_end_of_string_with_interpolations(context, line)
746
fi
747
else
748
parse_single_interpolated_string_fragment(context, is_first, fragments)
749
fi
750
751
let end = context.location
752
753
let expression_count mut = 0
754
let should_poison mut = false
755
let total_fragment_length mut = 0
756
757
for e in fragments do
758
if e.is_expression then
759
expression_count = expression_count + 1
760
if e.expression.is_poisoned then
761
should_poison = true
762
fi
763
else
764
let fragment = cast Trees.Expressions.Literals.STRING?(e.expression)!
765
let fragment_length = fragment.value_string.length
766
767
total_fragment_length = total_fragment_length + fragment_length
768
fi
769
od
770
771
let result = Trees.Expressions.STRING_INTERPOLATION(start::end, fragments, total_fragment_length, expression_count)
772
773
return result
774
si
775
776
skip_to_end_of_string_with_interpolations(context: CONTEXT, line: int) is
777
let retries mut = 50
778
779
while
780
context.current_token != Lexical.TOKEN.EXIT_STRING /\
781
context.current_token != Lexical.TOKEN.CANCEL_STRING /\
782
context.location.start_line == line /\
783
!context.is_end_of_file /\
784
retries > 0
785
do
786
context.next_token()
787
retries = retries - 1
788
od
789
si
790
791
parse_single_interpolated_string_fragment(
792
context: CONTEXT,
793
is_first: bool,
794
into: Collections.MutableList[Trees.Expressions.INTERPOLATION_FRAGMENT]
795
) ->
796
(success: bool, line: int)
797
is
798
// ENTER_STRING expression (':' FORMAT_STRING)? (CONTINUE_STRING expression (':' FORMAT_STRING)? )* (EXIT_STRING | CANCEL_STRING)
799
// ^ we're here ^ or here ^ or here
800
801
// we've either just entered a string interpolation, or we've just passed a closing curly bracket
802
// either way we're expecting a string fragment
803
804
if is_first then
805
if !context.expect_token(Lexical.TOKEN.ENTER_STRING) then
806
return (false, 0)
807
fi
808
else
809
if
810
context.current_token != Lexical.TOKEN.CONTINUE_STRING /\
811
context.current_token != Lexical.TOKEN.EXIT_STRING
812
then
813
context.logger.error(context.location, "syntax error: expected }} but found {context.current_token_name}")
814
815
return (false, 0)
816
fi
817
fi
818
819
into.add(
820
Trees.Expressions.INTERPOLATION_FRAGMENT(
821
false,
822
Trees.Expressions.Literals.STRING(context.location, context.current_string!),
823
null,
824
null
825
)
826
)
827
828
let line = context.location.start_line
829
830
context.next_token()
831
832
return (true, line)
833
si
834
835
parse_single_interpolated_expression(context: CONTEXT, into: Collections.MutableList[Trees.Expressions.INTERPOLATION_FRAGMENT]) -> (success: bool, line: int) is
836
// ENTER_STRING expression (':' FORMAT_STRING)? (CONTINUE_STRING expression (':' FORMAT_STRING)? )* (EXIT_STRING | CANCEL_STRING)
837
// ^ we're here ^ or here
838
839
let start = context.location
840
841
let expression: Trees.Expressions.Expression mut
842
843
// Neither an interpolated expression nor the alignment
844
// after it is ever a formal-argument list, and the `:` that
845
// can follow either opens a format specifier rather than a
846
// type. Clear the flag the enclosing expression list may
847
// have left set for the whole fragment, so nothing inside
848
// it consumes that `:`.
849
let previous_allow_tuple_element = context.allow_tuple_element
850
context.allow_tuple_element = false
851
852
if context.current_token != Lexical.TOKEN.CONTINUE_STRING then
853
expression = expression_parser.parse(context)!
854
else
855
expression = Trees.Expressions.Literals.STRING(context.location, "")
856
context.logger.error(context.location, "expected an expression")
857
context.next_token()
858
fi
859
860
if expression.is_poisoned then
861
if
862
context.current_token != Lexical.TOKEN.COMMA /\
863
context.current_token != Lexical.TOKEN.COLON /\
864
context.current_token != Lexical.TOKEN.CONTINUE_STRING /\
865
context.current_token != Lexical.TOKEN.EXIT_STRING
866
then
867
context.allow_tuple_element = previous_allow_tuple_element
868
return (false, 0)
869
fi
870
fi
871
872
let alignment: Trees.Expressions.Expression? mut = null
873
let format: string? mut = null
874
875
let line mut = 0
876
877
if context.current_token == Lexical.TOKEN.COMMA then
878
context.next_token()
879
880
alignment = expression_parser.parse(context)!
881
882
if alignment.is_poisoned then
883
if
884
context.current_token != Lexical.TOKEN.COLON /\
885
context.current_token != Lexical.TOKEN.CONTINUE_STRING /\
886
context.current_token != Lexical.TOKEN.EXIT_STRING
887
then
888
context.allow_tuple_element = previous_allow_tuple_element
889
return (false, 0)
890
fi
891
fi
892
893
line = alignment.location.end_line
894
fi
895
896
if context.current_token == Lexical.TOKEN.COLON then
897
context.expect_format_specifier()
898
899
context.next_token()
900
901
if context.expect_token(Lexical.TOKEN.FORMAT_STRING) then
902
format = context.current_string
903
line = context.location.end_line
904
905
context.next_token()
906
fi
907
fi
908
909
context.allow_tuple_element = previous_allow_tuple_element
910
911
into.add(Trees.Expressions.INTERPOLATION_FRAGMENT(true, expression, alignment, format))
912
913
return (true, line)
914
si
915
916
other_token(context: CONTEXT) -> Trees.Expressions.Expression is
917
super.other_token(context)
918
919
let result = Trees.Expressions.Literals.NONE(context.location)
920
921
result.poison()
922
923
return result
924
si
925
926
si
927
si