]> Repositorios git - scryer-prolog.git/commitdiff
Refactor result parsing to idiomatic Rust and extract into parsed_results.rs
authorNicolas Luck <[email protected]>
Wed, 12 Jul 2023 08:34:07 +0000 (10:34 +0200)
committerNicolas Luck <[email protected]>
Wed, 12 Jul 2023 08:34:07 +0000 (10:34 +0200)
src/machine/mod.rs
src/machine/parsed_results.rs [new file with mode: 0644]

index 75f08e6c888e65d8ec20d53b56fa08516aa7bf59..1aca907f6d4d427d88eff5d9f0e16feb65ff4f21 100644 (file)
@@ -15,6 +15,7 @@ pub mod machine_indices;
 pub mod machine_state;
 pub mod machine_state_impl;
 pub mod mock_wam;
+pub mod parsed_results;
 pub mod partial_string;
 pub mod preprocessor;
 pub mod stack;
@@ -46,13 +47,14 @@ use lazy_static::lazy_static;
 use ordered_float::OrderedFloat;
 
 use std::cmp::Ordering;
-use std::collections::BTreeMap;
 use std::env;
 use std::io::Read;
 use std::path::PathBuf;
 use std::sync::atomic::AtomicBool;
 use tokio::runtime::Runtime;
 
+use self::parsed_results::*;
+
 lazy_static! {
     pub static ref INTERRUPT: AtomicBool = AtomicBool::new(false);
 }
