From d9340344fff2cee0fa7a19cab336fb0e634736c1 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Wed, 6 Sep 2017 18:11:43 -0600 Subject: [PATCH] finalize operator support. --- README.md | 18 +++++++++++++++--- src/prolog/ast.rs | 12 +++++++++++- src/prolog/builtins.rs | 17 ++++++++++++----- src/prolog/io.rs | 2 ++ src/prolog/machine.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/prolog/macros.rs | 7 +++++++ src/prolog/parser | 2 +- 7 files changed, 89 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f4977fa4..dab78e7e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Extend rusty-wam to include the following, among other features: * call/N as a built-in meta-predicate (_done_). * ISO Prolog compliant throw/catch (_done_). * Built-in and user-defined operators of all fixities, with custom - associativity and precedence (_in progress_). + associativity and precedence (_done_). * Bignum and floating point arithmetic. * Built-in control operators (`,`, `;`, `->`, etc.). * Attributed variables using the SICStus Prolog interface and @@ -51,7 +51,7 @@ The following predicates are built-in to rusty-wam. * catch/3 * duplicate_term/2 * false/0 -* not/1 +* (\+)/1 * throw/1 * var/1 @@ -124,4 +124,16 @@ X = call(f, z). 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 (`X = _0` in an example above). \ No newline at end of file +a number preceded by an underscore (`X = _0` in an example above). + +Lastly, rusty-wam supports dynamic operators: +``` +prolog> :- op(500, yfx, +). +prolog> :- op(500, yfx, -). +prolog> :- op(200, fy, -). +prolog> :- op(400, yfx, *). +prolog> :- op(400, yfx, /). +prolog> ?- X = -5 + 3 - (2 * 4) / 8. +true. +X = -(+(-(5), 3), /(*(2, 4), 8)). +``` \ No newline at end of file diff --git a/src/prolog/ast.rs b/src/prolog/ast.rs index 7a8bdbe4..8edb881a 100644 --- a/src/prolog/ast.rs +++ b/src/prolog/ast.rs @@ -60,7 +60,12 @@ impl PredicateClause { } } +pub enum Declaration { + Op(usize, Specifier, Atom) +} + pub enum TopLevel { + Declaration(Declaration), Fact(Term), Predicate(Vec), Query(Vec), @@ -144,6 +149,10 @@ macro_rules! is_op { ($x:expr) => ( $x & (XF | YF | FX | FY | XFX | XFY | YFX) != 0 ) } +macro_rules! is_postfix { + ($x:expr) => ( $x & (XF | YF) != 0 ) +} + macro_rules! is_infix { ($x:expr) => ( ($x & (XFX | XFY | YFX)) != 0 ) } @@ -196,7 +205,8 @@ pub enum ParserError InadmissibleFact, InadmissibleQueryTerm, IncompleteReduction, - InconsistentPredicate, + InconsistentDeclaration, + InconsistentPredicate, ParseBigInt, ParseFloat(ParseFloatError), // TokenTooLong, diff --git a/src/prolog/builtins.rs b/src/prolog/builtins.rs index 8814f048..d7918594 100644 --- a/src/prolog/builtins.rs +++ b/src/prolog/builtins.rs @@ -101,7 +101,10 @@ fn get_builtins() -> Code { trust_me!(), proceed!(), duplicate_term!(), // duplicate_term/2, 71. - proceed!()] + proceed!(), + fact![get_value!(temp_v!(1), 2)], // =/2, 73. + proceed!(), + ] } pub fn build_code_dir() -> (Code, CodeDir, OpDir) @@ -111,9 +114,12 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir) let builtin_code = get_builtins(); - op_dir.insert((String::from(":-"), Fixity::In), (XFX, 1200)); - op_dir.insert((String::from("?-"), Fixity::Pre), (FX, 1200)); - + op_dir.insert((String::from(":-"), Fixity::In), (XFX, 1200)); + op_dir.insert((String::from(":-"), Fixity::Pre), (FX, 1200)); + op_dir.insert((String::from("?-"), Fixity::Pre), (FX, 1200)); + op_dir.insert((String::from("\\+"), Fixity::Pre), (FY, 900)); + op_dir.insert((String::from("="), Fixity::In), (XFX, 700)); + // 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 { @@ -123,10 +129,11 @@ pub fn build_code_dir() -> (Code, CodeDir, OpDir) code_dir.insert((String::from("atomic"), 1), (PredicateKeyType::BuiltIn, 1)); code_dir.insert((String::from("var"), 1), (PredicateKeyType::BuiltIn, 3)); code_dir.insert((String::from("false"), 0), (PredicateKeyType::BuiltIn, 61)); - code_dir.insert((String::from("not"), 1), (PredicateKeyType::BuiltIn, 62)); + code_dir.insert((String::from("\\+"), 1), (PredicateKeyType::BuiltIn, 62)); code_dir.insert((String::from("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71)); code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5)); code_dir.insert((String::from("throw"), 1), (PredicateKeyType::BuiltIn, 59)); + code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73)); (builtin_code, code_dir, op_dir) } diff --git a/src/prolog/io.rs b/src/prolog/io.rs index df6f73f6..cb005a04 100644 --- a/src/prolog/io.rs +++ b/src/prolog/io.rs @@ -250,6 +250,8 @@ pub fn read() -> String { pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b> { match tl { + &TopLevel::Declaration(ref decl) => + wam.submit_decl(decl), &TopLevel::Predicate(ref clauses) => { let mut cg = CodeGenerator::::new(); let compiled_pred = cg.compile_predicate(clauses); diff --git a/src/prolog/machine.rs b/src/prolog/machine.rs index 223ac206..6c235647 100644 --- a/src/prolog/machine.rs +++ b/src/prolog/machine.rs @@ -439,6 +439,47 @@ impl Machine { } } + pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a> { + match decl { + &Declaration::Op(prec, spec, ref name) => { + lazy_static! { + static ref ERR_STRING: String = String::from("an operator can't be both \ + infix and postfix."); + } + + if is_infix!(spec) { + match self.op_dir.get(&(name.clone(), Fixity::Post)) { + Some(_) => return EvalSession::EntryFailure(ERR_STRING.clone()), + _ => {} + }; + } + + if is_postfix!(spec) { + match self.op_dir.get(&(name.clone(), Fixity::In)) { + Some(_) => return EvalSession::EntryFailure(ERR_STRING.clone()), + _ => {} + }; + } + + if prec > 0 { + match spec { + XFY | XFX | YFX => self.op_dir.insert((name.clone(), Fixity::In), + (spec, prec)), + XF | YF => self.op_dir.insert((name.clone(), Fixity::Post), (spec, prec)), + FX | FY => self.op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)), + _ => None + }; + } else { + self.op_dir.remove(&(name.clone(), Fixity::Pre)); + self.op_dir.remove(&(name.clone(), Fixity::In)); + self.op_dir.remove(&(name.clone(), Fixity::Post)); + } + + EvalSession::EntrySuccess + } + } + } + pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a> { let mut heap_locs = HashMap::new(); diff --git a/src/prolog/macros.rs b/src/prolog/macros.rs index 2686cb63..8ac0f386 100644 --- a/src/prolog/macros.rs +++ b/src/prolog/macros.rs @@ -62,6 +62,13 @@ macro_rules! get_var_in_query { ) } + +macro_rules! get_value { + ($r:expr, $arg:expr) => ( + FactInstruction::GetValue($r, $arg) + ) +} + macro_rules! get_var_in_fact { ($r:expr, $arg:expr) => ( FactInstruction::GetVariable($r, $arg) diff --git a/src/prolog/parser b/src/prolog/parser index de2a1a73..b7a8133b 160000 --- a/src/prolog/parser +++ b/src/prolog/parser @@ -1 +1 @@ -Subproject commit de2a1a73649e2c52a05d19ff33f08c33c22b3973 +Subproject commit b7a8133b75f0a7d5b7e29c1f4edf18cae4f8c56f -- 2.54.0