Skip to content

Commit

Permalink
Allow assignments in match patterns
Browse files Browse the repository at this point in the history
Signed-off-by: Heinz N. Gies <heinz@licenser.net>
  • Loading branch information
Licenser committed Aug 15, 2024
1 parent e4d61f8 commit 5e1dfff
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 42 deletions.
4 changes: 2 additions & 2 deletions tremor-script/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,9 +342,9 @@ impl<'run, 'event> Scope<'run, 'event> {
self.reg.b1 = self.reg.v1.as_array().map_or(true, Vec::is_empty);
}

Check warning on line 343 in tremor-script/src/vm.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L326-L343

Added lines #L326 - L343 were not covered by tests
Op::TestEq => {
let rhs = last(&stack, *pc, *cc)?;
let rhs = pop(&mut stack, *pc, *cc)?;

Check warning on line 345 in tremor-script/src/vm.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L345

Added line #L345 was not covered by tests
self.reg.b1 =
exec_binary(mid, mid, crate::ast::BinOpKind::Eq, &self.reg.v1, rhs)?
exec_binary(mid, mid, crate::ast::BinOpKind::Eq, &self.reg.v1, &rhs)?
.try_as_bool()?;

Check warning on line 348 in tremor-script/src/vm.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L347-L348

Added lines #L347 - L348 were not covered by tests
}
Op::TestNeq => {
Expand Down
42 changes: 35 additions & 7 deletions tremor-script/src/vm/compiler/impls/imut_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ use tremor_value::Value;
use crate::{
ast::{
raw::{BytesDataType, Endian},
ArrayPredicatePattern, BaseExpr, BinOpKind, BooleanBinExpr, BooleanBinOpKind, BytesPart,
ClausePreCondition, Field, ImutExpr, Invoke, List, Merge, Patch, PatchOperation, Pattern,
PredicatePattern, Record, Segment, StrLitElement, StringLit,
ArrayPredicatePattern, AssignPattern, BaseExpr, BinOpKind, BooleanBinExpr,
BooleanBinOpKind, BytesPart, ClausePreCondition, Field, ImutExpr, Invoke, List, Merge,
Patch, PatchOperation, Pattern, PredicatePattern, Record, Segment, StrLitElement,
StringLit,
},
errors::Result,
vm::{
Expand Down Expand Up @@ -378,8 +379,7 @@ impl<'script> Compilable<'script> for ArrayPredicatePattern<'script> {
ArrayPredicatePattern::Expr(e) => {
let mid = e.meta().clone();
e.compile(compiler)?;
compiler.emit(Op::Binary { op: BinOpKind::Eq }, &mid);
compiler.emit(Op::LoadRB, &mid);
compiler.emit(Op::TestEq, &mid);

Check warning on line 382 in tremor-script/src/vm/compiler/impls/imut_expr.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm/compiler/impls/imut_expr.rs#L377-L382

Added lines #L377 - L382 were not covered by tests
}
ArrayPredicatePattern::Tilde(_) => todo!(),
ArrayPredicatePattern::Record(_) => todo!(),
Expand Down Expand Up @@ -424,7 +424,31 @@ impl<'script> Compilable<'script> for Pattern<'script> {
compiler.emit(Op::TestEq, &mid);

Check warning on line 424 in tremor-script/src/vm/compiler/impls/imut_expr.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm/compiler/impls/imut_expr.rs#L421-L424

Added lines #L421 - L424 were not covered by tests
}

Pattern::Assign(_) => todo!(),
#[allow(clippy::cast_possible_truncation)]
Pattern::Assign(p) => {
let AssignPattern {
id: _,
idx,
pattern,
} = p;
// FIXME: want a MID
let mid = NodeMeta::dummy();
compiler.comment("Assign pattern");
pattern.compile(compiler)?;
let dst = compiler.new_jump_point();
compiler.comment("Jump on no match");
compiler.emit(Op::JumpFalse { dst }, &mid);
compiler.comment("Store the value in the local");
compiler.emit(Op::CopyV1, &mid);
compiler.emit(
Op::StoreLocal {
idx: idx as u32,
elements: 0,
},
&mid,
);
compiler.set_jump_target(dst);

Check warning on line 450 in tremor-script/src/vm/compiler/impls/imut_expr.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm/compiler/impls/imut_expr.rs#L428-L450

Added lines #L428 - L450 were not covered by tests
}
Pattern::Tuple(t) => {
compiler.comment("Tuple pattern");
let mid = *t.mid;
Expand All @@ -449,9 +473,13 @@ impl<'script> Compilable<'script> for Pattern<'script> {
compiler.emit(Op::CopyV1, &mid);
compiler.emit(Op::ArrayReverse, &mid);
for (i, e) in t.exprs.into_iter().enumerate() {
compiler.comment(&format!("Test tuple element {}", i));
compiler.comment(&format!("Test tuple element {i}"));
compiler.emit(Op::ArrayPop, &mid);
compiler.comment("Load value in register to test");
compiler.emit(Op::SwapV1, &mid);
e.compile(compiler)?;
compiler.comment("restore original test value");
compiler.emit(Op::LoadV1, &mid);
compiler.comment("Jump on no match");
compiler.emit(Op::JumpFalse { dst: end_and_pop }, &mid);

Check warning on line 484 in tremor-script/src/vm/compiler/impls/imut_expr.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm/compiler/impls/imut_expr.rs#L452-L484

Added lines #L452 - L484 were not covered by tests
}
Expand Down
178 changes: 145 additions & 33 deletions tremor-script/src/vm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,7 @@ fn test_local_array_assign_nested() -> Result<()> {
}

#[test]
#[allow(clippy::too_many_lines)]
fn test_match_touple() -> Result<()> {
let p = compile(
false,
Expand All @@ -1058,79 +1059,86 @@ fn test_match_touple() -> Result<()> {
Array { size: 2 },
LoadV1,
TestIsArray,
JumpFalse { dst: 26 },
JumpFalse { dst: 28 },
InspectLen,
Const { idx: 3 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 26 },
JumpFalse { dst: 28 },
CopyV1,
ArrayReverse,
ArrayPop,
SwapV1,
Const { idx: 0 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 25 },
TestEq,
LoadV1,
JumpFalse { dst: 27 },
ArrayPop,
SwapV1,
Const { idx: 4 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 25 },
TestEq,
LoadV1,
JumpFalse { dst: 27 },
Pop,
JumpFalse { dst: 29 },
JumpFalse { dst: 31 },
Const { idx: 4 },
Jump { dst: 81 },
Jump { dst: 88 },
TestIsArray,
JumpFalse { dst: 54 },
JumpFalse { dst: 59 },
InspectLen,
Const { idx: 5 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 54 },
JumpFalse { dst: 59 },
CopyV1,
ArrayReverse,
ArrayPop,
SwapV1,
Const { idx: 0 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 53 },
TestEq,
LoadV1,
JumpFalse { dst: 58 },
ArrayPop,
SwapV1,
Const { idx: 1 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 53 },
TestEq,
LoadV1,
JumpFalse { dst: 58 },
ArrayPop,
SwapV1,
Const { idx: 6 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 53 },
TestEq,
LoadV1,
JumpFalse { dst: 58 },
Pop,
JumpFalse { dst: 57 },
JumpFalse { dst: 62 },
Const { idx: 6 },
Jump { dst: 81 },
Jump { dst: 88 },
TestIsArray,
JumpFalse { dst: 77 },
JumpFalse { dst: 84 },
InspectLen,
Const { idx: 3 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 77 },
JumpFalse { dst: 84 },
CopyV1,
ArrayReverse,
ArrayPop,
SwapV1,
Const { idx: 0 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 76 },
TestEq,
LoadV1,
JumpFalse { dst: 83 },
ArrayPop,
SwapV1,
Const { idx: 1 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 76 },
TestEq,
LoadV1,
JumpFalse { dst: 83 },
Pop,
JumpFalse { dst: 80 },
JumpFalse { dst: 87 },
Const { idx: 0 },
Jump { dst: 81 },
Jump { dst: 88 },
Const { idx: 7 },
LoadV1,
SwapV1,
Expand Down Expand Up @@ -1165,3 +1173,107 @@ fn test_match_search_tree() -> Result<()> {
assert_eq!(run(&p)?, 42);
Ok(())
}

#[test]
fn test_match_assign() -> Result<()> {
let p = compile(
false,
r"
match 42 of
case 24 => 24
case 7 => 7
case a = 42 => a
case _ => 0
end",
)?;

assert_eq!(
p.opcodes,
&[
StoreV1,
Const { idx: 0 },
LoadV1,
Const { idx: 1 },
TestEq,
JumpFalse { dst: 8 },
Const { idx: 1 },
Jump { dst: 22 },
Const { idx: 0 },
TestEq,
JumpFalse { dst: 13 },
CopyV1,
StoreLocal {
elements: 0,
idx: 0,
},
JumpFalse { dst: 16 },
LoadLocal { idx: 0 },
Jump { dst: 22 },
Const { idx: 2 },
TestEq,
JumpFalse { dst: 21 },
Const { idx: 2 },
Jump { dst: 22 },
Const { idx: 3 },
LoadV1,
SwapV1,
]
);

assert_eq!(run(&p)?, 42);
Ok(())
}

#[test]
fn test_match_assign_nested() -> Result<()> {
let p = compile(
false,
r"
match [42] of
case a = %(42) => a
case _ => 0
end",
)?;

assert_eq!(
p.opcodes,
&[
StoreV1,
Const { idx: 0 },
Const { idx: 1 },
Array { size: 1 },
LoadV1,
TestIsArray,
JumpFalse { dst: 21 },
InspectLen,
Const { idx: 2 },
Binary { op: Eq },
LoadRB,
JumpFalse { dst: 21 },
CopyV1,
ArrayReverse,
ArrayPop,
SwapV1,
Const { idx: 0 },
TestEq,
LoadV1,
JumpFalse { dst: 20 },
Pop,
JumpFalse { dst: 24 },
CopyV1,
StoreLocal {
elements: 0,
idx: 0,
},
JumpFalse { dst: 27 },
LoadLocal { idx: 0 },
Jump { dst: 28 },
Const { idx: 3 },
LoadV1,
SwapV1,
]
);

assert_eq!(run(&p)?, literal!([42]));
Ok(())
}

0 comments on commit 5e1dfff

Please sign in to comment.