Skip to content

Commit

Permalink
some matchy vm stuff
Browse files Browse the repository at this point in the history
Signed-off-by: Heinz N. Gies <[email protected]>
  • Loading branch information
Licenser committed Sep 28, 2024
1 parent 1421979 commit 6241dc7
Show file tree
Hide file tree
Showing 16 changed files with 384 additions and 119 deletions.
7 changes: 5 additions & 2 deletions tremor-script/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1673,8 +1673,6 @@ impl<'script> Pattern<'script> {
pub enum PredicatePattern<'script> {
/// Structural application
TildeEq {
/// Assignment bind point
assign: Cow<'script, str>,
/// Lhs
lhs: Cow<'script, str>,
/// Key
Expand Down Expand Up @@ -1974,6 +1972,11 @@ pub enum Path<'script> {
}

impl<'script> Path<'script> {
/// Get the length of the path
#[must_use]
pub(crate) fn len(&self) -> usize {
self.segments().len()
}

Check warning on line 1979 in tremor-script/src/ast.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/ast.rs#L1977-L1979

Added lines #L1977 - L1979 were not covered by tests
/// Get segments as slice
#[must_use]
pub(crate) fn segments(&self) -> &Segments<'script> {
Expand Down
10 changes: 2 additions & 8 deletions tremor-script/src/ast/eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,19 +437,13 @@ impl<'script> AstEq for PredicatePattern<'script> {
use PredicatePattern::{ArrayPatternEq, Bin, RecordPatternEq, TildeEq};
match (self, other) {
(
TildeEq { lhs, key, test },

Check warning on line 440 in tremor-script/src/ast/eq.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/ast/eq.rs#L440

Added line #L440 was not covered by tests
TildeEq {
assign,
lhs,
key,
test,
},
TildeEq {
assign: a2,
lhs: l2,
key: k2,
test: t2,
},
) => assign == a2 && lhs == l2 && key == k2 && test.ast_eq(t2.as_ref()),
) => lhs == l2 && key == k2 && test.ast_eq(t2.as_ref()),

Check warning on line 446 in tremor-script/src/ast/eq.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/ast/eq.rs#L446

Added line #L446 was not covered by tests
(
Bin {
lhs,
Expand Down
2 changes: 0 additions & 2 deletions tremor-script/src/ast/eq/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,6 @@ fn imut_expr() -> ImutExpr<'static> {
#[test]
fn predicate_pattern() {
assert!(PredicatePattern::TildeEq {
assign: "assign".into(),
lhs: "lhs".into(),
key: "key".into(),
test: Box::new(TestExpr {
Expand All @@ -479,7 +478,6 @@ fn predicate_pattern() {
}),
}
.ast_eq(&PredicatePattern::TildeEq {
assign: "assign".into(),
lhs: "lhs".into(),
key: "key".into(),
test: Box::new(TestExpr {
Expand Down
5 changes: 1 addition & 4 deletions tremor-script/src/ast/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1396,8 +1396,6 @@ impl<'script> Upable<'script> for PatternRaw<'script> {
pub enum PredicatePatternRaw<'script> {
/// we're forced to make this pub because of lalrpop
TildeEq {
/// we're forced to make this pub because of lalrpop
assign: Cow<'script, str>,
/// we're forced to make this pub because of lalrpop
lhs: Cow<'script, str>,
/// we're forced to make this pub because of lalrpop
Expand Down Expand Up @@ -1453,8 +1451,7 @@ impl<'script> Upable<'script> for PredicatePatternRaw<'script> {
TuplePatternEq,
};
Ok(match self {
TildeEq { assign, lhs, test } => PredicatePattern::TildeEq {
assign,
TildeEq { lhs, test } => PredicatePattern::TildeEq {
key: KnownKey::from(lhs.clone()),
lhs,
test: Box::new(test.up(helper)?),
Expand Down
3 changes: 0 additions & 3 deletions tremor-script/src/ast/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,6 @@ fn pp_is_exclusive() {
);
let teq = PredicatePattern::TildeEq {
lhs: "k1".into(),
assign: "k".into(),
key: "k1".into(),
test: Box::new(TestExpr {
mid: NodeMeta::dummy(),
Expand All @@ -365,7 +364,6 @@ fn pp_is_exclusive() {
};
let test_eq2 = PredicatePattern::TildeEq {
lhs: "k2".into(),
assign: "k".into(),
key: "k2".into(),
test: Box::new(TestExpr {
mid: NodeMeta::dummy(),
Expand All @@ -376,7 +374,6 @@ fn pp_is_exclusive() {
};
let teq3 = PredicatePattern::TildeEq {
lhs: "k1".into(),
assign: "k".into(),
key: "k1".into(),
test: Box::new(TestExpr {
mid: NodeMeta::dummy(),
Expand Down
1 change: 1 addition & 0 deletions tremor-script/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#![allow(clippy::large_enum_variant)]
#![allow(deprecated)]
#![allow(missing_docs)]
#![allow(non_snake_case)]

use crate::errors::ErrorKind::InvalidBinaryBoolean;
pub use crate::prelude::ValueType;
Expand Down
3 changes: 2 additions & 1 deletion tremor-script/src/extractor/re.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ use tremor_value::Value;
use value_trait::prelude::*;

pub(crate) fn execute(s: &str, result_needed: bool, compiled: &Regex) -> Result<'static> {
compiled.captures(s).map_or(Result::NoMatch, |caps| {
let res = compiled.captures(s);
res.map_or(Result::NoMatch, |caps| {

Check warning on line 142 in tremor-script/src/extractor/re.rs

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/extractor/re.rs#L141-L142

Added lines #L141 - L142 were not covered by tests
if result_needed {
let matches: HashMap<Cow<str>, Value, _> = compiled
.capture_names()
Expand Down
5 changes: 3 additions & 2 deletions tremor-script/src/grammar.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -1425,8 +1425,9 @@ WhenClause: Option<ImutExprRaw<'input>> = {

/// Predicate Patterns (aka tests) for record pattrens
PredicateFieldPattern: PredicatePatternRaw<'input> = {
<lhs:Ident> "~=" <expr:TestExpr> => PredicatePatternRaw::TildeEq { assign: lhs.id.clone(), lhs: lhs.id, test: expr},
<assign:Ident> "=" <lhs:Ident> "~=" <expr:TestExpr> => PredicatePatternRaw::TildeEq { assign: assign.id, lhs: lhs.id, test: expr} ,
<lhs:Ident> "~=" <expr:TestExpr> => PredicatePatternRaw::TildeEq { lhs: lhs.id, test: expr},
// FIXME: why was assign never used in here?
<_assign:Ident> "=" <lhs:Ident> "~=" <expr:TestExpr> => PredicatePatternRaw::TildeEq { lhs: lhs.id, test: expr} ,
<lhs:Ident> "~=" <rp:RecordPattern> => PredicatePatternRaw::RecordPatternEq { lhs: lhs.id, pattern: rp },
<lhs:Ident> "~=" <ap:ArrayPattern> => PredicatePatternRaw::ArrayPatternEq { lhs: lhs.id, pattern: ap },
<lhs:Ident> "~=" <ap:TuplePattern> => PredicatePatternRaw::TuplePatternEq { lhs: lhs.id, pattern: ap },
Expand Down
122 changes: 87 additions & 35 deletions tremor-script/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{borrow::Cow, mem};
use std::{borrow::Cow, mem, ptr};

use compiler::Program;
use simd_json::{prelude::*, ValueBuilder};
Expand All @@ -10,9 +10,10 @@ use crate::{
raw::{BytesDataType, Endian},
},
errors::{error_generic, Result},
extractor,
interpreter::{exec_binary, exec_unary, merge_values},
prelude::Ranged,
NodeMeta, Return,
EventContext, NodeMeta, Return,
};

pub(super) mod compiler;
Expand Down Expand Up @@ -46,6 +47,7 @@ impl Vm {
pub fn run<'run, 'prog, 'event>(
&self,
event: &mut Value<'event>,
ctx: &EventContext,
program: &'run Program<'prog>,
) -> Result<Return<'event>>
where
Expand All @@ -72,7 +74,7 @@ impl Vm {

// ensure that the opcodes and meta are the same length
assert_eq!(program.opcodes.len(), program.meta.len());
root.run(event, &mut pc, &mut cc)
root.run(event, ctx, &mut pc, &mut cc)
}

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L67-L78

Added lines #L67 - L78 were not covered by tests
}

Expand All @@ -81,6 +83,7 @@ impl<'run, 'event> Scope<'run, 'event> {
pub fn run<'prog>(
&mut self,
event: &'run mut Value<'event>,
ctx: &EventContext,
pc: &mut usize,
cc: &mut usize,
) -> Result<Return<'event>>
Expand Down Expand Up @@ -118,7 +121,13 @@ impl<'run, 'event> Scope<'run, 'event> {
Op::LoadEvent => stack.push(Cow::Owned(event.clone())),
Op::StoreEvent { elements } => unsafe {
let mut tmp = event as *mut Value;
nested_assign(elements, &mut stack, &mut tmp, mid, *pc, *cc)?;
if stack.len() < elements as usize {
return Err(format!("Stack underflow @{pc}:{cc}").into());
}
let path = stack
.drain(stack.len() - (elements as usize)..)
.collect::<Vec<_>>();
nested_assign(path, &mut tmp, mid)?;
let r: &mut Value = tmp
.as_mut()
.ok_or("this is nasty, we have a null pointer")?;
Expand All @@ -134,7 +143,14 @@ impl<'run, 'event> Scope<'run, 'event> {
let idx = idx as usize;
if let Some(var) = self.locals[idx].as_mut() {
let mut tmp = var as *mut Value;
nested_assign(elements, &mut stack, &mut tmp, mid, *pc, *cc)?;
if stack.len() < elements as usize {
return Err(format!("Stack underflow @{pc}:{cc}").into());
}
let path = stack
.drain(stack.len() - (elements as usize)..)
.collect::<Vec<_>>();

nested_assign(path, &mut tmp, mid)?;
let r: &mut Value = tmp
.as_mut()
.ok_or("this is nasty, we have a null pointer")?;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L142-L156

Added lines #L142 - L156 were not covered by tests
Expand All @@ -147,6 +163,7 @@ impl<'run, 'event> Scope<'run, 'event> {
}
},

// Others
Op::True => stack.push(Cow::Owned(Value::const_true())),
Op::False => stack.push(Cow::Owned(Value::const_false())),
Op::Null => stack.push(Cow::Owned(Value::null())),
Expand Down Expand Up @@ -300,20 +317,6 @@ impl<'run, 'event> Scope<'run, 'event> {
stack.push(Cow::Owned(Value::Bytes(bytes.into())));

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L317

Added line #L317 was not covered by tests
}

// Compairsons ops that store in the B1 register
// Op::Binary {
// op:
// op @ (BinOpKind::Eq
// | BinOpKind::NotEq
// | BinOpKind::Gte
// | BinOpKind::Gt
// | BinOpKind::Lte
// | BinOpKind::Lt),
// } => {
// let rhs = pop(&mut stack, *pc, *cc)?;
// let lhs = pop(&mut stack, *pc, *cc)?;
// self.registers.b1 = exec_binary(mid, mid, op, &lhs, &rhs)?.try_as_bool()?;
// }
Op::Binary { op } => {
let rhs = pop(&mut stack, *pc, *cc)?;
let lhs = pop(&mut stack, *pc, *cc)?;
Expand All @@ -333,6 +336,35 @@ impl<'run, 'event> Scope<'run, 'event> {
self.reg.b1 = self.reg.v1.contains_key(key.try_as_str()?);

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L335-L336

Added lines #L335 - L336 were not covered by tests
} // record operations on scope

Op::TestExtractor { extractor } => {
let extractor: &_ = &self.program.extractors[extractor as usize];
// FIXME: We don't always need the result
let extracted = extractor.extract(true, self.reg.v1.as_ref(), ctx);
match extracted {
extractor::Result::MatchNull => {
self.reg.b1 = true;
stack.push(Cow::Owned(Value::null()));
}
extractor::Result::Match(v) => {
self.reg.b1 = true;
stack.push(Cow::Owned(v));
}
extractor::Result::NoMatch => self.reg.b1 = false,
extractor::Result::Err(e) => {
return Err(format!("extractor error: {e}").into())

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L339-L354

Added lines #L339 - L354 were not covered by tests
}
}
}
Op::TestPresent { elements } => {
if stack.len() < elements as usize {
return Err(format!("Stack underflow @{pc}:{cc}").into());
}
let path = stack
.drain(stack.len() - (elements as usize)..)
.collect::<Vec<_>>();
self.reg.b1 = present(path, &self.reg.v1);

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L358-L365

Added lines #L358 - L365 were not covered by tests
}

Op::TestIsU64 => {
self.reg.b1 = self.reg.v1.is_u64();
}
Expand Down Expand Up @@ -555,34 +587,24 @@ impl<'run, 'event> Scope<'run, 'event> {
/// This function is unsafe since it works with pointers.
/// It remains safe since we never leak the pointer and just
/// traverse the nested value a pointer at a time.
unsafe fn nested_assign(
elements: u16,
stack: &mut Vec<Cow<Value>>,
tmp: &mut *mut Value,
mid: &NodeMeta,
pc: usize,
cc: usize,
) -> Result<()> {
for _ in 0..elements {
let target = pop(stack, pc, cc)?;
fn nested_assign(path: Vec<Cow<Value>>, tmp: &mut *mut Value, mid: &NodeMeta) -> Result<()> {
for target in path {
if let Some(idx) = target.as_usize() {
let array = tmp
.as_mut()
let array = unsafe { tmp.as_mut() }
.ok_or("this is nasty, we have a null pointer")?
.as_array_mut()
.ok_or("needs object")?;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L590-L596

Added lines #L590 - L596 were not covered by tests

*tmp = std::ptr::from_mut::<Value>(match array.get_mut(idx) {
*tmp = ptr::from_mut::<Value>(match array.get_mut(idx) {
Some(v) => v,
None => return Err("Index out of bounds".into()),

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L598-L600

Added lines #L598 - L600 were not covered by tests
});
} else if let Some(key) = target.as_str() {
let map = tmp
.as_mut()
let map = unsafe { tmp.as_mut() }
.ok_or("this is nasty, we have a null pointer")?
.as_object_mut()
.ok_or("needs object")?;
*tmp = std::ptr::from_mut::<Value>(match map.get_mut(key) {
*tmp = ptr::from_mut::<Value>(match map.get_mut(key) {
Some(v) => v,
None => map
.entry(key.to_string().into())
Expand All @@ -595,6 +617,36 @@ unsafe fn nested_assign(
Ok(())
}

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L617-L618

Added lines #L617 - L618 were not covered by tests

/// This function is unsafe since it works with pointers.
/// It remains safe since we never leak the pointer and just
/// traverse the nested value a pointer at a time.
fn present(keys: Vec<Cow<Value>>, val: &Value) -> bool {
let mut tmp = ptr::from_ref(val);

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L623-L624

Added lines #L623 - L624 were not covered by tests
// the path is stored reversed on the stack so we have to approach it from back to front
for target in keys {
if let Some(idx) = target.as_usize() {
let Some(array) = unsafe { tmp.as_ref() }.and_then(|v| v.as_array()) else {
return false;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L626-L629

Added lines #L626 - L629 were not covered by tests
};
let Some(v) = array.get(idx) else {
return false;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L631-L632

Added lines #L631 - L632 were not covered by tests
};
tmp = ptr::from_ref(v);
} else if let Some(key) = target.as_str() {
let Some(map) = unsafe { tmp.as_ref() }.and_then(|v| v.as_object()) else {
return false;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L634-L637

Added lines #L634 - L637 were not covered by tests
};
let Some(v) = map.get(key) else {
return false;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L639-L640

Added lines #L639 - L640 were not covered by tests
};
tmp = ptr::from_ref(v);

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L642

Added line #L642 was not covered by tests
} else {
return false;

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L644

Added line #L644 was not covered by tests
}
}
true
}

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

View check run for this annotation

Codecov / codecov/patch

tremor-script/src/vm.rs#L647-L648

Added lines #L647 - L648 were not covered by tests

#[inline]
fn pop<'run, 'event>(
stack: &mut Vec<Cow<'run, Value<'event>>>,
Expand Down
Loading

0 comments on commit 6241dc7

Please sign in to comment.