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_).
* 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).
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 {
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,

View 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)
}

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>
{
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);

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