@@ -181,32 +183,6 @@ pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
     None
 }
 
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum QueryResult {
-    True,
-    False,
-    Matches(Vec<QueryResultLine>),
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum QueryResultLine {
-    True,
-    False,
-    Match(BTreeMap<String, Value>),
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum Value {
-    Integer(Integer),
-    Rational(Rational),
-    Float(OrderedFloat<f64>),
-    Atom(Atom),
-    String(String),
-    List(Vec<Value>),
-    Structure(Atom, Vec<Value>),
-    Var,
-}
-
 impl Machine {
     #[inline]
     pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
@@ -360,118 +336,16 @@ impl Machine {
 
     pub fn parse_output(&self) -> QueryResult {
         let output = self.get_user_output();
-        let parsed_lines = output.split(";")
+        output.split(";")
             .map(|s| s.trim())
             .map(|s| s.replace(".", ""))
             .filter(|s| !s.is_empty())
-            .map(|s| {
-                match s.as_str() {
-                    "true" => QueryResultLine::True,
-                    "false" => QueryResultLine::False,
-                    _ => QueryResultLine::Match(
-                        s.split(",")
-                            .map(|s| s.trim())
-                            .filter(|s| !s.is_empty())
-                            .map(|s| {
-                                let mut iter = s.split(" = ");
-
-                                let key = iter.next().unwrap().to_string();
-                                let value = iter.next().unwrap().to_string();
-
-                                (key, Machine::parse_value(value))
-                            })
-                            .collect::<BTreeMap<_, _>>()
-                        )
-                }
-            })
-            .collect::<Vec<QueryResultLine>>();
-
-        // If there is only one line, and it is true or false, return that.
-        if parsed_lines.len() == 1 {
-            match parsed_lines[0].clone() {
-                QueryResultLine::True => return QueryResult::True,
-                QueryResultLine::False => return QueryResult::False,
-                _ => {}
-            }
-        }
-
-        // If there is at least one line with true and no matches, return true.
-        if parsed_lines.iter().any(|l| l == &QueryResultLine::True)
-          && !parsed_lines.iter().any(|l| {
-            if let &QueryResultLine::Match(_) = l { true } else { false }
-        }) {
-            return QueryResult::True;
-        }
-
-        // If there is at least one match, return all matches.
-        if parsed_lines.iter().any(|l| {
-            if let &QueryResultLine::Match(_) = l { true } else { false }
-        }) {
-            let all_matches = parsed_lines.into_iter()
-                .filter(|l| {
-                    if let &QueryResultLine::Match(_) = l { true } else { false }
-                })
-                .collect::<Vec<_>>();
-            return QueryResult::Matches(all_matches);
-        }
-
-        QueryResult::False
+            .map(QueryResultLine::try_from)
+            .filter_map(Result::ok)
+            .collect::<Vec<QueryResultLine>>()
+            .into()
     }
 
-    pub fn parse_value(string: String) -> Value {
-        let trimmed = string.trim();
-
-        if trimmed.starts_with("'") && trimmed.ends_with("'") {
-            Value::String(trimmed[1..trimmed.len() - 1].into())
-        } else 
-        if trimmed.starts_with("\"") && trimmed.ends_with("\"") {
-            Value::String(trimmed[1..trimmed.len() - 1].into())
-        } else if trimmed.starts_with("[") && trimmed.ends_with("]") {
-            let mut iter = trimmed[1..trimmed.len() - 1].split(",");
-
-            let mut values = vec![];
-
-            while let Some(value) = iter.next() {
-                values.push(Machine::parse_value(value.to_string()));
-            }
-
-            Value::List(values)
-        } else if trimmed.starts_with("{") && trimmed.ends_with("}") {
-            let mut iter = trimmed[1..trimmed.len() - 1].split(",");
-
-            let mut values = vec![];
-
-            while let Some(value) = iter.next() {
-                let mut iter = value.split(":");
-
-                let key = iter.next().unwrap().to_string();
-                let value = iter.next().unwrap().to_string();
-
-                values.push(Machine::parse_value(value));
-            }
-
-            Value::Structure(atom!("{}"), values)
-        } else if trimmed.starts_with("<<") && trimmed.ends_with(">>") {
-            let mut iter = trimmed[2..trimmed.len() - 2].split(",");
-
-            let mut values = vec![];
-
-            while let Some(value) = iter.next() {
-                let mut iter = value.split(":");
-
-                let key = iter.next().unwrap().to_string();
-                let value = iter.next().unwrap().to_string();
-
-                values.push(Machine::parse_value(value));
-            }
-
-            Value::Structure(atom!("<<>>"), values)
-        } else {
-            Value::String(string)
-        }
-    }
-
-
     pub(crate) fn configure_modules(&mut self) {
         fn update_call_n_indices(loader: &Module, target_code_dir: &mut CodeDir, arena: &mut Arena) {
             for arity in 1..66 {
diff --git a/src/machine/parsed_results.rs b/src/machine/parsed_results.rs
new file mode 100644 (file)
index 0000000..4bc562d
--- /dev/null
@@ -0,0 +1,149 @@
+use ordered_float::OrderedFloat;
+use rug::*;
+use std::{collections::BTreeMap};
+use crate::atom_table::*;
+
+use super::Machine;
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum QueryResult {
+    True,
+    False,
+    Matches(Vec<QueryResultLine>),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum QueryResultLine {
+    True,
+    False,
+    Match(BTreeMap<String, Value>),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Value {
+    Integer(Integer),
+    Rational(Rational),
+    Float(OrderedFloat<f64>),
+    Atom(Atom),
+    String(String),
+    List(Vec<Value>),
+    Structure(Atom, Vec<Value>),
+    Var,
+}
+
+impl From<Vec<QueryResultLine>> for QueryResult {
+    fn from(query_result_lines: Vec<QueryResultLine>) -> 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() {
+                QueryResultLine::True => return QueryResult::True,
+                QueryResultLine::False => return QueryResult::False,
+                _ => {}
+            }
+        }
+
+        // If there is at least one line with true and no matches, return true.
+        if query_result_lines.iter().any(|l| l == &QueryResultLine::True)
+            && !query_result_lines.iter().any(|l| {
+            if let &QueryResultLine::Match(_) = l { true } else { false }
+        }) {
+            return QueryResult::True;
+        }
+
+        // If there is at least one match, return all matches.
+        if query_result_lines.iter().any(|l| {
+            if let &QueryResultLine::Match(_) = l { true } else { false }
+        }) {
+            let all_matches = query_result_lines.into_iter()
+                .filter(|l| {
+                    if let &QueryResultLine::Match(_) = l { true } else { false }
+                })
+                .collect::<Vec<_>>();
+            return QueryResult::Matches(all_matches);
+        }
+
+        QueryResult::False
+    }
+}
+
+
+impl TryFrom<String> for QueryResultLine {
+    type Error = ();
+    fn try_from(string: String) -> Result<Self, Self::Error> {
+        match string.as_str() {
+            "true" => Ok(QueryResultLine::True),
+            "false" => Ok(QueryResultLine::False),
+            _ => Ok(QueryResultLine::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().unwrap().to_string();
+                        let value = iter.next().unwrap().to_string();
+
+                        Ok((key, Value::try_from(value)?))
+                    })
+                    .filter_map(Result::ok)
+                    .collect::<BTreeMap<_, _>>()
+                ))
+        }
+    }
+}
+
+impl TryFrom<String> for Value {
+    type Error = ();
+    fn try_from(string: String) -> Result<Self, Self::Error> {
+        let trimmed = string.trim();
+
+        if trimmed.starts_with("'") && trimmed.ends_with("'") {
+            Ok(Value::String(trimmed[1..trimmed.len() - 1].into()))
+        } else 
+        if trimmed.starts_with("\"") && trimmed.ends_with("\"") {
+            Ok(Value::String(trimmed[1..trimmed.len() - 1].into()))
+        } else if trimmed.starts_with("[") && trimmed.ends_with("]") {
+            let mut iter = trimmed[1..trimmed.len() - 1].split(",");
+
+            let mut values = vec![];
+
+            while let Some(s) = iter.next() {
+                values.push(Value::try_from(s.to_string())?);
+            }
+
+            Ok(Value::List(values))
+        } else if trimmed.starts_with("{") && trimmed.ends_with("}") {
+            let mut iter = trimmed[1..trimmed.len() - 1].split(",");
+
+            let mut values = vec![];
+
+            while let Some(value) = iter.next() {
+                let mut iter = value.split(":");
+
+                let key = iter.next().unwrap().to_string();
+                let value = iter.next().unwrap().to_string();
+
+                values.push(Value::try_from(value)?);
+            }
+
+            Ok(Value::Structure(atom!("{}"), values))
+        } else if trimmed.starts_with("<<") && trimmed.ends_with(">>") {
+            let mut iter = trimmed[2..trimmed.len() - 2].split(",");
+
+            let mut values = vec![];
+
+            while let Some(value) = iter.next() {
+                let mut iter = value.split(":");
+
+                let key = iter.next().unwrap().to_string();
+                let value = iter.next().unwrap().to_string();
+
+                values.push(Value::try_from(value)?);
+            }
+
+            Ok(Value::Structure(atom!("<<>>"), values))
+        } else {
+            Err(())
+        }
+    }
+}
\ No newline at end of file