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]]
name = "rusty-wam"
version = "0.7.4"
version = "0.7.5"
dependencies = [
"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)",

View File

@@ -6,16 +6,15 @@ mod prolog;
use prolog::io::*;
use prolog::machine::*;
use prolog::parser::toplevel::*;
#[cfg(test)]
mod tests;
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) => {
let result = eval(wam, &tl);
let result = compile(wam, &tl);
print(wam, result);
},
Err(s) => println!("{:?}", s)

View File

@@ -85,6 +85,42 @@ pub enum TopLevel {
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)]
pub enum Level {
Deep, Shallow
@@ -220,10 +256,11 @@ tokens exceeding 4096 chars in length. */
pub enum ParserError
{
Arithmetic(ArithmeticError),
CommaArityMismatch,
BuiltInArityMismatch(&'static str),
UnexpectedEOF,
FailedMatch(String),
IO(IOError),
ExpectedRel,
InadmissibleFact,
InadmissibleQueryTerm,
IncompleteReduction,
@@ -291,6 +328,7 @@ impl fmt::Display for Constant {
}
}
#[derive(Clone)]
pub enum Term {
AnonVar,
Clause(Cell<RegType>, TabledRc<Atom>, Vec<Box<Term>>, Option<Fixity>),
@@ -303,7 +341,7 @@ pub enum InlinedQueryTerm {
CompareNumber(CompareNumberQT, Vec<Box<Term>>),
IsAtomic(Vec<Box<Term>>),
IsVar(Vec<Box<Term>>),
IsInteger(Vec<Box<Term>>)
IsInteger(Vec<Box<Term>>)
}
impl InlinedQueryTerm {
@@ -312,7 +350,7 @@ impl InlinedQueryTerm {
&InlinedQueryTerm::CompareNumber(_, _) => 2,
&InlinedQueryTerm::IsAtomic(_) => 1,
&InlinedQueryTerm::IsInteger(_) => 1,
&InlinedQueryTerm::IsVar(_) => 1,
&InlinedQueryTerm::IsVar(_) => 1,
}
}
}
@@ -327,6 +365,10 @@ pub enum CompareNumberQT {
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 {
Arg(Vec<Box<Term>>),
CallN(Vec<Box<Term>>),
@@ -337,6 +379,7 @@ pub enum QueryTerm {
Functor(Vec<Box<Term>>),
Inlined(InlinedQueryTerm),
Is(Vec<Box<Term>>),
Jump(JumpStub),
Term(Term),
Throw(Vec<Box<Term>>)
}
@@ -352,6 +395,7 @@ impl QueryTerm {
&QueryTerm::Functor(_) => 3,
&QueryTerm::Inlined(ref term) => term.arity(),
&QueryTerm::Is(_) => 2,
&QueryTerm::Jump((ref vars, _)) => vars.len(),
&QueryTerm::CallN(ref terms) => terms.len(),
&QueryTerm::Cut => 0,
&QueryTerm::Term(ref term) => term.arity(),
@@ -387,7 +431,7 @@ impl<'a> ClauseType<'a> {
&ClauseType::Display => "display",
&ClauseType::Deep(_, _, name, _) => name.as_str(),
&ClauseType::DuplicateTerm => "duplicate_term",
&ClauseType::Functor => "functor",
&ClauseType::Functor => "functor",
&ClauseType::Is => "is",
&ClauseType::Root(name) => name.as_str(),
&ClauseType::Throw => "throw"
@@ -774,7 +818,10 @@ pub enum ControlInstruction {
ExecuteN(usize),
FunctorCall,
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),
IsExecute(RegType, ArithmeticTerm),
Proceed,
@@ -801,10 +848,12 @@ impl ControlInstruction {
&ControlInstruction::FunctorExecute => true,
&ControlInstruction::ThrowCall => true,
&ControlInstruction::ThrowExecute => true,
&ControlInstruction::Goto(_, _) => true,
&ControlInstruction::GotoExecute(..) => true,
&ControlInstruction::Proceed => true,
&ControlInstruction::IsCall(_, _) => true,
&ControlInstruction::IsExecute(_, _) => true,
&ControlInstruction::IsCall(..) => true,
&ControlInstruction::IsExecute(..) => true,
&ControlInstruction::JmpByCall(..) => true,
&ControlInstruction::JmpByExecute(..) => true,
_ => false
}
}

View File

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

View File

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

View File

@@ -1,8 +1,10 @@
use prolog::ast::*;
use prolog::codegen::*;
use prolog::debray_allocator::*;
use prolog::fixtures::*;
use prolog::heap_print::*;
use prolog::machine::*;
use prolog::parser::toplevel::*;
use termion::raw::IntoRawMode;
use termion::input::TermRead;
@@ -89,7 +91,7 @@ impl fmt::Display for CompareNumberQT {
&CompareNumberQT::LessThan => write!(f, "<"),
&CompareNumberQT::LessThanOrEqual => 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"),
&ControlInstruction::Execute(ref name, arity) =>
write!(f, "execute {}/{}", name, arity),
&ControlInstruction::Goto(p, arity) =>
write!(f, "goto {}/{}", p, arity),
&ControlInstruction::GotoExecute(p, arity) =>
write!(f, "goto_execute {}/{}", p, arity),
&ControlInstruction::IsCall(r, ref at) =>
write!(f, "is_call {}, {}", r, at),
&ControlInstruction::IsExecute(r, ref 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 =>
write!(f, "proceed"),
&ControlInstruction::ThrowCall =>
@@ -164,7 +170,7 @@ impl fmt::Display for BuiltInInstruction {
&BuiltInInstruction::CleanUpBlock =>
write!(f, "clean_up_block"),
&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) =>
write!(f, "dynamic_number_test {}", cmp),
&BuiltInInstruction::EraseBall =>
@@ -188,9 +194,9 @@ impl fmt::Display for BuiltInInstruction {
&BuiltInInstruction::IsInteger(r) =>
write!(f, "is_integer {}", r),
&BuiltInInstruction::DynamicIs =>
write!(f, "call_is"),
write!(f, "call_is"),
&BuiltInInstruction::IsVar(r) =>
write!(f, "is_var {}", r),
write!(f, "is_var {}", r),
&BuiltInInstruction::ResetBlock =>
write!(f, "reset_block"),
&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 {
let _ = stdout().flush();
@@ -380,46 +392,90 @@ pub fn read() -> String {
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 {
&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),
&TopLevel::Predicate(ref clauses) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new();
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,
&TopLevelPacket::Decl(ref tl, ref queue) => {
let mut code = match compile_relation(tl) {
Ok(code) => code,
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 {
let mut result = EvalSession::QueryFailure;
let mut output = PrinterOutputter::new();
let bindings = wam.heap_view(&heap_locs, output).result();
let stdin = stdin();

View File

@@ -71,7 +71,14 @@ impl<'a> QueryIterator<'a> {
let state = TermIterState::Clause(0, ClauseType::Throw, term);
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 {
match term {
&QueryTerm::Jump((ref vars, _)) => {
result.push(term);
arity = vars.len();
break;
},
&QueryTerm::Term(ref inner_term) =>
if let GenContext::Head = self.term_loc {
result.push(term);

View File

@@ -1672,8 +1672,8 @@ impl MachineState {
let val = self.try_functor();
self.p = self.cp;
val
}),
&ControlInstruction::Goto(p, arity) => {
}),
&ControlInstruction::GotoExecute(p, arity) => {
self.num_of_args = arity;
self.b0 = self.b;
self.p = CodePtr::DirEntry(p);
@@ -1692,6 +1692,17 @@ impl MachineState {
self.unify(a1, Addr::Con(Constant::Number(a2)));
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 =>
self.p = self.cp,
&ControlInstruction::ThrowCall => {

View File

@@ -12,7 +12,6 @@ use std::collections::{HashMap, HashSet};
use std::mem::swap;
use std::ops::Index;
use std::rc::Rc;
use std::vec::Vec;
pub struct Machine {
ms: machine_state::MachineState,
@@ -60,9 +59,8 @@ impl Machine {
self.ms.atom_tbl.clone()
}
fn add_user_code<'a>(&mut self, name: TabledRc<Atom>,
arity: usize, offset: usize)
-> EvalSession<'a>
pub fn add_user_code<'a>(&mut self, name: TabledRc<Atom>, arity: usize, mut code: Code)
-> EvalSession<'a>
{
match self.code_dir.get(&(name.clone(), arity)) {
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));
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 {
match &self.cached_query {
&Some(ref query) => query.len(),
@@ -255,7 +209,7 @@ impl Machine {
},
_ => {}
}
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 {
($cmp: expr, $at_1: expr, $at_2: expr) => (
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::Control(ControlInstruction::Goto($line, $arity))
Line::Control(ControlInstruction::GotoExecute($line, $arity))
)
}
@@ -465,3 +459,9 @@ macro_rules! cmp_eq {
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::io::*;
use prolog::machine::*;
use prolog::parser::toplevel::*;
use std::collections::HashSet;
use std::mem::swap;
@@ -69,6 +68,7 @@ pub fn collect_test_output<'a>(wam: &mut Machine, alloc_locs: AllocVarDict<'a>,
-> Vec<HashSet<String>>
{
let mut output = TestOutputter::new();
output = wam.heap_view(&heap_locs, output);
output.cache();
@@ -86,6 +86,7 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa
-> Vec<HashSet<String>>
{
let mut output = TestOutputter::new();
output = wam.heap_view(&heap_locs, output);
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
{
wam.reset();
match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) {
match parse_code(wam, buffer) {
Ok(tl) =>
match eval(wam, &tl) {
match compile(wam, &tl) {
EvalSession::InitialQuerySuccess(_, _) |
EvalSession::EntrySuccess |
EvalSession::SubsequentQuerySuccess =>
@@ -133,9 +134,9 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: Vec<HashSet<String>
{
wam.reset();
match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) {
match parse_code(wam, buffer) {
Ok(tl) =>
match eval(wam, &tl) {
match compile(wam, &tl) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output(wam, alloc_locs, heap_locs),
EvalSession::EntrySuccess => true,
@@ -152,9 +153,9 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str,
{
wam.reset();
match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) {
match parse_code(wam, buffer) {
Ok(tl) =>
match eval(wam, &tl) {
match compile(wam, &tl) {
EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) =>
result == collect_test_output_with_limit(wam, alloc_locs,
heap_locs, limit),