diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2022-10-27 20:20:46 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2022-10-27 20:20:46 -0300 |
commit | 9481722069fc463f2557be61cb9b8fcd4ed7e3bd (patch) | |
tree | 05e264958cf91dd638d06db16882e8ba6da5059a | |
parent | 8fa3870633377dd626faa2e2145ae068109e6456 (diff) |
Make multiple frames work
-rw-r--r-- | src/vm/de.rs | 122 | ||||
-rw-r--r-- | src/vm/mod.rs | 28 |
2 files changed, 131 insertions, 19 deletions
diff --git a/src/vm/de.rs b/src/vm/de.rs index 1f00995..5994984 100644 --- a/src/vm/de.rs +++ b/src/vm/de.rs @@ -162,18 +162,25 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> { &mut self, mut packs: Vec<Pack<'pat, 'de>>, ) -> Vec<Pack<'pat, 'de>> { + // this code attempts to maintain the logical invariant of: + // self.frames().iter_active().count() == packs.len() self.call_limit += 1; let mut index_iter = 0..; + let mut pack_index = packs.len(); while let Some(index) = index_iter.next().filter(|&i| { i < self.interp.frames.len() }) { // iterate backwards let index = self.interp.frames.len() - index - 1; let frame = &mut self.interp.frames[index]; + let has_pack = frame.matches; if frame.overstep > 0 { // handle overstep frame.overstep -= 1; } else { + if has_pack { + pack_index -= 1; + } // unwind frame if frame.prev() { // successfully unwound. do nothing. @@ -181,24 +188,49 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> { // find parent frame. let mut count = 1; let mut target = index; + let mut target_pack = pack_index; + let mut target_unwound = false; while count > 0 && target > 0 { target -= 1; match self.interp.frames[target].num_subtrees() { - Some(num) if num <= count => { + Some((num, _)) if num < count => { + if has_pack { + debug_assert!(target_pack > 0); + target_pack -= 1; + } count -= num; }, - Some(num) => { + Some((num, unwound)) => { + if has_pack { + debug_assert!(target_pack > 0); + target_pack -= 1; + } + target_unwound = unwound; count = 0; }, None => { + if has_pack { + if self.interp.frames[target].matches { + debug_assert!(target_pack > 0); + target_pack -= 1; + } + } count += 1; }, } } if count == 0 { - // has parent frame - let pack = packs.remove(index); - todo!("merge packs") + let frame = self.interp.frames.remove(target); + // TODO what to do with `frame`? + if has_pack { + // has parent frame + let pack = packs.remove(pack_index); + if !target_unwound { + packs.insert(target_pack, pack); + } else { + packs[target_pack].merge_from(pack); + } + } } } } @@ -225,7 +257,7 @@ where let target_type = self.frames().iter_active().fold( Type::IgnoredAny, |target_type, frame| { - match (target_type, frame.get_type(pat)) { + match (target_type, frame.get_type()) { (Type::IgnoredAny, Some((ty, _))) => ty, (ty, Some((Type::IgnoredAny, _))) => ty, (Type::String, Some((Type::Str, _))) => { @@ -328,15 +360,18 @@ macro_rules! vs { } let mut packs = Vec::new(); $this.frames_mut().iter_active_mut().try_for_each(|frame| { - let ty = frame.get_type(pat); + let ty = frame.get_type(); match ty { | Some(($data_type, _)) | Some((Type::Any, _)) | Some((Type::IgnoredAny, _)) + | None => {}, - Some((_, false)) => todo!(), + Some((_, false)) => { + frame.matches = false; + return Ok(()); + }, Some((_, true)) => return Err(todo!()), - None => unreachable!(), } let mut pack = Pack::default(); if let Some(name) = frame.get_name(pat) { @@ -461,7 +496,7 @@ where let pat = self.interp.pat; let mut collecting = old_collecting; self.frames_mut().iter_active_mut().try_for_each(|frame| { - let ty = frame.get_type(pat); + let ty = frame.get_type(); match ty { | Some((Type::Map, _)) | Some((Type::Any, _)) @@ -528,7 +563,11 @@ where (packed_key.1.unwrap(), packed_value.1.unwrap()), ); } - todo!("merge kv"); + todo!("merge vecs of packs"); + //let mut merge_pack = packed_key.0; + //let value_pack = packed_value.0; + //merge_pack.merge_from(value_pack); + //dbg!(merge_pack); } todo!(); } @@ -679,6 +718,7 @@ mod tests { use crate::vm::Value; use crate::vm::PatternElement; use crate::vm::SerdeObject; + use crate::vm::Frame; use these::These; use serde_json::Deserializer as JsonDeserializer; use serde::de::DeserializeSeed as _; @@ -686,6 +726,8 @@ mod tests { #[test] #[should_panic] fn test_broken() { + // broken pattern, should never be emitted by parser. make sure it's + // not accepted. let consts = PatternConstants::<()>::default(); let mut err = Default::default(); let mut frames = Default::default(); @@ -695,6 +737,7 @@ mod tests { #[test] fn test_empty_create() { + // test creating the parser with an empty pattern. let mut consts = PatternConstants::<()>::default(); consts.protos.push(Vec::new()); let mut err = Default::default(); @@ -705,6 +748,7 @@ mod tests { #[test] fn test_empty_match() { + // test matching something with an empty pattern. let mut consts = PatternConstants::<()>::default(); consts.protos.push(Vec::new()); let mut der = JsonDeserializer::from_str("{}"); @@ -716,6 +760,7 @@ mod tests { #[test] fn test_simple_match() { + // test matching a simple value let mut consts = PatternConstants::<()>::default(); consts.strings.push("hello".into()); consts.protos.push(vec![ @@ -738,6 +783,7 @@ mod tests { #[test] fn test_simple_error() { + // test a value that doesn't match (serde_json error) let mut consts = PatternConstants::<()>::default(); consts.strings.push("hello".into()); consts.protos.push(vec![ @@ -759,6 +805,60 @@ mod tests { } #[test] + fn test_basic_multiframe() { + // test multiple frames (matching and non-matching) + let mut consts = PatternConstants::<()>::default(); + consts.strings.push("a".into()); + consts.strings.push("b".into()); + consts.protos.push(vec![ + PatternElement::Value { + name_and_value: These::Both(0, Value::Type { + ty: Type::U64, + skippable: true, + }), + }, + ]); + consts.protos.push(vec![ + PatternElement::Value { + name_and_value: These::Both(1, Value::Type { + ty: Type::Bool, + skippable: true, + }), + }, + ]); + let mut der = JsonDeserializer::from_str(r#"10"#); + let mut err = Default::default(); + let mut frames: Vec<_> = Default::default(); + frames.push(Frame { + ops: &consts.protos[0], + iar: None, + matches: true, + overstep: 0, + }); + frames.push(Frame { + ops: &consts.protos[1], + iar: None, + matches: true, + overstep: 0, + }); + let interp = Interpreter { + pat: &consts, + error: &mut err, + frames: &mut frames, + }; + let packed = Packer::new(interp, MAX_CALLS).deserialize(&mut der); + let (packs, obj) = packed.unwrap(); + assert!(obj.is_none()); + assert_eq!( + packs[0].subpacks[0]["a"].1, + SerdeObject::U64(10), + ); + assert_eq!(packs.len(), 1); + assert!(frames[0].matches); + assert!(!frames[1].matches); + } + + #[test] fn test_map() { let mut consts = PatternConstants::<()>::default(); consts.strings.push("key".into()); diff --git a/src/vm/mod.rs b/src/vm/mod.rs index afb98cc..dca9faa 100644 --- a/src/vm/mod.rs +++ b/src/vm/mod.rs @@ -344,11 +344,20 @@ where } } +/// Packed serde objects and datafu internal representation. +/// +/// This is an iterative store of key-value pairs. #[derive(Clone, Debug, Default)] pub struct Pack<'pat, 'de> { subpacks: Vec<IndexMap<&'pat str, (Pack<'pat, 'de>, SerdeObject<'de>)>>, } +impl<'pat, 'de> Pack<'pat, 'de> { + fn merge_from(&mut self, mut other: Self) { + todo!("merge packs"); + } +} + /// The Datafu interpreter, sorta. #[derive(Debug)] pub(crate) struct Interpreter<'pat, 'state, O: Serialize> { @@ -402,9 +411,8 @@ impl<'pat> Frame<'pat> { /// Gets the type currently associated with this frame. /// /// Returns the type and whether it is required to match. - fn get_type<O: Serialize>( + fn get_type( &self, - pat: &'pat PatternConstants<O>, ) -> Option<(Type, bool)> { match self.op() { | PatternElement::Value { name_and_value, .. } @@ -467,13 +475,14 @@ impl<'pat> Frame<'pat> { self.ops[self.iar.expect("ops[iar]")] } - /// Counts the number of *active* subtrees, if any. + /// Counts the number of *active* subtrees, if any, and whether any + /// subtrees have been unwound. /// /// # Panics /// /// Panics if iteration hasn't begun. - fn num_subtrees(&self) -> Option<usize> { - let iar = self.iar.expect("iar"); + fn num_subtrees(&self) -> Option<(usize, bool)> { + let iar = self.iar?; // check if there are any subtrees matches!( self.ops[iar], @@ -481,9 +490,12 @@ impl<'pat> Frame<'pat> { | PatternElement::SubtreeMarker ).then(|| { // count the number of subtrees - self.ops[0..=iar].iter().rev().take_while(|x| { - matches!(x, PatternElement::ValueSubtree { .. }) - }).count() + ( + self.ops[0..=iar].iter().rev().take_while(|x| { + matches!(x, PatternElement::ValueSubtree { .. }) + }).count(), + self.ops.len() - 1 != iar, + ) }) } |