# 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"
dependencies = [
"lazy_static",
"memchr",
- "regex-automata",
+ "regex-automata 0.1.10",
]
[[package]]
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"
"proc-macro2 1.0.47",
"quote 1.0.21",
"ref_thread_local",
+ "regex",
"ring",
"ripemd160",
"roxmltree",
hyper-tls = "0.5.0"
tokio = { version = "1", features = ["full"] }
futures = "0.3"
+regex = "1.9.1"
[dev-dependencies]
assert_cmd = "1.0.3"
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")
+ }),
+ ]))
+ );
+ }
}
use ordered_float::OrderedFloat;
use rug::*;
use std::collections::BTreeMap;
+use regex::Regex;
+use std::collections::HashMap;
pub type QueryResult = Result<QueryResolution, String>;
}
}
+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> {
"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<_, _>>()
+ )
+ ),
}
}
}
}
Ok(Value::Structure(atom!("<<>>"), values))
+ } else if !trimmed.contains(",") && !trimmed.contains("'") && !trimmed.contains("\"") {
+ Ok(Value::String(trimmed.into()))
} else {
Err(())
}