From: Mark Thom Date: Sun, 5 Mar 2017 02:22:43 +0000 (-0700) Subject: transition to l3 X-Git-Tag: v0.8.110~762 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=42ce902b3c3858f4f23d2a8601b83cac45c0f905;p=scryer-prolog.git transition to l3 --- diff --git a/Cargo.lock b/Cargo.lock index c38c995f..bac78161 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,9 +1,10 @@ [root] name = "rusty-wam" -version = "0.3.5" +version = "0.4.0" dependencies = [ "lalrpop 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-util 0.12.5 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -197,6 +198,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termion" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread-id" version = "2.0.0" @@ -259,6 +268,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b" "checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e" "checksum term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3deff8a2b3b6607d6d7cc32ac25c0b33709453ca9cceac006caac51e963cf94a" +"checksum termion 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e710c59ecea168019486885ade43ea5329bb9a08a117410052fb81b250f40ae" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d" "checksum unicode-xid 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f69506a2561962651710609304bbb961fa3da598c812f877975a82e48ee144f9" diff --git a/Cargo.toml b/Cargo.toml index f79cd5ae..30fe64b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "rusty-wam" -version = "0.3.5" +version = "0.4.0" authors = ["Mark Thom"] build = "build.rs" -[dependencies] +[dependencies.termion] +version = "1.2.0" [dependencies.lalrpop-util] version = "0.12.5" [build-dependencies.lalrpop] -version = "0.12.5" \ No newline at end of file +version = "0.12.5" + diff --git a/README.md b/README.md index c47c5a32..ba933921 100644 --- a/README.md +++ b/README.md @@ -8,135 +8,56 @@ pure Prolog. ## Progress -The language L2 is implemented as a simple REPL. It supports -unification on queries without backtracking, where rules and facts are -limited to a single name/arity pairing, in the familiar Prolog -syntax. No data types apart from atoms are currently supported. +The language L3 is implemented as a simple REPL. L3 is pure Prolog -- +Prolog without cuts, meta- or extra-logical operators, or side effects +of any kind. No data types apart from atoms are currently supported. -An example of the level of interaction currently supported is: +## Tutorial +To enter a multi-clause predicate, the brackets ":{" and "}:" are used +as delimiters. They must be entirely contained with their own lines. +For example, ``` -l2> p(Z, Z). -l2> ?- p(Z, Z). -yes -Z = _0 -l2> ?- p(Z, z). -yes -Z = z -l2> ?- p(Z, w). -yes -Z = w -l2> clouds(are, nice). -l2> ?- p(z, w). -no -l2> ?- p(w, w). -yes -l2> ?- clouds(Z, Z). -no -l2> ?- clouds(are, W). -yes -W = nice -l2> ?- clouds(W, nice). -yes -W = are -l2> ?- p(Z, h(Z, W), f(W)). -no -l2> p(Z, h(Z, W), f(W)). -l2> ?- p(z, h(z, z), f(w)). -no -l2> ?- p(z, h(z, w), f(w)). -yes -l2> ?- p(z, h(z, W), f(w)). -yes -W = w -l2> ?- p(Z, h(Z, w), f(Z)). -yes -Z = w -l2> ?- p(z, h(Z, w), f(Z)). -no -l2> p(f(X), h(Y, f(a)), Y). -l2> ?- p(Z, h(Z, W), f(W)). -yes -Z = f(f(a)) -W = f(a) -l2> p(X, Y) :- q(X, Z), r(Z, Y). -l2> q(q, s). -l2> r(s, t). -l2> ?- p(X, Y). -yes -X = q -Y = t -l2> ?- p(q, t). -yes -l2> ?- p(t, q). -no -l2> ?- p(q, T). -yes -T = t -l2> ?- p(Q, t). -yes -Q = q -l2> ?- p(t, t). -no -l2> p(X, Y) :- q(f(f(X)), R), r(S, T). -l2> q(f(f(X)), r). -l2> ?- p(X, Y). +l3> :{ +p(f(f(X)), h(W), Y) :- g(W), h(W), f(X). +p(X, Y, Z) :- h(Y), z(Z). +}: +l3> :{ +h(x). +h(y). +h(z). +}: +``` + +Single clause predicates can entered without brackets, as in +``` +l3> p(X) :- q(X). +l3> f(s). +l3> z(Z). +``` + +Queries are issued as +``` +l3> ?- p(X, Y, Z). +``` + +Given the above work, the result of the query will be +``` +l3> ?- p(X, Y, Z). yes -Y = _1 X = _0 -l2> q(f(f(x)), r). -l2> ?- p(X, Y). -yes -Y = _1 -X = x -l2> p(X, Y) :- q(X, Y), r(X, Y). -l2> q(s, t). -l2> r(X, Y) :- r(a). -l2> r(a). -l2> ?- p(X, Y). -yes -Y = t -X = s -l2> ?- p(t, S). -no -l2> ?- p(t, s). -no -l2> ?- p(s, T). -yes -T = t -l2> ?- p(S, t). -yes -S = s -l2> p(f(f(a), g(b), X), g(b), h) :- q(X, Y). -l2> q(X, Y). -l2> ?- p(f(X, Y, Z), g(b), h). -yes -Z = _4 -X = f(a) -Y = g(b) -l2> ?- p(f(X, g(Y), c), g(Z), X). -no -l2> ?- p(f(X, g(Y), c), g(Z), h). -yes -Z = b -Y = b -X = f(a) -l2> ?- p(Z, Y, X). -yes -X = h -Z = f(f(a), g(b), _7) -Y = g(b) -l2> ?- p(f(X, Y, Z), Y, h). -yes -X = f(a) -Z = _4 -Y = g(b) -l2> quit +Y = x +Z = _2 +Press ; to continue or A to abort. ``` +Pressing ; will backtrack through other possible answers, if any exist. +Pressing A will abort the search and return to the prompt. + Note that the values of variables belonging to successful queries are printed out, on one line each. Uninstantiated variables are denoted by -a number preceded by an underscore. +a number preceded by an underscore (X = _0 is an example in the +above). ## Occurs check diff --git a/src/l3/and_stack.rs b/src/l3/and_stack.rs new file mode 100644 index 00000000..5e05eada --- /dev/null +++ b/src/l3/and_stack.rs @@ -0,0 +1,80 @@ +use l3::ast::*; + +use std::ops::{Index, IndexMut}; +use std::vec::Vec; + +pub struct Frame { + pub global_index: usize, + pub e: usize, + pub cp: CodePtr, + perms: Vec +} + +impl Frame { + fn new(global_index: usize, e: usize, cp: CodePtr, n: usize) -> Self { + Frame { + global_index: global_index, + e: e, + cp: cp, + perms: vec![Addr::HeapCell(0); n] + } + } +} + +pub struct AndStack(Vec); + +impl AndStack { + pub fn new() -> Self { + AndStack(Vec::new()) + } + + pub fn push(&mut self, global_index: usize, e: usize, cp: CodePtr, n: usize) { + self.0.push(Frame::new(global_index, e, cp, n)); + } + + pub fn top(&self) -> Option<&Frame> { + self.0.last() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn clear(&mut self) { + self.0.clear() + } + + // drop the last n frames. + pub fn drop_frames(&mut self, n: usize) { + let len = self.0.len(); + self.0.truncate(len - n); + } +} + +impl Index for AndStack { + type Output = Frame; + + fn index(&self, index: usize) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for AndStack { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Index for Frame { + type Output = Addr; + + fn index(&self, index: usize) -> &Self::Output { + self.perms.index(index - 1) + } +} + +impl IndexMut for Frame { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.perms.index_mut(index - 1) + } +} diff --git a/src/l3/ast.rs b/src/l3/ast.rs new file mode 100644 index 00000000..693be9df --- /dev/null +++ b/src/l3/ast.rs @@ -0,0 +1,303 @@ +use std::cell::Cell; +use std::collections::HashMap; +use std::ops::{Add, AddAssign}; +use std::vec::Vec; + +pub type Var = String; + +pub type Atom = String; + +pub enum PredicateClause { + Fact(Term), + Rule(Rule) +} + +impl PredicateClause { + pub fn name(&self) -> &Atom { + match self { + &PredicateClause::Fact(ref t) => t.name(), + &PredicateClause::Rule(ref rule) => rule.head.0.name() + } + } + + pub fn arity(&self) -> usize { + match self { + &PredicateClause::Fact(ref t) => t.arity(), + &PredicateClause::Rule(ref rule) => rule.head.0.arity() + } + } +} + +pub enum TopLevel { + Fact(Term), + Predicate(Vec), + Query(Term), + Rule(Rule) +} + +#[derive(Clone, Copy)] +pub enum Level { + Deep, Shallow +} + +#[derive(Clone, Copy)] +pub enum RegType { + Perm(usize), + Temp(usize) +} + +impl RegType { + pub fn reg_num(self) -> usize { + match self { + RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num + } + } + + pub fn is_perm(self) -> bool { + match self { + RegType::Perm(_) => true, + _ => false + } + } +} + +#[derive(Clone, Copy)] +pub enum VarReg { + ArgAndNorm(RegType, usize), + Norm(RegType) +} + +impl VarReg { + pub fn norm(self) -> RegType { + match self { + VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg + } + } + + pub fn root_register(self) -> usize { + match self { + VarReg::ArgAndNorm(_, root) => root, + VarReg::Norm(root) => root.reg_num() + } + } +} + +pub enum Term { + Atom(Cell, Atom), + Clause(Cell, Atom, Vec>), + Var(Cell, Var) +} + +pub struct Rule { + pub head: (Term, Term), + pub clauses: Vec +} + +pub enum TermRef<'a> { + Atom(Level, &'a Cell, &'a Atom), + Clause(Level, &'a Cell, &'a Atom, &'a Vec>), + Var(Level, &'a Cell, &'a Var) +} + +pub enum FactInstruction { + GetStructure(Level, Atom, usize, RegType), + GetValue(RegType, usize), + GetVariable(RegType, usize), + UnifyVariable(RegType), + UnifyValue(RegType) +} + +pub enum QueryInstruction { + PutStructure(Level, Atom, usize, RegType), + PutValue(RegType, usize), + PutVariable(RegType, usize), + SetVariable(RegType), + SetValue(RegType) +} + +pub enum ChoiceInstruction { + RetryMeElse(usize), + TrustMe, + TryMeElse(usize) +} + +pub enum ControlInstruction { + Allocate(usize), + Call(Atom, usize), + Deallocate, + Proceed +} + +pub type CompiledFact = Vec; + +pub type CompiledQuery = Vec; + +pub enum Line { + Choice(ChoiceInstruction), + Control(ControlInstruction), + Fact(CompiledFact), + Query(CompiledQuery) +} + +pub enum LineOrCodeOffset<'a> { + Instruction(&'a Line), + Offset(usize) +} + +impl<'a> From<&'a Line> for LineOrCodeOffset<'a> { + fn from(line: &'a Line) -> Self { + LineOrCodeOffset::Instruction(line) + } +} + +pub type Code = Vec; + +#[derive(Clone, Copy, PartialEq)] +pub enum Addr { + HeapCell(usize), + StackCell(usize, usize), + Str(usize) +} + +impl Addr { + pub fn is_ref(self) -> bool { + match self { + Addr::HeapCell(_) | Addr::StackCell(_, _) => true, + _ => false + } + } + + pub fn as_ref(self) -> Option { + match self { + Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)), + Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)), + _ => None + } + } +} + +impl From for Addr { + fn from(r: Ref) -> Self { + match r { + Ref::HeapCell(hc) => Addr::HeapCell(hc), + Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc) + } + } +} + +#[derive(Clone, Copy, PartialEq)] +pub enum Ref { + HeapCell(usize), + StackCell(usize, usize) +} + +#[derive(Clone, PartialEq)] +pub enum HeapCellValue { + NamedStr(usize, Atom), + Ref(Ref), + Str(usize) +} + +impl From for HeapCellValue { + fn from(addr: Addr) -> HeapCellValue { + match addr { + Addr::HeapCell(hc) => + HeapCellValue::Ref(Ref::HeapCell(hc)), + Addr::StackCell(fr, sc) => + HeapCellValue::Ref(Ref::StackCell(fr, sc)), + Addr::Str(hc) => + HeapCellValue::Str(hc) + } + } +} + +impl HeapCellValue { + pub fn as_addr(&self, focus: usize) -> Addr { + match self { + &HeapCellValue::Ref(r) => Addr::from(r), + &HeapCellValue::Str(s) => Addr::Str(s), + &HeapCellValue::NamedStr(_, _) => Addr::Str(focus) + } + } +} + +#[derive(Clone, Copy)] +pub enum CodePtr { + DirEntry(usize), + TopLevel +} + +impl Default for CodePtr { + fn default() -> Self { + CodePtr::TopLevel + } +} + +impl Add for CodePtr { + type Output = CodePtr; + + fn add(self, rhs: usize) -> Self::Output { + match self { + CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs), + CodePtr::TopLevel => CodePtr::TopLevel + } + } +} + +impl AddAssign for CodePtr { + fn add_assign(&mut self, rhs: usize) { + match self { + &mut CodePtr::DirEntry(ref mut p) => *p += rhs, + _ => {} + } + } +} + +pub type Heap = Vec; + +pub type Registers = Vec; + +impl Term { + pub fn subterms(&self) -> usize { + match self { + &Term::Clause(_, _, ref terms) => terms.len(), + _ => 1 + } + } + + pub fn name(&self) -> &Atom { + match self { + &Term::Atom(_, ref atom) + | &Term::Var(_, ref atom) + | &Term::Clause(_, ref atom, _) => atom + } + } + + pub fn arity(&self) -> usize { + match self { + &Term::Atom(_, _) | &Term::Var(_, _) => 0, + &Term::Clause(_, _, ref child_terms) => child_terms.len() + } + } +} + +pub type HeapVarDict = HashMap; + +pub enum EvalResult { + EntryFailure, + EntrySuccess, + InitialQuerySuccess(HeapVarDict), + QueryFailure, + SubsequentQuerySuccess, +} + +impl EvalResult { + #[allow(dead_code)] + pub fn failed_query(&self) -> bool { + if let &EvalResult::QueryFailure = self { + true + } else { + false + } + } +} diff --git a/src/l3/codegen.rs b/src/l3/codegen.rs new file mode 100644 index 00000000..21065704 --- /dev/null +++ b/src/l3/codegen.rs @@ -0,0 +1,447 @@ +use l3::ast::*; +use l3::iterators::{FactIterator, QueryIterator}; + +use std::cell::Cell; +use std::cmp::max; +use std::collections::HashMap; +use std::vec::Vec; + +trait CompilationTarget<'a> { + type Iterator : Iterator>; + + fn iter(&'a Term) -> Self::Iterator; + + fn to_structure(Level, Atom, usize, RegType) -> Self; + + fn argument_to_variable(RegType, usize) -> Self; + fn argument_to_value(RegType, usize) -> Self; + fn subterm_to_variable(RegType) -> Self; + fn subterm_to_value(RegType) -> Self; + + fn clause_arg_to_instr(RegType) -> Self; +} + +impl<'a> CompilationTarget<'a> for FactInstruction { + type Iterator = FactIterator<'a>; + + fn iter(term: &'a Term) -> Self::Iterator { + term.breadth_first_iter() + } + + fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self { + FactInstruction::GetStructure(lvl, atom, arity, reg) + } + + fn argument_to_variable(arg: RegType, val: usize) -> Self { + FactInstruction::GetVariable(arg, val) + } + + fn argument_to_value(arg: RegType, val: usize) -> Self { + FactInstruction::GetValue(arg, val) + } + + fn subterm_to_variable(val: RegType) -> Self { + FactInstruction::UnifyVariable(val) + } + + fn subterm_to_value(val: RegType) -> Self { + FactInstruction::UnifyValue(val) + } + + fn clause_arg_to_instr(val: RegType) -> Self { + FactInstruction::UnifyVariable(val) + } +} + +impl<'a> CompilationTarget<'a> for QueryInstruction { + type Iterator = QueryIterator<'a>; + + fn iter(term: &'a Term) -> Self::Iterator { + term.post_order_iter() + } + + fn to_structure(lvl: Level, atom: Atom, arity: usize, reg: RegType) -> Self { + QueryInstruction::PutStructure(lvl, atom, arity, reg) + } + + fn argument_to_variable(arg: RegType, val: usize) -> Self { + QueryInstruction::PutVariable(arg, val) + } + + fn argument_to_value(arg: RegType, val: usize) -> Self { + QueryInstruction::PutValue(arg, val) + } + + fn subterm_to_variable(val: RegType) -> Self { + QueryInstruction::SetVariable(val) + } + + fn subterm_to_value(val: RegType) -> Self { + QueryInstruction::SetValue(val) + } + + fn clause_arg_to_instr(val: RegType) -> Self { + QueryInstruction::SetValue(val) + } +} + +struct TermMarker<'a> { + bindings: HashMap<&'a Var, VarReg>, + arg_c: usize, + perm_c: usize, + temp_c: usize +} + +impl<'a> TermMarker<'a> { + fn new() -> TermMarker<'a> { + TermMarker { bindings: HashMap::new(), + arg_c: 1, + perm_c: 1, + temp_c: 1 } + } + + fn reset(&mut self) { + self.bindings.clear(); + self.perm_c = 1; + } + + fn contains_var(&self, var: &'a Var) -> bool { + self.bindings.contains_key(var) + } + + fn get(&self, var: &'a Var) -> VarReg { + *self.bindings.get(var).unwrap() + } + + fn insert(&mut self, var: &'a Var, r: VarReg) { + self.bindings.insert(var, r); + } + + fn mark_non_var(&mut self, lvl: Level, cell: &Cell) { + let reg_type = cell.get(); + + if reg_type.reg_num() == 0 { + match lvl { + Level::Deep if reg_type.is_perm() => { + let perm = self.perm_c; + self.perm_c += 1; + cell.set(RegType::Perm(perm)); + }, + Level::Deep => { + let temp = self.temp_c; + self.temp_c += 1; + cell.set(RegType::Temp(temp)); + }, + Level::Shallow if reg_type.is_perm() => { + let arg = self.arg_c; + self.arg_c += 1; + cell.set(RegType::Perm(arg)); + }, + Level::Shallow => { + let arg = self.arg_c; + self.arg_c += 1; + cell.set(RegType::Temp(arg)); + } + }; + } + } + + fn mark_old_var(&mut self, lvl: Level, var: &'a Var) -> VarReg + { + let reg = self.get(var); + + match lvl { + Level::Deep => VarReg::Norm(reg.norm()), + Level::Shallow => { + let reg = VarReg::ArgAndNorm(reg.norm(), self.arg_c); + + self.arg_c += 1; + self.insert(var, reg); + + reg + } + } + } + + fn mark_new_var(&mut self, lvl: Level, var: &'a Var, reg: RegType) -> VarReg + { + let inner_reg = if reg.is_perm() { + let perm = self.perm_c; + self.perm_c += 1; + RegType::Perm(perm) + } else { + let temp = self.temp_c; + self.temp_c += 1; + RegType::Temp(temp) + }; + + let reg = match lvl { + Level::Deep => VarReg::Norm(inner_reg), + Level::Shallow => { + let reg = VarReg::ArgAndNorm(inner_reg, self.arg_c); + self.arg_c += 1; + reg + } + }; + + self.insert(var, reg); + reg + } + + fn advance_at_head(&mut self, term: &'a Term) { + self.arg_c = 1; + self.temp_c = max(term.subterms(), self.temp_c) + 1; + } + + fn advance(&mut self, term: &'a Term) { + self.arg_c = 1; + self.temp_c = term.subterms() + 1; + } +} + +#[derive(Copy, Clone)] +enum TermStatus { + New, Old, Recurrent +} + +pub struct CodeGenerator<'a> { + marker: TermMarker<'a> +} + +type VariableFixture<'a> = (TermStatus, Vec<&'a Cell>); +type VariableFixtures<'a> = HashMap<&'a Var, VariableFixture<'a>>; + +impl<'a> CodeGenerator<'a> { + pub fn new() -> Self { + CodeGenerator { marker: TermMarker::new() } + } + + pub fn vars(&self) -> &HashMap<&Var, VarReg> { + &self.marker.bindings + } + + fn to_structure(&mut self, + lvl: Level, + name: &'a Atom, + cell: &'a Cell, + arity: usize) + -> Target + where Target: CompilationTarget<'a> + { + self.marker.mark_non_var(lvl, cell); + Target::to_structure(lvl, name.clone(), arity, cell.get()) + } + + fn var_term(&mut self, + lvl: Level, + cell: &'a Cell, + var: &'a Var) + -> Target + where Target: CompilationTarget<'a> + { + if !self.marker.contains_var(var) { + let reg = self.marker.mark_new_var(lvl, var, cell.get().norm()); + cell.set(reg); + + match reg { + VarReg::ArgAndNorm(arg, norm) => + Target::argument_to_variable(arg, norm), + VarReg::Norm(norm) => + Target::subterm_to_variable(norm) + } + } else { + let reg = self.marker.mark_old_var(lvl, var); + cell.set(reg); + + match reg { + VarReg::ArgAndNorm(arg, norm) => + Target::argument_to_value(arg, norm), + VarReg::Norm(norm) => + Target::subterm_to_value(norm) + } + } + } + + fn non_var_subterm(&mut self, cell: &'a Cell) -> Target + where Target: CompilationTarget<'a> + { + self.marker.mark_non_var(Level::Deep, cell); + Target::clause_arg_to_instr(cell.get()) + } + + fn subterm_to_instr(&mut self, subterm: &'a Term) -> Target + where Target: CompilationTarget<'a> + { + match subterm { + &Term::Atom(ref cell, _) | &Term::Clause(ref cell, _, _) => + self.non_var_subterm(cell), + &Term::Var(ref cell, ref var) => + self.var_term(Level::Deep, cell, var) + } + } + + fn compile_target(&mut self, term: &'a Term) -> Vec + where Target: CompilationTarget<'a> + { + let iter = Target::iter(term); + let mut target = Vec::new(); + + for term in iter { + match term { + TermRef::Atom(lvl, term, atom) => + target.push(self.to_structure(lvl, atom, term, 0)), + TermRef::Clause(lvl, term, atom, terms) => { + target.push(self.to_structure(lvl, atom, term, terms.len())); + + for subterm in terms { + target.push(self.subterm_to_instr(subterm.as_ref())); + } + }, + TermRef::Var(lvl @ Level::Shallow, ref cell, ref var) => + target.push(self.var_term(lvl, cell, var)), + _ => {} + }; + } + + target + } + + fn mark_vars_in_term(iter: Iter, vs: &mut VariableFixtures<'a>) + where Iter : Iterator> + { + for term in iter { + if let TermRef::Var(_, reg_cell, var) = term { + let mut status = vs.entry(var) + .or_insert((TermStatus::New, Vec::new())); + + status.1.push(reg_cell); + + match status.0 { + TermStatus::Old => status.0 = TermStatus::Recurrent, + _ => {} + }; + } + } + + for &mut (ref mut term_status, ref mut cb) in vs.values_mut() { + match *term_status { + TermStatus::New => *term_status = TermStatus::Old, + TermStatus::Recurrent => { + for cell_reg in cb.drain(0..) { + cell_reg.set(VarReg::Norm(RegType::Perm(0))); + } + }, + _ => {} + } + } + } + + fn mark_perm_vars(rule: &'a Rule) -> VariableFixtures { + let &Rule { head: (ref p0, ref p1), ref clauses } = rule; + let mut vfs = HashMap::new(); + + let iter = p0.breadth_first_iter().chain(p1.breadth_first_iter()); + + Self::mark_vars_in_term(iter, &mut vfs); + + for term in clauses { + Self::mark_vars_in_term(term.breadth_first_iter(), &mut vfs); + } + + vfs + } + + fn add_conditional_call(compiled_query: &mut Code, term: &Term) { + match term { + &Term::Atom(_, ref atom) => { + let call = ControlInstruction::Call(atom.clone(), 0); + compiled_query.push(Line::Control(call)); + }, + &Term::Clause(_, ref atom, ref terms) => { + let call = ControlInstruction::Call(atom.clone(), terms.len()); + compiled_query.push(Line::Control(call)); + }, + _ => {} + } + } + + pub fn compile_rule(&mut self, rule: &'a Rule) -> Code { + let vfs = Self::mark_perm_vars(&rule); + let &Rule { head: (ref p0, ref p1), ref clauses } = rule; + let mut perm_vars = 0; + + for &(term_status, _) in vfs.values() { + if let TermStatus::Recurrent = term_status { + perm_vars += 1; + } + } + + let mut body = Vec::new(); + + body.push(Line::Control(ControlInstruction::Allocate(perm_vars))); + + self.marker.advance(p0); + body.push(Line::Fact(self.compile_target(p0))); + + self.marker.advance_at_head(p1); + body.push(Line::Query(self.compile_target(p1))); + + Self::add_conditional_call(&mut body, p1); + + body = clauses.iter() + .map(|ref term| self.compile_query(term)) + .fold(body, |mut body, ref mut cqs| { + body.append(cqs); + body + }); + + body.push(Line::Control(ControlInstruction::Deallocate)); + body + } + + pub fn compile_fact(&mut self, term: &'a Term) -> Code { + self.marker.advance(term); + + let mut compiled_fact = vec![Line::Fact(self.compile_target(term))]; + let proceed = Line::Control(ControlInstruction::Proceed); + + compiled_fact.push(proceed); + compiled_fact + } + + pub fn compile_query(&mut self, term: &'a Term) -> Code { + self.marker.advance(term); + + let mut compiled_query = vec![Line::Query(self.compile_target(term))]; + Self::add_conditional_call(&mut compiled_query, term); + + compiled_query + } + + pub fn compile_predicate(&mut self, clauses: &'a Vec) -> Code + { + let mut code = Vec::new(); + + for (i, clause) in clauses.iter().enumerate() { + self.marker.reset(); + + let mut clause_code = match clause { + &PredicateClause::Fact(ref fact) => + self.compile_fact(fact), + &PredicateClause::Rule(ref rule) => + self.compile_rule(rule) + }; + + let choice = match i { + 0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1), + _ if i == clauses.len() - 1 => ChoiceInstruction::TrustMe, + _ => ChoiceInstruction::RetryMeElse(clause_code.len() + 1) + }; + + code.push(Line::Choice(choice)); + code.append(&mut clause_code); + } + + code + } +} diff --git a/src/l3/heapview.rs b/src/l3/heapview.rs new file mode 100644 index 00000000..d25040a1 --- /dev/null +++ b/src/l3/heapview.rs @@ -0,0 +1,86 @@ +use l3::and_stack::*; +use l3::ast::*; + +use std::vec::Vec; + +#[derive(Clone, Copy)] +pub enum HeapCellView<'a> { + Str(usize, &'a Atom), + HeapVar(usize), + StackVar(usize, usize) +} + +pub struct HeapCellViewer<'a> { + heap: &'a Heap, + and_stack: &'a AndStack, + state_stack: Vec +} + +impl<'a> HeapCellViewer<'a> { + pub fn new(heap: &'a Heap, and_stack: &'a AndStack, focus: Addr) -> Self { + HeapCellViewer { + heap: heap, + and_stack: and_stack, + state_stack: vec![focus] + } + } + + fn follow_stack_ref(&mut self, mut fr: usize, mut sc: usize) -> HeapCellView<'a> + { + loop { + match self.and_stack[fr][sc] { + Addr::HeapCell(hc) | Addr::Str(hc) => + return self.follow_heap_ref(hc), + Addr::StackCell(fr1, sc1) => { + if fr1 == fr && sc1 == sc { + return HeapCellView::StackVar(fr, sc); + } + + fr = fr1; sc = sc1; + } + } + } + } + + fn follow_heap_ref(&mut self, mut focus: usize) -> HeapCellView<'a> { + loop { + match &self.heap[focus] { + &HeapCellValue::NamedStr(arity, ref name) => { + for i in (1 .. arity + 1).rev() { + self.state_stack.push(Addr::HeapCell(focus + i)); + } + + return HeapCellView::Str(arity, name); + }, + &HeapCellValue::Ref(Ref::HeapCell(hc)) => { + if focus == hc { + return HeapCellView::HeapVar(hc); + } else { + focus = hc; + } + }, + &HeapCellValue::Ref(Ref::StackCell(fr, sc)) => + return self.follow_stack_ref(fr, sc), + &HeapCellValue::Str(cell_num) => + focus = cell_num, + } + } + } +} + +impl<'a> Iterator for HeapCellViewer<'a> { + type Item = HeapCellView<'a>; + + fn next(&mut self) -> Option { + if let Some(addr) = self.state_stack.pop() { + match addr { + Addr::HeapCell(hc) | Addr::Str(hc) => + return Some(self.follow_heap_ref(hc)), + Addr::StackCell(fr, sc) => + return Some(self.follow_stack_ref(fr, sc)) + } + } + + None + } +} diff --git a/src/l3/io.rs b/src/l3/io.rs new file mode 100644 index 00000000..ad5be2b0 --- /dev/null +++ b/src/l3/io.rs @@ -0,0 +1,255 @@ +use l3::ast::*; +use l3::codegen::*; +use l3::l3_parser::*; +use l3::machine::*; + +use termion::raw::IntoRawMode; +use termion::input::TermRead; +use termion::event::Key; + +use std::io::{Write, stdin, stdout}; +use std::fmt; + +impl fmt::Display for FactInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &FactInstruction::GetStructure(Level::Deep, ref name, ref arity, ref r) => + write!(f, "get_structure {}/{}, {}", name, arity, r), + &FactInstruction::GetStructure(Level::Shallow, ref name, ref arity, ref r) => + write!(f, "get_structure {}/{}, A{}", name, arity, r.reg_num()), + &FactInstruction::GetValue(ref x, ref a) => + write!(f, "get_value {}, A{}", x, a), + &FactInstruction::GetVariable(ref x, ref a) => + write!(f, "get_variable {}, A{}", x, a), + &FactInstruction::UnifyVariable(ref r) => + write!(f, "unify_variable {}", r), + &FactInstruction::UnifyValue(ref r) => + write!(f, "unify_value {}", r) + } + } +} + +impl fmt::Display for QueryInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &QueryInstruction::PutStructure(Level::Deep, ref name, ref arity, ref r) => + write!(f, "put_structure {}/{}, {}", name, arity, r.reg_num()), + &QueryInstruction::PutStructure(Level::Shallow, ref name, ref arity, ref r) => + write!(f, "put_structure {}/{}, A{}", name, arity, r.reg_num()), + &QueryInstruction::PutValue(ref x, ref a) => + write!(f, "put_value {}, A{}", x, a), + &QueryInstruction::PutVariable(ref x, ref a) => + write!(f, "put_variable {}, A{}", x, a), + &QueryInstruction::SetVariable(ref r) => + write!(f, "set_variable {}", r), + &QueryInstruction::SetValue(ref r) => + write!(f, "set_value {}", r), + } + } +} + +impl fmt::Display for ControlInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ControlInstruction::Allocate(num_cells) => + write!(f, "allocate {}", num_cells), + &ControlInstruction::Call(ref name, ref arity) => + write!(f, "call {}/{}", name, arity), + &ControlInstruction::Deallocate => + write!(f, "deallocate"), + &ControlInstruction::Proceed => + write!(f, "proceed") + } + } +} + +impl fmt::Display for ChoiceInstruction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ChoiceInstruction::TryMeElse(offset) => + write!(f, "try_me_else {}", offset), + &ChoiceInstruction::RetryMeElse(offset) => + write!(f, "retry_me_else {}", offset), + &ChoiceInstruction::TrustMe => + write!(f, "trust_me") + } + } +} + +impl fmt::Display for Level { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &Level::Shallow => write!(f, "A"), + &Level::Deep => write!(f, "X") + } + } +} + +impl fmt::Display for VarReg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), + &VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), + &VarReg::ArgAndNorm(RegType::Perm(reg), arg) => + write!(f, "Y{} A{}", reg, arg), + &VarReg::ArgAndNorm(RegType::Temp(reg), arg) => + write!(f, "X{} A{}", reg, arg) + } + } +} + +impl fmt::Display for RegType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &RegType::Perm(val) => write!(f, "Y{}", val), + &RegType::Temp(val) => write!(f, "X{}", val) + } + } +} + + +fn is_consistent(predicate: &Vec) -> bool { + let name = predicate.first().unwrap().name(); + let arity = predicate.first().unwrap().arity(); + + for clause in predicate.iter().skip(1) { + if !(name == clause.name() && arity == clause.arity()) { + return false; + } + } + + true +} + +#[allow(dead_code)] +pub fn print_code(code: &Code) { + for clause in code { + match clause { + &Line::Fact(ref fact) => + for fact_instr in fact { + println!("{}", fact_instr); + }, + &Line::Choice(ref choice) => + println!("{}", choice), + &Line::Control(ref control) => + println!("{}", control), + &Line::Query(ref query) => + for query_instr in query { + println!("{}", query_instr); + } + } + } +} + +pub fn read() -> String { + let _ = stdout().flush(); + + let mut buffer = String::new(); + let mut result = String::new(); + + let stdin = stdin(); + stdin.read_line(&mut buffer).unwrap(); + + if &*buffer.trim() == ":{" { + buffer.clear(); + + stdin.read_line(&mut buffer).unwrap(); + + while &*buffer.trim() != "}:" { + result += buffer.as_str(); + buffer.clear(); + stdin.read_line(&mut buffer).unwrap(); + } + } else { + result = buffer; + } + + result +} + +pub fn eval(wam: &mut Machine, buffer: &str) -> EvalResult +{ + let result = parse_TopLevel(buffer); + let mut cg = CodeGenerator::new(); + + match &result { + &Ok(TopLevel::Predicate(ref clauses)) => { + if is_consistent(clauses) { + let compiled_pred = cg.compile_predicate(clauses); + wam.add_predicate(clauses, compiled_pred); + + EvalResult::EntrySuccess + } else { + let msg = r"Error: predicate is inconsistent. +Each predicate must have the same name and arity."; + + println!("{}", msg); + EvalResult::EntryFailure + } + }, + &Ok(TopLevel::Fact(ref fact)) => { + let compiled_fact = cg.compile_fact(&fact); + wam.add_fact(fact, compiled_fact); + EvalResult::EntrySuccess + }, + &Ok(TopLevel::Rule(ref rule)) => { + let compiled_rule = cg.compile_rule(&rule); + wam.add_rule(rule, compiled_rule); + EvalResult::EntrySuccess + }, + &Ok(TopLevel::Query(ref query)) => { + let compiled_query = cg.compile_query(&query); + wam.run_query(compiled_query, &cg) + }, + &Err(_) => { + println!("Grammatical error of some kind!"); + EvalResult::EntryFailure + } + } +} + +pub fn print(wam: &mut Machine, result: EvalResult) { + match result { + EvalResult::InitialQuerySuccess(heap_locs) => { + println!("yes"); + + 'outer: loop { + let mut result = EvalResult::QueryFailure; + let bindings = wam.heap_view(&heap_locs); + + let stdin = stdin(); + let mut stdout = stdout().into_raw_mode().unwrap(); + + write!(stdout, "{}\n\r", bindings).unwrap(); + stdout.flush().unwrap(); + + if !wam.or_stack_is_empty() { + write!(stdout, "Press ; to continue or A to abort.\n\r").unwrap(); + stdout.flush().unwrap(); + + for c in stdin.keys() { + match c.unwrap() { + Key::Char(';') => { + result = wam.continue_query(); + break; + }, + Key::Char('a') | Key::Char('A') => + break 'outer, + _ => {} + } + }; + + if let &EvalResult::QueryFailure = &result { + write!(stdout, "no\n\r").unwrap(); + stdout.flush().unwrap(); + break; + } + } else { + break; + } + } + }, + EvalResult::QueryFailure => println!("no"), + _ => {} + }; +} diff --git a/src/l3/iterators.rs b/src/l3/iterators.rs new file mode 100644 index 00000000..729f8be5 --- /dev/null +++ b/src/l3/iterators.rs @@ -0,0 +1,175 @@ +use l3::ast::*; + +use std::cell::Cell; +use std::collections::VecDeque; +use std::vec::Vec; + +enum IteratorState<'a> { + Atom(Level, &'a Cell, &'a Atom), + Clause(Level, usize, &'a Cell, &'a Atom, &'a Vec>), + IsolatedAtom(&'a Cell, &'a Atom), + IsolatedVar(&'a Cell, &'a Var), + RootClause(usize, &'a Vec>), + Var(Level, &'a Cell, &'a Var) +} + +impl<'a> IteratorState<'a> { + fn to_state(lvl: Level, term: &'a Term) -> IteratorState<'a> + { + match term { + &Term::Atom(ref cell, ref atom) => + IteratorState::Atom(lvl, cell, atom), + &Term::Clause(ref cell, ref atom, ref child_terms) => + IteratorState::Clause(lvl, 0, cell, atom, child_terms), + &Term::Var(ref cell, ref var) => + IteratorState::Var(lvl, cell, var) + } + } +} + +pub struct QueryIterator<'a> { + state_stack: Vec> +} + +impl<'a> QueryIterator<'a> { + fn push_clause(&mut self, + lvl: Level, + child_num: usize, + cell: &'a Cell, + name: &'a Atom, + child_terms: &'a Vec>) + { + self.state_stack.push(IteratorState::Clause(lvl, + child_num, + cell, + name, + child_terms)); + } + + fn push_root_clause(&mut self, + child_num: usize, + child_terms: &'a Vec>) + { + self.state_stack.push(IteratorState::RootClause(child_num, child_terms)); + } + + fn push_subterm(&mut self, lvl: Level, term: &'a Term) { + self.state_stack.push(IteratorState::to_state(lvl, term)); + } + + fn new(term: &'a Term) -> QueryIterator<'a> { + let state = match term { + &Term::Atom(ref cell, ref atom) => + IteratorState::IsolatedAtom(cell, atom), + &Term::Clause(_, _, ref terms) => + IteratorState::RootClause(0, terms), + &Term::Var(ref cell, ref var) => + IteratorState::IsolatedVar(cell, var) + }; + + QueryIterator { state_stack: vec![state] } + } +} + +impl<'a> Iterator for QueryIterator<'a> { + type Item = TermRef<'a>; + + fn next(&mut self) -> Option { + while let Some(iter_state) = self.state_stack.pop() { + match iter_state { + IteratorState::Atom(lvl, cell, atom) => + return Some(TermRef::Atom(lvl, cell, atom)), + IteratorState::Clause(lvl, child_num, cell, atom, child_terms) => { + if child_num == child_terms.len() { + return Some(TermRef::Clause(lvl, cell, atom, child_terms)); + } else { + self.push_clause(lvl, child_num + 1, cell, atom, child_terms); + self.push_subterm(Level::Deep, child_terms[child_num].as_ref()); + } + }, + IteratorState::IsolatedAtom(cell, atom) => + return Some(TermRef::Atom(Level::Shallow, cell, atom)), + IteratorState::IsolatedVar(cell, var) => + return Some(TermRef::Var(Level::Shallow, cell, var)), + IteratorState::RootClause(child_num, child_terms) => { + if child_num == child_terms.len() { + return None; + } else { + self.push_root_clause(child_num + 1, child_terms); + self.push_subterm(Level::Shallow, child_terms[child_num].as_ref()); + } + }, + IteratorState::Var(lvl, cell, var) => + return Some(TermRef::Var(lvl, cell, var)) + }; + } + + None + } +} + +pub struct FactIterator<'a> { + state_queue: VecDeque>, +} + +impl<'a> FactIterator<'a> { + fn push_subterm(&mut self, lvl: Level, term: &'a Term) { + self.state_queue.push_back(IteratorState::to_state(lvl, term)); + } + + fn new(term: &'a Term) -> FactIterator<'a> { + let states = match term { + &Term::Atom(ref cell, ref atom) => + vec![IteratorState::IsolatedAtom(cell, atom)], + &Term::Clause(_, _, ref terms) => + vec![IteratorState::RootClause(0, terms)], + &Term::Var(ref cell, ref var) => + vec![IteratorState::IsolatedVar(cell, var)] + }; + + FactIterator { state_queue: VecDeque::from(states) } + } +} + +impl<'a> Iterator for FactIterator<'a> { + type Item = TermRef<'a>; + + fn next(&mut self) -> Option { + while let Some(state) = self.state_queue.pop_front() { + match state { + IteratorState::Atom(lvl, cell, atom) => + return Some(TermRef::Atom(lvl, cell, atom)), + IteratorState::Clause(lvl, _, cell, atom, child_terms) => { + for child_term in child_terms { + self.push_subterm(Level::Deep, child_term); + } + + return Some(TermRef::Clause(lvl, cell, atom, child_terms)); + }, + IteratorState::IsolatedAtom(cell, atom) => + return Some(TermRef::Atom(Level::Shallow, cell, atom)), + IteratorState::IsolatedVar(cell, var) => + return Some(TermRef::Var(Level::Shallow, cell, var)), + IteratorState::RootClause(_, child_terms) => { + for child_term in child_terms { + self.push_subterm(Level::Shallow, child_term); + } + }, + IteratorState::Var(lvl, cell, var) => + return Some(TermRef::Var(lvl, cell, var)) + } + } + + None + } +} + +impl Term { + pub fn post_order_iter(&self) -> QueryIterator { + QueryIterator::new(self) + } + + pub fn breadth_first_iter(&self) -> FactIterator { + FactIterator::new(self) + } +} diff --git a/src/l3/l3_parser.lalrpop b/src/l3/l3_parser.lalrpop new file mode 100644 index 00000000..7d97375f --- /dev/null +++ b/src/l3/l3_parser.lalrpop @@ -0,0 +1,59 @@ +use l3::ast::*; + +use std::cell::Cell; + +grammar; + +pub TopLevel: TopLevel = { + "?-" "." => TopLevel::Query(t), + => TopLevel::Predicate(<>), + "." => TopLevel::Rule(<>), + "." => TopLevel::Fact(<>) +}; + +Atom : Atom = { + r"[a-z][a-z0-9_]*" => <>.trim().to_string(), +}; + +BoxedTerm : Box = { + => Box::new(t) +}; + +Clause : Term = { + "(" ",")*> ")" => { + let mut ts = ts; + ts.push(t); + Term::Clause(Cell::new(RegType::Temp(0)), a, ts) + } +}; + +Predicate : Vec = { + )+> => { + let mut pcs = pcs; + pcs.push(pc); + pcs + } +}; + +PredicateClause : PredicateClause = { + "." => PredicateClause::Rule(<>), + "." => PredicateClause::Fact(<>) +}; + +Rule : Rule = { + ":-" )*> => + Rule { head: (c, h), clauses: cs }, + ":-" )*> => + Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h), + clauses: cs } +}; + +Term : Term = { + => <>, + => Term::Atom(Cell::new(RegType::Temp(0)), <>), + => Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), <>) +}; + +Var : Var = { + r"[A-Z][a-z0-9_]*" => <>.trim().to_string(), +}; \ No newline at end of file diff --git a/src/l3/l3_parser.rs b/src/l3/l3_parser.rs new file mode 100644 index 00000000..dad3ada5 --- /dev/null +++ b/src/l3/l3_parser.rs @@ -0,0 +1,2177 @@ +use l3::ast::*; +use std::cell::Cell; +extern crate lalrpop_util as __lalrpop_util; + +mod __parse__TopLevel { + #![allow(non_snake_case, non_camel_case_types, unused_mut, unused_variables, unused_imports)] + + use l3::ast::*; + use std::cell::Cell; + extern crate lalrpop_util as __lalrpop_util; + #[allow(dead_code)] + pub enum __Symbol<'input> { + Term_22_28_22(&'input str), + Term_22_29_22(&'input str), + Term_22_2c_22(&'input str), + Term_22_2e_22(&'input str), + Term_22_3a_2d_22(&'input str), + Term_22_3f_2d_22(&'input str), + Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(&'input str), + Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(&'input str), + Termerror(__lalrpop_util::ErrorRecovery), + Nt_28_22_2c_22_20_3cTerm_3e_29(Term), + Nt_28_22_2c_22_20_3cTerm_3e_29_2a(::std::vec::Vec), + Nt_28_22_2c_22_20_3cTerm_3e_29_2b(::std::vec::Vec), + Nt_28_3cBoxedTerm_3e_20_22_2c_22_29(Box), + Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2a(::std::vec::Vec>), + Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(::std::vec::Vec>), + Nt_28_3cPredicateClause_3e_29(PredicateClause), + Nt_28_3cPredicateClause_3e_29_2b(::std::vec::Vec), + NtAtom(Atom), + NtBoxedTerm(Box), + NtClause(Term), + NtPredicate(Vec), + NtPredicateClause(PredicateClause), + NtRule(Rule), + NtTerm(Term), + NtTopLevel(TopLevel), + NtVar(Var), + Nt____TopLevel(TopLevel), + } + const __ACTION: &'static [i32] = &[ + // State 0 + 0, 0, 0, 0, 0, 11, 12, 13, 0, + // State 1 + 0, 0, 0, 0, 0, 0, 12, 13, 0, + // State 2 + 17, 0, 0, -26, 18, 0, 0, 0, 0, + // State 3 + 0, 0, 0, -25, 19, 0, 0, 0, 0, + // State 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 5 + 0, 0, 0, 0, 0, 0, -12, -12, 0, + // State 6 + 0, 0, 0, 20, 0, 0, 0, 0, 0, + // State 7 + 0, 0, 0, 21, 0, 0, 0, 0, 0, + // State 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 9 + 0, 0, 0, -27, 0, 0, 0, 0, 0, + // State 10 + 0, 0, 0, 0, 0, 0, 12, 25, 0, + // State 11 + 0, 0, 0, -32, 0, 0, 0, 0, 0, + // State 12 + -14, 0, 0, -14, -14, 0, 0, 0, 0, + // State 13 + 0, 0, 0, 0, 0, 0, -13, -13, 0, + // State 14 + 0, 0, 0, 26, 0, 0, 0, 0, 0, + // State 15 + 0, 0, 0, 27, 0, 0, 0, 0, 0, + // State 16 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 17 + 0, 0, 0, 0, 0, 0, 40, 41, 0, + // State 18 + 0, 0, 0, 0, 0, 0, 40, 41, 0, + // State 19 + 0, 0, 0, 0, 0, 0, -19, -19, 0, + // State 20 + 0, 0, 0, 0, 0, 0, -20, -20, 0, + // State 21 + 43, 0, 0, -26, 0, 0, 0, 0, 0, + // State 22 + 0, 0, 0, -25, 0, 0, 0, 0, 0, + // State 23 + 0, 0, 0, 44, 0, 0, 0, 0, 0, + // State 24 + -14, 0, 0, -14, 0, 0, 0, 0, 0, + // State 25 + 0, 0, 0, 0, 0, 0, -19, -19, 0, + // State 26 + 0, 0, 0, 0, 0, 0, -20, -20, 0, + // State 27 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 28 + 46, -26, -26, 0, 0, 0, 0, 0, 0, + // State 29 + 0, 47, 48, 0, 0, 0, 0, 0, 0, + // State 30 + 0, -25, -25, 0, 0, 0, 0, 0, 0, + // State 31 + 0, -15, -15, 0, 0, 0, 0, 0, 0, + // State 32 + 0, -27, -27, 0, 0, 0, 0, 0, 0, + // State 33 + 0, -32, -32, 0, 0, 0, 0, 0, 0, + // State 34 + -14, -14, -14, 0, 0, 0, 0, 0, 0, + // State 35 + 49, 0, -26, -26, 0, 0, 0, 0, 0, + // State 36 + 0, 0, -25, -25, 0, 0, 0, 0, 0, + // State 37 + 0, 0, 51, -23, 0, 0, 0, 0, 0, + // State 38 + 0, 0, -27, -27, 0, 0, 0, 0, 0, + // State 39 + 0, 0, -32, -32, 0, 0, 0, 0, 0, + // State 40 + -14, 0, -14, -14, 0, 0, 0, 0, 0, + // State 41 + 0, 0, 51, -21, 0, 0, 0, 0, 0, + // State 42 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 43 + 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 44 + 0, 55, 56, 0, 0, 0, 0, 0, 0, + // State 45 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 46 + 0, 0, 0, -16, -16, 0, 0, 0, 0, + // State 47 + 0, 0, 0, 0, 0, 0, -9, -9, 0, + // State 48 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 49 + 0, 0, 61, -24, 0, 0, 0, 0, 0, + // State 50 + 0, 0, 0, 0, 0, 0, 40, 41, 0, + // State 51 + 0, 0, 61, -22, 0, 0, 0, 0, 0, + // State 52 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 53 + 0, 64, 48, 0, 0, 0, 0, 0, 0, + // State 54 + 0, 0, 0, -17, -17, 0, 0, 0, 0, + // State 55 + 0, 0, 0, 0, 0, 0, -10, -10, 0, + // State 56 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 57 + 0, 66, 48, 0, 0, 0, 0, 0, 0, + // State 58 + 0, 0, 0, 0, 0, 0, 34, 35, 0, + // State 59 + 0, 68, 48, 0, 0, 0, 0, 0, 0, + // State 60 + 0, 0, 0, 0, 0, 0, 40, 41, 0, + // State 61 + 0, 0, -4, -4, 0, 0, 0, 0, 0, + // State 62 + 0, 70, 56, 0, 0, 0, 0, 0, 0, + // State 63 + 0, 0, 0, -16, 0, 0, 0, 0, 0, + // State 64 + 0, 71, 56, 0, 0, 0, 0, 0, 0, + // State 65 + 0, -16, -16, 0, 0, 0, 0, 0, 0, + // State 66 + 0, 72, 56, 0, 0, 0, 0, 0, 0, + // State 67 + 0, 0, -16, -16, 0, 0, 0, 0, 0, + // State 68 + 0, 0, -5, -5, 0, 0, 0, 0, 0, + // State 69 + 0, 0, 0, -17, 0, 0, 0, 0, 0, + // State 70 + 0, -17, -17, 0, 0, 0, 0, 0, 0, + // State 71 + 0, 0, -17, -17, 0, 0, 0, 0, 0, + ]; + const __EOF_ACTION: &'static [i32] = &[ + 0, + 0, + 0, + 0, + -29, + 0, + 0, + 0, + -33, + 0, + 0, + 0, + 0, + -18, + 0, + 0, + 0, + 0, + 0, + -30, + -31, + 0, + 0, + 0, + 0, + -19, + -20, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + -28, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ]; + const __GOTO: &'static [i32] = &[ + // State 0 + 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 4, 5, 6, 7, 8, 9, 10, 0, + // State 1 + 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 14, 15, 16, 0, 10, 0, + // State 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 10 + 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 23, 0, 0, 0, 24, 0, 10, 0, + // State 11 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 12 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 13 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 14 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 16 + 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 0, 0, 0, 32, 0, 33, 0, + // State 17 + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 38, 0, 39, 0, + // State 18 + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 42, 0, 39, 0, + // State 19 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 20 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 21 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 22 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 23 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 24 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 25 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 26 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 27 + 0, 0, 0, 0, 0, 0, 0, 0, 29, 45, 31, 0, 0, 0, 32, 0, 33, 0, + // State 28 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 29 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 30 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 31 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 32 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 33 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 34 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 35 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 36 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 37 + 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 38 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 39 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 40 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 41 + 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 42 + 0, 0, 0, 0, 0, 53, 0, 0, 29, 54, 31, 0, 0, 0, 32, 0, 33, 0, + // State 43 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 44 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 45 + 0, 0, 0, 0, 0, 57, 0, 0, 29, 58, 31, 0, 0, 0, 32, 0, 33, 0, + // State 46 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 47 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 48 + 0, 0, 0, 0, 0, 59, 0, 0, 29, 60, 31, 0, 0, 0, 32, 0, 33, 0, + // State 49 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 50 + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 62, 0, 39, 0, + // State 51 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 52 + 0, 0, 0, 0, 0, 0, 0, 0, 29, 63, 31, 0, 0, 0, 32, 0, 33, 0, + // State 53 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 54 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 55 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 56 + 0, 0, 0, 0, 0, 0, 0, 0, 29, 65, 31, 0, 0, 0, 32, 0, 33, 0, + // State 57 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 58 + 0, 0, 0, 0, 0, 0, 0, 0, 29, 67, 31, 0, 0, 0, 32, 0, 33, 0, + // State 59 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 60 + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 37, 0, 0, 0, 69, 0, 39, 0, + // State 61 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 62 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 63 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 64 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 65 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 66 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 67 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 68 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 69 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 70 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // State 71 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; + fn __expected_tokens(__state: usize) -> Vec<::std::string::String> { + const __TERMINAL: &'static [&'static str] = &[ + r###""(""###, + r###"")""###, + r###"",""###, + r###"".""###, + r###"":-""###, + r###""?-""###, + r###"r#"[A-Z][a-z0-9_]*"#"###, + r###"r#"[a-z][a-z0-9_]*"#"###, + ]; + __ACTION[(__state * 9)..].iter().zip(__TERMINAL).filter_map(|(&state, terminal)| { + if state == 0 { + None + } else { + Some(terminal.to_string()) + } + }).collect() + } + pub fn parse_TopLevel< + 'input, + >( + input: &'input str, + ) -> Result> + { + let mut __tokens = super::__intern_token::__Matcher::new(input); + let mut __states = vec![0_i32]; + let mut __symbols = vec![]; + let mut __integer; + let mut __lookahead; + let mut __last_location = Default::default(); + '__shift: loop { + __lookahead = match __tokens.next() { + Some(Ok(v)) => v, + None => break '__shift, + Some(Err(e)) => return Err(e), + }; + __last_location = __lookahead.2.clone(); + __integer = match __lookahead.1 { + (0, _) if true => 0, + (1, _) if true => 1, + (2, _) if true => 2, + (3, _) if true => 3, + (4, _) if true => 4, + (5, _) if true => 5, + (6, _) if true => 6, + (7, _) if true => 7, + _ => { + let __state = *__states.last().unwrap() as usize; + let __error = __lalrpop_util::ParseError::UnrecognizedToken { + token: Some(__lookahead), + expected: __expected_tokens(__state), + }; + return Err(__error); + } + }; + '__inner: loop { + let __state = *__states.last().unwrap() as usize; + let __action = __ACTION[__state * 9 + __integer]; + if __action > 0 { + let __symbol = match __integer { + 0 => match __lookahead.1 { + (0, __tok0) => __Symbol::Term_22_28_22(__tok0), + _ => unreachable!(), + }, + 1 => match __lookahead.1 { + (1, __tok0) => __Symbol::Term_22_29_22(__tok0), + _ => unreachable!(), + }, + 2 => match __lookahead.1 { + (2, __tok0) => __Symbol::Term_22_2c_22(__tok0), + _ => unreachable!(), + }, + 3 => match __lookahead.1 { + (3, __tok0) => __Symbol::Term_22_2e_22(__tok0), + _ => unreachable!(), + }, + 4 => match __lookahead.1 { + (4, __tok0) => __Symbol::Term_22_3a_2d_22(__tok0), + _ => unreachable!(), + }, + 5 => match __lookahead.1 { + (5, __tok0) => __Symbol::Term_22_3f_2d_22(__tok0), + _ => unreachable!(), + }, + 6 => match __lookahead.1 { + (6, __tok0) => __Symbol::Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(__tok0), + _ => unreachable!(), + }, + 7 => match __lookahead.1 { + (7, __tok0) => __Symbol::Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(__tok0), + _ => unreachable!(), + }, + _ => unreachable!(), + }; + __states.push(__action - 1); + __symbols.push((__lookahead.0, __symbol, __lookahead.2)); + continue '__shift; + } else if __action < 0 { + if let Some(r) = __reduce(input, __action, Some(&__lookahead.0), &mut __states, &mut __symbols, ::std::marker::PhantomData::<()>) { + return r; + } + } else { + let __state = *__states.last().unwrap() as usize; + let __error = __lalrpop_util::ParseError::UnrecognizedToken { + token: Some(__lookahead), + expected: __expected_tokens(__state), + }; + return Err(__error) + } + } + } + loop { + let __state = *__states.last().unwrap() as usize; + let __action = __EOF_ACTION[__state]; + if __action < 0 { + if let Some(r) = __reduce(input, __action, None, &mut __states, &mut __symbols, ::std::marker::PhantomData::<()>) { + return r; + } + } else { + let __state = *__states.last().unwrap() as usize; + let __error = __lalrpop_util::ParseError::UnrecognizedToken { + token: None, + expected: __expected_tokens(__state), + }; + return Err(__error); + } + } + } + pub fn __reduce< + 'input, + >( + input: &'input str, + __action: i32, + __lookahead_start: Option<&usize>, + __states: &mut ::std::vec::Vec, + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)>, + _: ::std::marker::PhantomData<()>, + ) -> Option>> + { + let __nonterminal = match -__action { + 1 => { + // ("," ) = ",", Term => ActionFn(19); + let __sym1 = __pop_NtTerm(__symbols); + let __sym0 = __pop_Term_22_2c_22(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action19::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29(__nt), __end)); + 0 + } + 2 => { + // ("," )* = => ActionFn(17); + let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); + let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); + let __nt = super::__action17::<>(input, &__start, &__end); + let __states_len = __states.len(); + __states.truncate(__states_len - 0); + __symbols.push((__start, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29_2a(__nt), __end)); + 1 + } + 3 => { + // ("," )* = ("," )+ => ActionFn(18); + let __sym0 = __pop_Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action18::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29_2a(__nt), __end)); + 1 + } + 4 => { + // ("," )+ = ",", Term => ActionFn(30); + let __sym1 = __pop_NtTerm(__symbols); + let __sym0 = __pop_Term_22_2c_22(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action30::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__nt), __end)); + 2 + } + 5 => { + // ("," )+ = ("," )+, ",", Term => ActionFn(31); + let __sym2 = __pop_NtTerm(__symbols); + let __sym1 = __pop_Term_22_2c_22(__symbols); + let __sym0 = __pop_Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym2.2.clone(); + let __nt = super::__action31::<>(input, __sym0, __sym1, __sym2); + let __states_len = __states.len(); + __states.truncate(__states_len - 3); + __symbols.push((__start, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__nt), __end)); + 2 + } + 6 => { + // ( ",") = BoxedTerm, "," => ActionFn(25); + let __sym1 = __pop_Term_22_2c_22(__symbols); + let __sym0 = __pop_NtBoxedTerm(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action25::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29(__nt), __end)); + 3 + } + 7 => { + // ( ",")* = => ActionFn(23); + let __start = __symbols.last().map(|s| s.2.clone()).unwrap_or_default(); + let __end = __lookahead_start.cloned().unwrap_or_else(|| __start.clone()); + let __nt = super::__action23::<>(input, &__start, &__end); + let __states_len = __states.len(); + __states.truncate(__states_len - 0); + __symbols.push((__start, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2a(__nt), __end)); + 4 + } + 8 => { + // ( ",")* = ( ",")+ => ActionFn(24); + let __sym0 = __pop_Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action24::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2a(__nt), __end)); + 4 + } + 9 => { + // ( ",")+ = BoxedTerm, "," => ActionFn(36); + let __sym1 = __pop_Term_22_2c_22(__symbols); + let __sym0 = __pop_NtBoxedTerm(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action36::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(__nt), __end)); + 5 + } + 10 => { + // ( ",")+ = ( ",")+, BoxedTerm, "," => ActionFn(37); + let __sym2 = __pop_Term_22_2c_22(__symbols); + let __sym1 = __pop_NtBoxedTerm(__symbols); + let __sym0 = __pop_Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym2.2.clone(); + let __nt = super::__action37::<>(input, __sym0, __sym1, __sym2); + let __states_len = __states.len(); + __states.truncate(__states_len - 3); + __symbols.push((__start, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(__nt), __end)); + 5 + } + 11 => { + // () = PredicateClause => ActionFn(22); + let __sym0 = __pop_NtPredicateClause(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action22::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::Nt_28_3cPredicateClause_3e_29(__nt), __end)); + 6 + } + 12 => { + // ()+ = PredicateClause => ActionFn(40); + let __sym0 = __pop_NtPredicateClause(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action40::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::Nt_28_3cPredicateClause_3e_29_2b(__nt), __end)); + 7 + } + 13 => { + // ()+ = ()+, PredicateClause => ActionFn(41); + let __sym1 = __pop_NtPredicateClause(__symbols); + let __sym0 = __pop_Nt_28_3cPredicateClause_3e_29_2b(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action41::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::Nt_28_3cPredicateClause_3e_29_2b(__nt), __end)); + 7 + } + 14 => { + // Atom = r#"[a-z][a-z0-9_]*"# => ActionFn(5); + let __sym0 = __pop_Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action5::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtAtom(__nt), __end)); + 8 + } + 15 => { + // BoxedTerm = Term => ActionFn(6); + let __sym0 = __pop_NtTerm(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action6::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtBoxedTerm(__nt), __end)); + 9 + } + 16 => { + // Clause = Atom, "(", BoxedTerm, ")" => ActionFn(38); + let __sym3 = __pop_Term_22_29_22(__symbols); + let __sym2 = __pop_NtBoxedTerm(__symbols); + let __sym1 = __pop_Term_22_28_22(__symbols); + let __sym0 = __pop_NtAtom(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym3.2.clone(); + let __nt = super::__action38::<>(input, __sym0, __sym1, __sym2, __sym3); + let __states_len = __states.len(); + __states.truncate(__states_len - 4); + __symbols.push((__start, __Symbol::NtClause(__nt), __end)); + 10 + } + 17 => { + // Clause = Atom, "(", ( ",")+, BoxedTerm, ")" => ActionFn(39); + let __sym4 = __pop_Term_22_29_22(__symbols); + let __sym3 = __pop_NtBoxedTerm(__symbols); + let __sym2 = __pop_Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(__symbols); + let __sym1 = __pop_Term_22_28_22(__symbols); + let __sym0 = __pop_NtAtom(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym4.2.clone(); + let __nt = super::__action39::<>(input, __sym0, __sym1, __sym2, __sym3, __sym4); + let __states_len = __states.len(); + __states.truncate(__states_len - 5); + __symbols.push((__start, __Symbol::NtClause(__nt), __end)); + 10 + } + 18 => { + // Predicate = ()+, PredicateClause => ActionFn(8); + let __sym1 = __pop_NtPredicateClause(__symbols); + let __sym0 = __pop_Nt_28_3cPredicateClause_3e_29_2b(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action8::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::NtPredicate(__nt), __end)); + 11 + } + 19 => { + // PredicateClause = Rule, "." => ActionFn(9); + let __sym1 = __pop_Term_22_2e_22(__symbols); + let __sym0 = __pop_NtRule(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action9::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::NtPredicateClause(__nt), __end)); + 12 + } + 20 => { + // PredicateClause = Term, "." => ActionFn(10); + let __sym1 = __pop_Term_22_2e_22(__symbols); + let __sym0 = __pop_NtTerm(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action10::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::NtPredicateClause(__nt), __end)); + 12 + } + 21 => { + // Rule = Clause, ":-", Term => ActionFn(32); + let __sym2 = __pop_NtTerm(__symbols); + let __sym1 = __pop_Term_22_3a_2d_22(__symbols); + let __sym0 = __pop_NtClause(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym2.2.clone(); + let __nt = super::__action32::<>(input, __sym0, __sym1, __sym2); + let __states_len = __states.len(); + __states.truncate(__states_len - 3); + __symbols.push((__start, __Symbol::NtRule(__nt), __end)); + 13 + } + 22 => { + // Rule = Clause, ":-", Term, ("," )+ => ActionFn(33); + let __sym3 = __pop_Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__symbols); + let __sym2 = __pop_NtTerm(__symbols); + let __sym1 = __pop_Term_22_3a_2d_22(__symbols); + let __sym0 = __pop_NtClause(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym3.2.clone(); + let __nt = super::__action33::<>(input, __sym0, __sym1, __sym2, __sym3); + let __states_len = __states.len(); + __states.truncate(__states_len - 4); + __symbols.push((__start, __Symbol::NtRule(__nt), __end)); + 13 + } + 23 => { + // Rule = Atom, ":-", Term => ActionFn(34); + let __sym2 = __pop_NtTerm(__symbols); + let __sym1 = __pop_Term_22_3a_2d_22(__symbols); + let __sym0 = __pop_NtAtom(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym2.2.clone(); + let __nt = super::__action34::<>(input, __sym0, __sym1, __sym2); + let __states_len = __states.len(); + __states.truncate(__states_len - 3); + __symbols.push((__start, __Symbol::NtRule(__nt), __end)); + 13 + } + 24 => { + // Rule = Atom, ":-", Term, ("," )+ => ActionFn(35); + let __sym3 = __pop_Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__symbols); + let __sym2 = __pop_NtTerm(__symbols); + let __sym1 = __pop_Term_22_3a_2d_22(__symbols); + let __sym0 = __pop_NtAtom(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym3.2.clone(); + let __nt = super::__action35::<>(input, __sym0, __sym1, __sym2, __sym3); + let __states_len = __states.len(); + __states.truncate(__states_len - 4); + __symbols.push((__start, __Symbol::NtRule(__nt), __end)); + 13 + } + 25 => { + // Term = Clause => ActionFn(13); + let __sym0 = __pop_NtClause(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action13::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtTerm(__nt), __end)); + 14 + } + 26 => { + // Term = Atom => ActionFn(14); + let __sym0 = __pop_NtAtom(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action14::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtTerm(__nt), __end)); + 14 + } + 27 => { + // Term = Var => ActionFn(15); + let __sym0 = __pop_NtVar(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action15::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtTerm(__nt), __end)); + 14 + } + 28 => { + // TopLevel = "?-", Term, "." => ActionFn(1); + let __sym2 = __pop_Term_22_2e_22(__symbols); + let __sym1 = __pop_NtTerm(__symbols); + let __sym0 = __pop_Term_22_3f_2d_22(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym2.2.clone(); + let __nt = super::__action1::<>(input, __sym0, __sym1, __sym2); + let __states_len = __states.len(); + __states.truncate(__states_len - 3); + __symbols.push((__start, __Symbol::NtTopLevel(__nt), __end)); + 15 + } + 29 => { + // TopLevel = Predicate => ActionFn(2); + let __sym0 = __pop_NtPredicate(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action2::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtTopLevel(__nt), __end)); + 15 + } + 30 => { + // TopLevel = Rule, "." => ActionFn(3); + let __sym1 = __pop_Term_22_2e_22(__symbols); + let __sym0 = __pop_NtRule(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action3::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::NtTopLevel(__nt), __end)); + 15 + } + 31 => { + // TopLevel = Term, "." => ActionFn(4); + let __sym1 = __pop_Term_22_2e_22(__symbols); + let __sym0 = __pop_NtTerm(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym1.2.clone(); + let __nt = super::__action4::<>(input, __sym0, __sym1); + let __states_len = __states.len(); + __states.truncate(__states_len - 2); + __symbols.push((__start, __Symbol::NtTopLevel(__nt), __end)); + 15 + } + 32 => { + // Var = r#"[A-Z][a-z0-9_]*"# => ActionFn(16); + let __sym0 = __pop_Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action16::<>(input, __sym0); + let __states_len = __states.len(); + __states.truncate(__states_len - 1); + __symbols.push((__start, __Symbol::NtVar(__nt), __end)); + 16 + } + 33 => { + // __TopLevel = TopLevel => ActionFn(0); + let __sym0 = __pop_NtTopLevel(__symbols); + let __start = __sym0.0.clone(); + let __end = __sym0.2.clone(); + let __nt = super::__action0::<>(input, __sym0); + return Some(Ok(__nt)); + } + _ => panic!("invalid action code {}", __action) + }; + let __state = *__states.last().unwrap() as usize; + let __next_state = __GOTO[__state * 18 + __nonterminal] - 1; + __states.push(__next_state); + None + } + fn __pop_Term_22_28_22< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Term_22_28_22(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Term_22_29_22< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Term_22_29_22(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Term_22_2c_22< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Term_22_2c_22(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Term_22_2e_22< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Term_22_2e_22(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Term_22_3a_2d_22< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Term_22_3a_2d_22(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Term_22_3f_2d_22< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Term_22_3f_2d_22(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Termr_23_22_5bA_2dZ_5d_5ba_2dz0_2d9___5d_2a_22_23(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, &'input str, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Termr_23_22_5ba_2dz_5d_5ba_2dz0_2d9___5d_2a_22_23(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Termerror< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, __lalrpop_util::ErrorRecovery, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Termerror(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_22_2c_22_20_3cTerm_3e_29< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Term, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_22_2c_22_20_3cTerm_3e_29_2a< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, ::std::vec::Vec, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29_2a(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_22_2c_22_20_3cTerm_3e_29_2b< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, ::std::vec::Vec, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_22_2c_22_20_3cTerm_3e_29_2b(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_3cBoxedTerm_3e_20_22_2c_22_29< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Box, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2a< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, ::std::vec::Vec>, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2a(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, ::std::vec::Vec>, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_3cBoxedTerm_3e_20_22_2c_22_29_2b(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_3cPredicateClause_3e_29< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, PredicateClause, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_3cPredicateClause_3e_29(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt_28_3cPredicateClause_3e_29_2b< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, ::std::vec::Vec, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt_28_3cPredicateClause_3e_29_2b(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtAtom< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Atom, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtAtom(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtBoxedTerm< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Box, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtBoxedTerm(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtClause< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Term, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtClause(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtPredicate< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Vec, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtPredicate(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtPredicateClause< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, PredicateClause, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtPredicateClause(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtRule< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Rule, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtRule(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtTerm< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Term, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtTerm(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtTopLevel< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, TopLevel, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtTopLevel(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_NtVar< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, Var, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::NtVar(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } + fn __pop_Nt____TopLevel< + 'input, + >( + __symbols: &mut ::std::vec::Vec<(usize,__Symbol<'input>,usize)> + ) -> (usize, TopLevel, usize) { + match __symbols.pop().unwrap() { + (__l, __Symbol::Nt____TopLevel(__v), __r) => (__l, __v, __r), + _ => panic!("symbol type mismatch") + } + } +} +pub use self::__parse__TopLevel::parse_TopLevel; +mod __intern_token { + extern crate lalrpop_util as __lalrpop_util; + pub struct __Matcher<'input> { + text: &'input str, + consumed: usize, + } + + fn __tokenize(text: &str) -> Option<(usize, usize)> { + let mut __chars = text.char_indices(); + let mut __current_match: Option<(usize, usize)> = None; + let mut __current_state: usize = 0; + loop { + match __current_state { + 0 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 40 => /* '(' */ { + __current_match = Some((0, __index + 1)); + __current_state = 1; + continue; + } + 41 => /* ')' */ { + __current_match = Some((1, __index + 1)); + __current_state = 2; + continue; + } + 44 => /* ',' */ { + __current_match = Some((2, __index + 1)); + __current_state = 3; + continue; + } + 46 => /* '.' */ { + __current_match = Some((3, __index + 1)); + __current_state = 4; + continue; + } + 58 => /* ':' */ { + __current_state = 5; + continue; + } + 63 => /* '?' */ { + __current_state = 6; + continue; + } + 65 ... 90 => { + __current_match = Some((6, __index + __ch.len_utf8())); + __current_state = 7; + continue; + } + 97 ... 122 => { + __current_match = Some((7, __index + __ch.len_utf8())); + __current_state = 8; + continue; + } + _ => { + return __current_match; + } + } + } + 1 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 2 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 3 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 4 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 5 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 45 => /* '-' */ { + __current_match = Some((4, __index + 1)); + __current_state = 10; + continue; + } + _ => { + return __current_match; + } + } + } + 6 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 45 => /* '-' */ { + __current_match = Some((5, __index + 1)); + __current_state = 11; + continue; + } + _ => { + return __current_match; + } + } + } + 7 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 48 ... 57 => { + __current_match = Some((6, __index + __ch.len_utf8())); + __current_state = 12; + continue; + } + 95 => /* '_' */ { + __current_match = Some((6, __index + 1)); + __current_state = 12; + continue; + } + 97 ... 122 => { + __current_match = Some((6, __index + __ch.len_utf8())); + __current_state = 12; + continue; + } + _ => { + return __current_match; + } + } + } + 8 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 48 ... 57 => { + __current_match = Some((7, __index + __ch.len_utf8())); + __current_state = 13; + continue; + } + 95 => /* '_' */ { + __current_match = Some((7, __index + 1)); + __current_state = 13; + continue; + } + 97 ... 122 => { + __current_match = Some((7, __index + __ch.len_utf8())); + __current_state = 13; + continue; + } + _ => { + return __current_match; + } + } + } + 9 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 10 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 11 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + _ => { + return __current_match; + } + } + } + 12 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 48 ... 57 => { + __current_match = Some((6, __index + __ch.len_utf8())); + __current_state = 12; + continue; + } + 95 => /* '_' */ { + __current_match = Some((6, __index + 1)); + __current_state = 12; + continue; + } + 97 ... 122 => { + __current_match = Some((6, __index + __ch.len_utf8())); + __current_state = 12; + continue; + } + _ => { + return __current_match; + } + } + } + 13 => { + let (__index, __ch) = match __chars.next() { Some(p) => p, None => return __current_match }; + match __ch as u32 { + 48 ... 57 => { + __current_match = Some((7, __index + __ch.len_utf8())); + __current_state = 13; + continue; + } + 95 => /* '_' */ { + __current_match = Some((7, __index + 1)); + __current_state = 13; + continue; + } + 97 ... 122 => { + __current_match = Some((7, __index + __ch.len_utf8())); + __current_state = 13; + continue; + } + _ => { + return __current_match; + } + } + } + _ => { panic!("invalid state {}", __current_state); } + } + } + } + + impl<'input> __Matcher<'input> { + pub fn new(s: &'input str) -> __Matcher<'input> { + __Matcher { text: s, consumed: 0 } + } + } + + impl<'input> Iterator for __Matcher<'input> { + type Item = Result<(usize, (usize, &'input str), usize), __lalrpop_util::ParseError>; + + fn next(&mut self) -> Option { + let __text = self.text.trim_left(); + let __whitespace = self.text.len() - __text.len(); + let __start_offset = self.consumed + __whitespace; + if __text.is_empty() { + self.text = __text; + self.consumed = __start_offset; + None + } else { + match __tokenize(__text) { + Some((__index, __length)) => { + let __result = &__text[..__length]; + let __remaining = &__text[__length..]; + let __end_offset = __start_offset + __length; + self.text = __remaining; + self.consumed = __end_offset; + Some(Ok((__start_offset, (__index, __result), __end_offset))) + } + None => { + Some(Err(__lalrpop_util::ParseError::InvalidToken { location: __start_offset })) + } + } + } + } + } +} + +#[allow(unused_variables)] +pub fn __action0< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, TopLevel, usize), +) -> TopLevel +{ + (__0) +} + +#[allow(unused_variables)] +pub fn __action1< + 'input, +>( + input: &'input str, + (_, _, _): (usize, &'input str, usize), + (_, t, _): (usize, Term, usize), + (_, _, _): (usize, &'input str, usize), +) -> TopLevel +{ + TopLevel::Query(t) +} + +#[allow(unused_variables)] +pub fn __action2< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Vec, usize), +) -> TopLevel +{ + TopLevel::Predicate(__0) +} + +#[allow(unused_variables)] +pub fn __action3< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Rule, usize), + (_, _, _): (usize, &'input str, usize), +) -> TopLevel +{ + TopLevel::Rule(__0) +} + +#[allow(unused_variables)] +pub fn __action4< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Term, usize), + (_, _, _): (usize, &'input str, usize), +) -> TopLevel +{ + TopLevel::Fact(__0) +} + +#[allow(unused_variables)] +pub fn __action5< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, &'input str, usize), +) -> Atom +{ + __0.trim().to_string() +} + +#[allow(unused_variables)] +pub fn __action6< + 'input, +>( + input: &'input str, + (_, t, _): (usize, Term, usize), +) -> Box +{ + Box::new(t) +} + +#[allow(unused_variables)] +pub fn __action7< + 'input, +>( + input: &'input str, + (_, a, _): (usize, Atom, usize), + (_, _, _): (usize, &'input str, usize), + (_, ts, _): (usize, ::std::vec::Vec>, usize), + (_, t, _): (usize, Box, usize), + (_, _, _): (usize, &'input str, usize), +) -> Term +{ + { + let mut ts = ts; + ts.push(t); + Term::Clause(Cell::new(RegType::Temp(0)), a, ts) + } +} + +#[allow(unused_variables)] +pub fn __action8< + 'input, +>( + input: &'input str, + (_, pcs, _): (usize, ::std::vec::Vec, usize), + (_, pc, _): (usize, PredicateClause, usize), +) -> Vec +{ + { + let mut pcs = pcs; + pcs.push(pc); + pcs + } +} + +#[allow(unused_variables)] +pub fn __action9< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Rule, usize), + (_, _, _): (usize, &'input str, usize), +) -> PredicateClause +{ + PredicateClause::Rule(__0) +} + +#[allow(unused_variables)] +pub fn __action10< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Term, usize), + (_, _, _): (usize, &'input str, usize), +) -> PredicateClause +{ + PredicateClause::Fact(__0) +} + +#[allow(unused_variables)] +pub fn __action11< + 'input, +>( + input: &'input str, + (_, c, _): (usize, Term, usize), + (_, _, _): (usize, &'input str, usize), + (_, h, _): (usize, Term, usize), + (_, cs, _): (usize, ::std::vec::Vec, usize), +) -> Rule +{ + Rule { head: (c, h), clauses: cs } +} + +#[allow(unused_variables)] +pub fn __action12< + 'input, +>( + input: &'input str, + (_, a, _): (usize, Atom, usize), + (_, _, _): (usize, &'input str, usize), + (_, h, _): (usize, Term, usize), + (_, cs, _): (usize, ::std::vec::Vec, usize), +) -> Rule +{ + Rule { head: (Term::Atom(Cell::new(RegType::Temp(0)), a), h), + clauses: cs } +} + +#[allow(unused_variables)] +pub fn __action13< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Term, usize), +) -> Term +{ + __0 +} + +#[allow(unused_variables)] +pub fn __action14< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Atom, usize), +) -> Term +{ + Term::Atom(Cell::new(RegType::Temp(0)), __0) +} + +#[allow(unused_variables)] +pub fn __action15< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Var, usize), +) -> Term +{ + Term::Var(Cell::new(VarReg::Norm(RegType::Temp(0))), __0) +} + +#[allow(unused_variables)] +pub fn __action16< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, &'input str, usize), +) -> Var +{ + __0.trim().to_string() +} + +#[allow(unused_variables)] +pub fn __action17< + 'input, +>( + input: &'input str, + __lookbehind: &usize, + __lookahead: &usize, +) -> ::std::vec::Vec +{ + vec![] +} + +#[allow(unused_variables)] +pub fn __action18< + 'input, +>( + input: &'input str, + (_, v, _): (usize, ::std::vec::Vec, usize), +) -> ::std::vec::Vec +{ + v +} + +#[allow(unused_variables)] +pub fn __action19< + 'input, +>( + input: &'input str, + (_, _, _): (usize, &'input str, usize), + (_, __0, _): (usize, Term, usize), +) -> Term +{ + (__0) +} + +#[allow(unused_variables)] +pub fn __action20< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, PredicateClause, usize), +) -> ::std::vec::Vec +{ + vec![__0] +} + +#[allow(unused_variables)] +pub fn __action21< + 'input, +>( + input: &'input str, + (_, v, _): (usize, ::std::vec::Vec, usize), + (_, e, _): (usize, PredicateClause, usize), +) -> ::std::vec::Vec +{ + { let mut v = v; v.push(e); v } +} + +#[allow(unused_variables)] +pub fn __action22< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, PredicateClause, usize), +) -> PredicateClause +{ + (__0) +} + +#[allow(unused_variables)] +pub fn __action23< + 'input, +>( + input: &'input str, + __lookbehind: &usize, + __lookahead: &usize, +) -> ::std::vec::Vec> +{ + vec![] +} + +#[allow(unused_variables)] +pub fn __action24< + 'input, +>( + input: &'input str, + (_, v, _): (usize, ::std::vec::Vec>, usize), +) -> ::std::vec::Vec> +{ + v +} + +#[allow(unused_variables)] +pub fn __action25< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Box, usize), + (_, _, _): (usize, &'input str, usize), +) -> Box +{ + (__0) +} + +#[allow(unused_variables)] +pub fn __action26< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Box, usize), +) -> ::std::vec::Vec> +{ + vec![__0] +} + +#[allow(unused_variables)] +pub fn __action27< + 'input, +>( + input: &'input str, + (_, v, _): (usize, ::std::vec::Vec>, usize), + (_, e, _): (usize, Box, usize), +) -> ::std::vec::Vec> +{ + { let mut v = v; v.push(e); v } +} + +#[allow(unused_variables)] +pub fn __action28< + 'input, +>( + input: &'input str, + (_, __0, _): (usize, Term, usize), +) -> ::std::vec::Vec +{ + vec![__0] +} + +#[allow(unused_variables)] +pub fn __action29< + 'input, +>( + input: &'input str, + (_, v, _): (usize, ::std::vec::Vec, usize), + (_, e, _): (usize, Term, usize), +) -> ::std::vec::Vec +{ + { let mut v = v; v.push(e); v } +} + +#[allow(unused_variables)] +pub fn __action30< + 'input, +>( + input: &'input str, + __0: (usize, &'input str, usize), + __1: (usize, Term, usize), +) -> ::std::vec::Vec +{ + let __start0 = __0.0.clone(); + let __end0 = __1.2.clone(); + let __temp0 = __action19( + input, + __0, + __1, + ); + let __temp0 = (__start0, __temp0, __end0); + __action28( + input, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action31< + 'input, +>( + input: &'input str, + __0: (usize, ::std::vec::Vec, usize), + __1: (usize, &'input str, usize), + __2: (usize, Term, usize), +) -> ::std::vec::Vec +{ + let __start0 = __1.0.clone(); + let __end0 = __2.2.clone(); + let __temp0 = __action19( + input, + __1, + __2, + ); + let __temp0 = (__start0, __temp0, __end0); + __action29( + input, + __0, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action32< + 'input, +>( + input: &'input str, + __0: (usize, Term, usize), + __1: (usize, &'input str, usize), + __2: (usize, Term, usize), +) -> Rule +{ + let __start0 = __2.2.clone(); + let __end0 = __2.2.clone(); + let __temp0 = __action17( + input, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action11( + input, + __0, + __1, + __2, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action33< + 'input, +>( + input: &'input str, + __0: (usize, Term, usize), + __1: (usize, &'input str, usize), + __2: (usize, Term, usize), + __3: (usize, ::std::vec::Vec, usize), +) -> Rule +{ + let __start0 = __3.0.clone(); + let __end0 = __3.2.clone(); + let __temp0 = __action18( + input, + __3, + ); + let __temp0 = (__start0, __temp0, __end0); + __action11( + input, + __0, + __1, + __2, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action34< + 'input, +>( + input: &'input str, + __0: (usize, Atom, usize), + __1: (usize, &'input str, usize), + __2: (usize, Term, usize), +) -> Rule +{ + let __start0 = __2.2.clone(); + let __end0 = __2.2.clone(); + let __temp0 = __action17( + input, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action12( + input, + __0, + __1, + __2, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action35< + 'input, +>( + input: &'input str, + __0: (usize, Atom, usize), + __1: (usize, &'input str, usize), + __2: (usize, Term, usize), + __3: (usize, ::std::vec::Vec, usize), +) -> Rule +{ + let __start0 = __3.0.clone(); + let __end0 = __3.2.clone(); + let __temp0 = __action18( + input, + __3, + ); + let __temp0 = (__start0, __temp0, __end0); + __action12( + input, + __0, + __1, + __2, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action36< + 'input, +>( + input: &'input str, + __0: (usize, Box, usize), + __1: (usize, &'input str, usize), +) -> ::std::vec::Vec> +{ + let __start0 = __0.0.clone(); + let __end0 = __1.2.clone(); + let __temp0 = __action25( + input, + __0, + __1, + ); + let __temp0 = (__start0, __temp0, __end0); + __action26( + input, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action37< + 'input, +>( + input: &'input str, + __0: (usize, ::std::vec::Vec>, usize), + __1: (usize, Box, usize), + __2: (usize, &'input str, usize), +) -> ::std::vec::Vec> +{ + let __start0 = __1.0.clone(); + let __end0 = __2.2.clone(); + let __temp0 = __action25( + input, + __1, + __2, + ); + let __temp0 = (__start0, __temp0, __end0); + __action27( + input, + __0, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action38< + 'input, +>( + input: &'input str, + __0: (usize, Atom, usize), + __1: (usize, &'input str, usize), + __2: (usize, Box, usize), + __3: (usize, &'input str, usize), +) -> Term +{ + let __start0 = __1.2.clone(); + let __end0 = __2.0.clone(); + let __temp0 = __action23( + input, + &__start0, + &__end0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action7( + input, + __0, + __1, + __temp0, + __2, + __3, + ) +} + +#[allow(unused_variables)] +pub fn __action39< + 'input, +>( + input: &'input str, + __0: (usize, Atom, usize), + __1: (usize, &'input str, usize), + __2: (usize, ::std::vec::Vec>, usize), + __3: (usize, Box, usize), + __4: (usize, &'input str, usize), +) -> Term +{ + let __start0 = __2.0.clone(); + let __end0 = __2.2.clone(); + let __temp0 = __action24( + input, + __2, + ); + let __temp0 = (__start0, __temp0, __end0); + __action7( + input, + __0, + __1, + __temp0, + __3, + __4, + ) +} + +#[allow(unused_variables)] +pub fn __action40< + 'input, +>( + input: &'input str, + __0: (usize, PredicateClause, usize), +) -> ::std::vec::Vec +{ + let __start0 = __0.0.clone(); + let __end0 = __0.2.clone(); + let __temp0 = __action22( + input, + __0, + ); + let __temp0 = (__start0, __temp0, __end0); + __action20( + input, + __temp0, + ) +} + +#[allow(unused_variables)] +pub fn __action41< + 'input, +>( + input: &'input str, + __0: (usize, ::std::vec::Vec, usize), + __1: (usize, PredicateClause, usize), +) -> ::std::vec::Vec +{ + let __start0 = __1.0.clone(); + let __end0 = __1.2.clone(); + let __temp0 = __action22( + input, + __1, + ); + let __temp0 = (__start0, __temp0, __end0); + __action21( + input, + __0, + __temp0, + ) +} + +pub trait __ToTriple<'input, > { + type Error; + fn to_triple(value: Self) -> Result<(usize,(usize, &'input str),usize),Self::Error>; +} + +impl<'input, > __ToTriple<'input, > for (usize, (usize, &'input str), usize) { + type Error = (); + fn to_triple(value: Self) -> Result<(usize,(usize, &'input str),usize),()> { + Ok(value) + } +} +impl<'input, > __ToTriple<'input, > for Result<(usize, (usize, &'input str), usize),()> { + type Error = (); + fn to_triple(value: Self) -> Result<(usize,(usize, &'input str),usize),()> { + value + } +} diff --git a/src/l3/machine.rs b/src/l3/machine.rs new file mode 100644 index 00000000..1d6d25c7 --- /dev/null +++ b/src/l3/machine.rs @@ -0,0 +1,677 @@ +use l3::ast::*; +use l3::codegen::*; +use l3::heapview::*; +use l3::and_stack::*; +use l3::or_stack::*; + +use std::collections::HashMap; +use std::ops::{Index, IndexMut}; +use std::vec::Vec; + +#[derive(Clone, Copy)] +enum MachineMode { + Read, + Write +} + +struct MachineState { + h: usize, + s: usize, + p: CodePtr, + b: usize, + e: usize, + num_of_args: usize, + cp: CodePtr, + fail: bool, + heap: Heap, + mode: MachineMode, + and_stack: AndStack, + or_stack: OrStack, + registers: Registers, + trail: Vec, + tr: usize, + hb: usize +} + +type CodeDir = HashMap<(Atom, usize), usize>; + +impl Index for MachineState { + type Output = Addr; + + fn index(&self, reg: RegType) -> &Self::Output { + match reg { + RegType::Temp(temp) => &self.registers[temp], + RegType::Perm(perm) => { + let e = self.e; + &self.and_stack[e][perm] + } + } + } +} + +impl IndexMut for MachineState { + fn index_mut(&mut self, reg: RegType) -> &mut Self::Output { + match reg { + RegType::Temp(temp) => &mut self.registers[temp], + RegType::Perm(perm) => { + let e = self.e; + &mut self.and_stack[e][perm] + } + } + } +} + +pub struct Machine { + ms: MachineState, + code: Code, + code_dir: CodeDir +} + +impl Machine { + pub fn new() -> Self { + Machine { + ms: MachineState::new(), + code: Vec::new(), + code_dir: HashMap::new() + } + } + + pub fn failed(&self) -> bool { + self.ms.fail + } + + pub fn add_fact(&mut self, fact: &Term, mut code: Code) { + let p = self.code.len(); + let name = fact.name().clone(); + let arity = fact.arity(); + + self.code.append(&mut code); + self.code_dir.insert((name, arity), p); + } + + pub fn add_rule(&mut self, rule: &Rule, mut code: Code) { + let p = self.code.len(); + let name = rule.head.0.name().clone(); + let arity = rule.head.0.arity(); + + self.code.append(&mut code); + self.code_dir.insert((name, arity), p); + } + + pub fn add_predicate(&mut self, pred: &Vec, mut code: Code) + { + let p = self.code.len(); + let name = pred.first().unwrap().name().clone(); + let arity = pred.first().unwrap().arity(); + + self.code.append(&mut code); + self.code_dir.insert((name, arity), p); + } + + fn execute_instr<'a>(&mut self, instr_src: LineOrCodeOffset<'a>) -> bool + { + let mut instr = match instr_src { + LineOrCodeOffset::Instruction(instr) => instr, + LineOrCodeOffset::Offset(p) => &self.code[p] + }; + + loop { + match instr { + &Line::Choice(ref choice_instr) => + self.ms.execute_choice_instr(choice_instr), + &Line::Fact(ref fact) => { + for fact_instr in fact { + self.ms.execute_fact_instr(&fact_instr); + } + self.ms.p += 1; + }, + &Line::Query(ref query) => { + for query_instr in query { + self.ms.execute_query_instr(&query_instr); + } + self.ms.p += 1; + }, + &Line::Control(ref control_instr) => + self.ms.execute_ctrl_instr(&self.code_dir, control_instr), + } + + if self.failed() { + let p = self.ms + .or_stack + .top() + .map(|fr| fr.bp) + .unwrap_or_default(); + + if let CodePtr::TopLevel = p { + return false; + } else { + self.ms.fail = false; + self.ms.p = p; + } + } + + match self.ms.p { + CodePtr::DirEntry(p) if p < self.code.len() => + instr = &self.code[p], + _ => break + } + } + + true + } + + pub fn heap_view(&self, var_dir: &HeapVarDict) -> String { + let mut result = String::new(); + + for (var, addr) in var_dir { + let mut arities = Vec::new(); + let viewer = HeapCellViewer::new(&self.ms.heap, + &self.ms.and_stack, + *addr); + + if result != "" { + result += "\n\r"; + } + + result += var.as_str(); + result += " = "; + + for view in viewer { + match arities.pop() { + Some(n) => arities.push(n-1), + None => {} + } + + if !(arities.is_empty() || result.ends_with("(")) { + result += ", "; + } + + match view { + HeapCellView::Str(arity, ref name) => { + result += name.as_str(); + + if arity > 0 { + arities.push(arity); + result += "("; + } + }, + HeapCellView::HeapVar(cell_num) => { + result += "_"; + result += cell_num.to_string().as_str(); + }, + HeapCellView::StackVar(fr, sc) => { + result += "_s_"; + result += fr.to_string().as_str(); + result += "_"; + result += sc.to_string().as_str(); + } + } + + while let Some(&0) = arities.last() { + result += ")"; + arities.pop(); + } + } + } + + result + } + + pub fn run_query(&mut self, code: Code, cg: &CodeGenerator) -> EvalResult + { + let mut succeeded = true; + let mut heap_locs = HashMap::new(); + + for instr in code.iter().take(1) { + succeeded = self.execute_instr(LineOrCodeOffset::from(instr)); + } + + if succeeded { + for (var, vr) in cg.vars() { + let addr = self.ms.registers[vr.root_register()]; + heap_locs.insert((*var).clone(), addr); + } + + for instr in code.iter().skip(1) { + succeeded = self.execute_instr(LineOrCodeOffset::from(instr)); + if !succeeded { + break; + } + } + } + + if succeeded { + EvalResult::InitialQuerySuccess(heap_locs) + } else { + EvalResult::QueryFailure + } + } + + pub fn or_stack_is_empty(&self) -> bool { + self.ms.or_stack.is_empty() + } + + pub fn continue_query(&mut self) -> EvalResult + { + if !self.or_stack_is_empty() { + let b = self.ms.b; + self.ms.p = self.ms.or_stack[b].bp; + + let succeeded = if let CodePtr::DirEntry(p) = self.ms.p { + self.execute_instr(LineOrCodeOffset::Offset(p)) + } else { + false + }; + + if succeeded { + EvalResult::SubsequentQuerySuccess + } else { + EvalResult::QueryFailure + } + } else { + EvalResult::QueryFailure + } + } + + pub fn reset(&mut self) { + self.ms.reset(); + } +} + +impl MachineState { + fn new() -> MachineState { + MachineState { h: 0, + s: 0, + p: CodePtr::TopLevel, + b: 0, + e: 0, + num_of_args: 0, + cp: CodePtr::TopLevel, + fail: false, + heap: Vec::with_capacity(256), + mode: MachineMode::Write, + and_stack: AndStack::new(), + or_stack: OrStack::new(), + registers: vec![Addr::HeapCell(0); 32], + trail: Vec::new(), + tr: 0, + hb: 0 + } + } + + fn num_frames(&self) -> usize { + self.and_stack.len() + self.or_stack.len() + } + + fn store(&self, a: Addr) -> Addr { + match a { + Addr::HeapCell(r) => self.heap[r].as_addr(r), + Addr::StackCell(fr, sc) => self.and_stack[fr][sc], + addr => addr + } + } + + fn deref(&self, a: Addr) -> Addr { + let mut a = a; + + loop { + let value = self.store(a); + + if value.is_ref() && value != a { + a = value; + continue; + } + + return a; + }; + } + + fn bind(&mut self, r1: Ref, a2: Addr) { + let t2 = self.store(a2); + + match r1 { + Ref::StackCell(fr, sc) => + self.and_stack[fr][sc] = t2, + Ref::HeapCell(hc) => + self.heap[hc] = HeapCellValue::from(t2) + }; + + self.trail(r1); + } + + fn unify(&mut self, a1: Addr, a2: Addr) { + let mut pdl = vec![a1, a2]; + + self.fail = false; + + while !(pdl.is_empty() || self.fail) { + let d1 = self.deref(pdl.pop().unwrap()); + let d2 = self.deref(pdl.pop().unwrap()); + + if d1 != d2 { + match (self.store(d1), self.store(d2)) { + (Addr::HeapCell(hc), _) => + self.bind(Ref::HeapCell(hc), d2), + (_, Addr::HeapCell(hc)) => + self.bind(Ref::HeapCell(hc), d1), + (Addr::StackCell(fr, sc), _) => + self.bind(Ref::StackCell(fr, sc), d2), + (_, Addr::StackCell(fr, sc)) => + self.bind(Ref::StackCell(fr, sc), d1), + (Addr::Str(a1), Addr::Str(a2)) => { + let r1 = &self.heap[a1]; + let r2 = &self.heap[a2]; + + if let &HeapCellValue::NamedStr(n1, ref f1) = r1 { + if let &HeapCellValue::NamedStr(n2, ref f2) = r2 { + if n1 == n2 && *f1 == *f2 { + for i in 1 .. n1 + 1 { + pdl.push(Addr::HeapCell(a1 + i)); + pdl.push(Addr::HeapCell(a2 + i)); + } + + continue; + } + } + } + + self.fail = true; + } + }; + } + } + } + + fn trail(&mut self, r: Ref) { + match r { + Ref::HeapCell(hc) => { + if hc < self.hb { + self.trail.push(r); + self.tr += 1; + } + }, + Ref::StackCell(fr, _) => { + let fr_gi = self.and_stack[fr].global_index; + let b_gi = if !self.or_stack.is_empty() { + self.or_stack[self.b].global_index + } else { + 0 + }; + + if fr_gi < b_gi { + self.trail.push(r); + self.tr += 1; + } + } + } + } + + fn unwind_trail(&mut self, a1: usize, a2: usize) { + for i in a1 .. a2 { + match self.trail[i] { + Ref::HeapCell(r) => + self.heap[r] = HeapCellValue::Ref(self.trail[i]), + Ref::StackCell(fr, sc) => + self.and_stack[fr][sc] = Addr::StackCell(fr, sc) + } + } + } + + fn execute_query_instr(&mut self, instr: &QueryInstruction) { + match instr { + &QueryInstruction::PutStructure(_, ref name, arity, reg) => { + self.heap.push(HeapCellValue::Str(self.h + 1)); + self.heap.push(HeapCellValue::NamedStr(arity, name.clone())); + + self[reg] = Addr::Str(self.h + 1); + + self.h += 2; + }, + &QueryInstruction::PutValue(norm, arg) => + self.registers[arg] = self[norm], + &QueryInstruction::PutVariable(norm, arg) => { + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h))); + + self[norm] = Addr::HeapCell(self.h); + self.registers[arg] = Addr::HeapCell(self.h); + + self.h += 1; + }, + &QueryInstruction::SetVariable(reg) => { + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h))); + self[reg] = Addr::HeapCell(self.h); + + self.h += 1; + }, + &QueryInstruction::SetValue(reg) => { + let heap_val = self[reg]; + self.heap.push(HeapCellValue::from(heap_val)); + + self.h += 1; + }, + } + } + + fn execute_fact_instr(&mut self, instr: &FactInstruction) { + match instr { + &FactInstruction::GetStructure(_, ref name, arity, reg) => { + let addr = self.deref(self[reg]); + + match self.store(addr) { + Addr::Str(a) => { + let result = &self.heap[a]; + + if let &HeapCellValue::NamedStr(narity, ref str) = result { + if narity == arity && *name == *str { + self.s = a + 1; + self.mode = MachineMode::Read; + } else { + self.fail = true; + } + } + }, + Addr::HeapCell(_) | Addr::StackCell(_, _) => { + self.heap.push(HeapCellValue::Str(self.h + 1)); + self.heap.push(HeapCellValue::NamedStr(arity, name.clone())); + + let h = self.h; + + self.bind(addr.as_ref().unwrap(), Addr::HeapCell(h)); + + self.h += 2; + self.mode = MachineMode::Write; + } + }; + }, + &FactInstruction::GetVariable(norm, arg) => + self[norm] = self.registers[arg], + &FactInstruction::GetValue(norm, arg) => { + let norm_addr = self[norm]; + let reg_addr = self.registers[arg]; + + self.unify(norm_addr, reg_addr); + }, + &FactInstruction::UnifyVariable(reg) => { + match self.mode { + MachineMode::Read => + self[reg] = self.heap[self.s].as_addr(self.s), + MachineMode::Write => { + self.heap.push(HeapCellValue::Ref(Ref::HeapCell(self.h))); + self[reg] = Addr::HeapCell(self.h); + self.h += 1; + } + }; + + self.s += 1; + }, + &FactInstruction::UnifyValue(reg) => { + let s = self.s; + + match self.mode { + MachineMode::Read => { + let reg_addr = self[reg]; + self.unify(reg_addr, Addr::HeapCell(s)); + }, + MachineMode::Write => { + let heap_val = self.store(self[reg]); + self.heap.push(HeapCellValue::from(heap_val)); + self.h += 1; + } + }; + + self.s += 1; + } + }; + } + + fn execute_ctrl_instr(&mut self, code_dir: &CodeDir, instr: &ControlInstruction) + { + match instr { + &ControlInstruction::Allocate(num_cells) => { + let num_frames = self.num_frames(); + + self.and_stack.push(num_frames + 1, self.e, self.cp, num_cells); + + self.e = self.and_stack.len() - 1; + self.p += 1; + }, + &ControlInstruction::Call(ref name, arity) => { + let compiled_tl_index = code_dir.get(&(name.clone(), arity)) + .map(|index| *index); + + match compiled_tl_index { + Some(compiled_tl_index) => { + self.cp = self.p + 1; + self.num_of_args = arity; + self.p = CodePtr::DirEntry(compiled_tl_index); + }, + None => self.fail = true + }; + }, + &ControlInstruction::Deallocate => { + let e = self.e; + + let num_frame_e = self.and_stack.top().unwrap().global_index; + let num_frame_b = self.or_stack + .top() + .map(|fr| fr.global_index) + .unwrap_or(0); + + self.p = self.and_stack[e].cp; + self.e = self.and_stack[e].e; + + if num_frame_e > num_frame_b { + let top_e = self.and_stack.top().unwrap().e; + self.and_stack.drop_frames(top_e - self.e + 1); + } + }, + &ControlInstruction::Proceed => + self.p = self.cp, + }; + } + + fn execute_choice_instr(&mut self, instr: &ChoiceInstruction) + { + match instr { + &ChoiceInstruction::TryMeElse(offset) => { + let n = self.num_of_args; + let num_frames = self.num_frames(); + + self.or_stack.push(num_frames + 1, + self.e, + self.cp, + self.b, + self.p + offset, + self.tr, + self.h, + self.num_of_args); + + self.b = self.or_stack.len() - 1; + let b = self.b; + + for i in 1 .. n + 1 { + self.or_stack[b][i] = self.registers[i]; + } + + self.hb = self.h; + self.p += 1; + }, + &ChoiceInstruction::RetryMeElse(offset) => { + let b = self.b; + let n = self.or_stack[b].num_args(); + + for i in 1 .. n + 1 { + self.registers[i] = self.or_stack[b][i]; + } + + self.e = self.or_stack[b].e; + self.cp = self.or_stack[b].cp; + + self.or_stack[b].bp = self.p + offset; + + let old_tr = self.or_stack[b].tr; + let curr_tr = self.tr; + + self.unwind_trail(old_tr, curr_tr); + self.tr = self.or_stack[b].tr; + + self.trail.truncate(self.tr); + self.heap.truncate(self.or_stack[b].h); + + self.h = self.or_stack[b].h; + self.hb = self.h; + + self.p += 1; + }, + &ChoiceInstruction::TrustMe => { + let b = self.b; + let n = self.or_stack[b].num_args(); + + for i in 1 .. n + 1 { + self.registers[i] = self.or_stack[b][i]; + } + + self.e = self.or_stack[b].e; + self.cp = self.or_stack[b].cp; + + let old_tr = self.or_stack[b].tr; + let curr_tr = self.tr; + + self.unwind_trail(old_tr, curr_tr); + + self.tr = self.or_stack[b].tr; + self.trail.truncate(self.tr); + + self.h = self.or_stack[b].h; + self.heap.truncate(self.h); + + self.b = self.or_stack[b].b; + + self.or_stack.pop(); + + self.hb = self.h; + self.p += 1; + } + } + } + + fn reset(&mut self) { + self.h = 0; + self.hb = 0; + self.e = 0; + self.b = 0; + self.s = 0; + self.tr = 0; + self.p = CodePtr::TopLevel; + self.cp = CodePtr::TopLevel; + self.num_of_args = 0; + + self.fail = false; + self.trail.clear(); + self.heap.clear(); + self.mode = MachineMode::Write; + self.and_stack.clear(); + self.or_stack.clear(); + self.registers = vec![Addr::HeapCell(0); 32]; + } +} diff --git a/src/l3/mod.rs b/src/l3/mod.rs new file mode 100644 index 00000000..8cdc4610 --- /dev/null +++ b/src/l3/mod.rs @@ -0,0 +1,9 @@ +pub mod and_stack; +pub mod ast; +pub mod codegen; +pub mod heapview; +pub mod io; +pub mod iterators; +pub mod l3_parser; +pub mod machine; +pub mod or_stack; diff --git a/src/l3/or_stack.rs b/src/l3/or_stack.rs new file mode 100644 index 00000000..19eb0ad3 --- /dev/null +++ b/src/l3/or_stack.rs @@ -0,0 +1,112 @@ +use l3::ast::*; + +use std::ops::{Index, IndexMut}; +use std::vec::Vec; + +pub struct Frame { + pub global_index: usize, + pub e: usize, + pub cp: CodePtr, + pub b: usize, + pub bp: CodePtr, + pub tr: usize, + pub h: usize, + args: Vec +} + +impl Frame { + fn new(global_index: usize, + e: usize, + cp: CodePtr, + b: usize, + bp: CodePtr, + tr: usize, + h: usize, + n: usize) + -> Self + { + Frame { + global_index: global_index, + e: e, + cp: cp, + b: b, + bp: bp, + tr: tr, + h: h, + args: vec![Addr::HeapCell(0); n] + } + } + + pub fn num_args(&self) -> usize { + self.args.len() + } +} + +pub struct OrStack(Vec); + +impl OrStack { + pub fn new() -> Self { + OrStack(Vec::new()) + } + + pub fn push(&mut self, + global_index: usize, + e: usize, + cp: CodePtr, + b: usize, + bp: CodePtr, + tr: usize, + h: usize, + n: usize) + { + self.0.push(Frame::new(global_index, e, cp, b, bp, tr, h, n)); + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn clear(&mut self) { + self.0.clear() + } + + pub fn top(&self) -> Option<&Frame> { + self.0.last() + } + + pub fn pop(&mut self) { + self.0.pop(); + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +impl Index for OrStack { + type Output = Frame; + + fn index(&self, index: usize) -> &Self::Output { + self.0.index(index) + } +} + +impl IndexMut for OrStack { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.0.index_mut(index) + } +} + +impl Index for Frame { + type Output = Addr; + + fn index(&self, index: usize) -> &Self::Output { + self.args.index(index - 1) + } +} + +impl IndexMut for Frame { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + self.args.index_mut(index - 1) + } +} diff --git a/src/main.rs b/src/main.rs index f1d55bbd..8cbe432f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,157 +1,203 @@ -mod l2; - -use l2::ast::*; -use l2::codegen::*; -use l2::machine::*; - -use std::io::{self, Write}; - -fn submit(wam: &mut Machine, buffer: String) -> bool { - let result = l2::l2_parser::parse_TopLevel(&*buffer); - - let mut cg = CodeGenerator::new(); - - match &result { - &Ok(TopLevel::Fact(ref fact)) => { - let compiled_fact = cg.compile_fact(&fact); - wam.add_fact(fact, compiled_fact); - }, - &Ok(TopLevel::Rule(ref rule)) => { - let compiled_rule = cg.compile_rule(&rule); - wam.add_rule(rule, compiled_rule); - }, - &Ok(TopLevel::Query(ref query)) => { - let compiled_query = cg.compile_query(&query); - let output = wam.run_query(compiled_query, &cg); - - match output { - Some(result) => { - println!("yes"); - - if result != "" { - println!("{}", result); - } - }, - None => println!("no") - } - }, - &Err(_) => println!("Grammatical error of some kind!"), - }; - - let result = wam.failed(); - wam.reset(); - result -} +extern crate termion; +mod l3; + +use l3::io::*; +use l3::machine::*; #[cfg(test)] mod tests { use super::*; - - #[inline] - fn submit_ss(wam: &mut Machine, buffer: &'static str) -> bool { - submit(wam, String::from(buffer)) + use l3::ast::*; + + fn submit(wam: &mut Machine, buffer: &str) -> EvalResult { + let result = eval(wam, buffer); + wam.reset(); + result } - + #[test] fn test_queries_on_facts() { let mut wam = Machine::new(); - submit_ss(&mut wam, "p(Z, Z)."); - submit_ss(&mut wam, "clouds(are, nice)."); + submit(&mut wam, "p(Z, Z)."); + submit(&mut wam, "clouds(are, nice)."); - // submit_ss returns true on failure, false on success. - assert_eq!(submit_ss(&mut wam, "?- p(Z, Z)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(Z, z)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(Z, w)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(z, w)."), true); - assert_eq!(submit_ss(&mut wam, "?- p(w, w)."), false); - assert_eq!(submit_ss(&mut wam, "?- clouds(Z, Z)."), true); - assert_eq!(submit_ss(&mut wam, "?- clouds(are, Z)."), false); - assert_eq!(submit_ss(&mut wam, "?- clouds(Z, nice)."), false); + // submit returns true on failure, false on success. + assert_eq!(submit(&mut wam, "?- p(Z, Z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(Z, z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(Z, w).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(z, w).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(w, w).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- clouds(Z, Z).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- clouds(are, Z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- clouds(Z, nice).").failed_query(), false); - assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, W), f(W))."), true); + assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W)).").failed_query(), true); - submit_ss(&mut wam, "p(Z, h(Z, W), f(W))."); + submit(&mut wam, "p(Z, h(Z, W), f(W))."); - assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, z), f(w))."), true); - assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, w), f(w))."), false); - assert_eq!(submit_ss(&mut wam, "?- p(z, h(z, W), f(w))."), false); - assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, w), f(Z))."), false); - assert_eq!(submit_ss(&mut wam, "?- p(z, h(Z, w), f(Z))."), true); + assert_eq!(submit(&mut wam, "?- p(z, h(z, z), f(w)).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(z, h(z, w), f(w)).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(z, h(z, W), f(w)).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(Z, h(Z, w), f(Z)).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(z, h(Z, w), f(Z)).").failed_query(), true); - submit_ss(&mut wam, "p(f(X), h(Y, f(a)), Y)."); + submit(&mut wam, "p(f(X), h(Y, f(a)), Y)."); - assert_eq!(submit_ss(&mut wam, "?- p(Z, h(Z, W), f(W))."), false); + assert_eq!(submit(&mut wam, "?- p(Z, h(Z, W), f(W)).").failed_query(), false); } #[test] fn test_queries_on_rules() { let mut wam = Machine::new(); - submit_ss(&mut wam, "p(X, Y) :- q(X, Z), r(Z, Y)."); - submit_ss(&mut wam, "q(q, s)."); - submit_ss(&mut wam, "r(s, t)."); + submit(&mut wam, "p(X, Y) :- q(X, Z), r(Z, Y)."); + submit(&mut wam, "q(q, s)."); + submit(&mut wam, "r(s, t)."); - assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(q, t)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(t, q)."), true); - assert_eq!(submit_ss(&mut wam, "?- p(q, T)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(Q, t)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(t, t)."), true); + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(q, t).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(t, q).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(q, T).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(Q, t).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(t, t).").failed_query(), true); - submit_ss(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T)."); - submit_ss(&mut wam, "q(f(f(X)), r)."); + submit(&mut wam, "p(X, Y) :- q(f(f(X)), R), r(S, T)."); + submit(&mut wam, "q(f(f(X)), r)."); - assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false); + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); - submit_ss(&mut wam, "q(f(f(x)), r)."); + submit(&mut wam, "q(f(f(x)), r)."); - assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false); + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); - submit_ss(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y)."); - submit_ss(&mut wam, "q(s, t)."); - submit_ss(&mut wam, "r(X, Y) :- r(a)."); - submit_ss(&mut wam, "r(a)."); + submit(&mut wam, "p(X, Y) :- q(X, Y), r(X, Y)."); + submit(&mut wam, "q(s, t)."); + submit(&mut wam, "r(X, Y) :- r(a)."); + submit(&mut wam, "r(a)."); - assert_eq!(submit_ss(&mut wam, "?- p(X, Y)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(t, S)."), true); - assert_eq!(submit_ss(&mut wam, "?- p(t, s)."), true); - assert_eq!(submit_ss(&mut wam, "?- p(s, T)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(S, t)."), false); + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(t, S).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(t, s).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(s, T).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(S, t).").failed_query(), false); - submit_ss(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y)."); - submit_ss(&mut wam, "q(X, Y)."); + submit(&mut wam, "p(f(f(a), g(b), X), g(b), h) :- q(X, Y)."); + submit(&mut wam, "q(X, Y)."); - assert_eq!(submit_ss(&mut wam, "?- p(f(X, Y, Z), g(b), h)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X)."), true); - assert_eq!(submit_ss(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(Z, Y, X)."), false); - assert_eq!(submit_ss(&mut wam, "?- p(f(X, Y, Z), Y, h)."), false); + assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), g(b), h).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), X).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(f(X, g(Y), Z), g(Z), h).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(Z, Y, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(f(X, Y, Z), Y, h).").failed_query(), false); + } + + #[test] + fn test_queries_on_predicates() { + let mut wam = Machine::new(); + + submit(&mut wam, "p(X, a). p(b, X)."); + + assert_eq!(submit(&mut wam, "?- p(x, Y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, a).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(b, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(a, b).").failed_query(), true); + + submit(&mut wam, "p(X, Y, a). p(X, a, Y). p(X, Y, a)."); + + assert_eq!(submit(&mut wam, "?- p(c, d, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(a, a, a).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(b, c, d).").failed_query(), true); + + submit(&mut wam, "p(X, a). p(X, Y) :- q(Z), p(X, X)."); + + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(x, a).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, a).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), true); + + submit(&mut wam, "q(z)."); + + assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(x, a).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); + + submit(&mut wam, "p(X, a). p(X, Y) :- q(Y), p(X, X)."); + + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, b).").failed_query(), true); + + submit(&mut wam, "p(a, z). p(X, Y) :- q(Y), p(X, Y)."); + + assert_eq!(submit(&mut wam, "?- p(X, Y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(a, z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(a, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(b, a).").failed_query(), true); + + submit(&mut wam, "p(X, Y, Z) :- q(X), r(Y), s(Z). + p(a, b, Z) :- q(Z)."); + + submit(&mut wam, "q(x)."); + submit(&mut wam, "r(y)."); + submit(&mut wam, "s(z)."); + + assert_eq!(submit(&mut wam, "?- p(X, Y, Z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(a, b, c).").failed_query(), true); + assert_eq!(submit(&mut wam, "?- p(a, b, C).").failed_query(), false); + + submit(&mut wam, "p(X) :- q(X). p(X) :- r(X)."); + submit(&mut wam, "q(X) :- a."); + submit(&mut wam, "r(X) :- s(X, t). r(X) :- t(X, u)."); + + submit(&mut wam, "s(x, t)."); + submit(&mut wam, "t(y, u)."); + + assert_eq!(submit(&mut wam, "?- p(X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(x).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(y).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(z).").failed_query(), true); + + submit(&mut wam, "p(f(f(X)), h(W), Y) :- g(W), h(W), f(X). + p(X, Y, Z) :- h(Y), g(W), z(Z)."); + submit(&mut wam, "g(f(X)) :- z(X). g(X) :- h(X)."); + submit(&mut wam, "h(w). h(x). h(z)."); + submit(&mut wam, "f(s)."); + submit(&mut wam, "z(Z)."); + + assert_eq!(submit(&mut wam, "?- p(X, Y, Z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, X, Z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(f(f(Z)), Y, Z).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, X, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(X, Y, X).").failed_query(), false); + assert_eq!(submit(&mut wam, "?- p(f(f(X)), h(f(X)), Y).").failed_query(), true); } } -fn l2_repl() { +fn l3_repl() { let mut wam = Machine::new(); - + loop { - print!("l2> "); - - let _ = io::stdout().flush(); - let mut buffer = String::new(); + print!("l3> "); - io::stdin().read_line(&mut buffer).unwrap(); + let buffer = read(); - if &*buffer == "quit\n" { + if buffer == "quit\n" { break; - } else if &*buffer == "clear\n" { + } else if buffer == "clear\n" { wam = Machine::new(); continue; } - submit(&mut wam, buffer); + let result = eval(&mut wam, buffer.trim()); + print(&mut wam, result); + + wam.reset(); } } fn main() { - l2_repl(); + l3_repl(); }