1use sylt_common::error::Error;
2
3use crate::statement::block_statement;
4
5use super::*;
6
7#[derive(Debug, Clone)]
11pub enum ExpressionKind {
12 Get(Assignable),
15
16 TypeConstant(Type),
18
19 Add(Box<Expression>, Box<Expression>),
21 Sub(Box<Expression>, Box<Expression>),
23 Mul(Box<Expression>, Box<Expression>),
25 Div(Box<Expression>, Box<Expression>),
27 Neg(Box<Expression>),
29
30 Is(Box<Expression>, Box<Expression>),
32
33 Eq(Box<Expression>, Box<Expression>),
35 Neq(Box<Expression>, Box<Expression>),
37 Gt(Box<Expression>, Box<Expression>),
39 Gteq(Box<Expression>, Box<Expression>),
41 Lt(Box<Expression>, Box<Expression>),
43 Lteq(Box<Expression>, Box<Expression>),
45 AssertEq(Box<Expression>, Box<Expression>),
47
48 In(Box<Expression>, Box<Expression>),
50
51 And(Box<Expression>, Box<Expression>),
53 Or(Box<Expression>, Box<Expression>),
55 Not(Box<Expression>),
57
58 IfExpression {
60 condition: Box<Expression>,
61 pass: Box<Expression>,
62 fail: Box<Expression>,
63 },
64
65 Duplicate(Box<Expression>),
67
68 IfShort {
70 condition: Box<Expression>,
71 fail: Box<Expression>,
72 },
73
74 Function {
76 name: String,
77 params: Vec<(Identifier, Type)>,
78 ret: Type,
79
80 body: Box<Statement>,
81 },
82 Instance {
84 blob: Assignable,
85 fields: Vec<(String, Expression)>, },
87 Tuple(Vec<Expression>),
89 List(Vec<Expression>),
91 Set(Vec<Expression>),
93 Dict(Vec<Expression>),
96
97 Float(f64),
98 Int(i64),
99 Str(String),
100 Bool(bool),
101 Nil,
102}
103
104#[derive(Debug, Clone)]
106pub struct Expression {
107 pub span: Span,
108 pub kind: ExpressionKind,
109}
110
111fn function<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
113 use RuntimeType::Void;
114 use TypeKind::Resolved;
115
116 let span = ctx.span();
117 let mut ctx = expect!(ctx, T::Fn, "Expected 'fn' for function expression");
118 let mut params = Vec::new();
119 let ret = loop {
121 match ctx.token() {
122 T::Identifier(name) => {
123 let ident = Identifier {
125 span: ctx.span(),
126 name: name.clone(),
127 };
128 ctx = expect!(ctx.skip(1), T::Colon, "Expected ':' after parameter name");
129 let (_ctx, param) = parse_type(ctx)?;
131 ctx = _ctx; params.push((ident, param));
134
135 ctx = if matches!(ctx.token(), T::Comma | T::Arrow | T::LeftBrace) {
136 ctx.skip_if(T::Comma)
137 } else {
138 raise_syntax_error!(ctx, "Expected ',' '{{' or '->' after type parameter")
139 };
140 }
141
142 T::Arrow => {
144 ctx = ctx.skip(1);
145 break if let Ok((_ctx, ret)) = parse_type(ctx) {
146 ctx = _ctx; ret
148 } else {
149 Type {
150 span: ctx.span(),
152 kind: Resolved(Void),
153 }
154 };
155 }
156
157 T::LeftBrace => {
158 break Type {
160 span: ctx.span(),
161 kind: Resolved(Void),
162 };
163 }
164
165 t => {
166 raise_syntax_error!(ctx, "Didn't expect '{:?}' in function", t);
167 }
168 }
169 };
170
171 let (ctx, mut statement) = block_statement(ctx)?;
173
174 let statements = if let StatementKind::Block { statements } = &mut statement.kind {
177 statements
178 } else {
179 unreachable!("Function blocks should only be blocks");
180 };
181
182 if !matches!(ret.kind, Resolved(Void)) {
183 let last_statement = statements.pop();
186 if let Some(Statement {
187 span,
188 kind: StatementKind::StatementExpression { value },
189 }) = last_statement
190 {
191 statements.push(Statement {
192 span,
193 kind: StatementKind::Ret { value },
194 });
195 } else if let Some(statement) = last_statement {
196 statements.push(statement);
197 }
198 }
199
200 use ExpressionKind::Function;
201 let function = Function {
202 name: "lambda".into(),
203 params,
204 ret,
205 body: Box::new(statement),
206 };
207
208 Ok((
209 ctx,
210 Expression {
211 span,
212 kind: function,
213 },
214 ))
215}
216
217fn parse_precedence<'t>(ctx: Context<'t>, prec: Prec) -> ParseResult<'t, Expression> {
219 let (mut ctx, mut expr) = prefix(ctx)?;
221 while prec <= precedence(ctx.token()) {
222 if let Ok((_ctx, _expr)) = infix(ctx, &expr) {
223 ctx = _ctx;
225 expr = _expr;
226 } else {
227 break;
228 }
229 }
230 Ok((ctx, expr))
231}
232
233#[rustfmt::skip]
238fn precedence(token: &T) -> Prec {
239 use Prec;
240
241 match token {
242 T::LeftBracket => Prec::Index,
243
244 T::Star | T::Slash => Prec::Factor,
245
246 T::Minus | T::Plus => Prec::Term,
247
248 T::EqualEqual
249 | T::Greater
250 | T::GreaterEqual
251 | T::Less
252 | T::LessEqual
253 | T::NotEqual => Prec::Comp,
254
255 T::And => Prec::BoolAnd,
256 T::Or => Prec::BoolOr,
257
258 T::Is => Prec::Index,
259 T::In => Prec::Index,
260
261 T::AssertEqual => Prec::Assert,
262
263 T::Arrow => Prec::Arrow,
264
265 _ => Prec::No,
266 }
267}
268
269fn value<'t>(ctx: Context<'t>) -> Result<(Context<'t>, Expression), (Context<'t>, Vec<Error>)> {
271 use ExpressionKind::*;
272 let (token, span, ctx) = ctx.eat();
273 let kind = match token.clone() {
274 T::Float(f) => Float(f),
275 T::Int(i) => Int(i),
276 T::Bool(b) => Bool(b),
277 T::Nil => Nil,
278 T::String(s) => Str(s),
279 t => {
280 raise_syntax_error!(ctx, "Cannot parse value, '{:?}' is not a valid value", t);
281 }
282 };
283 Ok((ctx, Expression { span, kind }))
284}
285
286fn prefix<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
288 use ExpressionKind::{Get, TypeConstant};
289
290 match ctx.token() {
291 T::LeftParen => grouping_or_tuple(ctx),
292 T::LeftBracket => list(ctx),
293 T::LeftBrace => set_or_dict(ctx),
294
295 T::Colon => {
296 let span = ctx.span();
297 let (ctx, ty) = parse_type(ctx.skip(1))?;
298 Ok((
299 ctx,
300 Expression {
301 span,
302 kind: TypeConstant(ty),
303 },
304 ))
305 }
306
307 T::Float(_) | T::Int(_) | T::Bool(_) | T::String(_) | T::Nil => value(ctx),
308 T::Minus | T::Bang => unary(ctx),
309
310 T::Identifier(_) => {
311 let span = ctx.span();
312 match (blob(ctx), assignable(ctx)) {
313 (Ok(result), _) => Ok(result),
314 (_, Ok((ctx, assign))) => Ok((
315 ctx,
316 Expression {
317 span,
318 kind: Get(assign),
319 },
320 )),
321 (Err((ctx, _)), Err(_)) => {
322 raise_syntax_error!(ctx, "Neither a blob instantiation or an identifier");
323 }
324 }
325 }
326
327 t => {
328 raise_syntax_error!(ctx, "No valid expression starts with '{:?}'", t);
329 }
330 }
331}
332
333fn unary<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
335 use ExpressionKind::{Neg, Not};
336
337 let (op, span, ctx) = ctx.eat();
338 let (ctx, expr) = parse_precedence(ctx, Prec::Factor)?;
339 let expr = Box::new(expr);
340
341 let kind = match op {
342 T::Minus => Neg(expr),
343 T::Bang => Not(expr),
344
345 _ => {
346 raise_syntax_error!(ctx, "Invalid unary operator");
347 }
348 };
349 Ok((ctx, Expression { span, kind }))
350}
351
352fn if_short<'t>(ctx: Context<'t>, lhs: &Expression) -> ParseResult<'t, Expression> {
353 use ExpressionKind::*;
354
355 let span = ctx.span();
356 let ctx = expect!(ctx, T::If, "Expected 'if' at start of if-expression");
357
358 let lhs = Expression {
359 span: lhs.span,
360 kind: Duplicate(Box::new(lhs.clone())),
361 };
362
363 let (ctx, condition) = infix(ctx, &lhs)?;
364 let ctx = expect!(
365 ctx,
366 T::Else,
367 "Expected 'else' after short if-expression condition"
368 );
369 let (ctx, rhs) = parse_precedence(ctx, Prec::No)?;
370
371 let condition = Box::new(condition.clone());
372 let fail = Box::new(rhs);
373 Ok((
374 ctx,
375 Expression {
376 span,
377 kind: IfShort {
378 condition,
379 fail,
380 },
381 },
382 ))
383}
384
385
386fn if_expression<'t>(ctx: Context<'t>, lhs: &Expression) -> ParseResult<'t, Expression> {
387 let span = ctx.span();
388 let ctx = expect!(ctx, T::If, "Expected 'if' at start of if-expression");
389
390 use ExpressionKind::*;
391 let (ctx, condition) = parse_precedence(ctx, Prec::No)?;
392
393 let ctx = expect!(
394 ctx,
395 T::Else,
396 "Expected 'else' after if-expression condition"
397 );
398 let (ctx, rhs) = parse_precedence(ctx, Prec::No)?;
399 let condition = Box::new(condition.clone());
400 let pass = Box::new(lhs.clone());
401 let fail = Box::new(rhs);
402 Ok((
403 ctx,
404 Expression {
405 span,
406 kind: IfExpression {
407 condition,
408 pass,
409 fail,
410 },
411 },
412 ))
413}
414
415fn arrow_call<'t>(ctx: Context<'t>, lhs: &Expression) -> ParseResult<'t, Expression> {
416 let ctx = expect!(ctx, T::Arrow, "Expected '->' in arrow function call");
417 let (ctx, rhs) = expression(ctx)?;
418
419 use ExpressionKind::*;
420 use AssignableKind::{Call, ArrowCall};
421
422 fn prepend_expresion<'t>(ctx: Context<'t>, lhs: Expression, rhs: Expression) -> ParseResult<'t, Expression> {
423 let span = ctx.span();
424 let kind = match rhs.kind {
425 Get(Assignable {
426 kind: Call(callee, args),
427 ..
428 }) => Get(Assignable {
429 kind: ArrowCall(Box::new(lhs), callee, args),
430 span: rhs.span,
431 }),
432
433 Get(Assignable {
434 kind: ArrowCall(pre, callee, args),
435 ..
436 }) => {
437 let (_, pre) = prepend_expresion(ctx, lhs, *pre)?;
438 Get(Assignable {
439 kind: ArrowCall(Box::new(pre), callee, args),
440 span: rhs.span,
441 })
442 }
443
444 _ => { raise_syntax_error!(ctx, "Expected a call-expression after '->'"); }
445 };
446 Ok((ctx, Expression { span, kind }))
447 }
448
449 prepend_expresion(ctx, lhs.clone(), rhs)
450}
451
452fn infix<'t>(ctx: Context<'t>, lhs: &Expression) -> ParseResult<'t, Expression> {
454 use ExpressionKind::*;
455
456 match (ctx.token(), precedence(ctx.skip(1).token())) {
460 (T::If, Prec::No) => {
461 return if_expression(ctx, lhs);
462 }
463 (T::If, _) => {
464 return if_short(ctx, lhs);
465 }
466 (T::Arrow, _) => {
469 return arrow_call(ctx, lhs);
470 }
471 _ => {}
472 }
473
474 let (op, span, ctx) = ctx.eat();
480
481 match op {
482 T::Plus
483 | T::Minus
484 | T::Star
485 | T::Slash
486 | T::EqualEqual
487 | T::NotEqual
488 | T::Greater
489 | T::GreaterEqual
490 | T::Less
491 | T::LessEqual
492 | T::Is
493
494 | T::And
495 | T::Or
496
497 | T::AssertEqual
498
499 | T::In
500 => {}
501
502 _ => {
504 return Err((ctx, Vec::new()));
505 }
506 };
507
508
509 let (ctx, rhs) = parse_precedence(ctx, precedence(op).next())?;
510
511 let lhs = Box::new(lhs.clone());
513 let rhs = Box::new(rhs);
514
515 let kind = match op {
517 T::Plus => Add(lhs, rhs),
519 T::Minus => Sub(lhs, rhs),
520 T::Star => Mul(lhs, rhs),
521 T::Slash => Div(lhs, rhs),
522 T::EqualEqual => Eq(lhs, rhs),
523 T::NotEqual => Neq(lhs, rhs),
524 T::Greater => Gt(lhs, rhs),
525 T::GreaterEqual => Gteq(lhs, rhs),
526 T::Less => Lt(lhs, rhs),
527 T::LessEqual => Lteq(lhs, rhs),
528 T::Is => Is(lhs, rhs),
529
530 T::And => And(lhs, rhs),
532 T::Or => Or(lhs, rhs),
533
534 T::AssertEqual => AssertEq(lhs, rhs),
535
536 T::In => In(lhs, rhs),
537
538 _ => {
540 unreachable!();
541 }
542 };
543
544 Ok((ctx, Expression { span, kind }))
545}
546
547fn grouping_or_tuple<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
555 let span = ctx.span();
556 let ctx = expect!(ctx, T::LeftParen, "Expected '('");
557 let (mut ctx, skip_newlines) = ctx.push_skip_newlines(true);
558
559 let mut exprs = Vec::new();
561
562 let mut is_tuple = matches!(ctx.token(), T::Comma | T::RightParen);
563 loop {
564 ctx = ctx.skip_if(T::Comma);
566 match ctx.token() {
567 T::EOF | T::RightParen => {
569 break;
570 }
571
572 _ => {
574 let (_ctx, expr) = expression(ctx)?;
575 exprs.push(expr);
576 ctx = _ctx; is_tuple |= matches!(ctx.token(), T::Comma);
580 }
581 }
582 }
583
584 let ctx = ctx.pop_skip_newlines(skip_newlines);
585 let ctx = expect!(ctx, T::RightParen, "Expected ')'");
586
587 use ExpressionKind::Tuple;
588 let result = if is_tuple {
589 Expression {
590 span,
591 kind: Tuple(exprs),
592 }
593 } else {
594 exprs.remove(0)
595 };
596 Ok((ctx, result))
597}
598
599fn blob<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
601 let span = ctx.span();
602 let (ctx, blob) = assignable(ctx)?;
603 let ctx = expect!(ctx, T::LeftBrace, "Expected '{{' after blob name");
604 let (mut ctx, skip_newlines) = ctx.push_skip_newlines(true);
605
606 let mut fields = Vec::new();
608 loop {
609 match ctx.token() {
610 T::RightBrace | T::EOF => {
612 break;
613 }
614
615 T::Identifier(name) => {
617 let name = name.clone();
619
620 ctx = expect!(ctx.skip(1), T::Colon, "Expected ':' after field name");
621 let (_ctx, expr) = expression(ctx)?;
623 ctx = _ctx; if !matches!(ctx.token(), T::Comma | T::RightBrace) {
626 raise_syntax_error!(
627 ctx,
628 "Expected a field delimiter ',' - but got {:?}",
629 ctx.token()
630 );
631 }
632 ctx = ctx.skip_if(T::Comma);
633
634 fields.push((name, expr));
635 }
636
637 t => {
638 raise_syntax_error!(ctx, "Unexpected token ('{:?}') in blob initalizer", t);
639 }
640 }
641 }
642
643 let ctx = ctx.pop_skip_newlines(skip_newlines);
644 let ctx = expect!(ctx, T::RightBrace, "Expected '}}' after blob initalizer");
645
646 if matches!(ctx.token(), T::Else) {
647 raise_syntax_error!(ctx, "Parsed a blob instance not an if-statement");
648 }
649
650 use ExpressionKind::Instance;
651 Ok((
652 ctx,
653 Expression {
654 span,
655 kind: Instance { blob, fields },
656 },
657 ))
658}
659
660fn list<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
662 let span = ctx.span();
663 let ctx = expect!(ctx, T::LeftBracket, "Expected '['");
664 let (mut ctx, skip_newlines) = ctx.push_skip_newlines(true);
665
666 let mut exprs = Vec::new();
668 loop {
669 match ctx.token() {
670 T::EOF | T::RightBracket => {
672 break;
673 }
674
675 _ => {
677 let (_ctx, expr) = expression(ctx)?;
678 exprs.push(expr);
679 ctx = _ctx; ctx = ctx.skip_if(T::Comma);
681 }
682 }
683 }
684
685 let ctx = ctx.pop_skip_newlines(skip_newlines);
686 let ctx = expect!(ctx, T::RightBracket, "Expected ']'");
687 use ExpressionKind::List;
688 Ok((
689 ctx,
690 Expression {
691 span,
692 kind: List(exprs),
693 },
694 ))
695}
696
697fn set_or_dict<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
701 let span = ctx.span();
702 let ctx = expect!(ctx, T::LeftBrace, "Expected '{{'");
703 let (mut ctx, skip_newlines) = ctx.push_skip_newlines(true);
704
705 let mut exprs = Vec::new();
707 let mut is_dict = None;
709 loop {
710 match ctx.token() {
711 T::EOF | T::RightBrace => {
713 break;
714 }
715
716 T::Colon => {
718 if let Some(is_dict) = is_dict {
720 raise_syntax_error!(
721 ctx,
722 "Empty dict pair is invalid in a {}",
723 if is_dict { "dict" } else { "set" }
724 );
725 }
726 is_dict = Some(true);
727 ctx = ctx.skip(1);
728 }
729
730 _ => {
732 let (_ctx, expr) = expression(ctx)?;
734 ctx = _ctx; exprs.push(expr);
736
737 if *is_dict.get_or_insert_with(|| matches!(ctx.token(), T::Colon)) {
740 ctx = expect!(ctx, T::Colon, "Expected ':' for dict pair");
741 let (_ctx, expr) = expression(ctx)?;
743 ctx = _ctx; exprs.push(expr);
745 }
746
747 ctx = ctx.skip_if(T::Comma);
748 }
749 }
750 }
751
752 let ctx = ctx.pop_skip_newlines(skip_newlines);
753 let ctx = expect!(ctx, T::RightBrace, "Expected '}}'");
754
755 use ExpressionKind::{Dict, Set};
756 let kind = if is_dict.unwrap_or(false) {
758 Dict(exprs)
759 } else {
760 Set(exprs)
761 };
762
763 Ok((ctx, Expression { span, kind }))
764}
765
766pub fn expression<'t>(ctx: Context<'t>) -> ParseResult<'t, Expression> {
772 match ctx.token() {
773 T::Fn => function(ctx),
774 _ => parse_precedence(ctx, Prec::No),
775 }
776}
777
778#[cfg(test)]
783mod test {
784 use super::ExpressionKind::*;
785 use crate::expression;
786 use crate::test;
787 use crate::Assignable;
788 use crate::AssignableKind::*;
789
790 test!(expression, value: "0" => Int(0));
791 test!(expression, add: "0 + 1.0" => Add(_, _));
792 test!(expression, mul: "\"abc\" * \"abc\"" => Mul(_, _));
793 test!(expression, ident: "a" => Get(Assignable { kind: Read(_), .. }));
794 test!(expression, access: "a.b" => Get(Assignable { kind: Access(_, _), .. }));
795 test!(expression, index_ident: "a[a]" => Get(Assignable { kind: Index(_, _), .. }));
796 test!(expression, index_expr: "a[1 + 2 + 3]" => Get(Assignable { kind: Index(_, _), .. }));
797 test!(expression, grouping: "(0 * 0) + 1" => Add(_, _));
798 test!(expression, grouping_one: "(0)" => Int(0));
799 test!(expression, tuple: "(0, 0)" => Tuple(_));
800 test!(expression, tuple_one: "(0,)" => Tuple(_));
801 test!(expression, tuple_empty: "()" => Tuple(_));
802 test!(expression, list: "[0, 0]" => List(_));
803 test!(expression, set: "{1, 1}" => Set(_));
804 test!(expression, dict: "{1: 1}" => Dict(_));
805 test!(expression, zero_set: "{}" => Set(_));
806 test!(expression, zero_dict: "{:}" => Dict(_));
807
808 test!(expression, in_list: "a in [1, 2, 3]" => In(_, _));
809 test!(expression, in_set: "2 in {1, 1, 2}" => In(_, _));
810 test!(expression, in_grouping: "1 + 2 in b" => Add(_, _));
811 test!(expression, in_grouping_paren: "(1 + 2) in b" => In(_, _));
812
813 test!(expression, call_simple_paren: "a()" => Get(_));
814 test!(expression, call_call: "a()()" => Get(_));
815 test!(expression, call_simple_bang: "a'" => Get(_));
816 test!(expression, call_chaining_paren: "a().b" => Get(_));
817 test!(expression, call_chaining_bang: "a'.b" => Get(_));
818 test!(expression, call_args_paren: "a(1, 2, 3)" => Get(_));
819 test!(expression, call_args_bang: "a' 1, 2, 3" => Get(_));
820 test!(expression, call_args_chaining_paren: "a(1, 2, 3).b" => Get(_));
821 test!(expression, call_args_chaining_paren_trailing: "a(1, 2, 3,).b" => Get(_));
822 test!(expression, assignable_index: "a[0]" => Get(_));
823 test!(expression, assignable_index_twice: "a[0][1]" => Get(_));
824 test!(expression, assignable_mixed: "a[0]()" => Get(_));
825 test!(expression, assignable_mixed_many: "a()[0]()[1]()()()[2][3]" => Get(_));
826
827 test!(expression, call_args_chaining_bang: "a' 1, 2, 3 .b" => Get(_));
829 test!(expression, call_args_chaining_bang_trailing: "a' 1, 2, 3, .b" => Get(_));
830
831 test!(expression, call_arrow: "1 + 0 -> a' 2, 3" => Add(_, _));
832 test!(expression, call_arrow_grouping: "(1 + 0) -> a' 2, 3" => Get(_));
833
834 test!(expression, instance: "A { a: 1 + 1, b: nil }" => Instance { .. });
835 test!(expression, instance_more: "A { a: 2, \n c: 2 }" => Instance { .. });
836 test!(expression, instance_empty: "A {}" => Instance { .. });
837
838 test!(expression, simple: "fn -> {}" => _);
839 test!(expression, argument: "fn a: int -> int { ret a + 1 }" => _);
840
841 test!(expression, booleans: "true && false || !false" => _);
842 test!(expression, bool_and: "true && a" => _);
843 test!(expression, bool_or: "a || false" => _);
844 test!(expression, bool_neg: "!a" => _);
845 test!(expression, bool_neg_multiple: "!a && b" => _);
846 test!(expression, bool_neg_multiple_rev: "a && !b" => _);
847
848 test!(expression, cmp_is: "a is B" => _);
849 test!(expression, cmp_eq: "a == b" => _);
850 test!(expression, cmp_neq: "a != b" => _);
851 test!(expression, cmp_leq: "a <= b" => _);
852 test!(expression, cmp_geq: "a >= b" => _);
853 test!(expression, cmp_gt: "a > b" => _);
854 test!(expression, cmp_lt: "a < b" => _);
855 test!(expression, neg: "-a" => _);
856
857 test!(expression, expr: "-a + b < 3 * true && false / 2" => _);
858
859 test!(expression, type_expr_int: ":int" => _);
860 test!(expression, type_expr_void: ":void" => _);
861 test!(expression, type_expr_float: ":float" => _);
862 test!(expression, type_expr_str: ":str" => _);
863 test!(expression, type_expr_custom: ":A" => _);
864 test!(expression, type_expr_custom_chaining: ":A.b.C" => _);
865
866 test!(expression, void_simple: "fn {}" => _);
867 test!(expression, void_argument: "fn a: int { ret a + 1 }" => _);
868
869 test!(expression, if_expr: "a if b else c" => IfExpression { .. });
870 test!(expression, if_expr_more: "1 + 1 + 1 if b else 2 + 2 + 2" => IfExpression { .. });
871}