inline and expand conditionals whenever possible
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -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)",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>),
|
||||
@@ -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(),
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
{
|
||||
@@ -255,6 +254,9 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<'a, TermMarker>
|
||||
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 =>
|
||||
@@ -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>
|
||||
|
||||
124
src/prolog/io.rs
124
src/prolog/io.rs
@@ -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;
|
||||
@@ -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 =>
|
||||
@@ -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,
|
||||
&TopLevelPacket::Decl(ref tl, ref queue) => {
|
||||
let mut code = match compile_relation(tl) {
|
||||
Ok(code) => code,
|
||||
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)
|
||||
if let Err(e) = compile_appendix(&mut code, queue) {
|
||||
return EvalSession::from(e);
|
||||
};
|
||||
|
||||
wam.submit_query(compiled_query, cg.take_vars())
|
||||
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."))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1673,7 +1673,7 @@ impl MachineState {
|
||||
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 => {
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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))
|
||||
)
|
||||
}
|
||||
|
||||
Submodule src/prolog/parser updated: aa164cabe6...9e80f2bd82
@@ -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();
|
||||
|
||||
@@ -115,9 +116,9 @@ 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),
|
||||
|
||||
Reference in New Issue
Block a user