]> Repositorios git - scryer-prolog.git/commitdiff
finalize operator support.
authorMark Thom <[email protected]>
Thu, 7 Sep 2017 00:11:43 +0000 (18:11 -0600)
committerMark Thom <[email protected]>
Thu, 7 Sep 2017 00:11:43 +0000 (18:11 -0600)
README.md
src/prolog/ast.rs
src/prolog/builtins.rs
src/prolog/io.rs
src/prolog/machine.rs
src/prolog/macros.rs
src/prolog/parser

index f4977fa4e85af76e4a427cf54be845ff9c1d0047..dab78e7e868e9200737280c75c2a9be8e586a74e 100644 (file)
--- 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
index 7a8bdbe4aa534041775ee39bd855bb55990acc38..8edb881ad6c617eb1ee6ce20a7dc6152b21071a2 100644 (file)
@@ -60,7 +60,12 @@ impl PredicateClause {
     }
 }
 
+pub enum Declaration {
+    Op(usize, Specifier, Atom)
+}
+
 pub enum TopLevel {
+    Declaration(Declaration),
     Fact(Term),
     Predicate(Vec<PredicateClause>),
     Query(Vec<QueryTerm>),
@@ -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,
index 8814f048aada9031a995e7660d3e5d4a27c6a27d..d791859417bb3f801214e8d65d348cbf6fe717b1 100644 (file)
@@ -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)
 }
index df6f73f6d9329056c5e05f496d19af1958e084f5..cb005a04a20b2852fc704bbe345273bcf071722a 100644 (file)
@@ -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::<DebrayAllocator>::new();
             let compiled_pred = cg.compile_predicate(clauses);
index 223ac2064d1dc7b62886254ca3217fa79f5dc534..6c235647a91d1a69beedf62fe0f067ff72845109 100644 (file)
@@ -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();
index 2686cb63c0d0572d7491c67085b688a851d9b467..8ac0f3861c41d3c5a9a1e79b0cf042b47fdcd700 100644 (file)
@@ -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)
index de2a1a73649e2c52a05d19ff33f08c33c22b3973..b7a8133b75f0a7d5b7e29c1f4edf18cae4f8c56f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit de2a1a73649e2c52a05d19ff33f08c33c22b3973
+Subproject commit b7a8133b75f0a7d5b7e29c1f4edf18cae4f8c56f