use super::{
streams::Stream, Atom, AtomCell, HeapCellValue, HeapCellValueTag, Machine, MachineConfig,
- QueryResolution, QueryResolutionLine, QueryResult, Value,
+ QueryResolutionLine, QueryResult, Value,
};
pub struct QueryState<'a> {
}
pub fn run_query(&mut self, query: String) -> QueryResult {
- // println!("Query: {}", query);
- // Parse the query so we can analyze and then call the term
- let mut parser = Parser::new(
- Stream::from_owned_string(query, &mut self.machine_st.arena),
- &mut self.machine_st,
- );
- let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
- let term = parser
- .read_term(&op_dir, Tokens::Default)
- .expect("Failed to parse query");
-
- self.allocate_stub_choice_point();
-
- // Write parsed term to heap
- let term_write_result =
- write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
- .expect("couldn't write term to heap");
-
- let var_names: IndexMap<_, _> = term_write_result
- .var_dict
- .iter()
- .map(|(var_key, cell)| match var_key {
- // NOTE: not the intention behind Var::InSitu here but
- // we can hijack it to store anonymous variables
- // without creating problems.
- VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))),
- VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()),
- })
- .collect();
-
- // Write term to heap
- self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc];
-
- self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
- let call_index_p = self
- .indices
- .code_dir
- .get(&(atom!("call"), 1))
- .expect("couldn't get code index")
- .local()
- .unwrap();
-
- self.machine_st.execute_at_index(1, call_index_p);
-
- let stub_b = self.machine_st.b;
-
- let mut matches: Vec<QueryResolutionLine> = Vec::new();
- // Call the term
- loop {
- self.dispatch_loop();
-
- //println!("b: {}", self.machine_st.b);
- //println!("stub_b: {}", stub_b);
- //println!("fail: {}", self.machine_st.fail);
-
- if !self.machine_st.ball.stub.is_empty() {
- // NOTE: this means an exception was thrown, at which
- // point we backtracked to the stub choice point.
- // this should halt the search for solutions as it
- // does in the Scryer top-level. the exception term is
- // contained in self.machine_st.ball.
- let error_string = self
- .machine_st
- .ball
- .stub
- .iter()
- .filter(|h| {
- matches!(
- h.get_tag(),
- HeapCellValueTag::Atom | HeapCellValueTag::Fixnum
- )
- })
- .map(|h| match h.get_tag() {
- HeapCellValueTag::Atom => {
- let (name, _) = cell_as_atom_cell!(h).get_name_and_arity();
- name.as_str().to_string()
- }
- HeapCellValueTag::Fixnum => h.get_value().clone().to_string(),
- _ => unreachable!(),
- })
- .collect::<Vec<String>>()
- .join(" ");
-
- return Err(error_string);
- }
-
- /*
- if self.machine_st.fail {
- // NOTE: only print results on success
- self.machine_st.fail = false;
- println!("fail!");
- matches.push(QueryResolutionLine::False);
- break;
- };
- */
-
- if self.machine_st.p == LIB_QUERY_SUCCESS {
- if term_write_result.var_dict.is_empty() {
- matches.push(QueryResolutionLine::True);
- break;
- }
- } else if self.machine_st.p == BREAK_FROM_DISPATCH_LOOP_LOC {
- // NOTE: only print results on success
- // self.machine_st.fail = false;
- // println!("b == stub_b");
- matches.push(QueryResolutionLine::False);
- break;
- }
-
- let mut bindings: BTreeMap<String, Value> = BTreeMap::new();
-
- for (var_key, term_to_be_printed) in &term_write_result.var_dict {
- if var_key.to_string().starts_with('_') {
- continue;
- }
- let mut printer = HCPrinter::new(
- &mut self.machine_st.heap,
- Arc::clone(&self.machine_st.atom_tbl),
- &mut self.machine_st.stack,
- &self.indices.op_dir,
- PrinterOutputter::new(),
- *term_to_be_printed,
- );
-
- printer.ignore_ops = false;
- printer.numbervars = true;
- printer.quoted = true;
- printer.max_depth = 1000; // NOTE: set this to 0 for unbounded depth
- printer.double_quotes = true;
- printer.var_names.clone_from(&var_names);
-
- let outputter = printer.print();
-
- let output: String = outputter.result();
- // println!("Result: {} = {}", var_key.to_string(), output);
-
- if var_key.to_string() != output {
- bindings.insert(
- var_key.to_string(),
- Value::try_from(output).expect("Couldn't convert Houtput to Value"),
- );
- }
- }
-
- matches.push(QueryResolutionLine::Match(bindings));
-
- // NOTE: there are outstanding choicepoints, backtrack
- // through them for further solutions. if
- // self.machine_st.b == stub_b we've backtracked to the stub
- // choice point, so we should break.
- self.machine_st.backtrack();
-
- if self.machine_st.b <= stub_b {
- // NOTE: out of choicepoints to backtrack through, no
- // more solutions to gather.
- break;
- }
- }
-
- // NOTE: deallocate stub choice point
- if self.machine_st.b == stub_b {
- self.trust_me();
- }
-
- Ok(QueryResolution::from(matches))
+ self.run_query_iter(query).collect()
}
pub fn run_query_iter(&mut self, query: String) -> QueryState {