From: Mark Thom Date: Wed, 17 Jan 2018 06:26:59 +0000 (-0700) Subject: add an atom table. X-Git-Tag: v0.8.110~619 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=d8be7b5b499379f27396e16e899fe03229662a4a;p=scryer-prolog.git add an atom table. --- diff --git a/src/main.rs b/src/main.rs index 32ef1d88..6ea09b57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ mod tests; fn process_buffer(wam: &mut Machine, buffer: &str) { - match parse_code(buffer, wam.op_dir()) { + match parse_code(buffer, wam.atom_tbl(), wam.op_dir()) { Ok(tl) => { let result = eval(wam, &tl); print(wam, result); diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index e489d099..c1ce933a 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -2,6 +2,7 @@ use prolog::num::bigint::BigInt; use prolog::num::{Float, ToPrimitive, Zero}; use prolog::num::rational::Ratio; use prolog::ordered_float::*; +use prolog::tabled_rc::*; use std::cell::Cell; use std::cmp::Ordering; @@ -59,7 +60,7 @@ impl PredicateClause { } } - pub fn name(&self) -> Option> { + pub fn name(&self) -> Option> { match self { &PredicateClause::Fact(ref term) => term.name(), &PredicateClause::Rule(ref rule) => @@ -73,7 +74,7 @@ impl PredicateClause { } pub enum Declaration { - Op(usize, Specifier, Rc) + Op(usize, Specifier, TabledRc) } pub enum TopLevel { @@ -266,19 +267,13 @@ pub enum Fixity { #[derive(Clone, Eq, Hash, PartialEq)] pub enum Constant { - Atom(Rc), + Atom(TabledRc), Number(Number), String(Rc), Usize(usize), EmptyList } -impl<'a> From<&'a str> for Constant { - fn from(input: &str) -> Constant { - Constant::Atom(Rc::new(String::from(input))) - } -} - impl fmt::Display for Constant { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -298,7 +293,7 @@ impl fmt::Display for Constant { pub enum Term { AnonVar, - Clause(Cell, Rc, Vec>, Option), + Clause(Cell, TabledRc, Vec>, Option), Cons(Cell, Box, Box), Constant(Cell, Constant), Var(Cell, Rc) @@ -373,7 +368,7 @@ pub struct Rule { pub enum ClauseType<'a> { CallN, Catch, - Deep(Level, &'a Cell, &'a Rc, Option), + Deep(Level, &'a Cell, &'a TabledRc, Option), Is, Root, Throw, @@ -745,7 +740,7 @@ pub enum ControlInstruction { Allocate(usize), // num_frames. ArgCall, ArgExecute, - Call(Rc, usize, usize), // name, arity, perm_vars after threshold. + Call(TabledRc, usize, usize), // name, arity, perm_vars after threshold. CallN(usize), // arity. CatchCall, CatchExecute, @@ -754,7 +749,7 @@ pub enum ControlInstruction { DisplayExecute, DuplicateTermCall, DuplicateTermExecute, - Execute(Rc, usize), + Execute(TabledRc, usize), ExecuteN(usize), FunctorCall, FunctorExecute, @@ -797,7 +792,7 @@ impl ControlInstruction { pub enum IndexingInstruction { SwitchOnTerm(usize, usize, usize, usize), SwitchOnConstant(usize, HashMap), - SwitchOnStructure(usize, HashMap<(Rc, usize), usize>) + SwitchOnStructure(usize, HashMap<(TabledRc, usize), usize>) } impl From for Line { @@ -809,7 +804,7 @@ impl From for Line { pub enum FactInstruction { GetConstant(Level, Constant, RegType), GetList(Level, RegType), - GetStructure(Level, Rc, usize, RegType, Option), + GetStructure(Level, TabledRc, usize, RegType, Option), GetValue(RegType, usize), GetVariable(RegType, usize), UnifyConstant(Constant), @@ -823,7 +818,7 @@ pub enum QueryInstruction { GetVariable(RegType, usize), PutConstant(Level, Constant, RegType), PutList(Level, RegType), - PutStructure(Level, Rc, usize, RegType, Option), + PutStructure(Level, TabledRc, usize, RegType, Option), PutUnsafeValue(usize, usize), PutValue(RegType, usize), PutVariable(RegType, usize), @@ -907,7 +902,7 @@ pub enum Ref { #[derive(Clone, PartialEq)] pub enum HeapCellValue { Addr(Addr), - NamedStr(usize, Rc, Option), // arity, name. + NamedStr(usize, TabledRc, Option), // arity, name, fixity if it has one. } impl HeapCellValue { @@ -1035,7 +1030,7 @@ impl Term { } } - pub fn name(&self) -> Option> { + pub fn name(&self) -> Option> { match self { &Term::Constant(_, Constant::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => Some(atom.clone()), diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 0048004f..0ccd6a6c 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -1,10 +1,11 @@ use prolog::ast::*; use prolog::num::bigint::{BigInt}; +use prolog::tabled_rc::*; use std::collections::HashMap; use std::rc::Rc; -pub type PredicateKey = (Rc, usize); // name, arity, type. +pub type PredicateKey = (TabledRc, usize); // name, arity, type. #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum PredicateKeyType { @@ -12,13 +13,13 @@ pub enum PredicateKeyType { User } -pub type OpDirKey = (Rc, Fixity); +pub type OpDirKey = (TabledRc, Fixity); // name and fixity -> operator type and precedence. pub type OpDir = HashMap; pub type CodeDir = HashMap; -fn get_builtins() -> Code { +fn get_builtins(atom_tbl: TabledData) -> Code { vec![internal_call_n!(), // callN/N, 0. is_atomic!(temp_v!(1)), // atomic/1, 1. proceed!(), @@ -114,25 +115,25 @@ fn get_builtins() -> Code { retry!(7), trust!(10), try_me_else!(4), - fact![get_constant!(Constant::from("!"), temp_v!(1)), - get_structure!(String::from(","), 2, temp_v!(2), Some(infix!())), + fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)), + get_structure!(atom_tbl, ",", 2, temp_v!(2), Some(infix!())), unify_variable!(temp_v!(1)), unify_variable!(temp_v!(2))], set_cp!(temp_v!(3)), goto!(83, 3), retry_me_else!(4), - fact![get_constant!(Constant::from("!"), temp_v!(1)), - get_constant!(Constant::from("!"), temp_v!(2))], + fact![get_constant!(atom!("!", atom_tbl), temp_v!(1)), + get_constant!(atom!("!", atom_tbl), temp_v!(2))], set_cp!(temp_v!(3)), proceed!(), trust_me!(), - fact![get_constant!(Constant::from("!"), temp_v!(1))], + fact![get_constant!(atom!("!", atom_tbl), temp_v!(1))], set_cp!(temp_v!(3)), query![put_value!(temp_v!(2), 1)], execute_n!(1), retry_me_else!(8), allocate!(3), - fact![get_structure!(String::from(","), 2, temp_v!(2), Some(infix!())), + fact![get_structure!(atom_tbl, ",", 2, temp_v!(2), Some(infix!())), unify_variable!(perm_v!(2)), unify_variable!(perm_v!(1)), get_var_in_fact!(perm_v!(3), 3)], @@ -146,7 +147,7 @@ fn get_builtins() -> Code { retry_me_else!(10), allocate!(1), get_level!(), - fact![get_constant!(Constant::from("!"), temp_v!(2)), + fact![get_constant!(atom!("!", atom_tbl), temp_v!(2)), get_var_in_fact!(perm_v!(1), 3)], neck_cut!(), call_n!(1), @@ -167,12 +168,12 @@ fn get_builtins() -> Code { indexed_try!(3), trust!(5), try_me_else!(3), - fact![get_structure!(String::from("->"), 2, temp_v!(1), Some(infix!())), + fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())), unify_variable!(temp_v!(1)), unify_variable!(temp_v!(2))], goto!(139, 3), trust_me!(), - fact![get_structure!(String::from("->"), 2, temp_v!(1), Some(infix!())), + fact![get_structure!(atom_tbl, "->", 2, temp_v!(1), Some(infix!())), unify_void!(2)], query![put_value!(temp_v!(2), 1)], neck_cut!(), @@ -231,12 +232,13 @@ fn get_builtins() -> Code { goto!(149, 3), // goto get_arg/3. trust_me!(), query![get_var_in_query!(temp_v!(4), 1), - put_structure!(Level::Shallow, + put_structure!(atom_tbl, + Level::Shallow, String::from("type_error"), 1, temp_v!(1), None), - set_constant!(Constant::Atom(rc_atom!("integer_expected")))], + set_constant!(atom!("integer_expected", atom_tbl))], goto!(59, 1), // goto throw/1. try_me_else!(5), // arg_/3, 173. fact![get_value!(temp_v!(1), 2), @@ -277,76 +279,76 @@ fn get_builtins() -> Code { ] } -pub fn build_code_dir() -> (Code, CodeDir, OpDir) +pub fn build_code_dir(atom_tbl: TabledData) -> (Code, CodeDir, OpDir) { let mut code_dir = HashMap::new(); let mut op_dir = HashMap::new(); - let builtin_code = get_builtins(); + let builtin_code = get_builtins(atom_tbl.clone()); - op_dir.insert((rc_atom!(":-"), Fixity::In), (XFX, 1200)); - op_dir.insert((rc_atom!(":-"), Fixity::Pre), (FX, 1200)); - op_dir.insert((rc_atom!("?-"), Fixity::Pre), (FX, 1200)); + op_dir.insert((tabled_rc!(":-", atom_tbl), Fixity::In), (XFX, 1200)); + op_dir.insert((tabled_rc!(":-", atom_tbl), Fixity::Pre), (FX, 1200)); + op_dir.insert((tabled_rc!("?-", atom_tbl), Fixity::Pre), (FX, 1200)); // control operators. - op_dir.insert((rc_atom!("\\+"), Fixity::Pre), (FY, 900)); - op_dir.insert((rc_atom!("="), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!("\\+", atom_tbl), Fixity::Pre), (FY, 900)); + op_dir.insert((tabled_rc!("=", atom_tbl), Fixity::In), (XFX, 700)); // arithmetic operators. - op_dir.insert((rc_atom!("is"), Fixity::In), (XFX, 700)); - op_dir.insert((rc_atom!("+"), Fixity::In), (YFX, 500)); - op_dir.insert((rc_atom!("-"), Fixity::In), (YFX, 500)); - op_dir.insert((rc_atom!("/\\"), Fixity::In), (YFX, 500)); - op_dir.insert((rc_atom!("\\/"), Fixity::In), (YFX, 500)); - op_dir.insert((rc_atom!("xor"), Fixity::In), (YFX, 500)); - op_dir.insert((rc_atom!("//"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("/"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("div"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("*"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("-"), Fixity::Pre), (FY, 200)); - op_dir.insert((rc_atom!("rdiv"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("<<"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!(">>"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("mod"), Fixity::In), (YFX, 400)); - op_dir.insert((rc_atom!("rem"), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("is", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!("+", atom_tbl), Fixity::In), (YFX, 500)); + op_dir.insert((tabled_rc!("-", atom_tbl), Fixity::In), (YFX, 500)); + op_dir.insert((tabled_rc!("/\\", atom_tbl), Fixity::In), (YFX, 500)); + op_dir.insert((tabled_rc!("\\/", atom_tbl), Fixity::In), (YFX, 500)); + op_dir.insert((tabled_rc!("xor", atom_tbl), Fixity::In), (YFX, 500)); + op_dir.insert((tabled_rc!("//", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("/", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("div", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("*", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("-", atom_tbl), Fixity::Pre), (FY, 200)); + op_dir.insert((tabled_rc!("rdiv", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("<<", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!(">>", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("mod", atom_tbl), Fixity::In), (YFX, 400)); + op_dir.insert((tabled_rc!("rem", atom_tbl), Fixity::In), (YFX, 400)); // arithmetic comparison operators. - op_dir.insert((rc_atom!(">"), Fixity::In), (XFX, 700)); - op_dir.insert((rc_atom!("<"), Fixity::In), (XFX, 700)); - op_dir.insert((rc_atom!("=\\="), Fixity::In), (XFX, 700)); - op_dir.insert((rc_atom!("=:="), Fixity::In), (XFX, 700)); - op_dir.insert((rc_atom!(">="), Fixity::In), (XFX, 700)); - op_dir.insert((rc_atom!("=<"), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!(">", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!("<", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!("=\\=", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!("=:=", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!(">=", atom_tbl), Fixity::In), (XFX, 700)); + op_dir.insert((tabled_rc!("=<", atom_tbl), Fixity::In), (XFX, 700)); // control operators. - op_dir.insert((rc_atom!(";"), Fixity::In), (XFY, 1100)); - op_dir.insert((rc_atom!("->"), Fixity::In), (XFY, 1050)); + op_dir.insert((tabled_rc!(";", atom_tbl), Fixity::In), (XFY, 1100)); + op_dir.insert((tabled_rc!("->", atom_tbl), Fixity::In), (XFY, 1050)); // there are 63 registers in the VM, so call/N is defined for all 0 <= N <= 62 // (an extra register is needed for the predicate name) for arity in 0 .. 63 { - code_dir.insert((rc_atom!("call"), arity), (PredicateKeyType::BuiltIn, 0)); + code_dir.insert((tabled_rc!("call", atom_tbl), arity), (PredicateKeyType::BuiltIn, 0)); } - code_dir.insert((rc_atom!("atomic"), 1), (PredicateKeyType::BuiltIn, 1)); - code_dir.insert((rc_atom!("var"), 1), (PredicateKeyType::BuiltIn, 3)); - code_dir.insert((rc_atom!("false"), 0), (PredicateKeyType::BuiltIn, 61)); - code_dir.insert((rc_atom!("\\+"), 1), (PredicateKeyType::BuiltIn, 62)); - code_dir.insert((rc_atom!("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71)); - code_dir.insert((rc_atom!("catch"), 3), (PredicateKeyType::BuiltIn, 5)); - code_dir.insert((rc_atom!("throw"), 1), (PredicateKeyType::BuiltIn, 59)); - code_dir.insert((rc_atom!("="), 2), (PredicateKeyType::BuiltIn, 73)); - code_dir.insert((rc_atom!("true"), 0), (PredicateKeyType::BuiltIn, 75)); + code_dir.insert((tabled_rc!("atomic", atom_tbl), 1), (PredicateKeyType::BuiltIn, 1)); + code_dir.insert((tabled_rc!("var", atom_tbl), 1), (PredicateKeyType::BuiltIn, 3)); + code_dir.insert((tabled_rc!("false", atom_tbl), 0), (PredicateKeyType::BuiltIn, 61)); + code_dir.insert((tabled_rc!("\\+", atom_tbl), 1), (PredicateKeyType::BuiltIn, 62)); + code_dir.insert((tabled_rc!("duplicate_term", atom_tbl), 2), (PredicateKeyType::BuiltIn, 71)); + code_dir.insert((tabled_rc!("catch", atom_tbl), 3), (PredicateKeyType::BuiltIn, 5)); + code_dir.insert((tabled_rc!("throw", atom_tbl), 1), (PredicateKeyType::BuiltIn, 59)); + code_dir.insert((tabled_rc!("=", atom_tbl), 2), (PredicateKeyType::BuiltIn, 73)); + code_dir.insert((tabled_rc!("true", atom_tbl), 0), (PredicateKeyType::BuiltIn, 75)); - code_dir.insert((rc_atom!(","), 2), (PredicateKeyType::BuiltIn, 76)); - code_dir.insert((rc_atom!(";"), 2), (PredicateKeyType::BuiltIn, 120)); - code_dir.insert((rc_atom!("->"), 2), (PredicateKeyType::BuiltIn, 138)); + code_dir.insert((tabled_rc!(",", atom_tbl), 2), (PredicateKeyType::BuiltIn, 76)); + code_dir.insert((tabled_rc!(";", atom_tbl), 2), (PredicateKeyType::BuiltIn, 120)); + code_dir.insert((tabled_rc!("->", atom_tbl), 2), (PredicateKeyType::BuiltIn, 138)); - code_dir.insert((rc_atom!("functor"), 3), (PredicateKeyType::BuiltIn, 146)); - code_dir.insert((rc_atom!("arg"), 3), (PredicateKeyType::BuiltIn, 150)); - code_dir.insert((rc_atom!("integer"), 1), (PredicateKeyType::BuiltIn, 147)); + code_dir.insert((tabled_rc!("functor", atom_tbl), 3), (PredicateKeyType::BuiltIn, 146)); + code_dir.insert((tabled_rc!("arg", atom_tbl), 3), (PredicateKeyType::BuiltIn, 150)); + code_dir.insert((tabled_rc!("integer", atom_tbl), 1), (PredicateKeyType::BuiltIn, 147)); - code_dir.insert((rc_atom!("display"), 1), (PredicateKeyType::BuiltIn, 192)); + code_dir.insert((tabled_rc!("display", atom_tbl), 1), (PredicateKeyType::BuiltIn, 192)); (builtin_code, code_dir, op_dir) } diff --git a/src/prolog/heap_print.rs b/src/prolog/heap_print.rs index 9488d42a..89dc9a03 100644 --- a/src/prolog/heap_print.rs +++ b/src/prolog/heap_print.rs @@ -1,12 +1,13 @@ use prolog::ast::*; use prolog::heap_iter::*; +use prolog::tabled_rc::*; use std::cell::Cell; use std::rc::Rc; #[derive(Clone)] pub enum TokenOrRedirect { - Atom(Rc), + Atom(TabledRc), Redirect, Open, Close, @@ -20,7 +21,7 @@ pub enum TokenOrRedirect { pub trait HeapCellValueFormatter { // this function belongs to the display predicate formatter, which it uses // to format all clauses. - fn format_struct(&self, arity: usize, name: Rc, state_stack: &mut Vec) + fn format_struct(&self, arity: usize, name: TabledRc, state_stack: &mut Vec) { state_stack.push(TokenOrRedirect::Close); @@ -37,7 +38,7 @@ pub trait HeapCellValueFormatter { // this can be overloaded to handle special cases, falling back on the default of // format_struct when convenient. - fn format_clause(&self, usize, Rc, Option, &mut Vec); + fn format_clause(&self, usize, TabledRc, Option, &mut Vec); } pub trait HeapCellValueOutputter { @@ -94,7 +95,7 @@ impl HeapCellValueOutputter for PrinterOutputter { pub struct DisplayFormatter {} impl HeapCellValueFormatter for DisplayFormatter { - fn format_clause(&self, arity: usize, name: Rc, fixity: Option, + fn format_clause(&self, arity: usize, name: TabledRc, fixity: Option, state_stack: &mut Vec) { if fixity.is_some() { @@ -102,7 +103,7 @@ impl HeapCellValueFormatter for DisplayFormatter { new_name += name.as_ref(); new_name += "'"; - let name = Rc::new(new_name); + let name = TabledRc::new(new_name, name.table()); self.format_struct(arity, name, state_stack); } else { self.format_struct(arity, name, state_stack); @@ -113,7 +114,7 @@ impl HeapCellValueFormatter for DisplayFormatter { pub struct TermFormatter {} impl HeapCellValueFormatter for TermFormatter { - fn format_clause(&self, arity: usize, name: Rc, fixity: Option, + fn format_clause(&self, arity: usize, name: TabledRc, fixity: Option, state_stack: &mut Vec) { if let Some(fixity) = fixity { diff --git a/src/prolog/indexing.rs b/src/prolog/indexing.rs index b2b10afc..48a26d98 100644 --- a/src/prolog/indexing.rs +++ b/src/prolog/indexing.rs @@ -1,8 +1,8 @@ use prolog::ast::*; +use prolog::tabled_rc::*; use std::collections::{HashMap, VecDeque}; use std::hash::Hash; -use std::rc::Rc; #[derive(Clone, Copy)] enum IntIndex { @@ -12,7 +12,7 @@ enum IntIndex { pub struct CodeOffsets { pub constants: HashMap, pub lists: ThirdLevelIndex, - pub structures: HashMap<(Rc, usize), ThirdLevelIndex> + pub structures: HashMap<(TabledRc, usize), ThirdLevelIndex> } impl CodeOffsets { @@ -145,7 +145,7 @@ impl CodeOffsets { } } - fn switch_on_structure(str_ind: HashMap<(Rc, usize), ThirdLevelIndex>, + fn switch_on_structure(str_ind: HashMap<(TabledRc, usize), ThirdLevelIndex>, prelude: &mut CodeDeque) -> IntIndex { diff --git a/src/prolog/iterators.rs b/src/prolog/iterators.rs index 90701d49..fa5a9f56 100644 --- a/src/prolog/iterators.rs +++ b/src/prolog/iterators.rs @@ -54,7 +54,7 @@ impl<'a> QueryIterator<'a> { | &QueryTerm::Is(ref terms) => { let state = TermIterState::Clause(0, ClauseType::Is, terms); QueryIterator { state_stack: vec![state] } - }, + }, &QueryTerm::Inlined(InlinedQueryTerm::IsAtomic(ref terms)) | &QueryTerm::Inlined(InlinedQueryTerm::IsInteger(ref terms)) | &QueryTerm::Inlined(InlinedQueryTerm::IsVar(ref terms)) => diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index 2f0d0189..0bf516f2 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -8,6 +8,7 @@ use prolog::num::{Integer, ToPrimitive, Zero}; use prolog::num::bigint::{BigInt, BigUint}; use prolog::num::rational::Ratio; use prolog::or_stack::*; +use prolog::tabled_rc::*; use std::cmp::max; use std::ops::{Index, IndexMut}; @@ -172,6 +173,7 @@ pub(super) enum MachineMode { } pub struct MachineState { + pub(super) atom_tbl: TabledData, pub(super) s: usize, pub(super) p: CodePtr, pub(super) b: usize, @@ -194,8 +196,9 @@ pub struct MachineState { } impl MachineState { - pub(super) fn new() -> MachineState { - MachineState { s: 0, + pub(super) fn new(atom_tbl: TabledData) -> MachineState { + MachineState { atom_tbl, + s: 0, p: CodePtr::default(), b: 0, b0: 0, @@ -440,7 +443,8 @@ impl MachineState { }; } - fn get_number(&self, at: &ArithmeticTerm) -> Result> { + fn get_number(&self, at: &ArithmeticTerm) -> Result> { + match at { &ArithmeticTerm::Reg(r) => { let addr = self[r].clone(); @@ -448,7 +452,13 @@ impl MachineState { match item { Addr::Con(Constant::Number(n)) => Ok(n), - _ => Err(functor!("instantiation_error", 1, [atom!("(is)/2")])) + _ => { + let atom_tbl = self.atom_tbl.clone(); + Err(functor!(self.atom_tbl, + "instantiation_error", + 1, + [heap_atom!("(is)/2", atom_tbl)])) + } } }, &ArithmeticTerm::Interm(i) => Ok(self.interms[i-1].clone()), @@ -465,7 +475,10 @@ impl MachineState { if let Some(r) = Ratio::from_float(fl.into_inner()) { Ok(Rc::new(r)) } else { - Err(functor!("instantiation_error", 1, [atom!("(is)/2")])) + Err(functor!(self.atom_tbl, + "instantiation_error", + 1, + [heap_atom!("(is)/2", self.atom_tbl)])) }, Number::Integer(bi) => Ok(Rc::new(Ratio::from_integer((*bi).clone()))) @@ -514,9 +527,11 @@ impl MachineState { let r2 = try_or_fail!(self, self.get_rational(a2)); if *r2 == Ratio::zero() { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("zero_divisor")])); + [heap_atom!("zero_divisor", atom_tbl)])); return; } @@ -530,9 +545,11 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => { if *n2 == BigInt::zero() { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("zero_divisor")])); + [heap_atom!("zero_divisor", atom_tbl)])); return; } @@ -540,9 +557,11 @@ impl MachineState { self.p += 1; }, _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } } @@ -554,9 +573,11 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => { if *n2 == BigInt::zero() { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("zero_divisor")])); + [heap_atom!("zero_divisor", atom_tbl)])); return; } @@ -564,9 +585,11 @@ impl MachineState { self.p += 1; }, _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } } @@ -582,9 +605,11 @@ impl MachineState { let n2 = try_or_fail!(self, self.get_number(a2)); if n2.is_zero() { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("zero_divisor")])); + [heap_atom!("zero_divisor", atom_tbl)])); return; } @@ -602,9 +627,11 @@ impl MachineState { _ => self.interms[t - 1] = Number::Integer(Rc::new(&*n1 >> usize::max_value())) }, _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } } @@ -622,9 +649,11 @@ impl MachineState { _ => self.interms[t - 1] = Number::Integer(Rc::new(&*n1 << usize::max_value())) }, _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } } @@ -639,9 +668,11 @@ impl MachineState { (Number::Integer(n1), Number::Integer(n2)) => self.signed_bitwise_op(&*n1, &*n2, t, |u_n1, u_n2| u_n1 ^ u_n2), _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } }; @@ -656,9 +687,11 @@ impl MachineState { (Number::Integer(n1), Number::Integer(n2)) => self.signed_bitwise_op(&*n1, &*n2, t, |u_n1, u_n2| u_n1 & u_n2), _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } }; @@ -673,9 +706,11 @@ impl MachineState { (Number::Integer(n1), Number::Integer(n2)) => self.signed_bitwise_op(&*n1, &*n2, t, |u_n1, u_n2| u_n1 | u_n2), _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } }; @@ -689,18 +724,22 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => { if *n2 == BigInt::zero() { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("zero_divisor")])); + [heap_atom!("zero_divisor", atom_tbl)])); return; } self.interms[t - 1] = Number::Integer(Rc::new(n1.mod_floor(&n2))); }, _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } } @@ -714,18 +753,22 @@ impl MachineState { match (n1, n2) { (Number::Integer(n1), Number::Integer(n2)) => { if *n2 == BigInt::zero() { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("zero_divisor")])); + [heap_atom!("zero_divisor", atom_tbl)])); return; } self.interms[t - 1] = Number::Integer(Rc::new(&*n1 % &*n2)); }, _ => { - self.throw_exception(functor!("evaluation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "evaluation_error", 1, - [atom!("expected_integer_args")])); + [heap_atom!("expected_integer_args", atom_tbl)])); return; } } @@ -1041,7 +1084,7 @@ impl MachineState { } } - fn try_call_predicate(&mut self, code_dir: &CodeDir, name: Rc, arity: usize) + fn try_call_predicate(&mut self, code_dir: &CodeDir, name: TabledRc, arity: usize) { let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1); @@ -1056,7 +1099,7 @@ impl MachineState { }; } - fn try_execute_predicate(&mut self, code_dir: &CodeDir, name: Rc, arity: usize) + fn try_execute_predicate(&mut self, code_dir: &CodeDir, name: TabledRc, arity: usize) { let compiled_tl_index = code_dir.get(&(name, arity)).map(|index| index.1); @@ -1116,9 +1159,11 @@ impl MachineState { if let HeapCellValue::NamedStr(narity, name, _) = result { if narity + arity > 63 { - self.throw_exception(functor!("representation_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "representation_error", 1, - [atom!("exceeds_max_arity")])); + [heap_atom!("exceeds_max_arity", atom_tbl)])); return None; } @@ -1138,13 +1183,16 @@ impl MachineState { }, Addr::Con(Constant::Atom(name)) => (name, 0), Addr::HeapCell(_) | Addr::StackCell(_, _) => { - self.throw_exception(functor!("instantiation_error", 0, [])); + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, "instantiation_error", 0, [])); return None; }, _ => { - self.throw_exception(functor!("type_error", + let atom_tbl = self.atom_tbl.clone(); + self.throw_exception(functor!(atom_tbl, + "type_error", 2, - [atom!("callable"), + [heap_atom!("callable", atom_tbl), HeapCellValue::Addr(addr)])); return None; } @@ -1193,7 +1241,10 @@ impl MachineState { _ => self.fail = true }; } else { - return Err(functor!("type_error", 1, [atom!("compound_expected")])); + return Err(functor!(self.atom_tbl, + "type_error", + 1, + [heap_atom!("compound_expected", self.atom_tbl)])); } } @@ -1419,10 +1470,10 @@ impl MachineState { self.unify(a1, f_a); } else { - return Err(functor!("instantiation_error", 0, [])); + return Err(functor!(self.atom_tbl, "instantiation_error", 0, [])); } } else { - return Err(functor!("instantiation_error", 0, [])); + return Err(functor!(self.atom_tbl, "instantiation_error", 0, [])); } }, _ => { diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index e3128fe8..536c7ab0 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -3,10 +3,13 @@ use prolog::builtins::*; use prolog::codegen::*; use prolog::heap_print::*; use prolog::fixtures::*; +use prolog::tabled_rc::*; pub(crate) mod machine_state; -use std::collections::HashMap; +use std::cell::RefCell; +use std::collections::{HashMap, HashSet}; +use std::mem::swap; use std::ops::Index; use std::rc::Rc; use std::vec::Vec; @@ -37,13 +40,14 @@ impl Index for Machine { impl Machine { pub fn new() -> Self { - let (code, code_dir, op_dir) = build_code_dir(); + let atom_tbl = Rc::new(RefCell::new(HashSet::new())); + let (code, code_dir, op_dir) = build_code_dir(atom_tbl.clone()); Machine { - ms: machine_state::MachineState::new(), - code: code, - code_dir: code_dir, - op_dir: op_dir, + ms: machine_state::MachineState::new(atom_tbl), + code, + code_dir, + op_dir, cached_query: None } } @@ -52,7 +56,13 @@ impl Machine { self.ms.fail } - fn add_user_code<'a>(&mut self, name: Rc, arity: usize, offset: usize) -> EvalSession<'a> + pub fn atom_tbl(&self) -> TabledData { + self.ms.atom_tbl.clone() + } + + fn add_user_code<'a>(&mut self, name: TabledRc, + arity: usize, offset: usize) + -> EvalSession<'a> { match self.code_dir.get(&(name.clone(), arity)) { Some(&(PredicateKeyType::BuiltIn, _)) => @@ -369,9 +379,8 @@ impl Machine { } pub fn clear(&mut self) { - self.reset(); - self.code.clear(); - self.code_dir.clear(); + let mut machine = Machine::new(); + swap(self, &mut machine); } pub fn reset(&mut self) { diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 53cc2144..9d13ee21 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -1,3 +1,14 @@ +macro_rules! tabled_rc { + ($e:expr, $tbl:expr) => ( + TabledRc::new(String::from($e), $tbl.clone()) + ) +} + +macro_rules! atom { + ($e:expr, $tbl:expr) => ( + Constant::Atom(tabled_rc!($e, $tbl)) + ) +} macro_rules! internal_call_n { () => ( @@ -41,22 +52,25 @@ macro_rules! query { ) } +macro_rules! heap_atom { + ($name:expr, $tbl:expr) => ( + HeapCellValue::Addr(Addr::Con(atom!($name, $tbl))) + ) +} + macro_rules! functor { - ($name:expr, $len:expr, [$($args:expr),*]) => {{ + ($tbl:expr, $name:expr, $len:expr, [$($args:expr),*]) => {{ if $len > 0 { - vec![ HeapCellValue::NamedStr($len, Rc::new(String::from($name)), None), $($args),* ] + vec![ HeapCellValue::NamedStr($len, + tabled_rc!($name, $tbl), + None), + $($args),* ] } else { - vec![ atom!($name) ] + vec![ heap_atom!($name, $tbl) ] } }} } -macro_rules! atom { - ($name:expr) => ( - HeapCellValue::Addr(Addr::Con(Constant::Atom(Rc::new(String::from($name))))) - ) -} - macro_rules! fact { [$($x:expr),+] => ( Line::Fact(vec![$($x),+]) @@ -101,8 +115,8 @@ macro_rules! put_var { } macro_rules! put_structure { - ($lvl:expr, $name:expr, $arity:expr, $r:expr, $fix:expr) => ( - QueryInstruction::PutStructure($lvl, Rc::new($name), $arity, $r, $fix) + ($tbl:expr, $lvl:expr, $name:expr, $arity:expr, $r:expr, $fix:expr) => ( + QueryInstruction::PutStructure($lvl, tabled_rc!($name, $tbl), $arity, $r, $fix) ) } @@ -317,8 +331,12 @@ macro_rules! get_constant { } macro_rules! get_structure { - ($atom:expr, $arity:expr, $r:expr, $fix:expr) => ( - FactInstruction::GetStructure(Level::Shallow, Rc::new($atom), $arity, $r, $fix) + ($tbl:expr, $atom:expr, $arity:expr, $r:expr, $fix:expr) => ( + FactInstruction::GetStructure(Level::Shallow, + tabled_rc!($atom, $tbl), + $arity, + $r, + $fix) ) } diff --git a/src/prolog/mod.rs b/src/prolog/mod.rs index ad5c1b82..0eaa1d9c 100644 --- a/src/prolog/mod.rs +++ b/src/prolog/mod.rs @@ -22,3 +22,4 @@ pub mod machine; pub mod or_stack; pub mod parser; pub mod targets; +pub mod tabled_rc; diff --git a/src/prolog/parser b/src/prolog/parser index dcf51680..3b1dd579 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit dcf51680fb2f030ad2dcdd77237c8faedc8f7107 +Subproject commit 3b1dd579b411a440cc4b475471231fb6f9f2ada9 diff --git a/src/prolog/tabled_rc.rs b/src/prolog/tabled_rc.rs index e16386c7..70bebcb2 100644 --- a/src/prolog/tabled_rc.rs +++ b/src/prolog/tabled_rc.rs @@ -2,15 +2,15 @@ use std::cell::RefCell; use std::collections::HashSet; use std::fmt; use std::hash::{Hash, Hasher}; -use std::ops::{Deref, DerefMut}; +use std::ops::Deref; use std::rc::Rc; -pub type TabledData = HashSet>; +pub type TabledData = Rc>>>; #[derive(Clone, PartialEq, Eq)] pub struct TabledRc { atom: Rc, - table: Rc>> + table: TabledData } impl Hash for TabledRc { @@ -21,16 +21,26 @@ impl Hash for TabledRc { } impl TabledRc { - pub fn new(atom: T, table: Rc>>) -> Self { - TabledRc { atom: Rc::new(atom), table } + pub fn new(atom: T, table: TabledData) -> Self { + let atom = match table.borrow_mut().take(&atom) { + Some(atom) => atom.clone(), + None => Rc::new(atom) + }; + + table.borrow_mut().insert(atom.clone()); + + TabledRc { atom, table } + } + + pub fn table(&self) -> TabledData { + self.table.clone() } } impl Drop for TabledRc { fn drop(&mut self) { if Rc::strong_count(&self.atom) == 2 { - let mut table = self.table.borrow_mut(); - table.deref_mut().remove(&self.atom); + self.table.borrow_mut().remove(&self.atom); } } } diff --git a/src/prolog/targets.rs b/src/prolog/targets.rs index 852094c1..783c502e 100644 --- a/src/prolog/targets.rs +++ b/src/prolog/targets.rs @@ -1,7 +1,6 @@ use prolog::ast::*; use prolog::iterators::*; - -use std::rc::Rc; +use prolog::tabled_rc::*; pub trait CompilationTarget<'a> { type Iterator : Iterator>; @@ -10,7 +9,7 @@ pub trait CompilationTarget<'a> { fn to_constant(Level, Constant, RegType) -> Self; fn to_list(Level, RegType) -> Self; - fn to_structure(Level, Rc, usize, RegType, Option) -> Self; + fn to_structure(Level, TabledRc, usize, RegType, Option) -> Self; fn to_void(usize) -> Self; fn is_void_instr(&self) -> bool; @@ -41,7 +40,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { FactInstruction::GetConstant(lvl, constant, reg) } - fn to_structure(lvl: Level, atom: Rc, arity: usize, reg: RegType, fixity: Option) + fn to_structure(lvl: Level, atom: TabledRc, arity: usize, + reg: RegType, fixity: Option) -> Self { FactInstruction::GetStructure(lvl, atom, arity, reg, fixity) @@ -105,7 +105,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { term.post_order_iter() } - fn to_structure(lvl: Level, atom: Rc, arity: usize, reg: RegType, fixity: Option) + fn to_structure(lvl: Level, atom: TabledRc, arity: usize, + reg: RegType, fixity: Option) -> Self { QueryInstruction::PutStructure(lvl, atom, arity, reg, fixity) diff --git a/src/test_utils.rs b/src/test_utils.rs index 744d0167..56d8f889 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -74,7 +74,7 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa mut heap_locs: HeapVarDict<'a>, limit: usize) -> HashSet { - let mut output = TestOutputter::new(); + let mut output = TestOutputter::new(); output = wam.heap_view(&heap_locs, output); let mut count = 1; @@ -82,9 +82,9 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa if count == limit { return output.result(); } - + while let EvalSession::SubsequentQuerySuccess = wam.continue_query(&alloc_locs, &mut heap_locs) - { + { output = wam.heap_view(&heap_locs, output); count += 1; @@ -97,11 +97,12 @@ pub fn collect_test_output_with_limit<'a>(wam: &mut Machine, alloc_locs: AllocVa output.result() } +#[allow(dead_code)] pub fn submit(wam: &mut Machine, buffer: &str) -> bool { wam.reset(); - match parse_code(buffer.trim(), wam.op_dir()) { + match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) { Ok(tl) => match eval(wam, &tl) { EvalSession::InitialQuerySuccess(_, _) | @@ -114,11 +115,12 @@ pub fn submit(wam: &mut Machine, buffer: &str) -> bool } } +#[allow(dead_code)] pub fn submit_query(wam: &mut Machine, buffer: &str, result: HashSet) -> bool { wam.reset(); - match parse_code(buffer.trim(), wam.op_dir()) { + match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) { Ok(tl) => match eval(wam, &tl) { EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) => @@ -130,13 +132,14 @@ pub fn submit_query(wam: &mut Machine, buffer: &str, result: HashSet) -> } } +#[allow(dead_code)] pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str, result: HashSet, limit: usize) -> bool { wam.reset(); - match parse_code(buffer.trim(), wam.op_dir()) { + match parse_code(buffer.trim(), wam.atom_tbl(), wam.op_dir()) { Ok(tl) => match eval(wam, &tl) { EvalSession::InitialQuerySuccess(alloc_locs, heap_locs) => @@ -149,24 +152,28 @@ pub fn submit_query_with_limit(wam: &mut Machine, buffer: &str, } } +#[allow(unused_macros)] macro_rules! expand_strs { ($arr:expr) => ( $arr.into_iter().map(|s| String::from(*s)).collect() ) } +#[allow(unused_macros)] macro_rules! assert_prolog_success_with_limit { ($wam:expr, $buf:expr, $res:expr, $limit:expr) => ( assert!(submit_query_with_limit($wam, $buf, expand_strs!($res), $limit)) ) } +#[allow(unused_macros)] macro_rules! assert_prolog_failure { ($wam: expr, $buf: expr) => ( assert_eq!(submit($wam, $buf), false) ) } +#[allow(unused_macros)] macro_rules! assert_prolog_success { ($wam:expr, $query:expr, $res:expr) => ( assert!(submit_query($wam, $query, expand_strs!($res)))