diff options
Diffstat (limited to 'src/vm/de.rs')
-rw-r--r-- | src/vm/de.rs | 122 |
1 files changed, 111 insertions, 11 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()); |