summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/vm/de.rs122
-rw-r--r--src/vm/mod.rs28
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,
+            )
         })
     }