Fix result parsing for complex string results
This commit is contained in:
41
Cargo.lock
generated
41
Cargo.lock
generated
@@ -2,6 +2,15 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -138,7 +147,7 @@ checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1673,12 +1682,41 @@ version = "0.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d813022b2e00774a48eaf43caaa3c20b45f040ba8cbf398e2e8911a06668dbe6"
|
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]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
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]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@@ -1848,6 +1886,7 @@ dependencies = [
|
|||||||
"proc-macro2 1.0.47",
|
"proc-macro2 1.0.47",
|
||||||
"quote 1.0.21",
|
"quote 1.0.21",
|
||||||
"ref_thread_local",
|
"ref_thread_local",
|
||||||
|
"regex",
|
||||||
"ring",
|
"ring",
|
||||||
"ripemd160",
|
"ripemd160",
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ hyper = { version = "0.14", features = ["full"] }
|
|||||||
hyper-tls = "0.5.0"
|
hyper-tls = "0.5.0"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
|
regex = "1.9.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "1.0.3"
|
assert_cmd = "1.0.3"
|
||||||
|
|||||||
@@ -83,4 +83,56 @@ mod tests {
|
|||||||
Err(String::from("error(existence_error(procedure,triple/3),triple/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")
|
||||||
|
}),
|
||||||
|
]))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use crate::atom_table::*;
|
|||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use rug::*;
|
use rug::*;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use regex::Regex;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub type QueryResult = Result<QueryResolution, String>;
|
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 {
|
impl TryFrom<String> for QueryResolutionLine {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
fn try_from(string: String) -> Result<Self, Self::Error> {
|
fn try_from(string: String) -> Result<Self, Self::Error> {
|
||||||
@@ -110,20 +131,17 @@ impl TryFrom<String> for QueryResolutionLine {
|
|||||||
"true" => Ok(QueryResolutionLine::True),
|
"true" => Ok(QueryResolutionLine::True),
|
||||||
"false" => Ok(QueryResolutionLine::False),
|
"false" => Ok(QueryResolutionLine::False),
|
||||||
_ => Ok(QueryResolutionLine::Match(
|
_ => Ok(QueryResolutionLine::Match(
|
||||||
string
|
parse_prolog_response(&string)
|
||||||
.split(",")
|
.iter()
|
||||||
.map(|s| s.trim())
|
.map(|(k, v)| -> Result<(String, Value), ()> {
|
||||||
.filter(|s| !s.is_empty())
|
let key = k.to_string();
|
||||||
.map(|s| -> Result<(String, Value), ()> {
|
let value = v.to_string();
|
||||||
let mut iter = s.split(" = ");
|
|
||||||
let key = iter.next().ok_or(())?.to_string();
|
|
||||||
let value = iter.next().ok_or(())?.to_string();
|
|
||||||
|
|
||||||
Ok((key, Value::try_from(value)?))
|
Ok((key, Value::try_from(value)?))
|
||||||
})
|
})
|
||||||
.filter_map(Result::ok)
|
.filter_map(Result::ok)
|
||||||
.collect::<BTreeMap<_, _>>(),
|
.collect::<BTreeMap<_, _>>()
|
||||||
)),
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,6 +193,8 @@ impl TryFrom<String> for Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Structure(atom!("<<>>"), values))
|
Ok(Value::Structure(atom!("<<>>"), values))
|
||||||
|
} else if !trimmed.contains(",") && !trimmed.contains("'") && !trimmed.contains("\"") {
|
||||||
|
Ok(Value::String(trimmed.into()))
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user