Skip to content

Commit 84c2d4c

Browse files
authored
Implement is expressions (#116)
Implements `is` expressions as specified in #114.
1 parent eb2236a commit 84c2d4c

22 files changed

+7159
-6672
lines changed

editor/vim/syntax/fir.vim

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ syntax keyword firKeyword
1414
\ impl
1515
\ import
1616
\ in
17+
\ is
1718
\ jump
1819
\ let
1920
\ loop

src/ast.rs

+15
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,8 @@ pub enum Expr {
548548
If(IfExpr),
549549

550550
Fn(FnExpr),
551+
552+
Is(IsExpr),
551553
}
552554

553555
#[derive(Debug, Clone)]
@@ -729,6 +731,15 @@ pub struct FnExpr {
729731
pub inferred_ty: Option<Ty>,
730732
}
731733

734+
/// `<expr> is <pat>`: matches expression against pattern.
735+
///
736+
/// Can bind variables.
737+
#[derive(Debug, Clone)]
738+
pub struct IsExpr {
739+
pub expr: Box<L<Expr>>,
740+
pub pat: L<Pat>,
741+
}
742+
732743
#[derive(Debug, Clone, PartialEq, Eq)]
733744
pub struct ImportDecl {
734745
/// Import path, e.g. `Fir.Prelude`.
@@ -1121,6 +1132,10 @@ impl Expr {
11211132
stmt.node.subst_ty_ids(substs);
11221133
}
11231134
}
1135+
1136+
Expr::Is(IsExpr { expr, pat: _ }) => {
1137+
expr.node.subst_ty_ids(substs);
1138+
}
11241139
}
11251140
}
11261141
}

src/ast/printer.rs

+8
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,14 @@ impl Expr {
816816
}
817817
buffer.push('}');
818818
}
819+
820+
Expr::Is(IsExpr { expr, pat }) => {
821+
buffer.push('(');
822+
expr.node.print(buffer, indent);
823+
buffer.push_str(" is ");
824+
pat.node.print(buffer);
825+
buffer.push(')');
826+
}
819827
}
820828
}
821829
}

src/interpreter.rs

+9
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,15 @@ fn eval<W: Write>(
963963

964964
ControlFlow::Val(variant)
965965
}
966+
967+
Expr::Is(IsExpr { expr, pat }) => {
968+
let val = val!(eval(w, pgm, heap, locals, &expr.node, &expr.loc));
969+
ControlFlow::Val(if try_bind_pat(pgm, heap, pat, locals, val) {
970+
pgm.true_alloc
971+
} else {
972+
pgm.false_alloc
973+
})
974+
}
966975
}
967976
}
968977

src/lexer.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ lexgen::lexer! {
3939
"impl" = TokenKind::Impl,
4040
"import" = TokenKind::Import,
4141
"in" = TokenKind::In,
42+
"is" = TokenKind::Is,
4243
"jump" = TokenKind::Jump,
4344
"let" = TokenKind::Let,
4445
"loop" = TokenKind::Loop,

src/lowering.rs

+12
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ pub enum Expr {
429429
Match(MatchExpr),
430430
If(IfExpr),
431431
ClosureAlloc(ClosureIdx),
432+
Is(IsExpr),
432433
}
433434

434435
#[derive(Debug, Clone)]
@@ -493,6 +494,12 @@ pub struct IfExpr {
493494
pub else_branch: Option<Vec<L<Stmt>>>,
494495
}
495496

497+
#[derive(Debug, Clone)]
498+
pub struct IsExpr {
499+
pub expr: Box<L<Expr>>,
500+
pub pat: L<Pat>,
501+
}
502+
496503
#[derive(Debug, Clone)]
497504
pub enum Pat {
498505
Var(LocalIdx),
@@ -1947,6 +1954,11 @@ fn lower_expr(
19471954

19481955
Expr::ClosureAlloc(closure_idx)
19491956
}
1957+
1958+
mono::Expr::Is(mono::IsExpr { expr, pat }) => Expr::Is(IsExpr {
1959+
expr: Box::new(lower_l_expr(expr, closures, indices, scope)),
1960+
pat: lower_l_pat(pat, indices, scope, &mut Default::default()),
1961+
}),
19501962
}
19511963
}
19521964

src/lowering/printer.rs

+8
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,14 @@ impl Expr {
458458
}
459459

460460
Expr::ClosureAlloc(idx) => write!(buffer, "closure{}", idx.0).unwrap(),
461+
462+
Expr::Is(IsExpr { expr, pat }) => {
463+
buffer.push('(');
464+
expr.node.print(buffer, indent);
465+
buffer.push_str(" is ");
466+
pat.node.print(buffer);
467+
buffer.push(')');
468+
}
461469
}
462470
}
463471
}

src/mono_ast.rs

+7
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ pub enum Expr {
241241
Match(MatchExpr),
242242
If(IfExpr),
243243
Fn(FnExpr),
244+
Is(IsExpr),
244245
}
245246

