From: Mark Thom Date: Wed, 25 Jul 2018 23:12:07 +0000 (-0600) Subject: preliminary read support X-Git-Tag: v0.8.110~441 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=38dcd6113e1220b9f17ccaf0270ee686d69a8719;p=scryer-prolog.git preliminary read support --- diff --git a/README.md b/README.md index eb04d83e..155e930e 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ The following predicates are built-in to rusty-wam. * `nonvar/1` * `once/1` * `rational/1` +* `read/1` * `repeat/0` * `reverse/2` * `select/3` diff --git a/src/prolog/arithmetic.rs b/src/prolog/arithmetic.rs index 436772fc..79ca2c90 100644 --- a/src/prolog/arithmetic.rs +++ b/src/prolog/arithmetic.rs @@ -31,7 +31,7 @@ impl<'a> ArithInstructionIterator<'a> { &Term::Cons(_, _, _) => return Err(ArithmeticError::InvalidTerm), &Term::Var(ref cell, ref var) => - TermIterState::Var(Level::Shallow, cell, (*var).clone()) + TermIterState::Var(Level::Shallow, cell, var.clone()) }; Ok(ArithInstructionIterator { state_stack: vec![state] }) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index f60639bc..620a0ef7 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -803,6 +803,7 @@ pub enum BuiltInClauseType { Is(RegType, ArithmeticTerm), KeySort, NotEq, + Read, Sort, } @@ -906,6 +907,7 @@ impl BuiltInClauseType { &BuiltInClauseType::Is(..) => clause_name!("is"), &BuiltInClauseType::KeySort => clause_name!("keysort"), &BuiltInClauseType::NotEq => clause_name!("\\=="), + &BuiltInClauseType::Read => clause_name!("read"), &BuiltInClauseType::Sort => clause_name!("sort"), } } @@ -925,6 +927,7 @@ impl BuiltInClauseType { &BuiltInClauseType::Is(..) => 2, &BuiltInClauseType::KeySort => 2, &BuiltInClauseType::NotEq => 2, + &BuiltInClauseType::Read => 1, &BuiltInClauseType::Sort => 2, } } @@ -950,6 +953,7 @@ impl BuiltInClauseType { ("keysort", 2) => Some(BuiltInClauseType::KeySort), ("\\==", 2) => Some(BuiltInClauseType::NotEq), ("sort", 2) => Some(BuiltInClauseType::Sort), + ("read", 1) => Some(BuiltInClauseType::Read), _ => None } } @@ -1015,7 +1019,7 @@ pub enum TermRef<'a> { Var(Level, &'a Cell, Rc) } -impl<'a> TermRef<'a> { +impl<'a> TermRef<'a> { pub fn level(self) -> Level { match self { TermRef::AnonVar(lvl) @@ -1796,7 +1800,7 @@ impl<'a> TermIterState<'a> { &Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant), &Term::Var(ref cell, ref var) => - TermIterState::Var(lvl, cell, (*var).clone()) + TermIterState::Var(lvl, cell, var.clone()) } } } diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index c887b4d8..dfa1994d 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use std::vec::Vec; pub struct QueryIterator<'a> { - state_stack: Vec> + state_stack: Vec>, } impl<'a> QueryIterator<'a> { @@ -120,6 +120,7 @@ impl<'a> Iterator for QueryIterator<'a> { pub struct FactIterator<'a> { state_queue: VecDeque>, + iterable_root: bool } impl<'a> FactIterator<'a> { @@ -132,10 +133,10 @@ impl<'a> FactIterator<'a> { .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref())) .collect(); - FactIterator { state_queue } + FactIterator { state_queue, iterable_root: false } } - fn new(term: &'a Term) -> Self { + fn new(term: &'a Term, iterable_root: bool) -> Self { let states = match term { &Term::AnonVar => vec![TermIterState::AnonVar(Level::Root)], @@ -151,7 +152,7 @@ impl<'a> FactIterator<'a> { vec![TermIterState::Var(Level::Root, cell, var.clone())] }; - FactIterator { state_queue: VecDeque::from(states) } + FactIterator { state_queue: VecDeque::from(states), iterable_root } } } @@ -169,7 +170,7 @@ impl<'a> Iterator for FactIterator<'a> { } match lvl { - Level::Root => continue, + Level::Root if !self.iterable_root => continue, _ => return Some(TermRef::Clause(lvl, cell, ct, child_terms)) }; }, @@ -196,8 +197,8 @@ impl Term { QueryIterator::from_term(self) } - pub fn breadth_first_iter(&self) -> FactIterator { - FactIterator::new(self) + pub fn breadth_first_iter(&self, iterable_root: bool) -> FactIterator { + FactIterator::new(self, iterable_root) } } diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 859a6a40..ce63ccf6 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -5,12 +5,12 @@ use prolog::heap_print::*; use prolog::machine::machine_errors::*; use prolog::num::{BigInt, BigUint, Zero, One}; use prolog::or_stack::*; +use prolog::read::*; use prolog::tabled_rc::*; use downcast::Any; use std::cmp::Ordering; -use std::collections::HashMap; use std::mem::swap; use std::ops::{Index, IndexMut}; use std::rc::Rc; @@ -32,13 +32,14 @@ impl Ball { } pub(crate) struct CodeDirs<'a> { - code_dir: &'a CodeDir, - modules: &'a ModuleDir + pub code_dir: &'a CodeDir, + pub op_dir: &'a OpDir, + pub modules: &'a ModuleDir } impl<'a> CodeDirs<'a> { - pub(super) fn new(code_dir: &'a CodeDir, modules: &'a HashMap) -> Self { - CodeDirs { code_dir, modules } + pub(super) fn new(code_dir: &'a CodeDir, op_dir: &'a OpDir, modules: &'a ModuleDir) -> Self { + CodeDirs { code_dir, op_dir, modules } } pub(super) fn get(&self, name: ClauseName, arity: usize, in_mod: ClauseName) -> Option @@ -202,7 +203,7 @@ pub(super) enum MachineMode { } pub struct MachineState { - pub(super) atom_tbl: TabledData, + pub(crate) atom_tbl: TabledData, pub(super) s: usize, pub(super) p: CodePtr, pub(super) b: usize, @@ -449,7 +450,8 @@ pub(crate) trait CallPolicy: Any { Ok(()) } - fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType) + fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, + code_dirs: CodeDirs<'a>) -> CallResult { match ct { @@ -492,6 +494,19 @@ pub(crate) trait CallPolicy: Any { machine_st.fail = !machine_st.is_cyclic_term(addr); return_from_clause!(machine_st.last_call, machine_st) }, + &BuiltInClauseType::Read => { + let mut reader = Reader::new(machine_st); + + match reader.read_stdin(code_dirs.op_dir) { + Ok(offset) => { + let addr = reader.machine_st[temp_v!(1)].clone(); + reader.machine_st.unify(addr, Addr::HeapCell(offset)); + }, + Err(err) => println!("{:?}", err) + }; + + return_from_clause!(reader.machine_st.last_call, reader.machine_st) + }, &BuiltInClauseType::Writeq => { let output = machine_st.print_term(machine_st[temp_v!(1)].clone(), WriteqFormatter {}, @@ -645,10 +660,11 @@ impl CallPolicy for CallWithInferenceLimitCallPolicy { self.increment() } - fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType) + fn call_builtin<'a>(&mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, + code_dirs: CodeDirs<'a>) -> CallResult { - self.prev_policy.call_builtin(machine_st, ct)?; + self.prev_policy.call_builtin(machine_st, ct, code_dirs)?; self.increment() } diff --git a/src/prolog/machine/machine_state_impl.rs b/src/prolog/machine/machine_state_impl.rs index 2ee034c0..290c4137 100644 --- a/src/prolog/machine/machine_state_impl.rs +++ b/src/prolog/machine/machine_state_impl.rs @@ -1825,7 +1825,7 @@ impl MachineState { }, &ControlInstruction::CallClause(ClauseType::BuiltIn(ref ct), _, _, lco) => { self.last_call = lco; - try_or_fail!(self, call_policy.call_builtin(self, ct)); + try_or_fail!(self, call_policy.call_builtin(self, ct, code_dirs)); }, &ControlInstruction::CallClause(ClauseType::Inlined(ref ct), ..) => self.execute_inlined(ct), diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index dc3bdd19..734baedc 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -298,7 +298,8 @@ impl Machine { Line::Cut(ref cut_instr) => self.ms.execute_cut_instr(cut_instr, &mut self.cut_policy), Line::Control(ref control_instr) => { - let code_dirs = CodeDirs::new(&self.code_dir, &self.modules); + let code_dirs = CodeDirs::new(&self.code_dir, &self.op_dir, + &self.modules); self.ms.execute_ctrl_instr(code_dirs, &mut self.call_policy, &mut self.cut_policy, control_instr) }, diff --git a/src/prolog/mod.rs b/src/prolog/mod.rs index 13412102..6d16892d 100644 --- a/src/prolog/mod.rs +++ b/src/prolog/mod.rs @@ -26,3 +26,4 @@ pub mod parser; pub mod heap_print; pub mod targets; pub mod tabled_rc; +pub mod read; diff --git a/src/prolog/parser b/src/prolog/parser index 6a754525..3fb28efa 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit 6a7545257bbfc660b37a0bc3d7a72edb244dda86 +Subproject commit 3fb28efa315852734613fcf34ee3467c5be8545c diff --git a/src/prolog/read.rs b/src/prolog/read.rs new file mode 100644 index 00000000..03280b46 --- /dev/null +++ b/src/prolog/read.rs @@ -0,0 +1,120 @@ +use prolog::ast::*; +use prolog::machine::machine_state::*; +use prolog::parser::parser::*; + +use std::collections::VecDeque; +use std::io::stdin; + +pub struct Reader<'a> { + pub machine_st: &'a mut MachineState, +} + +type SubtermDeque = VecDeque<(usize, usize)>; + +impl<'a> TermRef<'a> { + fn as_addr(&self, h: usize) -> Addr { + match self { + &TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h), + &TermRef::Cons(..) => Addr::HeapCell(h), + &TermRef::Constant(_, _, c) => Addr::Con(c.clone()), + &TermRef::Clause(..) => Addr::Str(h), + } + } +} + +impl<'a> Reader<'a> { + pub fn new(machine_st: &'a mut MachineState) -> Self { + Reader { machine_st } + } + + pub fn read_stdin(&mut self, op_dir: &'a OpDir) -> Result { + let mut buffer = String::new(); + + let stdin = stdin(); + stdin.read_line(&mut buffer).unwrap(); + + let mut parser = Parser::new(buffer.as_bytes(), self.machine_st.atom_tbl.clone()); + Ok(self.write_term_to_heap(parser.read_term(op_dir)?)) + } + + fn push_stub_addr(&mut self) { + let h = self.machine_st.heap.h; + self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(h))); + } + + fn modify_head_of_queue(&mut self, queue: &mut SubtermDeque, term: TermRef, h: usize) { + if let Some((arity, site_h)) = queue.pop_front() { + self.machine_st.heap[site_h] = HeapCellValue::Addr(term.as_addr(h)); + + if arity > 1 { + queue.push_front((arity - 1, site_h + 1)); + } + } + } + + fn write_term_to_heap(&mut self, term: Term) -> usize { + let h = self.machine_st.heap.h; + + let mut queue = SubtermDeque::new(); + let mut var_dict = HeapVarDict::new(); + + for term in term.breadth_first_iter(true) { + let h = self.machine_st.heap.h; + + match &term { + &TermRef::Cons(lvl, ..) => { + queue.push_back((2, h+1)); + self.machine_st.heap.push(HeapCellValue::Addr(Addr::Lis(h+1))); + + self.push_stub_addr(); + self.push_stub_addr(); + + if let Level::Root = lvl { + continue; + } + }, + &TermRef::Clause(lvl, _, ref ct, subterms) => { + queue.push_back((subterms.len(), h+1)); + let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), + ct.fixity()); + + self.machine_st.heap.push(named); + + for _ in 0 .. subterms.len() { + self.push_stub_addr(); + } + + if let Level::Root = lvl { + continue; + } + }, + &TermRef::AnonVar(Level::Root) + | &TermRef::Var(Level::Root, ..) + | &TermRef::Constant(Level::Root, ..) => + self.machine_st.heap.push(HeapCellValue::Addr(term.as_addr(h))), + &TermRef::AnonVar(_) => + continue, + &TermRef::Var(_, _, ref var) => { + if let Some((arity, site_h)) = queue.pop_front() { + if let Some(addr) = var_dict.get(var).cloned() { + self.machine_st.heap[site_h] = HeapCellValue::Addr(addr); + } else { + var_dict.insert(var.clone(), Addr::HeapCell(site_h)); + } + + if arity > 1 { + queue.push_front((arity - 1, site_h + 1)); + } + } + + continue; + }, + _ => {} + }; + + self.modify_head_of_queue(&mut queue, term, h); + } + + h + } +} diff --git a/src/prolog/targets.rs b/src/prolog/targets.rs index 9999c429..f6d1fb36 100644 --- a/src/prolog/targets.rs +++ b/src/prolog/targets.rs @@ -32,7 +32,7 @@ impl<'a> CompilationTarget<'a> for FactInstruction { type Iterator = FactIterator<'a>; fn iter(term: &'a Term) -> Self::Iterator { - term.breadth_first_iter() + term.breadth_first_iter(false) // do not iterate over the root clause if one exists. } fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {