finalize operator support.

This commit is contained in:
Mark Thom
2017-09-06 18:11:43 -06:00
parent 92de7acd22
commit d9340344ff
7 changed files with 89 additions and 10 deletions

View File

@@ -18,7 +18,7 @@ Extend rusty-wam to include the following, among other features:
* call/N as a built-in meta-predicate (_done_). * call/N as a built-in meta-predicate (_done_).
* ISO Prolog compliant throw/catch (_done_). * ISO Prolog compliant throw/catch (_done_).
* Built-in and user-defined operators of all fixities, with custom * 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. * Bignum and floating point arithmetic.
* Built-in control operators (`,`, `;`, `->`, etc.). * Built-in control operators (`,`, `;`, `->`, etc.).
* Attributed variables using the SICStus Prolog interface and * Attributed variables using the SICStus Prolog interface and
@@ -51,7 +51,7 @@ The following predicates are built-in to rusty-wam.
* catch/3 * catch/3
* duplicate_term/2 * duplicate_term/2
* false/0 * false/0
* not/1 * (\+)/1
* throw/1 * throw/1
* var/1 * var/1
@@ -124,4 +124,16 @@ X = call(f, z).
Note that the values of variables belonging to successful queries are Note that the values of variables belonging to successful queries are
printed out, on one line each. Uninstantiated variables are denoted by printed out, on one line each. Uninstantiated variables are denoted by
a number preceded by an underscore (`X = _0` in an example above). 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)).
```

View File

@@ -60,7 +60,12 @@ impl PredicateClause {
} }
} }
pub enum Declaration {
Op(usize, Specifier, Atom)
}
pub enum TopLevel { pub enum TopLevel {
Declaration(Declaration),
Fact(Term), Fact(Term),
Predicate(Vec<PredicateClause>), Predicate(Vec<PredicateClause>),
Query(Vec<QueryTerm>), Query(Vec<QueryTerm>),
@@ -144,6 +149,10 @@ macro_rules! is_op {
($x:expr) => ( $x & (XF | YF | FX | FY | XFX | XFY | YFX) != 0 ) ($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 { macro_rules! is_infix {
($x:expr) => ( ($x & (XFX | XFY | YFX)) != 0 ) ($x:expr) => ( ($x & (XFX | XFY | YFX)) != 0 )
} }
@@ -196,7 +205,8 @@ pub enum ParserError
InadmissibleFact, InadmissibleFact,
InadmissibleQueryTerm, InadmissibleQueryTerm,
IncompleteReduction, IncompleteReduction,
InconsistentPredicate, InconsistentDeclaration,
InconsistentPredicate,
ParseBigInt, ParseBigInt,
ParseFloat(ParseFloatError), ParseFloat(ParseFloatError),
// TokenTooLong, // TokenTooLong,

View File

@@ -101,7 +101,10 @@ fn get_builtins() -> Code {
trust_me!(), trust_me!(),
proceed!(), proceed!(),
duplicate_term!(), // duplicate_term/2, 71. 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) 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(); let builtin_code = get_builtins();
op_dir.insert((String::from(":-"), Fixity::In), (XFX, 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), (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 // 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) // (an extra register is needed for the predicate name)
for arity in 0 .. 63 { 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("atomic"), 1), (PredicateKeyType::BuiltIn, 1));
code_dir.insert((String::from("var"), 1), (PredicateKeyType::BuiltIn, 3)); 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("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("duplicate_term"), 2), (PredicateKeyType::BuiltIn, 71));
code_dir.insert((String::from("catch"), 3), (PredicateKeyType::BuiltIn, 5)); 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("throw"), 1), (PredicateKeyType::BuiltIn, 59));
code_dir.insert((String::from("="), 2), (PredicateKeyType::BuiltIn, 73));
(builtin_code, code_dir, op_dir) (builtin_code, code_dir, op_dir)
} }

View File

@@ -250,6 +250,8 @@ pub fn read() -> String {
pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b> pub fn eval<'a, 'b: 'a>(wam: &'a mut Machine, tl: &'b TopLevel) -> EvalSession<'b>
{ {
match tl { match tl {
&TopLevel::Declaration(ref decl) =>
wam.submit_decl(decl),
&TopLevel::Predicate(ref clauses) => { &TopLevel::Predicate(ref clauses) => {
let mut cg = CodeGenerator::<DebrayAllocator>::new(); let mut cg = CodeGenerator::<DebrayAllocator>::new();
let compiled_pred = cg.compile_predicate(clauses); let compiled_pred = cg.compile_predicate(clauses);

View 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> pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
{ {
let mut heap_locs = HashMap::new(); let mut heap_locs = HashMap::new();

View 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 { macro_rules! get_var_in_fact {
($r:expr, $arg:expr) => ( ($r:expr, $arg:expr) => (
FactInstruction::GetVariable($r, $arg) FactInstruction::GetVariable($r, $arg)