From 3ba50e643731811784da31f39f2577f3d9dd13fd Mon Sep 17 00:00:00 2001 From: "Heinz N. Gies" Date: Mon, 12 Aug 2024 21:48:42 +0200 Subject: [PATCH] More pattern matching Signed-off-by: Heinz N. Gies --- tremor-script/src/vm.rs | 30 +++++++++ .../src/vm/compiler/impls/imut_expr.rs | 64 ++++++++++++++++--- tremor-script/src/vm/op.rs | 13 +++- 3 files changed, 96 insertions(+), 11 deletions(-) diff --git a/tremor-script/src/vm.rs b/tremor-script/src/vm.rs index 3c0f34eebd..6bb1420805 100644 --- a/tremor-script/src/vm.rs +++ b/tremor-script/src/vm.rs @@ -348,6 +348,18 @@ impl<'run, 'event> Scope<'run, 'event> { .as_object() .map_or(true, halfbrown::SizedHashMap::is_empty); } + // Inspect + Op::InspectLen => { + let v = last(&mut stack, *pc, *cc)?; + let len = if let Some(v) = v.as_array() { + v.len() + } else if let Some(v) = v.as_object() { + v.len() + } else { + return Err("Not an array or object".into()); + }; + stack.push(Cow::Owned(Value::from(len))); + } // Records Op::RecordSet => { @@ -455,6 +467,24 @@ impl<'run, 'event> Scope<'run, 'event> { .to_vec(); stack.push(Cow::Owned(v.into())); } + + // Array + // FIXME: this is kind akeward, we use the stack here instead of the register + Op::ArrayPop => { + let arr = last_mut(&mut stack, *pc, *cc)? + .to_mut() + .as_array_mut() + .ok_or("needs array")?; + let v = arr + .pop() + .ok_or_else(|| error_generic(mid, mid, &"Empty array"))?; + stack.push(Cow::Owned(v)); + } + Op::ArrayReverse => { + let v = last_mut(&mut stack, *pc, *cc)?; + let arr = v.to_mut().as_array_mut().ok_or("needs array")?; + arr.reverse(); + } } *pc += 1; } diff --git a/tremor-script/src/vm/compiler/impls/imut_expr.rs b/tremor-script/src/vm/compiler/impls/imut_expr.rs index 369b9158f5..8898fe48c0 100644 --- a/tremor-script/src/vm/compiler/impls/imut_expr.rs +++ b/tremor-script/src/vm/compiler/impls/imut_expr.rs @@ -3,9 +3,9 @@ use tremor_value::Value; use crate::{ ast::{ raw::{BytesDataType, Endian}, - BaseExpr, BinOpKind, BooleanBinExpr, BooleanBinOpKind, BytesPart, ClausePreCondition, - Field, ImutExpr, Invoke, List, Merge, Patch, PatchOperation, Pattern, Record, Segment, - StrLitElement, StringLit, + ArrayPredicatePattern, BaseExpr, BinOpKind, BooleanBinExpr, BooleanBinOpKind, BytesPart, + ClausePreCondition, Field, ImutExpr, Invoke, List, Merge, Patch, PatchOperation, Pattern, + PredicatePattern, Record, Segment, StrLitElement, StringLit, }, errors::Result, vm::{ @@ -367,6 +367,17 @@ impl<'script> Compilable<'script> for BytesPart<'script> { } } +impl<'script> Compilable<'script> for PredicatePattern<'script> { + fn compile(self, _compiler: &mut Compiler<'script>) -> Result<()> { + todo!() + } +} +impl<'script> Compilable<'script> for ArrayPredicatePattern<'script> { + fn compile(self, _compiler: &mut Compiler<'script>) -> Result<()> { + todo!() + } +} + impl<'script> Compilable<'script> for Pattern<'script> { fn compile(self, compiler: &mut Compiler<'script>) -> Result<()> { self.compile_to_b(compiler) @@ -378,10 +389,11 @@ impl<'script> Compilable<'script> for Pattern<'script> { compiler.emit(Op::TestIsRecord, &r.mid); let dst = compiler.new_jump_point(); compiler.emit(Op::JumpFalse { dst }, &r.mid); - if r.fields.is_empty() { - } else { - todo!() + + for f in r.fields { + f.compile(compiler)?; } + compiler.set_jump_target(dst); } Pattern::Array(a) => { @@ -389,9 +401,9 @@ impl<'script> Compilable<'script> for Pattern<'script> { compiler.emit(Op::TestIsArray, &mid); let dst = compiler.new_jump_point(); compiler.emit(Op::JumpFalse { dst }, &mid); - if a.exprs.is_empty() { - } else { - todo!() + for e in a.exprs { + e.compile(compiler)?; + todo!("we need to look at all the array elements :sob:") } compiler.set_jump_target(dst); } @@ -403,7 +415,39 @@ impl<'script> Compilable<'script> for Pattern<'script> { } Pattern::Assign(_) => todo!(), - Pattern::Tuple(_) => todo!(), + Pattern::Tuple(t) => { + let mid = *t.mid; + compiler.emit(Op::TestIsArray, &mid); + let dst = compiler.new_jump_point(); + compiler.emit(Op::JumpFalse { dst }, &mid); + // copy the item to the stack so we can itterate + compiler.emit(Op::CopyV1, &mid); + compiler.emit(Op::InspectLen, &mid); + compiler.emit_const(t.exprs.len(), &mid); + + if t.open { + compiler.emit(Op::Binary { op: BinOpKind::Gte }, &mid); + } else { + compiler.emit(Op::Binary { op: BinOpKind::Eq }, &mid); + } + let end_and_pop = compiler.new_jump_point(); + + compiler.emit(Op::JumpFalse { dst: end_and_pop }, &mid); + + // reverse the array so we can pop in the right order + compiler.emit(Op::ArrayReverse, &mid); + for e in t.exprs { + compiler.emit(Op::ArrayPop, &mid); + e.compile(compiler)?; + compiler.emit(Op::JumpFalse { dst: end_and_pop }, &mid); + todo!("we need to look at all the array elements :sob:") + } + compiler.emit(Op::LoadRB, &mid); + compiler.set_jump_target(end_and_pop); + // remove the array from the stack + compiler.emit(Op::Pop, &mid); + compiler.set_jump_target(dst); + } Pattern::Extract(_) => todo!(), Pattern::DoNotCare => { compiler.emit(Op::True, &NodeMeta::dummy()); diff --git a/tremor-script/src/vm/op.rs b/tremor-script/src/vm/op.rs index f0d82cc9c3..8e81bdf56d 100644 --- a/tremor-script/src/vm/op.rs +++ b/tremor-script/src/vm/op.rs @@ -108,7 +108,7 @@ pub(crate) enum Op { end: u16, }, - // Tests + // Tests - does not pop the stack result is stored in the b register TestRecortPresent, TestIsU64, TestIsI64, @@ -117,6 +117,10 @@ pub(crate) enum Op { TestArrayIsEmpty, TestRecordIsEmpty, + // Inspect - does not pop the stack result is stored on the stack + //// returns the lenght of an array, object or 1 for scalar values + InspectLen, + // Patch RecordSet, RecordRemove, @@ -127,6 +131,8 @@ pub(crate) enum Op { TestIsArray, RecordMergeKey, RecordPop, + ArrayPop, + ArrayReverse, } impl Display for Op { @@ -185,12 +191,17 @@ impl Display for Op { Op::TestArrayIsEmpty => write!(f, "test_array_is_empty"), Op::TestRecordIsEmpty => write!(f, "test_record_is_empty"), + Op::InspectLen => write!(f, "inspect_len"), + Op::RecordSet => write!(f, "record_set"), Op::RecordRemove => write!(f, "record_remove"), Op::RecordGet => write!(f, "record_get"), Op::RecordMergeKey => write!(f, "record_merge_key"), Op::RecordMerge => write!(f, "record_merge"), + Op::RecordPop => write!(f, "record_pop"), + Op::ArrayPop => write!(f, "array_pop"), + Op::ArrayReverse => write!(f, "array_reverse"), } } }