]> Repositorios git - scryer-prolog.git/commitdiff
Rename LeafAnswer
authorbakaq <[email protected]>
Sat, 7 Sep 2024 04:15:05 +0000 (01:15 -0300)
committerbakaq <[email protected]>
Sun, 8 Dec 2024 23:18:05 +0000 (20:18 -0300)
src/machine/lib_machine.rs
src/machine/parsed_results.rs

index a4233696a1918294fef8a855880c012ce597335f..52fb3e020ec4964a8e9af9bf11b52b9a18bbffd5 100644 (file)
@@ -11,7 +11,7 @@ use indexmap::IndexMap;
 
 use super::{
     streams::Stream, Atom, AtomCell, HeapCellValue, HeapCellValueTag, Machine, MachineConfig,
-    QueryResolutionLine, QueryResult, PrologTerm,
+    LeafAnswer, PrologTerm,
 };
 
 pub struct QueryState<'a> {
@@ -31,7 +31,7 @@ impl Drop for QueryState<'_> {
 }
 
 impl Iterator for QueryState<'_> {
-    type Item = Result<QueryResolutionLine, String>;
+    type Item = Result<LeafAnswer, String>;
 
     fn next(&mut self) -> Option<Self::Item> {
         let var_names = &mut self.var_names;
@@ -82,10 +82,10 @@ impl Iterator for QueryState<'_> {
         if machine.machine_st.p == LIB_QUERY_SUCCESS {
             if term_write_result.var_dict.is_empty() {
                 self.machine.machine_st.backtrack();
-                return Some(Ok(QueryResolutionLine::True));
+                return Some(Ok(LeafAnswer::True));
             }
         } else if machine.machine_st.p == BREAK_FROM_DISPATCH_LOOP_LOC {
-            return Some(Ok(QueryResolutionLine::False));
+            return Some(Ok(LeafAnswer::False));
         }
 
         let mut bindings: BTreeMap<String, PrologTerm> = BTreeMap::new();
@@ -138,7 +138,7 @@ impl Iterator for QueryState<'_> {
         // choice point, so we should break.
         self.machine.machine_st.backtrack();
 
-        Some(Ok(QueryResolutionLine::Match(bindings)))
+        Some(Ok(LeafAnswer::LeafAnswer { bindings: bindings, residual_goals: vec![] }))
     }
 }
 
@@ -187,11 +187,7 @@ impl Machine {
         self.machine_st.block = stub_b;
     }
 
