summary refs log tree commit diff stats
path: root/src/vm
diff options
context:
space:
mode:
authorSoniEx2 <endermoneymod@gmail.com>2022-10-30 00:49:56 -0300
committerSoniEx2 <endermoneymod@gmail.com>2022-10-30 00:49:56 -0300
commita66111d9f9c99f91d9256209b5e9a65e42cde7f5 (patch)
treeaba85fd481ade96ba1be135c459af9d20eb409d7 /src/vm
parentc1210b511af8ffada948550180360859b64009d2 (diff)
Implement parser
Diffstat (limited to 'src/vm')
-rw-r--r--src/vm/de.rs61
-rw-r--r--src/vm/mod.rs29
2 files changed, 55 insertions, 35 deletions
diff --git a/src/vm/de.rs b/src/vm/de.rs
index 985b1b2..e26ec5e 100644
--- a/src/vm/de.rs
+++ b/src/vm/de.rs
@@ -14,7 +14,6 @@ use serde::de::IntoDeserializer as _;
 
 use smallvec::SmallVec;
 
-use these::These;
 
 use super::Frame;
 use super::Interpreter;
@@ -275,31 +274,51 @@ where
     {
         if let Err(e) = self.step_in() { return Err(e); }
         let pat = self.interp.pat;
-        let target_type = self.frames().iter_active().fold(
+        let target_type = self.frames().iter_active().try_fold(
             Type::IgnoredAny,
             |target_type, frame| {
-                match (target_type, frame.get_type()) {
-                    (Type::IgnoredAny, Some((ty, _))) => ty,
-                    (ty, Some((Type::IgnoredAny, _))) => ty,
-                    (Type::String, Some((Type::Str, _))) => {
+                Ok(match (target_type, frame.get_type()) {
+                    // required type binds stronger than any/ignored_any
+                    (Type::IgnoredAny, Some((ty, true))) => ty,
+                    (Type::Any, Some((ty, true))) => ty,
+                    (ty, Some((Type::IgnoredAny, true))) => ty,
+                    (ty, Some((Type::Any, true))) => ty,
+                    // prefer owned if any branch prefers owned
+                    (Type::String, Some((Type::Str, true))) => {
                         Type::String
                     },
-                    (Type::Str, Some((Type::String, _))) => {
+                    (Type::Str, Some((Type::String, true))) => {
                         Type::String
                     },
-                    (Type::Bytes, Some((Type::ByteBuf, _))) => {
+                    (Type::Bytes, Some((Type::ByteBuf, true))) => {
                         Type::ByteBuf
                     },
-                    (Type::ByteBuf, Some((Type::Bytes, _))) => {
+                    (Type::ByteBuf, Some((Type::Bytes, true))) => {
                         Type::ByteBuf
                     },
+                    // types which are the same are okay
                     (left, Some((right, _))) if left == right => {
                         left
                     },
+                    // optional type vs Any/IgnoredAny prefers Any
+                    (Type::IgnoredAny, Some((_, false))) => Type::Any,
+                    (Type::Any, Some((_, false))) => Type::Any,
+                    // types which are not the same are an error because we
+                    // only request a specific type if it's actually required
+                    (left, Some((right, _))) => {
+                        return Err(todo!());
+                    },
                     _ => Type::Any,
-                }
+                })
             },
         );
+        let target_type = match target_type {
+            Ok(target_type) => target_type,
+            Err(e) => {
+                self.interp.error.insert(e);
+                return Err(D::Error::custom("type conflict"));
+            },
+        };
         match target_type {
             Type::Any => deserializer.deserialize_any(&mut *self),
             Type::IgnoredAny => {
@@ -840,7 +859,6 @@ mod tests {
     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 _;
 
@@ -886,7 +904,8 @@ mod tests {
         consts.strings.push("hello".into());
         consts.protos.push(vec![
             PatternElement::Value {
-                name_and_value: These::Both(0, Value::Type {
+                name: Some(0),
+                value: Some(Value::Type {
                     ty: Type::U64,
                     skippable: false,
                 }),
@@ -909,7 +928,8 @@ mod tests {
         consts.strings.push("hello".into());
         consts.protos.push(vec![
             PatternElement::Value {
-                name_and_value: These::Both(0, Value::Type {
+                name: Some(0),
+                value: Some(Value::Type {
                     ty: Type::U64,
                     skippable: false,
                 }),
@@ -933,7 +953,8 @@ mod tests {
         consts.strings.push("b".into());
         consts.protos.push(vec![
             PatternElement::Value {
-                name_and_value: These::Both(0, Value::Type {
+                name: Some(0),
+                value: Some(Value::Type {
                     ty: Type::U64,
                     skippable: true,
                 }),
@@ -941,7 +962,8 @@ mod tests {
         ]);
         consts.protos.push(vec![
             PatternElement::Value {
-                name_and_value: These::Both(1, Value::Type {
+                name: Some(1),
+                value: Some(Value::Type {
                     ty: Type::Bool,
                     skippable: true,
                 }),
@@ -986,12 +1008,14 @@ mod tests {
         consts.strings.push("value".into());
         consts.protos.push(vec![
             PatternElement::Value {
-                name_and_value: These::This(0),
+                name: Some(0),
+                value: None,
             },
         ]);
         consts.protos.push(vec![
             PatternElement::Value {
-                name_and_value: These::That(Value::Type {
+                name: None,
+                value: Some(Value::Type {
                     ty: Type::Map,
                     skippable: false,
                 }),
@@ -1000,7 +1024,8 @@ mod tests {
                 key_subtree: Some(0),
             },
             PatternElement::Value {
-                name_and_value: These::Both(1, Value::Type {
+                name: Some(1),
+                value: Some(Value::Type {
                     ty: Type::U64,
                     skippable: false,
                 }),
diff --git a/src/vm/mod.rs b/src/vm/mod.rs
index 8f20aae..06f12e5 100644
--- a/src/vm/mod.rs
+++ b/src/vm/mod.rs
@@ -14,7 +14,6 @@ use std::marker::PhantomData;
 use indexmap::IndexMap;
 use regex::Regex;
 use serde::Serialize;
-use these::These;
 
 use crate::Predicate;
 //use crate::errors::MatchError;
@@ -82,9 +81,10 @@ impl<O: Serialize> std::fmt::Debug for PatternConstants<O> {
 pub(crate) enum PatternElement {
     /// A value is the core capturing element.
     Value {
-        /// The index of the (string) name to apply to this value and/or the
-        /// expected value of this entry.
-        name_and_value: These<usize, Value>,
+        /// The index of the (string) name to apply to this value.
+        name: Option<usize>,
+        /// The expected value of this entry.
+        value: Option<Value>,
     },
     /// A tag is the core iterative element. It is always followed by a value.
     Tag {
@@ -173,7 +173,7 @@ pub(crate) enum PatternToken {
     String(usize, bool),
     Regex(usize, bool),
     Parameter(usize, bool),
-    KeySubtree(usize, bool),
+    KeySubtree(usize),
     ValueSubtree(usize, bool),
 
     /// Represents a predicate which must be applied.
@@ -424,19 +424,16 @@ impl<'pat> Frame<'pat> {
         &self,
     ) -> Option<(Type, bool)> {
         match self.op() {
-            | PatternElement::Value { name_and_value, .. }
-            if name_and_value.is_there()
-            => {
-                match name_and_value.there() {
-                    | Some(Value::String { skippable, .. })
-                    | Some(Value::Regex { skippable, .. })
+            PatternElement::Value { value: Some(value), .. } => {
+                match value {
+                    | Value::String { skippable, .. }
+                    | Value::Regex { skippable, .. }
                     => {
                         Some((Type::Str, !skippable))
                     },
-                    Some(Value::Type { ty, skippable }) => {
+                    Value::Type { ty, skippable } => {
                         Some((ty, !skippable))
                     },
-                    None => todo!(),
                 }
             },
             PatternElement::Tag { .. } => panic!("attempt to get type of tag"),
@@ -451,10 +448,8 @@ impl<'pat> Frame<'pat> {
     ) -> Option<&'pat str> {
         let strings = &pat.strings;
         match self.op() {
-            | PatternElement::Value { name_and_value, .. }
-            if name_and_value.is_here()
-            => {
-                Some(&*strings[name_and_value.here().unwrap()])
+            PatternElement::Value { name: Some(name), .. } => {
+                Some(&*strings[name])
             },
             PatternElement::Tag { .. } => panic!("attempt to get name of tag"),
             _ => None,