inline and expand conditionals whenever possible

This commit is contained in:
Mark Thom
2018-01-23 21:01:53 -07:00
parent 677beedec3
commit 41dc8e8d6a
12 changed files with 250 additions and 166 deletions

2
Cargo.lock generated
View File

@@ -171,7 +171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "rusty-wam" name = "rusty-wam"
version = "0.7.4" version = "0.7.5"
dependencies = [ dependencies = [
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@@ -6,16 +6,15 @@ mod prolog;
use prolog::io::*; use prolog::io::*;
use prolog::machine::*; use prolog::machine::*;
use prolog::parser::toplevel::*;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
fn process_buffer(wam: &mut Machine, buffer: &str) fn process_buffer(wam: &mut Machine, buffer: &str)
{ {
match parse_code(buffer, wam.atom_tbl(), wam.op_dir()) { match parse_code(wam, buffer) {
Ok(tl) => { Ok(tl) => {
let result = eval(wam, &tl); let result = compile(wam, &tl);
print(wam, result); print(wam, result);
}, },
Err(s) => println!("{:?}", s) Err(s) => println!("{:?}", s)

View File

@@ -85,6 +85,42 @@ pub enum TopLevel {
Rule(Rule) Rule(Rule)
} }
impl TopLevel {
pub fn name(&self) -> Option<TabledRc<Atom>> {
match self {
&TopLevel::Declaration(_) => None,
&TopLevel::Fact(ref term) => term.name(),
&TopLevel::Predicate(ref clauses) =>
if let Some(ref term) = clauses.first() {
term.name()
} else {
None
},
&TopLevel::Query(_) => None,
&TopLevel::Rule(Rule { head: (QueryTerm::Term(ref term), _), .. }) =>
match term {
&Term::Clause(_, ref name, ..)
| &Term::Constant(_, Constant::Atom(ref name)) =>
Some(name.clone()),
_ =>
None
},
_ => None
}
}
pub fn arity(&self) -> usize {
match self {
&TopLevel::Declaration(_) => 0,
&TopLevel::Fact(ref term) => term.arity(),
&TopLevel::Predicate(ref clauses) =>
clauses.first().map(|t| t.arity()).unwrap_or(0),
&TopLevel::Query(_) => 0,
&TopLevel::Rule(Rule { head: (ref qt, _), ..}) => qt.arity(),
}
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub enum Level { pub enum Level {
Deep, Shallow Deep, Shallow
@@ -220,10 +256,11 @@ tokens exceeding 4096 chars in length. */
pub enum ParserError pub enum ParserError
{ {
Arithmetic(ArithmeticError), Arithmetic(ArithmeticError),
CommaArityMismatch, BuiltInArityMismatch(&'static str),
UnexpectedEOF, UnexpectedEOF,
FailedMatch(String), FailedMatch(String),
IO(IOError), IO(IOError),
ExpectedRel,
InadmissibleFact, InadmissibleFact,
InadmissibleQueryTerm, InadmissibleQueryTerm,
IncompleteReduction, IncompleteReduction,
@@ -291,6 +328,7 @@ impl fmt::Display for Constant {
} }
} }
#[derive(Clone)]
pub enum Term { pub enum Term {
AnonVar, AnonVar,
Clause(Cell<RegType>, TabledRc<Atom>, Vec<Box<Term>>, Option<Fixity>), Clause(Cell<RegType>, TabledRc<Atom>, Vec<Box<Term>>, Option<Fixity>),
@@ -303,7 +341,7 @@ pub enum InlinedQueryTerm {
CompareNumber(CompareNumberQT, Vec<Box<Term>>), CompareNumber(CompareNumberQT, Vec<Box<Term>>),
IsAtomic(Vec<Box<Term>>), IsAtomic(Vec<Box<Term>>),
IsVar(Vec<Box<Term>>), IsVar(Vec<Box<Term>>),
IsInteger(Vec<Box<Term>>) IsInteger(Vec<Box<Term>>)
} }
impl InlinedQueryTerm { impl InlinedQueryTerm {
@@ -312,7 +350,7 @@ impl InlinedQueryTerm {
&InlinedQueryTerm::CompareNumber(_, _) => 2, &InlinedQueryTerm::CompareNumber(_, _) => 2,
&InlinedQueryTerm::IsAtomic(_) => 1, &InlinedQueryTerm::IsAtomic(_) => 1,
&InlinedQueryTerm::IsInteger(_) => 1, &InlinedQueryTerm::IsInteger(_) => 1,
&InlinedQueryTerm::IsVar(_) => 1, &InlinedQueryTerm::IsVar(_) => 1,
} }
} }
} }
@@ -327,6 +365,10 @@ pub enum CompareNumberQT {
Equal Equal
} }
// vars of predicate, toplevel offset. Vec<Term> is always a vector
// of vars (we get their adjoining cells this way).
pub type JumpStub = (Vec<Term>, Rc<Cell<usize>>);
pub enum QueryTerm { pub enum QueryTerm {
Arg(Vec<Box<Term>>), Arg(Vec<Box<Term>>),
CallN(Vec<Box<Term>>), CallN(Vec<Box<Term>>),
@@ -337,6 +379,7 @@ pub enum QueryTerm {
Functor(Vec<Box<Term>>), Functor(Vec<Box<Term>>),
Inlined(InlinedQueryTerm), Inlined(InlinedQueryTerm),
Is(Vec<Box<Term>>), Is(Vec<Box<Term>>),
Jump(JumpStub),
Term(Term), Term(Term),
Throw(Vec<Box<Term>>) Throw(Vec<Box<Term>>)
} }
@@ -352,6 +395,7 @@ impl QueryTerm {
&QueryTerm::Functor(_) => 3, &QueryTerm::Functor(_) => 3,
&QueryTerm::Inlined(ref term) => term.arity(), &QueryTerm::Inlined(ref term) => term.arity(),
&QueryTerm::Is(_) => 2, &QueryTerm::Is(_) => 2,
&QueryTerm::Jump((ref vars, _)) => vars.len(),
&QueryTerm::CallN(ref terms) => terms.len(), &QueryTerm::CallN(ref terms) => terms.len(),
&QueryTerm::Cut => 0, &QueryTerm::Cut => 0,
&QueryTerm::Term(ref term) => term.arity(), &QueryTerm::Term(ref term) => term.arity(),
@@ -387,7 +431,7 @@ impl<'a> ClauseType<'a> {
&ClauseType::Display => "display", &ClauseType::Display => "display",
&ClauseType::Deep(_, _, name, _) => name.as_str(), &ClauseType::Deep(_, _, name, _) => name.as_str(),
&ClauseType::DuplicateTerm => "duplicate_term", &ClauseType::DuplicateTerm => "duplicate_term",
&ClauseType::Functor => "functor", &ClauseType::Functor => "functor",
&ClauseType::Is => "is", &ClauseType::Is => "is",
&ClauseType::Root(name) => name.as_str(), &ClauseType::Root(name) => name.as_str(),
&ClauseType::Throw => "throw" &ClauseType::Throw => "throw"
@@ -774,7 +818,10 @@ pub enum ControlInstruction {
ExecuteN(usize), ExecuteN(usize),
FunctorCall, FunctorCall,
FunctorExecute, FunctorExecute,
Goto(usize, usize), // p, arity. JmpByCall(usize, Rc<Cell<usize>>), // arity, global_offset.
JmpByExecute(usize, Rc<Cell<usize>>),
// GotoCall(usize, usize), // p, arity.
GotoExecute(usize, usize), // p, arity.
IsCall(RegType, ArithmeticTerm), IsCall(RegType, ArithmeticTerm),
IsExecute(RegType, ArithmeticTerm), IsExecute(RegType, ArithmeticTerm),
Proceed, Proceed,
@@ -801,10 +848,12 @@ impl ControlInstruction {
&ControlInstruction::FunctorExecute => true, &ControlInstruction::FunctorExecute => true,
&ControlInstruction::ThrowCall => true, &ControlInstruction::ThrowCall => true,
&ControlInstruction::ThrowExecute => true, &ControlInstruction::ThrowExecute => true,
&ControlInstruction::Goto(_, _) => true, &ControlInstruction::GotoExecute(..) => true,
&ControlInstruction::Proceed => true, &ControlInstruction::Proceed => true,
&ControlInstruction::IsCall(_, _) => true, &ControlInstruction::IsCall(..) => true,
&ControlInstruction::IsExecute(_, _) => true, &ControlInstruction::IsExecute(..) => true,
&ControlInstruction::JmpByCall(..) => true,
&ControlInstruction::JmpByExecute(..) => true,
_ => false _ => false
} }
} }

View File

@@ -36,7 +36,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_value!(perm_v!(1), 3), put_value!(perm_v!(1), 3),
put_unsafe_value!(4, 4)], put_unsafe_value!(4, 4)],
deallocate!(), deallocate!(),
goto!(12, 4), // goto catch/4. goto_execute!(12, 4), // goto catch/4.
try_me_else!(10), // catch/4, 12. try_me_else!(10), // catch/4, 12.
allocate!(3), allocate!(3),
fact![get_var_in_fact!(perm_v!(3), 1), fact![get_var_in_fact!(perm_v!(3), 1),
@@ -48,7 +48,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
query![put_value!(perm_v!(2), 1), query![put_value!(perm_v!(2), 1),
put_unsafe_value!(1, 2)], put_unsafe_value!(1, 2)],
deallocate!(), deallocate!(),
goto!(44, 2), //21: goto end_block/2. goto_execute!(44, 2), //21: goto end_block/2.
trust_me!(), trust_me!(),
allocate!(3), allocate!(3),
fact![get_var_in_fact!(perm_v!(2), 2), fact![get_var_in_fact!(perm_v!(2), 2),
@@ -62,7 +62,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_value!(perm_v!(2), 2), put_value!(perm_v!(2), 2),
put_value!(perm_v!(1), 3)], put_value!(perm_v!(1), 3)],
deallocate!(), deallocate!(),
goto!(32, 2), // goto handle_ball/2. goto_execute!(32, 2), // goto handle_ball/2.
try_me_else!(10), // handle_ball/2, 32. try_me_else!(10), // handle_ball/2, 32.
allocate!(2), allocate!(2),
get_level!(), get_level!(),
@@ -90,7 +90,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_value!(temp_v!(2), 1)], put_value!(temp_v!(2), 1)],
reset_block!(), reset_block!(),
deallocate!(), deallocate!(),
goto!(61, 0), goto_execute!(61, 0),
set_ball!(), // throw/1, 59. set_ball!(), // throw/1, 59.
unwind_stack!(), unwind_stack!(),
fail!(), // false/0, 61. fail!(), // false/0, 61.
@@ -100,7 +100,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
call_n!(1), call_n!(1),
cut!(), cut!(),
deallocate!(), deallocate!(),
goto!(61, 0), goto_execute!(61, 0),
trust_me!(), trust_me!(),
proceed!(), proceed!(),
duplicate_term!(), // duplicate_term/2, 71. duplicate_term!(), // duplicate_term/2, 71.
@@ -120,7 +120,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
unify_variable!(temp_v!(1)), unify_variable!(temp_v!(1)),
unify_variable!(temp_v!(2))], unify_variable!(temp_v!(2))],
set_cp!(temp_v!(3)), set_cp!(temp_v!(3)),
goto!(83, 3), goto_execute!(83, 3),
retry_me_else!(4), retry_me_else!(4),
fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)), fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)),
get_constant!(atom!("!", atom_tbl), temp_v!(2))], get_constant!(atom!("!", atom_tbl), temp_v!(2))],
@@ -143,7 +143,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_unsafe_value!(1, 2), put_unsafe_value!(1, 2),
put_value!(perm_v!(3), 3)], put_value!(perm_v!(3), 3)],
deallocate!(), deallocate!(),
goto!(83, 3), goto_execute!(83, 3),
retry_me_else!(10), retry_me_else!(10),
allocate!(1), allocate!(1),
get_level!(), get_level!(),
@@ -171,7 +171,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())), fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())),
unify_variable!(temp_v!(1)), unify_variable!(temp_v!(1)),
unify_variable!(temp_v!(2))], unify_variable!(temp_v!(2))],
goto!(139, 3), goto_execute!(139, 3),
trust_me!(), trust_me!(),
fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())), fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())),
unify_void!(2)], unify_void!(2)],
@@ -213,7 +213,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_value!(perm_v!(2), 4), put_value!(perm_v!(2), 4),
put_value!(perm_v!(4), 5)], put_value!(perm_v!(4), 5)],
deallocate!(), deallocate!(),
goto!(173, 5), // goto arg_/3. goto_execute!(173, 5), // goto arg_/3.
retry_me_else!(10), retry_me_else!(10),
allocate!(3), allocate!(3),
fact![get_var_in_fact!(perm_v!(1), 1), fact![get_var_in_fact!(perm_v!(1), 1),
@@ -229,7 +229,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_value!(perm_v!(2), 2), put_value!(perm_v!(2), 2),
put_value!(perm_v!(3), 3)], put_value!(perm_v!(3), 3)],
deallocate!(), deallocate!(),
goto!(149, 3), // goto get_arg/3. goto_execute!(149, 3), // goto get_arg/3.
trust_me!(), trust_me!(),
query![get_var_in_query!(temp_v!(4), 1), query![get_var_in_query!(temp_v!(4), 1),
put_structure!(atom_tbl, put_structure!(atom_tbl,
@@ -239,20 +239,20 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
temp_v!(1), temp_v!(1),
None), None),
set_constant!(atom!("integer_expected", atom_tbl))], set_constant!(atom!("integer_expected", atom_tbl))],
goto!(59, 1), // goto throw/1. goto_execute!(59, 1), // goto throw/1.
try_me_else!(5), // arg_/3, 173. try_me_else!(5), // arg_/3, 173.
fact![get_value!(temp_v!(1), 2), fact![get_value!(temp_v!(1), 2),
get_value!(temp_v!(1), 3)], get_value!(temp_v!(1), 3)],
neck_cut!(), neck_cut!(),
query![put_value!(temp_v!(4), 2), query![put_value!(temp_v!(4), 2),
put_value!(temp_v!(5), 3)], put_value!(temp_v!(5), 3)],
goto!(149, 3), // goto get_arg/3. goto_execute!(149, 3), // goto get_arg/3.
retry_me_else!(4), retry_me_else!(4),
fact![get_value!(temp_v!(1), 2)], fact![get_value!(temp_v!(1), 2)],
query![put_value!(temp_v!(4), 2), query![put_value!(temp_v!(4), 2),
get_var_in_query!(temp_v!(6), 3), get_var_in_query!(temp_v!(6), 3),
put_value!(temp_v!(5), 3)], put_value!(temp_v!(5), 3)],
goto!(149, 3), // goto get_arg/3 goto_execute!(149, 3), // goto get_arg/3
trust_me!(), trust_me!(),
allocate!(5), allocate!(5),
fact![get_var_in_fact!(perm_v!(2), 1), fact![get_var_in_fact!(perm_v!(2), 1),
@@ -273,7 +273,7 @@ fn get_builtins(atom_tbl: TabledData<Atom>) -> Code {
put_value!(perm_v!(3), 4), put_value!(perm_v!(3), 4),
put_value!(perm_v!(5), 5)], put_value!(perm_v!(5), 5)],
deallocate!(), deallocate!(),
goto!(173, 3), // goto arg_/3. goto_execute!(173, 3), // goto arg_/3.
display!(), // display/1, 192. display!(), // display/1, 192.
proceed!(), proceed!(),
dynamic_is!(), // is/2, 194. dynamic_is!(), // is/2, 194.

View File

@@ -28,6 +28,12 @@ pub enum EvalSession<'a> {
SubsequentQuerySuccess, SubsequentQuerySuccess,
} }
impl<'a> From<ParserError> for EvalSession<'a> {
fn from(err: ParserError) -> Self {
EvalSession::ParserError(err)
}
}
pub struct ConjunctInfo<'a> { pub struct ConjunctInfo<'a> {
pub perm_vs: VariableFixtures<'a>, pub perm_vs: VariableFixtures<'a>,
pub num_of_chunks: usize, pub num_of_chunks: usize,
@@ -79,12 +85,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
*self.var_count.get(var).unwrap() *self.var_count.get(var).unwrap()
} }
fn mark_non_callable(&mut self, fn mark_non_callable(&mut self, name: &'a Atom, arity: usize, term_loc: GenContext,
name: &'a Atom, vr: &'a Cell<VarReg>, code: &mut Code)
arity: usize,
term_loc: GenContext,
vr: &'a Cell<VarReg>,
code: &mut Code)
-> RegType -> RegType
{ {
match self.marker.bindings().get(name) { match self.marker.bindings().get(name) {
@@ -145,11 +147,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
}; };
} }
fn compile_clause<Target>(&mut self, fn compile_clause<Target>(&mut self, ct: ClauseType<'a>, term_loc: GenContext,
ct: ClauseType<'a>, is_exposed: bool, terms: &'a Vec<Box<Term>>,
term_loc: GenContext,
is_exposed: bool,
terms: &'a Vec<Box<Term>>,
target: &mut Vec<Target>) target: &mut Vec<Target>)
where Target: CompilationTarget<'a> where Target: CompilationTarget<'a>
{ {
@@ -252,9 +251,12 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
&QueryTerm::DuplicateTerm(_) => &QueryTerm::DuplicateTerm(_) =>
code.push(Line::Control(ControlInstruction::DuplicateTermCall)), code.push(Line::Control(ControlInstruction::DuplicateTermCall)),
&QueryTerm::Functor(_) => &QueryTerm::Functor(_) =>
code.push(Line::Control(ControlInstruction::FunctorCall)), code.push(Line::Control(ControlInstruction::FunctorCall)),
&QueryTerm::Inlined(_) => &QueryTerm::Inlined(_) =>
code.push(proceed!()), code.push(proceed!()),
&QueryTerm::Jump((ref vars, ref offset)) => {
code.push(jmp_call!(vars.len(), offset.clone()));
},
&QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => { &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref atom))) => {
let call = ControlInstruction::Call(atom.clone(), 0, pvs); let call = ControlInstruction::Call(atom.clone(), 0, pvs);
code.push(Line::Control(call)); code.push(Line::Control(call));
@@ -291,6 +293,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
*ctrl = ControlInstruction::DuplicateTermExecute, *ctrl = ControlInstruction::DuplicateTermExecute,
ControlInstruction::FunctorCall => ControlInstruction::FunctorCall =>
*ctrl = ControlInstruction::FunctorExecute, *ctrl = ControlInstruction::FunctorExecute,
ControlInstruction::JmpByCall(arity, offset) =>
*ctrl = ControlInstruction::JmpByExecute(arity, offset),
ControlInstruction::CatchCall => ControlInstruction::CatchCall =>
*ctrl = ControlInstruction::CatchExecute, *ctrl = ControlInstruction::CatchExecute,
ControlInstruction::ThrowCall => ControlInstruction::ThrowCall =>
@@ -323,7 +327,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
code.push(compare_number_instr!(cmp, code.push(compare_number_instr!(cmp,
at_1.unwrap_or(interm!(1)), at_1.unwrap_or(interm!(1)),
at_2.unwrap_or(interm!(2)))); at_2.unwrap_or(interm!(2))));
}, },
&InlinedQueryTerm::IsAtomic(ref inner_term) => &InlinedQueryTerm::IsAtomic(ref inner_term) =>
match inner_term[0].as_ref() { match inner_term[0].as_ref() {
&Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => { &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) => {
@@ -338,7 +342,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
} }
}, },
&InlinedQueryTerm::IsInteger(ref inner_term) => &InlinedQueryTerm::IsInteger(ref inner_term) =>
match inner_term[0].as_ref() { match inner_term[0].as_ref() {
&Term::Constant(_, Constant::Number(Number::Integer(_))) => { &Term::Constant(_, Constant::Number(Number::Integer(_))) => {
code.push(succeed!()); code.push(succeed!());
}, },
@@ -362,7 +366,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
let r = self.mark_non_callable(name, 1, term_loc, vr, code); let r = self.mark_non_callable(name, 1, term_loc, vr, code);
code.push(is_var!(r)); code.push(is_var!(r));
} }
} }
} }
Ok(()) Ok(())
@@ -375,11 +379,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
evaluator.eval(term) evaluator.eval(term)
} }
fn compile_seq(&mut self, fn compile_seq(&mut self, iter: ChunkedIterator<'a>, conjunct_info: &ConjunctInfo<'a>,
iter: ChunkedIterator<'a>, code: &mut Code, is_exposed: bool)
conjunct_info: &ConjunctInfo<'a>,
code: &mut Code,
is_exposed: bool)
-> Result<(), ParserError> -> Result<(), ParserError>
{ {
for (chunk_num, _, terms) in iter { for (chunk_num, _, terms) in iter {
@@ -405,12 +406,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
match terms[0].as_ref() { match terms[0].as_ref() {
&Term::Var(ref vr, ref name) => { &Term::Var(ref vr, ref name) => {
let r = self.mark_non_callable(name, let r = self.mark_non_callable(name, 2, term_loc, vr, code);
2,
term_loc,
vr,
code);
code.push(is_call!(r, at.unwrap_or(interm!(1)))); code.push(is_call!(r, at.unwrap_or(interm!(1))));
}, },
&Term::Constant(_, ref c @ Constant::Number(_)) => { &Term::Constant(_, ref c @ Constant::Number(_)) => {
@@ -466,17 +462,23 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm)
{ {
// add a proceed to bookend any trailing inlines or cuts.
match toc { match toc {
&QueryTerm::Inlined(_) | &QueryTerm::Cut => &QueryTerm::Inlined(_) | &QueryTerm::Cut =>
code.push(proceed!()), code.push(proceed!()),
_ => {} _ => {}
}; };
// perform lco.
let dealloc_index = Self::lco(code); let dealloc_index = Self::lco(code);
if conjunct_info.allocates() { if conjunct_info.allocates() {
code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
} }
// mark the first uninitialized jmp command (if there is one)
// by code.len() - index.
//TODO
} }
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError> pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError>

View File

@@ -1,8 +1,10 @@
use prolog::ast::*; use prolog::ast::*;
use prolog::codegen::*; use prolog::codegen::*;
use prolog::debray_allocator::*; use prolog::debray_allocator::*;
use prolog::fixtures::*;
use prolog::heap_print::*; use prolog::heap_print::*;
use prolog::machine::*; use prolog::machine::*;
use prolog::parser::toplevel::*;
use termion::raw::IntoRawMode; use termion::raw::IntoRawMode;
use termion::input::TermRead; use termion::input::TermRead;
@@ -89,7 +91,7 @@ impl fmt::Display for CompareNumberQT {
&CompareNumberQT::LessThan => write!(f, "<"), &CompareNumberQT::LessThan => write!(f, "<"),
&CompareNumberQT::LessThanOrEqual => write!(f, "<="), &CompareNumberQT::LessThanOrEqual => write!(f, "<="),
&CompareNumberQT::NotEqual => write!(f, "=\\="), &CompareNumberQT::NotEqual => write!(f, "=\\="),
&CompareNumberQT::Equal => write!(f, "=:="), &CompareNumberQT::Equal => write!(f, "=:="),
} }
} }
} }
@@ -129,12 +131,16 @@ impl fmt::Display for ControlInstruction {
write!(f, "deallocate"), write!(f, "deallocate"),
&ControlInstruction::Execute(ref name, arity) => &ControlInstruction::Execute(ref name, arity) =>
write!(f, "execute {}/{}", name, arity), write!(f, "execute {}/{}", name, arity),
&ControlInstruction::Goto(p, arity) => &ControlInstruction::GotoExecute(p, arity) =>
write!(f, "goto {}/{}", p, arity), write!(f, "goto_execute {}/{}", p, arity),
&ControlInstruction::IsCall(r, ref at) => &ControlInstruction::IsCall(r, ref at) =>
write!(f, "is_call {}, {}", r, at), write!(f, "is_call {}, {}", r, at),
&ControlInstruction::IsExecute(r, ref at) => &ControlInstruction::IsExecute(r, ref at) =>
write!(f, "is_execute {}, {}", r, at), write!(f, "is_execute {}, {}", r, at),
&ControlInstruction::JmpByCall(arity, ref offset) =>
write!(f, "jmp_by_call {}/{}", offset.get(), arity),
&ControlInstruction::JmpByExecute(arity, ref offset) =>
write!(f, "jmp_by_execute {}/{}", offset.get(), arity),
&ControlInstruction::Proceed => &ControlInstruction::Proceed =>
write!(f, "proceed"), write!(f, "proceed"),
&ControlInstruction::ThrowCall => &ControlInstruction::ThrowCall =>
@@ -164,7 +170,7 @@ impl fmt::Display for BuiltInInstruction {
&BuiltInInstruction::CleanUpBlock => &BuiltInInstruction::CleanUpBlock =>
write!(f, "clean_up_block"), write!(f, "clean_up_block"),
&BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) => &BuiltInInstruction::CompareNumber(cmp, ref at_1, ref at_2) =>
write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2), write!(f, "number_test {}, {}, {} ", cmp, at_1, at_2),
&BuiltInInstruction::DynamicCompareNumber(cmp) => &BuiltInInstruction::DynamicCompareNumber(cmp) =>
write!(f, "dynamic_number_test {}", cmp), write!(f, "dynamic_number_test {}", cmp),
&BuiltInInstruction::EraseBall => &BuiltInInstruction::EraseBall =>
@@ -188,9 +194,9 @@ impl fmt::Display for BuiltInInstruction {
&BuiltInInstruction::IsInteger(r) => &BuiltInInstruction::IsInteger(r) =>
write!(f, "is_integer {}", r), write!(f, "is_integer {}", r),
&BuiltInInstruction::DynamicIs => &BuiltInInstruction::DynamicIs =>
write!(f, "call_is"), write!(f, "call_is"),
&BuiltInInstruction::IsVar(r) => &BuiltInInstruction::IsVar(r) =>
write!(f, "is_var {}", r), write!(f, "is_var {}", r),
&BuiltInInstruction::ResetBlock => &BuiltInInstruction::ResetBlock =>
write!(f, "reset_block"), write!(f, "reset_block"),
&BuiltInInstruction::SetBall => &BuiltInInstruction::SetBall =>
@@ -354,6 +360,12 @@ pub fn print_code(code: &Code) {
} }
} }
pub fn parse_code(wam: &mut Machine, buffer: &str) -> Result<TopLevelPacket, ParserError>
{
let mut worker = TopLevelWorker::new(wam.atom_tbl(), wam.op_dir());
worker.parse_code(buffer)
}
pub fn read() -> String { pub fn read() -> String {
let _ = stdout().flush(); let _ = stdout().flush();
@@ -380,46 +392,90 @@ pub fn read() -> String {
result result
} }
pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b> // throw errors if declaration or query found.
fn compile_relation(tl: &TopLevel) -> Result<Code, ParserError>
{
let mut cg = CodeGenerator::<DebrayAllocator>::new();
match tl {
&TopLevel::Declaration(_) | &TopLevel::Query(_) =>
Err(ParserError::ExpectedRel),
&TopLevel::Predicate(ref clauses) =>
cg.compile_predicate(clauses),
&TopLevel::Fact(ref fact) =>
Ok(cg.compile_fact(fact)),
&TopLevel::Rule(ref rule) =>
cg.compile_rule(rule)
}
}
// set first jmp_by_call or jmp_by_index instruction to code.len() - idx,
// where idx is the place it occurs. It only does this to the *first* uninitialized
// jmp index it encounters, then returns.
fn set_first_index(code: &Code)
{
for (idx, line) in code.iter().enumerate() {
match line {
&Line::Control(ControlInstruction::JmpByExecute(_, ref offset))
| &Line::Control(ControlInstruction::JmpByCall(_, ref offset)) if offset.get() == 0 => {
offset.set(code.len() - idx);
break;
},
_ => {}
};
}
}
fn compile_appendix(code: &mut Code, queue: &Vec<TopLevel>) -> Result<(), ParserError>
{
for tl in queue.iter() {
set_first_index(code);
code.append(&mut compile_relation(tl)?);
}
Ok(())
}
fn compile_query<'a>(terms: &'a Vec<QueryTerm>, queue: &'a Vec<TopLevel>)
-> Result<(Code, AllocVarDict<'a>), ParserError>
{
let mut cg = CodeGenerator::<DebrayAllocator>::new();
let mut code = try!(cg.compile_query(terms));
compile_appendix(&mut code, queue)?;
Ok((code, cg.take_vars()))
}
pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b>
{ {
match tl { match tl {
&TopLevel::Declaration(ref decl) => &TopLevelPacket::Query(ref terms, ref queue) =>
match compile_query(terms, queue) {
Ok((code, vars)) => wam.submit_query(code, vars),
Err(e) => EvalSession::from(e)
},
&TopLevelPacket::Decl(TopLevel::Declaration(ref decl), _) =>
wam.submit_decl(decl), wam.submit_decl(decl),
&TopLevel::Predicate(ref clauses) => { &TopLevelPacket::Decl(ref tl, ref queue) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new(); let mut code = match compile_relation(tl) {
Ok(code) => code,
let compiled_pred = match cg.compile_predicate(clauses) {
Ok(pred) => pred,
Err(e) => return EvalSession::ParserError(e)
};
wam.add_predicate(clauses, compiled_pred)
},
&TopLevel::Fact(ref fact) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_fact = cg.compile_fact(fact);
wam.add_fact(fact, compiled_fact)
},
&TopLevel::Rule(ref rule) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_rule = match cg.compile_rule(rule) {
Ok(rule) => rule,
Err(e) => return EvalSession::ParserError(e)
};
wam.add_rule(rule, compiled_rule)
},
&TopLevel::Query(ref query) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_query = match cg.compile_query(query) {
Ok(query) => query,
Err(e) => return EvalSession::ParserError(e) Err(e) => return EvalSession::ParserError(e)
}; };
wam.submit_query(compiled_query, cg.take_vars()) if let Err(e) = compile_appendix(&mut code, queue) {
return EvalSession::from(e);
};
if !code.is_empty() {
if let Some(name) = tl.name() {
wam.add_user_code(name, tl.arity(), code)
} else {
EvalSession::NamelessEntry
}
} else {
EvalSession::ImpermissibleEntry(String::from("no code generated."))
}
} }
} }
} }
@@ -446,7 +502,7 @@ pub fn print(wam: &mut Machine, result: EvalSession) {
loop { loop {
let mut result = EvalSession::QueryFailure; let mut result = EvalSession::QueryFailure;
let mut output = PrinterOutputter::new(); let mut output = PrinterOutputter::new();
let bindings = wam.heap_view(&heap_locs, output).result(); let bindings = wam.heap_view(&heap_locs, output).result();
let stdin = stdin(); let stdin = stdin();

View File

@@ -71,7 +71,14 @@ impl<'a> QueryIterator<'a> {
let state = TermIterState::Clause(0, ClauseType::Throw, term); let state = TermIterState::Clause(0, ClauseType::Throw, term);
QueryIterator { state_stack: vec![state] } QueryIterator { state_stack: vec![state] }
}, },
&QueryTerm::Cut => QueryIterator { state_stack: vec![] } &QueryTerm::Cut => QueryIterator { state_stack: vec![] },
&QueryTerm::Jump((ref vars, _)) => {
let state_stack = vars.iter().rev().map(|t| {
TermIterState::to_state(Level::Shallow, t)
}).collect();
QueryIterator { state_stack }
}
} }
} }
} }
@@ -266,6 +273,11 @@ impl<'a> ChunkedIterator<'a>
while let Some(term) = item { while let Some(term) = item {
match term { match term {
&QueryTerm::Jump((ref vars, _)) => {
result.push(term);
arity = vars.len();
break;
},
&QueryTerm::Term(ref inner_term) => &QueryTerm::Term(ref inner_term) =>
if let GenContext::Head = self.term_loc { if let GenContext::Head = self.term_loc {
result.push(term); result.push(term);

View File

@@ -1672,8 +1672,8 @@ impl MachineState {
let val = self.try_functor(); let val = self.try_functor();
self.p = self.cp; self.p = self.cp;
val val
}), }),
&ControlInstruction::Goto(p, arity) => { &ControlInstruction::GotoExecute(p, arity) => {
self.num_of_args = arity; self.num_of_args = arity;
self.b0 = self.b; self.b0 = self.b;
self.p = CodePtr::DirEntry(p); self.p = CodePtr::DirEntry(p);
@@ -1692,6 +1692,17 @@ impl MachineState {
self.unify(a1, Addr::Con(Constant::Number(a2))); self.unify(a1, Addr::Con(Constant::Number(a2)));
self.p = self.cp; self.p = self.cp;
}, },
&ControlInstruction::JmpByCall(arity, ref offset) => {
self.cp = self.p + 1;
self.num_of_args = arity;
self.b0 = self.b;
self.p += offset.get();
},
&ControlInstruction::JmpByExecute(arity, ref offset) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p += offset.get();
},
&ControlInstruction::Proceed => &ControlInstruction::Proceed =>
self.p = self.cp, self.p = self.cp,
&ControlInstruction::ThrowCall => { &ControlInstruction::ThrowCall => {

View File

@@ -12,7 +12,6 @@ use std::collections::{HashMap, HashSet};
use std::mem::swap; use std::mem::swap;
use std::ops::Index; use std::ops::Index;
use std::rc::Rc; use std::rc::Rc;
use std::vec::Vec;
pub struct Machine { pub struct Machine {
ms: machine_state::MachineState, ms: machine_state::MachineState,
@@ -60,9 +59,8 @@ impl Machine {
self.ms.atom_tbl.clone() self.ms.atom_tbl.clone()
} }
fn add_user_code<'a>(&mut self, name: TabledRc<Atom>, pub fn add_user_code<'a>(&mut self, name: TabledRc<Atom>, arity: usize, mut code: Code)
arity: usize, offset: usize) -> EvalSession<'a>
-> EvalSession<'a>
{ {
match self.code_dir.get(&(name.clone(), arity)) { match self.code_dir.get(&(name.clone(), arity)) {
Some(&(PredicateKeyType::BuiltIn, _)) => Some(&(PredicateKeyType::BuiltIn, _)) =>
@@ -70,58 +68,14 @@ impl Machine {
_ => {} _ => {}
}; };
let offset = self.code.len();
self.code.append(&mut code);
self.code_dir.insert((name, arity), (PredicateKeyType::User, offset)); self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
EvalSession::EntrySuccess EvalSession::EntrySuccess
} }
pub fn add_fact<'a>(&mut self, fact: &Term, mut code: Code) -> EvalSession<'a>
{
match fact {
&Term::Clause(_, ref name, ..) | &Term::Constant(_, Constant::Atom(ref name)) => {
let p = self.code.len();
let arity = fact.arity();
self.code.append(&mut code);
self.add_user_code(name.clone(), arity, p)
},
_ => EvalSession::NamelessEntry
}
}
pub fn add_rule<'a>(&mut self, rule: &Rule, mut code: Code) -> EvalSession<'a>
{
match &rule.head.0 {
&QueryTerm::Term(Term::Clause(_, ref name, ..))
| &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) => {
let p = self.code.len();
let arity = rule.head.0.arity();
self.code.append(&mut code);
self.add_user_code(name.clone(), arity, p)
},
_ => EvalSession::NamelessEntry
}
}
pub fn add_predicate<'a>(&mut self, clauses: &Vec<PredicateClause>, mut code: Code)
-> EvalSession<'a>
{
let p = self.code.len();
if let Some(ref clause) = clauses.first() {
if let Some(name) = clause.name() {
let arity = clause.arity();
self.code.append(&mut code);
self.add_user_code(name.clone(), arity, p)
} else {
EvalSession::NamelessEntry
}
} else {
EvalSession::ImpermissibleEntry(String::from("predicate must have clauses."))
}
}
fn cached_query_size(&self) -> usize { fn cached_query_size(&self) -> usize {
match &self.cached_query { match &self.cached_query {
&Some(ref query) => query.len(), &Some(ref query) => query.len(),
@@ -255,7 +209,7 @@ impl Machine {
}, },
_ => {} _ => {}
} }
self.ms.p = CodePtr::TopLevel(cn, p); self.ms.p = CodePtr::TopLevel(cn, p);
} }

View File

@@ -28,12 +28,6 @@ macro_rules! deallocate {
) )
} }
macro_rules! compare_number {
($cmp: expr, $terms: expr) => (
QueryTerm::Inlined(InlinedQueryTerm::CompareNumber($cmp, $terms))
)
}
macro_rules! compare_number_instr { macro_rules! compare_number_instr {
($cmp: expr, $at_1: expr, $at_2: expr) => ( ($cmp: expr, $at_1: expr, $at_2: expr) => (
Line::BuiltIn(BuiltInInstruction::CompareNumber($cmp, $at_1, $at_2)) Line::BuiltIn(BuiltInInstruction::CompareNumber($cmp, $at_1, $at_2))
@@ -222,9 +216,9 @@ macro_rules! install_new_block {
) )
} }
macro_rules! goto { macro_rules! goto_execute {
($line:expr, $arity:expr) => ( ($line:expr, $arity:expr) => (
Line::Control(ControlInstruction::Goto($line, $arity)) Line::Control(ControlInstruction::GotoExecute($line, $arity))
) )
} }
@@ -465,3 +459,9 @@ macro_rules! cmp_eq {
CompareNumberQT::Equal CompareNumberQT::Equal
) )
} }
macro_rules! jmp_call {
($arity:expr, $offset:expr) => (
Line::Control(ControlInstruction::JmpByCall($arity, $offset))
)
}