-    pub fn run_query(&mut self, query: String) -> QueryResult {
-        self.run_query_iter(query).collect()
-    }
-
-    pub fn run_query_iter(&mut self, query: String) -> QueryState {
+    pub fn run_query(&mut self, query: String) -> QueryState {
         let mut parser = Parser::new(
             Stream::from_owned_string(query, &mut self.machine_st.arena),
             &mut self.machine_st,
@@ -767,14 +763,14 @@ mod tests {
 
             iterator.next();
 
-            assert_eq!(iterator.next(), Some(Ok(QueryResolutionLine::False)));
+            assert_eq!(iterator.next(), Some(Ok(LeafAnswer::False)));
             assert_eq!(iterator.next(), None);
         }
 
         {
             let mut iterator = machine.run_query_iter("false.".into());
 
-            assert_eq!(iterator.next(), Some(Ok(QueryResolutionLine::False)));
+            assert_eq!(iterator.next(), Some(Ok(LeafAnswer::False)));
             assert_eq!(iterator.next(), None);
         }
     }
@@ -786,8 +782,8 @@ mod tests {
 
         let mut iterator = machine.run_query_iter("true;false.".into());
 
-        assert_eq!(iterator.next(), Some(Ok(QueryResolutionLine::True)));
-        assert_eq!(iterator.next(), Some(Ok(QueryResolutionLine::False)));
+        assert_eq!(iterator.next(), Some(Ok(LeafAnswer::True)));
+        assert_eq!(iterator.next(), Some(Ok(LeafAnswer::False)));
         assert_eq!(iterator.next(), None);
     }
 
index b1641ef4032304273255d32f286f3cb33398cdb7..4ab1f91a2228c42be1c43995b8b1797c6d5b55f5 100644 (file)
@@ -7,126 +7,19 @@ use indexmap::IndexMap;
 use ordered_float::OrderedFloat;
 use std::cmp::Ordering;
 use std::collections::BTreeMap;
-use std::collections::HashMap;
-use std::fmt::Display;
-use std::fmt::Write;
-use std::iter::FromIterator;
 
 use super::Machine;
 use super::{HeapCellValue, Number};
 
-pub type QueryResult = Result<QueryResolution, String>;
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum QueryResolution {
-    True,
-    False,
-    Matches(Vec<QueryMatch>),
-}
-
-fn write_prolog_value_as_json<W: Write>(
-    writer: &mut W,
-    value: &PrologTerm,
-) -> Result<(), std::fmt::Error> {
-    match value {
-        PrologTerm::Integer(i) => write!(writer, "{}", i),
-        PrologTerm::Float(f) => write!(writer, "{}", f),
-        PrologTerm::Rational(r) => write!(writer, "{}", r),
-        PrologTerm::Atom(a) => writer.write_str(a.as_str()),
-        PrologTerm::String(s) => {
-            if let Err(_e) = serde_json::from_str::<serde_json::Value>(s.as_str()) {
-                //treat as string literal
-                //escape double quotes
-                write!(
-                    writer,
-                    "\"{}\"",
-                    s.replace('\"', "\\\"")
-                        .replace('\n', "\\n")
-                        .replace('\t', "\\t")
-                        .replace('\r', "\\r")
-                )
-            } else {
-                //return valid json string
-                writer.write_str(s)
-            }
-        }
-        PrologTerm::List(l) => {
-            writer.write_char('[')?;
-            if let Some((first, rest)) = l.split_first() {
-                write_prolog_value_as_json(writer, first)?;
-
-                for other in rest {
-                    writer.write_char(',')?;
-                    write_prolog_value_as_json(writer, other)?;
-                }
-            }
-            writer.write_char(']')
-        }
-        PrologTerm::Structure(s, l) => {
-            write!(writer, "\"{}\":[", s.as_str())?;
-
-            if let Some((first, rest)) = l.split_first() {
-                write_prolog_value_as_json(writer, first)?;
-                for other in rest {
-                    writer.write_char(',')?;
-                    write_prolog_value_as_json(writer, other)?;
-                }
-            }
-            writer.write_char(']')
-        }
-        _ => writer.write_str("null"),
-    }
-}
-
-fn write_prolog_match_as_json<W: std::fmt::Write>(
-    writer: &mut W,
-    query_match: &QueryMatch,
-) -> Result<(), std::fmt::Error> {
-    writer.write_char('{')?;
-    let mut iter = query_match.bindings.iter();
-
-    if let Some((k, v)) = iter.next() {
-        write!(writer, "\"{k}\":")?;
-        write_prolog_value_as_json(writer, v)?;
-
-        for (k, v) in iter {
-            write!(writer, ",\"{k}\":")?;
-            write_prolog_value_as_json(writer, v)?;
-        }
-    }
-    writer.write_char('}')
-}
-
-impl Display for QueryResolution {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            QueryResolution::True => f.write_str("true"),
-            QueryResolution::False => f.write_str("false"),
-            QueryResolution::Matches(matches) => {
-                f.write_char('[')?;
-                if let Some((first, rest)) = matches.split_first() {
-                    write_prolog_match_as_json(f, first)?;
-                    for other in rest {
-                        f.write_char(',')?;
-                        write_prolog_match_as_json(f, other)?;
-                    }
-                }
-                f.write_char(']')
-            }
-        }
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct QueryMatch {
-    pub bindings: BTreeMap<String, PrologTerm>,
-}
-
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub enum QueryResolutionLine {
+pub enum LeafAnswer {
     True,
     False,
-    Match(BTreeMap<String, PrologTerm>),
+    Exception(PrologTerm),
+    LeafAnswer {
+        bindings: BTreeMap<String, PrologTerm>,
+        residual_goals: Vec<PrologTerm>,
+    },
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -396,248 +289,3 @@ impl PrologTerm {
         term_stack.pop().unwrap()
     }
 }
-
-impl From<BTreeMap<&str, PrologTerm>> for QueryMatch {
-    fn from(bindings: BTreeMap<&str, PrologTerm>) -> Self {
-        QueryMatch {
-            bindings: bindings
-                .into_iter()
-                .map(|(k, v)| (k.to_string(), v))
-                .collect::<BTreeMap<_, _>>(),
-        }
-    }
-}
-
-impl From<BTreeMap<String, PrologTerm>> for QueryMatch {
-    fn from(bindings: BTreeMap<String, PrologTerm>) -> Self {
-        QueryMatch { bindings }
-    }
-}
-
-impl From<Vec<QueryResolutionLine>> for QueryResolution {
-    fn from(query_result_lines: Vec<QueryResolutionLine>) -> Self {
-        // If there is only one line, and it is true or false, return that.
-        if query_result_lines.len() == 1 {
-            match query_result_lines[0].clone() {
-                QueryResolutionLine::True => return QueryResolution::True,
-                QueryResolutionLine::False => return QueryResolution::False,
-                _ => {}
-            }
-        }
-
-        // If there is only one line, and it is an empty match, return false.
-        if query_result_lines.len() == 1 {
-            if let QueryResolutionLine::Match(m) = query_result_lines[0].clone() {
-                if m.is_empty() {
-                    return QueryResolution::False;
-                }
-            }
-        }
-
-        // If there is at least one line with true and no matches, return true.
-        if query_result_lines
-            .iter()
-            .any(|l| l == &QueryResolutionLine::True)
-            && !query_result_lines
-                .iter()
-                .any(|l| matches!(l, QueryResolutionLine::Match(_)))
-        {
-            return QueryResolution::True;
-        }
-
-        // If there is at least one match, return all matches.
-        let all_matches = query_result_lines
-            .into_iter()
-            .filter(|l| matches!(l, QueryResolutionLine::Match(_)))
-            .map(|l| match l {
-                QueryResolutionLine::Match(m) => QueryMatch::from(m),
-                _ => unreachable!(),
-            })
-            .collect::<Vec<_>>();
-
-        if !all_matches.is_empty() {
-            return QueryResolution::Matches(all_matches);
-        }
-
-        QueryResolution::False
-    }
-}
-
-impl FromIterator<QueryResolutionLine> for QueryResolution {
-    fn from_iter<I: IntoIterator<Item = QueryResolutionLine>>(iter: I) -> Self {
-        // TODO: Probably a good idea to implement From<Vec<QueryResolutionLine>> based on this
-        // instead.
-        iter.into_iter().collect::<Vec<_>>().into()
-    }
-}
-
-fn split_response_string(input: &str) -> Vec<String> {
-    let mut level_bracket = 0;
-    let mut level_parenthesis = 0;
-    let mut in_double_quotes = false;
-    let mut in_single_quotes = false;
-    let mut start = 0;
-    let mut result = Vec::new();
-
-    for (i, c) in input.chars().enumerate() {
-        match c {
-            '[' => level_bracket += 1,
-            ']' => level_bracket -= 1,
-            '(' => level_parenthesis += 1,
-            ')' => level_parenthesis -= 1,
-            '"' => in_double_quotes = !in_double_quotes,
-            '\'' => in_single_quotes = !in_single_quotes,
-            ',' if level_bracket == 0
-                && level_parenthesis == 0
-                && !in_double_quotes
-                && !in_single_quotes =>
-            {
-                result.push(input[start..i].trim().to_string());
-                start = i + 1;
-            }
-            _ => {}
-        }
-    }
-
-    result.push(input[start..].trim().to_string());
-    result
-}
-
-fn split_key_value_pairs(input: &str) -> Vec<(String, String)> {
-    let items = split_response_string(input);
-    let mut result = Vec::new();
-
-    for item in items {
-        let parts: Vec<&str> = item.splitn(2, '=').collect();
-        if parts.len() == 2 {
-            let key = parts[0].trim().to_string();
-            let value = parts[1].trim().to_string();
-            result.push((key, value));
-        }
-    }
-
-    result
-}
-
-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
-    for result in split_key_value_pairs(input) {
-        let key = result.0;
-        let value = result.1;
-        // 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> {
-        match string.as_str() {
-            "true" => Ok(QueryResolutionLine::True),
-            "false" => Ok(QueryResolutionLine::False),
-            _ => Ok(QueryResolutionLine::Match(
-                parse_prolog_response(&string)
-                    .iter()
-                    .map(|(k, v)| -> Result<(String, PrologTerm), ()> {
-                        let key = k.to_string();
-                        let value = v.to_string();
-                        Ok((key, PrologTerm::try_from(value)?))
-                    })
-                    .filter_map(Result::ok)
-                    .collect::<BTreeMap<_, _>>(),
-            )),
-        }
-    }
-}
-
-fn split_nested_list(input: &str) -> Vec<String> {
-    let mut level = 0;
-    let mut start = 0;
-    let mut result = Vec::new();
-
-    for (i, c) in input.chars().enumerate() {
-        match c {
-            '[' => level += 1,
-            ']' => level -= 1,
-            ',' if level == 0 => {
-                result.push(input[start..i].trim().to_string());
-                start = i + 1;
-            }
-            _ => {}
-        }
-    }
-
-    result.push(input[start..].trim().to_string());
-    result
-}
-
-impl TryFrom<String> for PrologTerm {
-    type Error = ();
-    fn try_from(string: String) -> Result<Self, Self::Error> {
-        let trimmed = string.trim();
-
-        if let Ok(float_value) = string.parse::<f64>() {
-            Ok(PrologTerm::Float(OrderedFloat(float_value)))
-        } else if let Ok(int_value) = string.parse::<i128>() {
-            Ok(PrologTerm::Integer(int_value.into()))
-        } else if trimmed.starts_with('\'') && trimmed.ends_with('\'')
-            || trimmed.starts_with('"') && trimmed.ends_with('"')
-        {
-            Ok(PrologTerm::String(trimmed[1..trimmed.len() - 1].into()))
-        } else if trimmed.starts_with('[') && trimmed.ends_with(']') {
-            let split = split_nested_list(&trimmed[1..trimmed.len() - 1]);
-
-            let values = split
-                .into_iter()
-                .map(PrologTerm::try_from)
-                .collect::<Result<Vec<_>, _>>()?;
-
-            Ok(PrologTerm::List(values))
-        } else if trimmed.starts_with('{') && trimmed.ends_with('}') {
-            let iter = trimmed[1..trimmed.len() - 1].split(',');
-            let mut values = vec![];
-
-            for value in iter {
-                let items: Vec<_> = value.split(':').collect();
-                if items.len() == 2 {
-                    let _key = items[0].to_string();
-                    let value = items[1].to_string();
-                    values.push(PrologTerm::try_from(value)?);
-                }
-            }
-
-            Ok(PrologTerm::Structure("{}".into(), values))
-        } else if trimmed.starts_with("<<") && trimmed.ends_with(">>") {
-            let iter = trimmed[2..trimmed.len() - 2].split(',');
-            let mut values = vec![];
-
-            for value in iter {
-                let items: Vec<_> = value.split(':').collect();
-                if items.len() == 2 {
-                    let _key = items[0].to_string();
-                    let value = items[1].to_string();
-                    values.push(PrologTerm::try_from(value)?);
-                }
-            }
-
-            Ok(PrologTerm::Structure("<<>>".into(), values))
-        } else if !trimmed.contains(',') && !trimmed.contains('\'') && !trimmed.contains('"') {
-            Ok(PrologTerm::String(trimmed.into()))
-        } else {
-            Err(())
-        }
-    }
-}
-
-impl From<&str> for PrologTerm {
-    fn from(str: &str) -> Self {
-        PrologTerm::String(str.to_string())
-    }
-}