Merge branch 'develop'
This commit is contained in:
@@ -527,7 +527,7 @@ 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 => {
|
||||
&BuiltInClauseType::Read => {
|
||||
match machine_st.read(stdin(), &indices.op_dir) {
|
||||
Ok(offset) => {
|
||||
let addr = machine_st[temp_v!(1)].clone();
|
||||
@@ -642,6 +642,17 @@ pub(crate) trait CallPolicy: Any {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_hook(&mut self, machine_st: &mut MachineState, _: &CompileTimeHook) -> CallResult
|
||||
{
|
||||
machine_st.cp = LocalCodePtr::TopLevel(0, 0);
|
||||
|
||||
machine_st.num_of_args = 2;
|
||||
machine_st.b0 = machine_st.b;
|
||||
machine_st.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn call_n<'a>(&mut self, machine_st: &mut MachineState, arity: usize,
|
||||
indices: MachineCodeIndices<'a>) //code_dirs: CodeDirs)
|
||||
-> CallResult
|
||||
@@ -674,7 +685,7 @@ pub(crate) trait CallPolicy: Any {
|
||||
return Err(machine_st.error_form(MachineError::existence_error(h, name, arity),
|
||||
stub));
|
||||
},
|
||||
ClauseType::System(_) => {
|
||||
ClauseType::Hook(_) | ClauseType::System(_) => {
|
||||
let name = Addr::Con(Constant::Atom(name, None));
|
||||
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ impl MachineState {
|
||||
self.fail = true;
|
||||
},
|
||||
(Addr::Lis(a1), Addr::Con(Constant::String(ref mut s)))
|
||||
| (Addr::Con(Constant::String(ref mut s)), Addr::Lis(a1))
|
||||
| (Addr::Con(Constant::String(ref mut s)), Addr::Lis(a1))
|
||||
if self.flags.double_quotes.is_chars() => {
|
||||
if let Some(c) = s.head() {
|
||||
pdl.push(Addr::Con(Constant::String(s.tail())));
|
||||
@@ -233,7 +233,7 @@ impl MachineState {
|
||||
self.fail = true;
|
||||
},
|
||||
(Addr::Con(Constant::EmptyList), Addr::Con(Constant::String(ref s)))
|
||||
| (Addr::Con(Constant::String(ref s)), Addr::Con(Constant::EmptyList))
|
||||
| (Addr::Con(Constant::String(ref s)), Addr::Con(Constant::EmptyList))
|
||||
if self.flags.double_quotes.is_chars() => {
|
||||
if s.is_expandable() && s.is_empty() {
|
||||
s.set_non_expandable();
|
||||
@@ -314,7 +314,7 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn trail(&mut self, r: Ref) {
|
||||
match r {
|
||||
Ref::HeapCell(hc) =>
|
||||
@@ -1457,7 +1457,7 @@ impl MachineState {
|
||||
for (v1, v2) in iter {
|
||||
match (v1, v2) {
|
||||
(HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Con(Constant::String(_))))
|
||||
| (HeapCellValue::Addr(Addr::Con(Constant::String(_))), HeapCellValue::Addr(Addr::Lis(_)))
|
||||
| (HeapCellValue::Addr(Addr::Con(Constant::String(_))), HeapCellValue::Addr(Addr::Lis(_)))
|
||||
if self.flags.double_quotes.is_chars() => {},
|
||||
(HeapCellValue::Addr(Addr::Con(Constant::EmptyList)),
|
||||
HeapCellValue::Addr(Addr::Con(Constant::String(ref s))))
|
||||
@@ -1577,7 +1577,7 @@ impl MachineState {
|
||||
(HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::Addr(Addr::Lis(_))) =>
|
||||
continue,
|
||||
(HeapCellValue::Addr(Addr::Lis(_)), HeapCellValue::NamedStr(ar, n, _))
|
||||
| (HeapCellValue::NamedStr(ar, n, _), HeapCellValue::Addr(Addr::Lis(_))) =>
|
||||
| (HeapCellValue::NamedStr(ar, n, _), HeapCellValue::Addr(Addr::Lis(_))) =>
|
||||
if ar == 2 && n.as_str() == "." {
|
||||
continue;
|
||||
} else if ar < 2 {
|
||||
@@ -2045,7 +2045,7 @@ impl MachineState {
|
||||
|
||||
self.p += 1;
|
||||
}
|
||||
|
||||
|
||||
fn handle_call_clause<'a>(&mut self, indices: MachineCodeIndices<'a>,
|
||||
call_policy: &mut Box<CallPolicy>,
|
||||
cut_policy: &mut Box<CutPolicy>,
|
||||
@@ -2068,6 +2068,8 @@ impl MachineState {
|
||||
try_or_fail!(self, call_policy.call_builtin(self, ct, indices)),
|
||||
&ClauseType::CallN =>
|
||||
try_or_fail!(self, call_policy.call_n(self, arity, indices)),
|
||||
&ClauseType::Hook(ref hook) =>
|
||||
try_or_fail!(self, call_policy.compile_hook(self, hook)),
|
||||
&ClauseType::Inlined(ref ct) =>
|
||||
self.execute_inlined(ct),
|
||||
&ClauseType::Named(ref name, ref idx) | &ClauseType::Op(ref name, _, ref idx) =>
|
||||
@@ -2087,8 +2089,8 @@ impl MachineState {
|
||||
&ControlInstruction::Allocate(num_cells) =>
|
||||
self.allocate(num_cells),
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) =>
|
||||
self.handle_call_clause(indices, call_policy, cut_policy, ct, arity, lco,
|
||||
use_default_cp),
|
||||
self.handle_call_clause(indices, call_policy, cut_policy,
|
||||
ct, arity, lco, use_default_cp),
|
||||
&ControlInstruction::Deallocate => self.deallocate(),
|
||||
&ControlInstruction::JmpBy(arity, offset, _, lco) => {
|
||||
if !lco {
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
|
||||
use prolog::instructions::*;
|
||||
use prolog::codegen::*;
|
||||
use prolog::compile::*;
|
||||
use prolog::debray_allocator::*;
|
||||
use prolog::heap_print::*;
|
||||
use prolog::instructions::*;
|
||||
|
||||
mod machine_errors;
|
||||
pub(super) mod machine_state;
|
||||
pub(super) mod term_expansion;
|
||||
|
||||
#[macro_use] mod machine_state_impl;
|
||||
mod system_calls;
|
||||
@@ -53,7 +56,8 @@ pub struct Machine {
|
||||
code: Code,
|
||||
pub(super) code_dir: Rc<RefCell<CodeDir>>,
|
||||
pub(super) op_dir: OpDir,
|
||||
// term_dir: TermDir,
|
||||
term_dir: TermDir,
|
||||
term_expanders: Code,
|
||||
pub(super) modules: ModuleDir,
|
||||
cached_query: Option<Code>
|
||||
}
|
||||
@@ -80,7 +84,8 @@ impl Index<LocalCodePtr> for Machine {
|
||||
&None => panic!("Out-of-bounds top level index.")
|
||||
}
|
||||
},
|
||||
LocalCodePtr::DirEntry(p, _) => &self.code[p]
|
||||
LocalCodePtr::DirEntry(p, _) => &self.code[p],
|
||||
LocalCodePtr::UserTermExpansion(p) => &self.term_expanders[p]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +120,7 @@ impl<'a> SubModuleUser for MachineCodeIndices<'a> {
|
||||
static LISTS: &str = include_str!("../lib/lists.pl");
|
||||
static CONTROL: &str = include_str!("../lib/control.pl");
|
||||
static QUEUES: &str = include_str!("../lib/queues.pl");
|
||||
static NUMBERVARS: &str = include_str!("../lib/numbervars.pl");
|
||||
static NUMVARS: &str = include_str!("../lib/numbervars.pl");
|
||||
|
||||
impl Machine {
|
||||
pub fn new() -> Self {
|
||||
@@ -126,7 +131,8 @@ impl Machine {
|
||||
code: Code::new(),
|
||||
code_dir: Rc::new(RefCell::new(CodeDir::new())),
|
||||
op_dir: default_op_dir(),
|
||||
// term_dir: TermDir::new(),
|
||||
term_dir: TermDir::new(),
|
||||
term_expanders: Code::new(),
|
||||
modules: HashMap::new(),
|
||||
cached_query: None
|
||||
};
|
||||
@@ -138,7 +144,7 @@ impl Machine {
|
||||
compile_user_module(&mut wam, LISTS.as_bytes());
|
||||
compile_user_module(&mut wam, CONTROL.as_bytes());
|
||||
compile_user_module(&mut wam, QUEUES.as_bytes());
|
||||
compile_user_module(&mut wam, NUMBERVARS.as_bytes());
|
||||
compile_user_module(&mut wam, NUMVARS.as_bytes());
|
||||
|
||||
wam
|
||||
}
|
||||
@@ -245,8 +251,29 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn add_term_expansion_clause(&mut self, clause: PredicateClause) -> Result<(), ParserError>
|
||||
{
|
||||
let key = (clause_name!("term_expansion"), 2);
|
||||
let preds = self.term_dir.entry(key).or_insert(Predicate(vec![]));
|
||||
|
||||
preds.0.push(clause);
|
||||
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, self.ms.flags);
|
||||
let code = cg.compile_predicate(&preds.0)?;
|
||||
|
||||
Ok(self.term_expanders = code)
|
||||
}
|
||||
|
||||
fn lookup_instr(&self, p: CodePtr) -> Option<Line> {
|
||||
match p {
|
||||
CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) =>
|
||||
if p < self.term_expanders.len() {
|
||||
Some(self.term_expanders[p].clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
CodePtr::Local(LocalCodePtr::TopLevel(_, p)) =>
|
||||
match &self.cached_query {
|
||||
&Some(ref cq) => Some(cq[p].clone()),
|
||||
@@ -342,6 +369,8 @@ impl Machine {
|
||||
|
||||
match self.ms.p {
|
||||
CodePtr::Local(LocalCodePtr::DirEntry(p, _)) if p < self.code.len() => {},
|
||||
CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) if p < self.term_expanders.len() => {},
|
||||
CodePtr::Local(LocalCodePtr::UserTermExpansion(_)) => self.ms.fail = true,
|
||||
CodePtr::Local(_) => break,
|
||||
_ => {}
|
||||
};
|
||||
|
||||
@@ -203,7 +203,7 @@ impl MachineState {
|
||||
},
|
||||
&SystemClauseType::GetDoubleQuotes => {
|
||||
let a1 = self[temp_v!(1)].clone();
|
||||
|
||||
|
||||
match self.flags.double_quotes {
|
||||
DoubleQuotes::Chars =>
|
||||
self.unify(a1, Addr::Con(atom!("chars"))),
|
||||
@@ -435,14 +435,7 @@ impl MachineState {
|
||||
return Err(err);
|
||||
},
|
||||
&SystemClauseType::Succeed => {},
|
||||
&SystemClauseType::UnwindStack => self.unwind_stack(),
|
||||
&SystemClauseType::CompileAndRunQuery => {}
|
||||
/* let addr = self[temp_v!(1)].clone();
|
||||
|
||||
match term_write(&self, addr) {
|
||||
Err(e) => machine_error
|
||||
Ok(term) =>
|
||||
}*/
|
||||
&SystemClauseType::UnwindStack => self.unwind_stack()
|
||||
};
|
||||
|
||||
self.set_p();
|
||||
|
||||
148
src/prolog/machine/term_expansion.rs
Normal file
148
src/prolog/machine/term_expansion.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::parser::*;
|
||||
|
||||
use prolog::heap_iter::*;
|
||||
use prolog::instructions::HeapCellValue;
|
||||
use prolog::machine::*;
|
||||
use prolog::read::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::io::Read;
|
||||
|
||||
pub struct TermStream<R: Read> {
|
||||
stack: Vec<Term>,
|
||||
parser: Parser<R>,
|
||||
in_module: bool
|
||||
}
|
||||
|
||||
impl<R: Read> TermStream<R> {
|
||||
pub fn new(src: R, atom_tbl: TabledData<Atom>, flags: MachineFlags) -> Self {
|
||||
TermStream {
|
||||
stack: Vec::new(),
|
||||
parser: Parser::new(src, atom_tbl, flags),
|
||||
in_module: false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn add_to_top(&mut self, buf: &str) {
|
||||
self.parser.add_to_top(buf);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn eof(&mut self) -> Result<bool, ParserError> {
|
||||
Ok(self.stack.is_empty() && self.parser.eof()?)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn empty_tokens(&mut self) {
|
||||
self.parser.reset();
|
||||
}
|
||||
|
||||
fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
|
||||
match term {
|
||||
Term::Cons(_, head, tail) => {
|
||||
let mut terms = vec![*head];
|
||||
let mut tail = *tail;
|
||||
|
||||
while let Term::Cons(_, head, next_tail) = tail {
|
||||
terms.push(*head);
|
||||
tail = *next_tail;
|
||||
}
|
||||
|
||||
if let Term::Constant(_, Constant::EmptyList) = tail {
|
||||
Ok(self.stack.extend(terms.into_iter().rev()))
|
||||
} else {
|
||||
Err(ParserError::ExpectedTopLevelTerm)
|
||||
}
|
||||
},
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) =>
|
||||
Ok(self.stack.push(term)),
|
||||
_ => Err(ParserError::ExpectedTopLevelTerm)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_term(&mut self, wam: &mut Machine, op_dir: &OpDir) -> Result<Term, ParserError>
|
||||
{
|
||||
loop {
|
||||
while let Some(term) = self.stack.pop() {
|
||||
match wam.try_expand_term(&term)? {
|
||||
Some(term) => self.enqueue_term(term)?,
|
||||
None => return Ok(term)
|
||||
};
|
||||
}
|
||||
|
||||
let term = self.parser.read_term(composite_op!(self.in_module, &wam.op_dir, op_dir))?;
|
||||
self.stack.push(term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
fn try_expand_term(&mut self, term: &Term) -> Result<Option<Term>, ParserError> {
|
||||
let term_h = write_term_to_heap(term, &mut self.ms);
|
||||
let h = self.ms.heap.h;
|
||||
|
||||
self.ms[temp_v!(1)] = Addr::HeapCell(term_h);
|
||||
self.ms.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||
self.ms[temp_v!(2)] = Addr::HeapCell(h);
|
||||
|
||||
let code = vec![call_clause!(ClauseType::Hook(CompileTimeHook::TermExpansion), 2, 0, true)];
|
||||
self.submit_query(code, AllocVarDict::new());
|
||||
|
||||
if self.failed() {
|
||||
self.reset();
|
||||
Ok(None)
|
||||
} else {
|
||||
let term = read_term_from_heap(&self.ms, Addr::HeapCell(h))?;
|
||||
self.reset();
|
||||
Ok(Some(term))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_term_from_heap(machine_st: &MachineState, addr: Addr) -> Result<Term, ParserError>
|
||||
{
|
||||
let pre_order_iter = HCPreOrderIterator::new(machine_st, addr);
|
||||
let post_order_iter = HCPostOrderIterator::new(pre_order_iter);
|
||||
|
||||
let mut stack = vec![];
|
||||
|
||||
for value in post_order_iter {
|
||||
match value {
|
||||
HeapCellValue::NamedStr(arity, ref name, fixity)
|
||||
if stack.len() >= arity => {
|
||||
let stack_len = stack.len();
|
||||
let subterms: Vec<_> = stack.drain(stack_len - arity ..).collect();
|
||||
|
||||
stack.push(Box::new(Term::Clause(Cell::default(), name.clone(), subterms,
|
||||
fixity)));
|
||||
},
|
||||
HeapCellValue::Addr(Addr::Con(constant)) =>
|
||||
stack.push(Box::new(Term::Constant(Cell::default(), constant))),
|
||||
HeapCellValue::Addr(Addr::Lis(_))
|
||||
if stack.len() >= 2 => {
|
||||
let stack_len = stack.len();
|
||||
let (head, tail) = {
|
||||
let mut iter = stack.drain(stack_len - 2 ..);
|
||||
(iter.next().unwrap(), iter.next().unwrap())
|
||||
};
|
||||
|
||||
stack.push(Box::new(Term::Cons(Cell::default(), head, tail)));
|
||||
},
|
||||
HeapCellValue::Addr(Addr::HeapCell(h)) =>
|
||||
stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}", h))))),
|
||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
|
||||
stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}_{}", sc, fr))))),
|
||||
_ => return Err(ParserError::IncompleteReduction)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(term) = stack.pop() {
|
||||
if stack.is_empty() {
|
||||
return Ok(*term);
|
||||
}
|
||||
}
|
||||
|
||||
Err(ParserError::IncompleteReduction)
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
use prolog_parser::ast::*;
|
||||
|
||||
use prolog::heap_iter::*;
|
||||
use prolog::instructions::*;
|
||||
use prolog::machine::machine_state::MachineState;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub fn term_write(machine_st: &MachineState, addr: Addr) -> Result<Term, ParserError>
|
||||
{
|
||||
let pre_order_iter = HCPreOrderIterator::new(machine_st, addr);
|
||||
let post_order_iter = HCPostOrderIterator::new(pre_order_iter);
|
||||
|
||||
let mut stack = vec![];
|
||||
|
||||
for value in post_order_iter {
|
||||
match value {
|
||||
HeapCellValue::NamedStr(arity, ref name, fixity)
|
||||
if stack.len() >= arity => {
|
||||
let stack_len = stack.len();
|
||||
let subterms: Vec<_> = stack.drain(stack_len - arity ..).collect();
|
||||
|
||||
stack.push(Box::new(Term::Clause(Cell::default(), name.clone(), subterms,
|
||||
fixity)));
|
||||
},
|
||||
HeapCellValue::Addr(Addr::Con(constant)) =>
|
||||
stack.push(Box::new(Term::Constant(Cell::default(), constant))),
|
||||
HeapCellValue::Addr(Addr::Lis(_))
|
||||
if stack.len() >= 2 => {
|
||||
let stack_len = stack.len();
|
||||
let mut iter = stack.drain(stack_len - 2 ..);
|
||||
|
||||
let head = iter.next().unwrap();
|
||||
let tail = iter.next().unwrap();
|
||||
|
||||
stack.push(Box::new(Term::Cons(Cell::default(), head, tail)));
|
||||
},
|
||||
HeapCellValue::Addr(Addr::HeapCell(h)) =>
|
||||
stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}", h))))),
|
||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)) =>
|
||||
stack.push(Box::new(Term::Var(Cell::default(), Rc::new(format!("_{}_{}", sc, fr))))),
|
||||
_ => return Err(ParserError::IncompleteReduction)
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(term) = stack.pop() {
|
||||
if stack.is_empty() {
|
||||
return Ok(*term);
|
||||
}
|
||||
}
|
||||
|
||||
Err(ParserError::IncompleteReduction)
|
||||
}
|
||||
Reference in New Issue
Block a user