From: Mark Thom Date: Wed, 24 Jan 2018 04:01:53 +0000 (-0700) Subject: inline and expand conditionals whenever possible X-Git-Tag: v0.8.110~609 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=41dc8e8d6ae5de61703598005ca143ad6a891aa3;p=scryer-prolog.git inline and expand conditionals whenever possible --- diff --git a/Cargo.lock b/Cargo.lock index 966a4013..ddb719f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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)", diff --git a/src/main.rs b/src/main.rs index 6ea09b57..c9ce711c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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) diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 103f769a..7f5087d5 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -85,6 +85,42 @@ pub enum TopLevel { Rule(Rule) } +impl TopLevel { + pub fn name(&self) -> Option> { + 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, TabledRc, Vec>, Option), @@ -303,7 +341,7 @@ pub enum InlinedQueryTerm { CompareNumber(CompareNumberQT, Vec>), IsAtomic(Vec>), IsVar(Vec>), - IsInteger(Vec>) + IsInteger(Vec>) } 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 is always a vector +// of vars (we get their adjoining cells this way). +pub type JumpStub = (Vec, Rc>); + pub enum QueryTerm { Arg(Vec>), CallN(Vec>), @@ -337,6 +379,7 @@ pub enum QueryTerm { Functor(Vec>), Inlined(InlinedQueryTerm), Is(Vec>), + Jump(JumpStub), Term(Term), Throw(Vec>) } @@ -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>), // arity, global_offset. + JmpByExecute(usize, Rc>), + // 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 } } diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 58e37a25..bb761027 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -36,7 +36,7 @@ fn get_builtins(atom_tbl: TabledData) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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. diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 34d90b93..5f3b2482 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -28,6 +28,12 @@ pub enum EvalSession<'a> { SubsequentQuerySuccess, } +impl<'a> From 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, - code: &mut Code) + fn mark_non_callable(&mut self, name: &'a Atom, arity: usize, term_loc: GenContext, + vr: &'a Cell, 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(&mut self, - ct: ClauseType<'a>, - term_loc: GenContext, - is_exposed: bool, - terms: &'a Vec>, + fn compile_clause(&mut self, ct: ClauseType<'a>, term_loc: GenContext, + is_exposed: bool, terms: &'a Vec>, target: &mut Vec) 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 diff --git a/src/prolog/io.rs b/src/prolog/io.rs index 276a531e..248b2863 100644 --- a/src/prolog/io.rs +++ b/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; @@ -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 +{ + 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 { + let mut cg = CodeGenerator::::new(); + match tl { - &TopLevel::Declaration(ref decl) => - wam.submit_decl(decl), - &TopLevel::Predicate(ref clauses) => { - let mut cg = CodeGenerator::::new(); + &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) + } +} - let compiled_pred = match cg.compile_predicate(clauses) { - Ok(pred) => pred, - Err(e) => return EvalSession::ParserError(e) - }; +// 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; + }, + _ => {} + }; + } +} - wam.add_predicate(clauses, compiled_pred) - }, - &TopLevel::Fact(ref fact) => { - let mut cg = CodeGenerator::::new(); +fn compile_appendix(code: &mut Code, queue: &Vec) -> Result<(), ParserError> +{ + for tl in queue.iter() { + set_first_index(code); + code.append(&mut compile_relation(tl)?); + } - let compiled_fact = cg.compile_fact(fact); - wam.add_fact(fact, compiled_fact) - }, - &TopLevel::Rule(ref rule) => { - let mut cg = CodeGenerator::::new(); + Ok(()) +} - let compiled_rule = match cg.compile_rule(rule) { - Ok(rule) => rule, - Err(e) => return EvalSession::ParserError(e) - }; +fn compile_query<'a>(terms: &'a Vec, queue: &'a Vec) + -> Result<(Code, AllocVarDict<'a>), ParserError> +{ + let mut cg = CodeGenerator::::new(); + let mut code = try!(cg.compile_query(terms)); + + compile_appendix(&mut code, queue)?; - wam.add_rule(rule, compiled_rule) - }, - &TopLevel::Query(ref query) => { - let mut cg = CodeGenerator::::new(); + Ok((code, cg.take_vars())) +} - let compiled_query = match cg.compile_query(query) { - Ok(query) => query, +pub fn compile<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevelPacket) -> EvalSession<'b> +{ + match tl { + &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), + &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(); diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index 8db60dcc..06f4301a 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -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); diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index d50a1c00..55b63f9e 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -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 => { diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 536c7ab0..8d9e43f0 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -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, - arity: usize, offset: usize) - -> EvalSession<'a> + pub fn add_user_code<'a>(&mut self, name: TabledRc, 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, 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); } diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 6ad024a5..50ebd443 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -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)) + ) +} diff --git a/src/prolog/parser b/src/prolog/parser index aa164cab..9e80f2bd 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit aa164cabe63b508a1227f15e4bb40b517717a2f3 +Subproject commit 9e80f2bd8268425c2128772b336f616be8d2c5d8 diff --git a/src/test_utils.rs b/src/test_utils.rs index 8507ff37..bb31d99e 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -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> { 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> { 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 { 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),