246247
#[derive(Debug, Clone)]
@@ -320,6 +321,12 @@ pub struct FnExpr {
320321
pub body: Vec<L<Stmt>>,
321322
}
322323

324+
#[derive(Debug, Clone)]
325+
pub struct IsExpr {
326+
pub expr: Box<L<Expr>>,
327+
pub pat: L<Pat>,
328+
}
329+
323330
#[derive(Debug, Clone)]
324331
pub enum StringPart {
325332
Str(String),

src/mono_ast/printer.rs

+8
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,14 @@ impl Expr {
732732
stmt.node.print(buffer, indent + 4);
733733
}
734734
}
735+
736+
Expr::Is(IsExpr { expr, pat }) => {
737+
buffer.push('(');
738+
expr.node.print(buffer, indent);
739+
buffer.push_str(" is ");
740+
pat.node.print(buffer);
741+
buffer.push(')');
742+
}
735743
}
736744
}
737745
}

src/monomorph.rs

+5
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,11 @@ fn mono_expr(
903903
body,
904904
})
905905
}
906+
907+
ast::Expr::Is(ast::IsExpr { expr, pat }) => mono::Expr::Is(mono::IsExpr {
908+
expr: Box::new(mono_l_expr(expr, ty_map, poly_pgm, mono_pgm, locals)),
909+
pat: mono_l_pat(pat, ty_map, poly_pgm, mono_pgm, locals),
910+
}),
906911
}
907912
}
908913

src/parser.lalrpop

+19-12
Original file line numberDiff line numberDiff line change
@@ -63,26 +63,27 @@ extern {
6363
INDENT => Token { kind: TokenKind::Indent, .. },
6464
DEDENT => Token { kind: TokenKind::Dedent, .. },
6565
NEWLINE => Token { kind: TokenKind::Newline, .. },
66+
"Fn" => Token { kind: TokenKind::UpperFn, .. },
6667
"as" => Token { kind: TokenKind::As, .. },
6768
"break" => Token { kind: TokenKind::Break, .. },
6869
"continue" => Token { kind: TokenKind::Continue, .. },
69-
"type" => Token { kind: TokenKind::Type, .. },
70-
"fn" => Token { kind: TokenKind::Fn, .. },
71-
"Fn" => Token { kind: TokenKind::UpperFn, .. },
72-
"let" => Token { kind: TokenKind::Let, .. },
73-
"if" => Token { kind: TokenKind::If, .. },
74-
"else" => Token { kind: TokenKind::Else, .. },
7570
"elif" => Token { kind: TokenKind::Elif, .. },
76-
"match" => Token { kind: TokenKind::Match, .. },
71+
"else" => Token { kind: TokenKind::Else, .. },
72+
"fn" => Token { kind: TokenKind::Fn, .. },
7773
"for" => Token { kind: TokenKind::For, .. },
78-
"while" => Token { kind: TokenKind::While, .. },
79-
"in" => Token { kind: TokenKind::In, .. },
80-
"return" => Token { kind: TokenKind::Return, .. },
74+
"if" => Token { kind: TokenKind::If, .. },
75+
"impl" => Token { kind: TokenKind::Impl, .. },
8176
"import" => Token { kind: TokenKind::Import, .. },
77+
"in" => Token { kind: TokenKind::In, .. },
78+
"is" => Token { kind: TokenKind::Is, .. },
79+
"let" => Token { kind: TokenKind::Let, .. },
80+
"loop" => Token { kind: TokenKind::Loop, .. },
81+
"match" => Token { kind: TokenKind::Match, .. },
8282
"prim" => Token { kind: TokenKind::Prim, .. },
83+
"return" => Token { kind: TokenKind::Return, .. },
8384
"trait" => Token { kind: TokenKind::Trait, .. },
84-
"impl" => Token { kind: TokenKind::Impl, .. },
85-
"loop" => Token { kind: TokenKind::Loop, .. },
85+
"type" => Token { kind: TokenKind::Type, .. },
86+
"while" => Token { kind: TokenKind::While, .. },
8687
IntLit => Token { kind: TokenKind::Int { .. }, .. },
8788
HexIntLit => Token { kind: TokenKind::HexInt { .. }, .. },
8889
BinIntLit => Token { kind: TokenKind::BinInt { .. }, .. },
@@ -947,6 +948,12 @@ InlineExpr: Expr = {
947948
op: BinOp::GtEq,
948949
}),
949950

951+
<l1:@L> <expr:InlineExpr> <r1:@R> "is" <l2:@L> <pat:Pat> <r2:@R> =>
952+
Expr::Is(IsExpr {
953+
expr: Box::new(L::new(module, l1, r1, expr)),
954+
pat: L::new(module, l2, r2, pat),
955+
}),
956+
950957
#[precedence(level = "10")]
951958
#[assoc(side = "left")]
952959
<l1:@L> <left:InlineExpr> <r1:@R> "&&" <l2:@L> <right:InlineExpr> <r2:@R> =>

0 commit comments

Comments
 (0)