Revert "remove Term"
This reverts commit 3b5879841aedecba5057c70c71da0ba23e5cd84a.
This commit is contained in:
@@ -3,17 +3,13 @@ use crate::codegen::CodeGenSettings;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::disjuncts::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::CodeIndex;
|
||||
use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl {
|
||||
OpDecl::new(OpDesc::build_with(prec, spec), name)
|
||||
@@ -25,47 +21,43 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result<OpDeclSpec, CompilationError
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
|
||||
let (focus, _cell) = subterm_index(term.heap, term.focus);
|
||||
|
||||
let name = match term_predicate_key(term.heap, focus + 3) {
|
||||
Some((name, 0)) => name,
|
||||
_ => {
|
||||
fn setup_op_decl(mut terms: Vec<Term>) -> Result<OpDecl, CompilationError> {
|
||||
// should allow non-partial lists?
|
||||
let name = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
other => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclNameType(term.heap[focus + 3]),
|
||||
DirectiveError::InvalidOpDeclNameType(other),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let spec = match term_predicate_key(term.heap, focus + 2) {
|
||||
Some((name, _)) => name,
|
||||
None => {
|
||||
let spec = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
other => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus + 2]),
|
||||
));
|
||||
DirectiveError::InvalidOpDeclSpecDomain(other),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let spec = to_op_decl_spec(spec)?;
|
||||
let prec = term.deref_loc(focus + 1);
|
||||
|
||||
let prec = read_heap_cell!(prec,
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
match u16::try_from(n.get_num()) {
|
||||
Ok(n) if n <= 1200 => n,
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclPrecDomain(n),
|
||||
));
|
||||
}
|
||||
let prec = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
|
||||
Ok(n) if n <= 1200 => n,
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclPrecDomain(bi),
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
},
|
||||
other => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidOpDeclPrecType(prec),
|
||||
DirectiveError::InvalidOpDeclPrecType(other),
|
||||
));
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
if name == "[]" || name == "{}" {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
@@ -88,162 +80,129 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
|
||||
Ok(to_op_decl(prec, spec, name))
|
||||
}
|
||||
|
||||
fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> {
|
||||
let key_opt = term_predicate_key(term.heap, term.focus);
|
||||
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(_, slash, ref mut terms)
|
||||
if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
|
||||
{
|
||||
let arity = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
|
||||
if let Some((atom!("/") | atom!("//"), 2)) = key_opt {
|
||||
let arity_loc = term.nth_arg(term.focus, 2).unwrap();
|
||||
|
||||
let arity = match Number::try_from(term.deref_loc(arity_loc)) {
|
||||
Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
|
||||
Ok(Number::Integer(n)) => (&*n).try_into().ok(),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
let name_loc = term.nth_arg(term.focus, 1).unwrap();
|
||||
let name = term_predicate_key(term.heap, name_loc)
|
||||
.map(|(name, _)| name)
|
||||
let arity = match arity {
|
||||
Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
|
||||
Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
if matches!(key_opt, Some((atom!("/"), _))) {
|
||||
Ok((name, arity))
|
||||
} else {
|
||||
Ok((name, arity + 2))
|
||||
let name = match name {
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
if *slash == atom!("/") {
|
||||
Ok((name, arity))
|
||||
} else {
|
||||
Ok((name, arity + 2))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleExport)
|
||||
_ => Err(CompilationError::InvalidModuleExport),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, CompilationError> {
|
||||
setup_predicate_indicator(term)
|
||||
fn setup_module_export(mut term: Term) -> Result<ModuleExport, CompilationError> {
|
||||
setup_predicate_indicator(&mut term)
|
||||
.map(ModuleExport::PredicateKey)
|
||||
.or_else(|_| {
|
||||
let key_opt = term_predicate_key(term.heap, term.focus);
|
||||
|
||||
if let Some((atom!("op"), 3)) = key_opt {
|
||||
Ok(ModuleExport::OpDecl(setup_op_decl(term)?))
|
||||
if let Term::Clause(_, name, terms) = term {
|
||||
if terms.len() == 3 && name == atom!("op") {
|
||||
Ok(ModuleExport::OpDecl(setup_op_decl(terms)?))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/* TODO: should be unnecessary now.
|
||||
|
||||
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec());
|
||||
let rule = vec![head_term, body_term];
|
||||
|
||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||
}
|
||||
*/
|
||||
|
||||
pub(super) fn setup_module_export_list(
|
||||
term: FocusedHeapRefMut,
|
||||
mut export_list: Term,
|
||||
) -> Result<Vec<ModuleExport>, CompilationError> {
|
||||
let mut exports = vec![];
|
||||
let mut focus = term.focus;
|
||||
|
||||
loop {
|
||||
read_heap_cell!(term.heap[focus],
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h == focus {
|
||||
break;
|
||||
} else {
|
||||
focus = h;
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Lis, l) => {
|
||||
let term = FocusedHeapRefMut {
|
||||
heap: term.heap,
|
||||
focus: l,
|
||||
};
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
let module_export = setup_module_export(*t1)?;
|
||||
|
||||
exports.push(setup_module_export(&term)?);
|
||||
focus = l + 1;
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||
if name == atom!("[]") {
|
||||
return Ok(exports);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
);
|
||||
exports.push(module_export);
|
||||
export_list = *t2;
|
||||
}
|
||||
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
|
||||
Ok(exports)
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> {
|
||||
let name = term_predicate_key(term.heap, term.focus + 1)
|
||||
.map(|(name, _)| name)
|
||||
.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||
fn setup_module_decl(mut terms: Vec<Term>) -> Result<ModuleDecl, CompilationError> {
|
||||
let export_list = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
|
||||
term.focus = term.focus + 2;
|
||||
let exports = setup_module_export_list(term)?;
|
||||
let name = match name {
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(name),
|
||||
_ => None,
|
||||
}
|
||||
.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||
|
||||
let exports = setup_module_export_list(export_list)?;
|
||||
Ok(ModuleDecl { name, exports })
|
||||
}
|
||||
|
||||
fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result<ModuleSource, CompilationError> {
|
||||
read_heap_cell!(term.deref_loc(term.focus+1),
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
|
||||
|
||||
if (name, arity) == (atom!("library"), 1) {
|
||||
read_heap_cell!(term.deref_loc(s+1),
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
return Ok(ModuleSource::Library(name));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return Err(CompilationError::InvalidModuleDecl);
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
Ok(ModuleSource::File(name))
|
||||
} else {
|
||||
Err(CompilationError::InvalidUseModuleDecl)
|
||||
fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
|
||||
_ => Err(CompilationError::InvalidModuleDecl),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(CompilationError::InvalidUseModuleDecl)
|
||||
}
|
||||
)
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
|
||||
_ => Err(CompilationError::InvalidUseModuleDecl),
|
||||
}
|
||||
}
|
||||
|
||||
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
|
||||
|
||||
fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, CompilationError> {
|
||||
let module_src = setup_use_module_decl(&term)?;
|
||||
fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, CompilationError> {
|
||||
let mut export_list = terms.pop().unwrap();
|
||||
let module_src = match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
|
||||
_ => Err(CompilationError::InvalidModuleDecl),
|
||||
}
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
|
||||
_ => Err(CompilationError::InvalidUseModuleDecl),
|
||||
}?;
|
||||
|
||||
let mut exports = IndexSet::new();
|
||||
|
||||
let mut focus = term.focus + 2;
|
||||
|
||||
while let HeapCellValueTag::Lis = term.heap[focus].get_tag() {
|
||||
focus = term.heap[focus].get_value() as usize;
|
||||
|
||||
let term = FocusedHeapRefMut {
|
||||
heap: term.heap,
|
||||
focus,
|
||||
};
|
||||
|
||||
exports.insert(setup_module_export(&term)?);
|
||||
focus = focus + 1;
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
exports.insert(setup_module_export(*t1)?);
|
||||
export_list = *t2;
|
||||
}
|
||||
|
||||
if term.heap[focus] == empty_list_as_cell!() {
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
|
||||
Ok((module_src, exports))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
@@ -290,20 +249,18 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, Co
|
||||
*/
|
||||
|
||||
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
term: TermWriteResult,
|
||||
mut terms: Vec<Term>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
|
||||
fn get_meta_specs(
|
||||
term: FocusedHeapRefMut,
|
||||
arity: usize,
|
||||
) -> Result<Vec<MetaSpec>, CompilationError> {
|
||||
fn get_name_and_meta_specs(
|
||||
name: Atom,
|
||||
terms: &mut [Term],
|
||||
) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
|
||||
let mut meta_specs = vec![];
|
||||
|
||||
for meta_spec_loc in term.focus + 1..term.focus + arity + 1 {
|
||||
read_heap_cell!(term.deref_loc(meta_spec_loc),
|
||||
(HeapCellValueTag::Atom, (meta_spec, arity)) => {
|
||||
debug_assert_eq!(arity, 0);
|
||||
|
||||
for meta_spec in terms.iter_mut() {
|
||||
match meta_spec {
|
||||
Term::Literal(_, Literal::Atom(meta_spec)) => {
|
||||
let meta_spec = match meta_spec {
|
||||
atom!("+") => MetaSpec::Plus,
|
||||
atom!("-") => MetaSpec::Minus,
|
||||
@@ -314,322 +271,263 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
|
||||
meta_specs.push(meta_spec);
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
match usize::try_from(n.get_num()) {
|
||||
Ok(n) if n <= MAX_ARITY => {
|
||||
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
|
||||
Ok(n) if n <= MAX_ARITY => {
|
||||
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(meta_specs)
|
||||
Ok((name, meta_specs))
|
||||
}
|
||||
|
||||
let heap = loader.machine_heap();
|
||||
let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus + 1]));
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
|
||||
let spec = terms.pop().unwrap();
|
||||
let module_name = terms.pop().unwrap();
|
||||
|
||||
read_heap_cell!(cell,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
|
||||
|
||||
match (name, arity) {
|
||||
(atom!(":"), 2) => {
|
||||
let module_name = heap[s+1];
|
||||
let spec = heap[s+2];
|
||||
|
||||
read_heap_cell!(module_name,
|
||||
(HeapCellValueTag::Atom, (module_name, arity)) => {
|
||||
if arity == 0 {
|
||||
read_heap_cell!(spec,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
let term = FocusedHeapRefMut { heap, focus: s };
|
||||
return Ok((module_name, name, get_meta_specs(term, arity)?));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return Err(CompilationError::InvalidMetaPredicateDecl);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let term = FocusedHeapRefMut { heap, focus: s };
|
||||
let specs = get_meta_specs(term, arity)?;
|
||||
let module_name = loader.payload.compilation_target.module_name();
|
||||
|
||||
return Ok((module_name, name, specs));
|
||||
}
|
||||
match module_name {
|
||||
Term::Literal(_, Literal::Atom(module_name)) => match spec {
|
||||
Term::Clause(_, name, mut terms) => {
|
||||
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
|
||||
Ok((module_name, name, meta_specs))
|
||||
}
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
},
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
}
|
||||
|
||||
Err(CompilationError::InvalidMetaPredicateDecl)
|
||||
}
|
||||
_ => {
|
||||
Err(CompilationError::InvalidMetaPredicateDecl)
|
||||
Term::Clause(_, name, mut terms) => {
|
||||
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
|
||||
Ok((
|
||||
loader.payload.compilation_target.module_name(),
|
||||
name,
|
||||
meta_specs,
|
||||
))
|
||||
}
|
||||
)
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
mut term: TermWriteResult,
|
||||
mut terms: Vec<Term>,
|
||||
) -> Result<Declaration, CompilationError> {
|
||||
let mut focus = term.focus;
|
||||
let machine_st = LS::machine_st(&mut loader.payload);
|
||||
let term = terms.pop().unwrap();
|
||||
|
||||
loop {
|
||||
let decl = machine_st.heap[focus];
|
||||
|
||||
read_heap_cell!(decl,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus);
|
||||
|
||||
return match (name, arity) {
|
||||
(atom!("dynamic"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&focused)?;
|
||||
Ok(Declaration::Dynamic(name, arity))
|
||||
}
|
||||
(atom!("module"), 2) => {
|
||||
Ok(Declaration::Module(setup_module_decl(focused)?))
|
||||
}
|
||||
(atom!("op"), 3) => {
|
||||
Ok(Declaration::Op(setup_op_decl(&focused)?))
|
||||
}
|
||||
(atom!("non_counted_backtracking"), 1) => {
|
||||
focused.focus = focused.nth_arg(focused.focus, 1).unwrap();
|
||||
let (name, arity) = setup_predicate_indicator(&focused)?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
}
|
||||
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)),
|
||||
(atom!("use_module"), 2) => {
|
||||
let (name, exports) = setup_qualified_import(focused)?;
|
||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||
}
|
||||
(atom!("meta_predicate"), 1) => {
|
||||
term.focus = focus;
|
||||
let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?;
|
||||
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
|
||||
}
|
||||
_ => Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidDirective(name, arity)
|
||||
))
|
||||
};
|
||||
match term {
|
||||
Term::Clause(_, name, mut terms) => match (name, terms.len()) {
|
||||
(atom!("dynamic"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||
Ok(Declaration::Dynamic(name, arity))
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
focus = s;
|
||||
(atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)),
|
||||
(atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)),
|
||||
(atom!("non_counted_backtracking"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if focus != h {
|
||||
focus = h;
|
||||
} else {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::ExpectedDirective(decl),
|
||||
));
|
||||
}
|
||||
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
||||
(atom!("use_module"), 2) => {
|
||||
let (name, exports) = setup_qualified_import(terms)?;
|
||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::ExpectedDirective(decl),
|
||||
));
|
||||
(atom!("meta_predicate"), 1) => {
|
||||
let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
|
||||
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
|
||||
}
|
||||
);
|
||||
_ => Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::InvalidDirective(name, terms.len()),
|
||||
)),
|
||||
},
|
||||
other => Err(CompilationError::InvalidDirective(
|
||||
DirectiveError::ExpectedDirective(other),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
module_name: Atom,
|
||||
arity: usize,
|
||||
term: &TermWriteResult,
|
||||
terms: Vec<Term>,
|
||||
meta_specs: Vec<MetaSpec>,
|
||||
) -> IndexMap<usize, CodeIndex, FxBuildHasher> {
|
||||
use crate::machine::heap::Heap;
|
||||
let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
|
||||
) -> Vec<Term> {
|
||||
let mut arg_terms = Vec::with_capacity(terms.len());
|
||||
|
||||
let focus = {
|
||||
let heap = loader.machine_heap();
|
||||
let focus_cell =
|
||||
heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(term.focus)));
|
||||
|
||||
if focus_cell.get_tag() == HeapCellValueTag::Str {
|
||||
focus_cell.get_value() as usize
|
||||
} else {
|
||||
return index_ptrs;
|
||||
}
|
||||
};
|
||||
|
||||
for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) {
|
||||
for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
|
||||
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
|
||||
let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
|
||||
|
||||
if let Some((name, arity)) = predicate_key_opt {
|
||||
if let Some(name) = term.name() {
|
||||
if name == atom!("$call") {
|
||||
arg_terms.push(term);
|
||||
continue;
|
||||
}
|
||||
|
||||
struct QualifiedNameInfo {
|
||||
module_name: Atom,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
qualified_term_loc: usize,
|
||||
}
|
||||
let arity = term.arity();
|
||||
|
||||
fn get_qualified_name(
|
||||
heap: &Heap,
|
||||
module_term_loc: usize,
|
||||
qualified_term_loc: usize,
|
||||
) -> Option<QualifiedNameInfo> {
|
||||
let (module_term_loc, _) = subterm_index(heap, module_term_loc);
|
||||
let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc);
|
||||
|
||||
read_heap_cell!(heap[module_term_loc],
|
||||
(HeapCellValueTag::Atom, (module_name, arity)) => {
|
||||
if arity == 0 {
|
||||
if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) {
|
||||
return Some(QualifiedNameInfo {
|
||||
module_name,
|
||||
name,
|
||||
arity,
|
||||
qualified_term_loc,
|
||||
});
|
||||
}
|
||||
}
|
||||
module_term: &Term,
|
||||
qualified_term: &Term,
|
||||
) -> Option<(Atom, Atom)> {
|
||||
if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
|
||||
if let Some(name) = qualified_term.name() {
|
||||
return Some((*module_name, name));
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc);
|
||||
let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
|
||||
fn identity_fn(_module_name: Atom, term: Term) -> Term {
|
||||
term
|
||||
}
|
||||
|
||||
let (module_name, key, term_loc) = if subterm_key_opt == Some((atom!(":"), 2)) {
|
||||
match get_qualified_name(
|
||||
loader.machine_heap(),
|
||||
subterm_loc + 1,
|
||||
subterm_loc + 2,
|
||||
) {
|
||||
Some(QualifiedNameInfo {
|
||||
module_name,
|
||||
name,
|
||||
arity,
|
||||
qualified_term_loc,
|
||||
}) => (module_name, (name, arity + supp_args), qualified_term_loc),
|
||||
None => {
|
||||
fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
|
||||
Term::Clause(
|
||||
Cell::default(),
|
||||
atom!(":"),
|
||||
vec![
|
||||
Term::Literal(Cell::default(), Literal::Atom(module_name)),
|
||||
term,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
let process_term: fn(Atom, Term) -> Term;
|
||||
|
||||
let (module_name, key, term) = match term {
|
||||
Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
|
||||
if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1])
|
||||
{
|
||||
process_term = tag_with_module_name;
|
||||
(
|
||||
module_name,
|
||||
(name, terms[1].arity() + supp_args),
|
||||
terms.pop().unwrap(),
|
||||
)
|
||||
} else {
|
||||
arg_terms.push(Term::Clause(cell, atom!(":"), terms));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(module_name, (name, arity + supp_args), subterm_loc)
|
||||
term => {
|
||||
process_term = identity_fn;
|
||||
(module_name, (name, arity + supp_args), term)
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) {
|
||||
index_ptrs.insert(term_loc, index_ptr);
|
||||
continue;
|
||||
}
|
||||
let term = match term {
|
||||
Term::Clause(cell, name, mut terms) => {
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
arg_terms
|
||||
.push(process_term(module_name, Term::Clause(cell, name, terms)));
|
||||
|
||||
index_ptrs.insert(
|
||||
term_loc,
|
||||
loader.get_or_insert_qualified_code_index(module_name, key),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||
|
||||
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
|
||||
process_term(module_name, Term::Clause(cell, name, terms))
|
||||
}
|
||||
Term::Literal(cell, Literal::Atom(name)) => {
|
||||
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
|
||||
|
||||
process_term(
|
||||
module_name,
|
||||
Term::Clause(
|
||||
cell,
|
||||
name,
|
||||
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
|
||||
),
|
||||
)
|
||||
}
|
||||
term => term,
|
||||
};
|
||||
|
||||
arg_terms.push(term);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
arg_terms.push(term);
|
||||
}
|
||||
|
||||
index_ptrs
|
||||
arg_terms
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
key: PredicateKey,
|
||||
terms: &TermWriteResult,
|
||||
term: HeapCellValue,
|
||||
name: Atom,
|
||||
mut terms: Vec<Term>,
|
||||
call_policy: CallPolicy,
|
||||
) -> QueryClause {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
blunt_index_ptr(loader.machine_heap(), key, terms.focus);
|
||||
) -> QueryTerm {
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
terms.pop();
|
||||
}
|
||||
|
||||
let mut ct = loader.get_clause_type(key.0, key.1);
|
||||
let mut ct = loader.get_clause_type(name, terms.len());
|
||||
|
||||
if let ClauseType::Named(arity, name, idx) = ct {
|
||||
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
|
||||
let module_name = loader.payload.compilation_target.module_name();
|
||||
let code_indices =
|
||||
build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs);
|
||||
let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
|
||||
|
||||
return QueryClause {
|
||||
ct: ClauseType::Named(key.1, key.0, idx),
|
||||
term,
|
||||
code_indices,
|
||||
return QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::Named(arity, name, idx),
|
||||
terms,
|
||||
call_policy,
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
ct = ClauseType::Named(key.1, key.0, idx);
|
||||
ct = ClauseType::Named(arity, name, idx);
|
||||
}
|
||||
|
||||
QueryClause {
|
||||
ct,
|
||||
term,
|
||||
code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
call_policy,
|
||||
}
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
key: PredicateKey,
|
||||
module_name: Atom,
|
||||
terms: &TermWriteResult,
|
||||
term: HeapCellValue,
|
||||
name: Atom,
|
||||
mut terms: Vec<Term>,
|
||||
call_policy: CallPolicy,
|
||||
) -> QueryClause {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
blunt_index_ptr(loader.machine_heap(), key, terms.focus);
|
||||
) -> QueryTerm {
|
||||
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
|
||||
// supplementary code vector indices are unnecessary for
|
||||
// root-level clauses.
|
||||
terms.pop();
|
||||
}
|
||||
|
||||
let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1);
|
||||
let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
|
||||
|
||||
if let ClauseType::Named(arity, name, idx) = ct {
|
||||
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
|
||||
let code_indices =
|
||||
build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
|
||||
let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
|
||||
|
||||
return QueryClause {
|
||||
ct: ClauseType::Named(key.1, key.0, idx),
|
||||
term,
|
||||
code_indices,
|
||||
return QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::Named(arity, name, idx),
|
||||
terms,
|
||||
call_policy,
|
||||
};
|
||||
);
|
||||
}
|
||||
|
||||
ct = ClauseType::Named(key.1, key.0, idx);
|
||||
ct = ClauseType::Named(arity, name, idx);
|
||||
}
|
||||
|
||||
QueryClause {
|
||||
ct,
|
||||
term,
|
||||
code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
call_policy,
|
||||
}
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -642,66 +540,70 @@ impl Preprocessor {
|
||||
Preprocessor { settings }
|
||||
}
|
||||
|
||||
pub fn setup_fact<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: TermWriteResult,
|
||||
) -> Result<(Fact, VarData), CompilationError> {
|
||||
let heap = loader.machine_heap();
|
||||
fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
|
||||
let classifier = VariableClassifier::new(self.settings.default_call_policy());
|
||||
|
||||
if term_predicate_key(heap, term.focus).is_some() {
|
||||
let classifier = VariableClassifier::new(self.settings.default_call_policy());
|
||||
let var_data = classifier.classify_fact(loader, &term)?;
|
||||
|
||||
Ok((
|
||||
Fact {
|
||||
term_loc: term.focus,
|
||||
},
|
||||
var_data,
|
||||
))
|
||||
} else {
|
||||
Err(CompilationError::InadmissibleFact)
|
||||
let (head, var_data) = classifier.classify_fact(term)?;
|
||||
Ok((Fact { head }, var_data))
|
||||
}
|
||||
_ => Err(CompilationError::InadmissibleFact),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_rule<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: TermWriteResult,
|
||||
head: Term,
|
||||
body: Term,
|
||||
) -> Result<(Rule, VarData), CompilationError> {
|
||||
let classifier = VariableClassifier::new(self.settings.default_call_policy());
|
||||
let (clauses, var_data) = classifier.classify_rule(loader, &term)?;
|
||||
|
||||
let heap = loader.machine_heap();
|
||||
let head_loc = term_nth_arg(heap, term.focus, 1).unwrap();
|
||||
let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
|
||||
|
||||
if term_predicate_key(heap, head_loc).is_some() {
|
||||
Ok((
|
||||
match head {
|
||||
Term::Clause(_, name, terms) => Ok((
|
||||
Rule {
|
||||
term_loc: term.focus,
|
||||
head: (name, terms),
|
||||
clauses,
|
||||
},
|
||||
var_data,
|
||||
))
|
||||
} else {
|
||||
Err(CompilationError::InvalidRuleHead)
|
||||
)),
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok((
|
||||
Rule {
|
||||
head: (name, vec![]),
|
||||
clauses,
|
||||
},
|
||||
var_data,
|
||||
)),
|
||||
_ => Err(CompilationError::InvalidRuleHead),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: TermWriteResult,
|
||||
term: Term,
|
||||
) -> Result<PredicateClause, CompilationError> {
|
||||
let heap = &LS::machine_st(&mut loader.payload).heap;
|
||||
match term {
|
||||
Term::Clause(r, name, mut terms) => {
|
||||
let is_rule = name == atom!(":-") && terms.len() == 2;
|
||||
|
||||
match term_predicate_key(heap, term.focus) {
|
||||
Some((atom!(":-"), 2)) => {
|
||||
let (rule, var_data) = self.setup_rule(loader, term)?;
|
||||
Ok(PredicateClause::Rule(rule, var_data))
|
||||
if is_rule {
|
||||
let tail = terms.pop().unwrap();
|
||||
let head = terms.pop().unwrap();
|
||||
|
||||
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
|
||||
Ok(PredicateClause::Rule(rule, var_data))
|
||||
} else {
|
||||
let term = Term::Clause(r, name, terms);
|
||||
let (fact, var_data) = self.setup_fact(term)?;
|
||||
Ok(PredicateClause::Fact(fact, var_data))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let (fact, var_data) = self.setup_fact(loader, term)?;
|
||||
term => {
|
||||
let (fact, var_data) = self.setup_fact(term)?;
|
||||
Ok(PredicateClause::Fact(fact, var_data))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user