summary refs log tree commit diff stats
path: root/src/vm/de.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/de.rs')
-rw-r--r--src/vm/de.rs67
1 files changed, 38 insertions, 29 deletions
diff --git a/src/vm/de.rs b/src/vm/de.rs
index 6cb8e94..493b658 100644
--- a/src/vm/de.rs
+++ b/src/vm/de.rs
@@ -167,6 +167,7 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> {
                                 iar: None,
                                 overstep: 0,
                                 matches: true,
+                                poison: false,
                             };
                             // we want the "newest" frame last, so it is
                             // easier to unwind back.
@@ -199,7 +200,7 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> {
             // iterate backwards
             let index = orig_len - index - 1;
             let frame = &mut self.interp.frames[index];
-            let has_pack = frame.matches;
+            let mut has_pack = frame.matches;
             if frame.overstep > 0 {
                 // handle overstep
                 frame.overstep -= 1;
@@ -207,6 +208,16 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> {
                 if has_pack {
                     pack_index -= 1;
                 }
+                if frame.poison {
+                    if has_pack {
+                        packs.remove(pack_index);
+                    }
+                    frame.matches = false;
+                    has_pack = false;
+                    if frame.is_value() {
+                        frame.poison = false;
+                    }
+                }
                 // unwind frame
                 if frame.prev() {
                     // successfully unwound. do nothing.
@@ -250,13 +261,7 @@ impl<'pat, 'state, 'de, O: Serialize> Packer<'pat, 'state, O> {
                             }
                         } else {
                             if !optional {
-                                // FIXME we actually want to skip it entirely
-                                // but that currently causes wrong results
-                                // so instead we just error...
-                                self.interp.error.insert({
-                                    MatchError::ValidationError
-                                });
-                                return Err(E::custom("subtree failed"));
+                                target_frame.poison = true;
                             }
                         }
                         if let Some((0, _)) = target_frame.num_subtrees() {
@@ -746,12 +751,13 @@ where
         let mut subframes = Vec::new();
         let mut output_matches = Vec::new();
         self.frames().iter_active().for_each(|frame| {
-            if let Some(key_subtree) = frame.key_subtree() {
+            if let Some((key_subtree, _)) = frame.key_subtree() {
                 subframes.push(Frame {
                     ops: &pat.protos[key_subtree],
                     iar: None,
                     overstep: 0,
                     matches: true,
+                    poison: false,
                 });
             }
             output_matches.push(false);
@@ -859,6 +865,8 @@ where
             }
         }
         for (f, m) in self.frames_mut().iter_active_mut().zip(output_matches) {
+            // FIXME inspect frame.key_subtree() for optional?
+            // what is this even supposed to do again?
             f.matches = m;
         }
         let obj = SerdeObject::Map(obj_inner);
@@ -1164,12 +1172,14 @@ mod tests {
             iar: None,
             matches: true,
             overstep: 0,
+            poison: false,
         });
         frames.push(Frame {
             ops: &consts.protos[1],
             iar: None,
             matches: true,
             overstep: 0,
+            poison: false,
         });
         let interp = Interpreter {
             pat: &consts,
@@ -1209,7 +1219,8 @@ mod tests {
                 }),
             },
             PatternElement::Tag {
-                key_subtree: Some(0),
+                key_subtree: 0,
+                optional: true,
             },
             PatternElement::Value {
                 name: Some(1),
@@ -1405,7 +1416,6 @@ mod tests {
             None
         ).unwrap();
         let data = r#"{"a": {"1": {"y": true}, "2": {"x": true, "y": true}}}"#;
-        //let data = r#"{"a": {"2": {"x": true, "y": true}}}"#;
         let mut der = JsonDeserializer::from_str(data);
         let mut err = Default::default();
         let mut frames = Default::default();
@@ -1419,18 +1429,17 @@ mod tests {
             interp,
             MAX_CALLS,
         ).deserialize(&mut der);
-        // FIXME it's supposed to skip "1" altogether but it currently errors.
-        assert!(result.is_err());
-        //let (mut packs, obj) = result.unwrap();
-        //assert!(obj.is_none());
-        //assert_eq!(packs.len(), 1);
-        //let pack = &packs[0];
-        //assert_eq!(pack.subpacks.len(), 1);
-        //let b = &pack.subpacks[0]["b"];
-        //assert_eq!(b.1, SerdeObject::Str(From::from("2")));
-        //assert_eq!(b.0.subpacks.len(), 1);
-        //assert_eq!(b.0.subpacks[0]["x"].1, SerdeObject::Bool(true));
-        //assert_eq!(b.0.subpacks[0]["y"].1, SerdeObject::Bool(true));
+        let (mut packs, obj) = result.unwrap();
+        assert!(obj.is_none());
+        assert_eq!(packs.len(), 1);
+        let pack = &packs[0];
+        dbg!(pack);
+        assert_eq!(pack.subpacks.len(), 1);
+        let b = &pack.subpacks[0]["b"];
+        assert_eq!(b.1, SerdeObject::Str(From::from("2")));
+        assert_eq!(b.0.subpacks.len(), 1);
+        assert_eq!(b.0.subpacks[0]["x"].1, SerdeObject::Bool(true));
+        assert_eq!(b.0.subpacks[0]["y"].1, SerdeObject::Bool(true));
     }
 
     #[test]
@@ -1439,12 +1448,12 @@ mod tests {
         let consts = crate::parser::parse::<&'static str, &'static str, ()>(
             "
             :map
-            ->['projects'?]:map
-              ->[commit:?str]:?map
-                ->[url:?str]:?map
-                  ->[branch:?str]:?map
-                    (->['active'?]active:?bool)?
-                    (->['federate'?]federate:?bool)?
+            ->['projects'?]?:map
+              ->[commit:?str]?:?map
+                ->[url:?str]?:?map
+                  ->[branch:?str]?:?map
+                    (->['active'?]?active:?bool)
+                    (->['federate'?]?federate:?bool)?
             ",
             None,
             None