]> Repositorios git - scryer-prolog.git/commitdiff
Fix result parsing for complex string results
authorNicolas Luck <[email protected]>
Fri, 21 Jul 2023 12:35:44 +0000 (14:35 +0200)
committerNicolas Luck <[email protected]>
Fri, 21 Jul 2023 12:35:44 +0000 (14:35 +0200)
Cargo.lock
Cargo.toml
src/machine/lib_machine.rs
src/machine/parsed_results.rs

index 29cf7f677cf9769acb652bf3992776f92980676b..5ed25656cd780414dd185179ecf8da3f209db14a 100644 (file)
@@ -2,6 +2,15 @@
 # It is not intended for manual editing.
 version = 3
 
+[[package]]
+name = "aho-corasick"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "android_system_properties"
 version = "0.1.5"
@@ -138,7 +147,7 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
 dependencies = [
  "lazy_static",
  "memchr",
- "regex-automata",
+ "regex-automata 0.1.10",
 ]
 
 [[package]]
@@ -1673,12 +1682,41 @@ version = "0.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
 
+[[package]]
+name = "regex"
+version = "1.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata 0.3.3",
+ "regex-syntax",
+]
+
 [[package]]
 name = "regex-automata"
 version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
 
+[[package]]
+name = "regex-automata"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
+
 [[package]]
 name = "remove_dir_all"
 version = "0.5.3"
@@ -1848,6 +1886,7 @@ dependencies = [
  "proc-macro2 1.0.47",
  "quote 1.0.21",
  "ref_thread_local",
+ "regex",
  "ring",
  "ripemd160",
  "roxmltree",
index a6f97b04695712b17ccbc3eb26da529ce0e339d7..c64b7510208b444c0ef0085a661b7202c87c6b7f 100644 (file)
@@ -63,6 +63,7 @@ hyper = { version = "0.14", features = ["full"] }
 hyper-tls = "0.5.0"
 tokio = { version = "1", features = ["full"] }
 futures = "0.3"
+regex = "1.9.1"
 
 [dev-dependencies]
 assert_cmd = "1.0.3"
index f88577ceaec52fbbb4b41c219b992bef6f43011b..1dfdd2b28b875830c49e2f1d9d29bd8870c906d3 100644 (file)
@@ -83,4 +83,56 @@ mod tests {
             Err(String::from("error(existence_error(procedure,triple/3),triple/3)."))
         );
     }
+
+    #[test]
+    fn complex_results() {
+        let mut machine = Machine::new_lib();
+        machine.load_module_string(
+            "facts",
+                r#"
+                :- discontiguous(subject_class/2).
+                :- discontiguous(constructor/2).
+
+                subject_class("Todo", c).
+                constructor(c, '[{action: "addLink", source: "this", predicate: "todo://state", target: "todo://ready"}]').
+
+                subject_class("Recipe", xyz).
+                constructor(xyz, '[{action: "addLink", source: "this", predicate: "recipe://title", target: "literal://string:Meta%20Muffins"}]').
+            "#.to_string());
+
+        let result = machine.run_query(String::from("subject_class(\"Todo\", C), constructor(C, Actions)."));
+        assert_eq!(
+            result,
+            Ok(QueryResolution::Matches(vec![
+                QueryMatch::from(btreemap! {
+                    "C" => Value::from("c"),
+                    "Actions" => Value::from("[{action: \"addLink\", source: \"this\", predicate: \"todo://state\", target: \"todo://ready\"}]"),
+                }),
+            ]))
+        );
+
+        let result = machine.run_query(String::from("subject_class(\"Recipe\", C), constructor(C, Actions)."));
+        assert_eq!(
+            result,
+            Ok(QueryResolution::Matches(vec![
+                QueryMatch::from(btreemap! {
+                    "C" => Value::from("xyz"),
+                    "Actions" => Value::from("[{action: \"addLink\", source: \"this\", predicate: \"recipe://title\", target: \"literal://string:Meta%20Muffins\"}]"),
+                }),
+            ]))
+        );
+
+        let result = machine.run_query(String::from("subject_class(Class, _)."));
+        assert_eq!(
+            result,
+            Ok(QueryResolution::Matches(vec![
+                QueryMatch::from(btreemap! {
+                    "Class" => Value::from("Todo")
+                }),
+                QueryMatch::from(btreemap! {
+                    "Class" => Value::from("Recipe")
+                }),
+            ]))
+        );
+    }
 }
index f34eadeab3b835eddd643429e3c88c67b4ae2710..ba33089d150b877ab7a2ecd173aee48d9f9f075b 100644 (file)
@@ -2,6 +2,8 @@ use crate::atom_table::*;
 use ordered_float::OrderedFloat;
 use rug::*;
 use std::collections::BTreeMap;
+use regex::Regex;
+use std::collections::HashMap;
 
 pub type QueryResult = Result<QueryResolution, String>;
 
@@ -103,6 +105,25 @@ impl From<Vec<QueryResolutionLine>> for QueryResolution {
     }
 }
 
+fn parse_prolog_response(input: &str) -> HashMap<String, String> {
+    let mut map: HashMap<String, String> = HashMap::new();
+    // Use regex to match strings including commas inside them
+    let re = Regex::new(r"(\w+)\s=\s([^,]*'[^']*'[^,]*|[^,]*)").unwrap();
+    
+    for cap in re.captures_iter(input) {
+        let key = cap[1].to_string();
+        let value = cap[2].trim_end_matches(',').trim().to_string();
+        // cut off at given characters/strings:
+        let value = value.split("\n").next().unwrap().to_string();
+        let value = value.split("  ").next().unwrap().to_string();
+        let value = value.split("\t").next().unwrap().to_string();
+        let value = value.split("error").next().unwrap().to_string();
+        map.insert(key, value);
+    }
+    
+    map
+}
+
 impl TryFrom<String> for QueryResolutionLine {
     type Error = ();
     fn try_from(string: String) -> Result<Self, Self::Error> {
@@ -110,20 +131,17 @@ impl TryFrom<String> for QueryResolutionLine {
             "true" => Ok(QueryResolutionLine::True),
             "false" => Ok(QueryResolutionLine::False),
             _ => Ok(QueryResolutionLine::Match(
-                string
-                    .split(",")
-                    .map(|s| s.trim())
-                    .filter(|s| !s.is_empty())
-                    .map(|s| -> Result<(String, Value), ()> {
-                        let mut iter = s.split(" = ");
-                        let key = iter.next().ok_or(())?.to_string();
-                        let value = iter.next().ok_or(())?.to_string();
-
+                parse_prolog_response(&string)
+                    .iter()
+                    .map(|(k, v)| -> Result<(String, Value), ()> {
+                        let key = k.to_string();
+                        let value = v.to_string();
                         Ok((key, Value::try_from(value)?))
                     })
                     .filter_map(Result::ok)
-                    .collect::<BTreeMap<_, _>>(),
-            )),
+                    .collect::<BTreeMap<_, _>>()
+                )
+            ),
         }
     }
 }
@@ -175,6 +193,8 @@ impl TryFrom<String> for Value {
             }
 
             Ok(Value::Structure(atom!("<<>>"), values))
+        } else if !trimmed.contains(",") && !trimmed.contains("'") && !trimmed.contains("\"") {
+            Ok(Value::String(trimmed.into()))
         } else {
             Err(())
         }