View File

@@ -3,7 +3,6 @@ use prolog::fixtures::*;
use prolog::heap_print::*; use prolog::heap_print::*;
use prolog::io::*; use prolog::io::*;
use prolog::machine::*; use prolog::machine::*;
use prolog::parser::toplevel::*;
use std::collections::HashSet; use std::collections::HashSet;
use std::mem::swap; use std::mem::swap;
@@ -69,6 +68,7 @@ pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
-> Vec<HashSet<String>> -> Vec<HashSet<String>>
{ {
let mut output = TestOutputter::new(); let mut output = TestOutputter::new();
output = wam.heap_view(&heap_locs, output); output = wam.heap_view(&heap_locs, output);
output.cache(); output.cache();
@@ -86,6 +86,7 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa
-> Vec<HashSet<String>> -> Vec<HashSet<String>>
{ {
let mut output = TestOutputter::new(); let mut output = TestOutputter::new();
output = wam.heap_view(&heap_locs, output); output = wam.heap_view(&heap_locs, output);
output.cache(); output.cache();
@@ -114,10 +115,10 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa
pub fn submit(wam: &mut Machine, buffer: &str) -> bool pub fn submit(wam: &mut Machine, buffer: &str) -> bool
{ {
wam.reset(); wam.reset();
match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) { match parse_code(wam, buffer) {
Ok(tl) => Ok(tl) =>
match eval(wam, &tl) { match compile(wam, &tl) {
EvalSession::InitialQuerySuccess(_, _) | EvalSession::InitialQuerySuccess(_, _) |
EvalSession::EntrySuccess | EvalSession::EntrySuccess |
EvalSession::SubsequentQuerySuccess => EvalSession::SubsequentQuerySuccess =>
@@ -133,9 +134,9 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
{ {
wam.reset(); wam.reset();
match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) { match parse_code(wam, buffer) {
Ok(tl) => Ok(tl) =>
match eval(wam, &tl) { match compile(wam, &tl) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) => EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output(wam, alloc_locs, heap_locs), result == collect_test_output(wam, alloc_locs, heap_locs),
EvalSession::EntrySuccess => true, EvalSession::EntrySuccess => true,
@@ -152,9 +153,9 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
{ {
wam.reset(); wam.reset();
match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) { match parse_code(wam, buffer) {
Ok(tl) => Ok(tl) =>
match eval(wam, &tl) { match compile(wam, &tl) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) => EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output_with_limit(wam, alloc_locs, result == collect_test_output_with_limit(wam, alloc_locs,
heap_locs, limit), heap_locs, limit),