remove vestigial prolog/ directory (#444)
This commit is contained in:
1209
src/machine/arithmetic_ops.rs
Normal file
1209
src/machine/arithmetic_ops.rs
Normal file
File diff suppressed because it is too large
Load Diff
52
src/machine/attributed_variables.pl
Normal file
52
src/machine/attributed_variables.pl
Normal file
@@ -0,0 +1,52 @@
|
||||
:- module('$atts', []).
|
||||
|
||||
driver(Vars, Values) :-
|
||||
iterate(Vars, Values, ListOfListsOfGoalLists),
|
||||
!,
|
||||
call_goals(ListOfListsOfGoalLists),
|
||||
'$return_from_verify_attr'.
|
||||
|
||||
iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]) :-
|
||||
'$get_attr_list'(Var, Ls),
|
||||
call_verify_attributes(Ls, Var, Value, ListOfGoalLists),
|
||||
'$redo_attr_var_binding'(Var, Value),
|
||||
iterate(VarBindings, ValueBindings, ListsCubed).
|
||||
iterate([], [], []).
|
||||
|
||||
gather_modules(Attrs, []) :- var(Attrs), !.
|
||||
gather_modules([Attr|Attrs], [Module|Modules]) :-
|
||||
'$module_of'(Module, Attr), % write the owning module of Attr to Module.
|
||||
gather_modules(Attrs, Modules).
|
||||
|
||||
call_verify_attributes(Attrs, _, _, []) :-
|
||||
var(Attrs), !.
|
||||
call_verify_attributes([], _, _, []).
|
||||
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
||||
gather_modules([Attr|Attrs], Modules0),
|
||||
sort(Modules0, Modules),
|
||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||
|
||||
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
|
||||
catch(Module:verify_attributes(Var, Value, Goals),
|
||||
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
|
||||
Goals = []),
|
||||
verify_attrs(Modules, Var, Value, ListOfGoalLists).
|
||||
verify_attrs([], _, _, []).
|
||||
|
||||
call_goals([ListOfGoalLists | ListsCubed]) :-
|
||||
call_goals_0(ListOfGoalLists),
|
||||
call_goals(ListsCubed).
|
||||
call_goals([]).
|
||||
|
||||
call_goals_0([GoalList | GoalLists]) :-
|
||||
( var(GoalList), throw(error(instantiation_error, call_goals_0/1))
|
||||
; true
|
||||
),
|
||||
call_goals_1(GoalList),
|
||||
call_goals_0(GoalLists).
|
||||
call_goals_0([]).
|
||||
|
||||
call_goals_1([Goal | Goals]) :-
|
||||
call(Goal),
|
||||
call_goals_1(Goals).
|
||||
call_goals_1([]).
|
||||
176
src/machine/attributed_variables.rs
Normal file
176
src/machine/attributed_variables.rs
Normal file
@@ -0,0 +1,176 @@
|
||||
use crate::heap_iter::*;
|
||||
use crate::machine::*;
|
||||
|
||||
use crate::indexmap::IndexSet;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
|
||||
pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl");
|
||||
|
||||
pub(super) type Bindings = Vec<(usize, Addr)>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AttrVarInitializer {
|
||||
pub(super) attribute_goals: Vec<Addr>,
|
||||
pub(super) attr_var_queue: Vec<usize>,
|
||||
pub(super) bindings: Bindings,
|
||||
pub(super) cp: LocalCodePtr,
|
||||
pub(super) instigating_p: LocalCodePtr,
|
||||
pub(super) verify_attrs_loc: usize,
|
||||
pub(super) project_attrs_loc: usize,
|
||||
}
|
||||
|
||||
impl AttrVarInitializer {
|
||||
pub(super)
|
||||
fn new(verify_attrs_loc: usize, project_attrs_loc: usize) -> Self {
|
||||
AttrVarInitializer {
|
||||
attribute_goals: vec![],
|
||||
attr_var_queue: vec![],
|
||||
bindings: vec![],
|
||||
instigating_p: LocalCodePtr::default(),
|
||||
cp: LocalCodePtr::default(),
|
||||
verify_attrs_loc,
|
||||
project_attrs_loc,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn reset(&mut self) {
|
||||
self.attribute_goals.clear();
|
||||
self.attr_var_queue.clear();
|
||||
self.bindings.clear();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn backtrack(&mut self, queue_b: usize, bindings_b: usize) {
|
||||
self.attr_var_queue.truncate(queue_b);
|
||||
self.bindings.truncate(bindings_b);
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super)
|
||||
fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
||||
if self.attr_var_init.bindings.is_empty() {
|
||||
self.attr_var_init.instigating_p = self.p.local();
|
||||
|
||||
if self.last_call {
|
||||
self.attr_var_init.cp = self.cp;
|
||||
} else {
|
||||
self.attr_var_init.cp = self.p.local() + 1;
|
||||
}
|
||||
|
||||
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
|
||||
}
|
||||
|
||||
self.attr_var_init.bindings.push((h, addr));
|
||||
}
|
||||
|
||||
fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) {
|
||||
let iter = self
|
||||
.attr_var_init
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
|
||||
|
||||
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||
|
||||
let iter = self
|
||||
.attr_var_init
|
||||
.bindings
|
||||
.drain(0 ..)
|
||||
.map(|(_, addr)| HeapCellValue::Addr(addr));
|
||||
|
||||
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||
(var_list_addr, value_list_addr)
|
||||
}
|
||||
|
||||
fn verify_attributes(&mut self) {
|
||||
for (h, _) in &self.attr_var_init.bindings {
|
||||
self.heap[*h] = HeapCellValue::Addr(Addr::AttrVar(*h));
|
||||
}
|
||||
|
||||
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
|
||||
|
||||
self[temp_v!(1)] = var_list_addr;
|
||||
self[temp_v!(2)] = value_list_addr;
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn gather_attr_vars_created_since(&self, b: usize) -> IntoIter<Addr> {
|
||||
let mut attr_vars: Vec<_> = self.attr_var_init.attr_var_queue[b..]
|
||||
.iter()
|
||||
.filter_map(|h| match self.store(self.deref(Addr::HeapCell(*h))) {
|
||||
Addr::AttrVar(h) => Some(Addr::AttrVar(h)),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
attr_vars.sort_unstable_by(|a1, a2| {
|
||||
self.compare_term_test(a1, a2).unwrap_or(Ordering::Less)
|
||||
});
|
||||
|
||||
self.term_dedup(&mut attr_vars);
|
||||
attr_vars.into_iter()
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn verify_attr_interrupt(&mut self, p: usize) {
|
||||
self.allocate(self.num_of_args + 2);
|
||||
|
||||
let e = self.e;
|
||||
self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
|
||||
|
||||
for i in 1 .. self.num_of_args + 1 {
|
||||
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone();
|
||||
}
|
||||
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
|
||||
Addr::CutPoint(self.b0);
|
||||
self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
|
||||
Addr::Usize(self.num_of_args);
|
||||
|
||||
self.verify_attributes();
|
||||
|
||||
self.num_of_args = 2;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
|
||||
let mut seen_set = IndexSet::new();
|
||||
let mut seen_vars = vec![];
|
||||
|
||||
let mut iter = self.acyclic_pre_order_iter(addr);
|
||||
|
||||
while let Some(addr) = iter.next() {
|
||||
if let HeapCellValue::Addr(Addr::AttrVar(h)) = self.heap.index_addr(&addr).as_ref() {
|
||||
if seen_set.contains(h) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen_vars.push(addr);
|
||||
seen_set.insert(*h);
|
||||
|
||||
let mut l = h + 1;
|
||||
let mut list_elements = vec![];
|
||||
|
||||
while let Addr::Lis(elem) = self.store(self.deref(Addr::HeapCell(l))) {
|
||||
list_elements.push(self.heap[elem].as_addr(elem));
|
||||
l = elem + 1;
|
||||
}
|
||||
|
||||
for element in list_elements.into_iter().rev() {
|
||||
iter.stack().push(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
seen_vars
|
||||
}
|
||||
}
|
||||
177
src/machine/code_repo.rs
Normal file
177
src/machine/code_repo.rs
Normal file
@@ -0,0 +1,177 @@
|
||||
use crate::clause_types::*;
|
||||
use crate::codegen::*;
|
||||
use crate::debray_allocator::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::compile::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
use crate::indexmap::IndexSet;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::mem;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CodeRepo {
|
||||
pub(super) cached_query: Code,
|
||||
pub(super) goal_expanders: Code,
|
||||
pub(super) term_expanders: Code,
|
||||
pub(super) code: Code,
|
||||
pub(super) in_situ_code: Code,
|
||||
pub(super) term_dir: TermDir,
|
||||
}
|
||||
|
||||
impl CodeRepo {
|
||||
#[inline]
|
||||
pub(super) fn new() -> Self {
|
||||
CodeRepo {
|
||||
cached_query: vec![],
|
||||
goal_expanders: Code::new(),
|
||||
term_expanders: Code::new(),
|
||||
code: Code::new(),
|
||||
in_situ_code: Code::new(),
|
||||
term_dir: TermDir::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) {
|
||||
self.term_dir
|
||||
.get(&key)
|
||||
.map(|entry| ((entry.0).0.len(), entry.1.len()))
|
||||
.unwrap_or((0, 0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn truncate_terms(
|
||||
&mut self,
|
||||
key: PredicateKey,
|
||||
len: usize,
|
||||
queue_len: usize,
|
||||
) -> (Predicate, VecDeque<TopLevel>) {
|
||||
self.term_dir
|
||||
.get_mut(&key)
|
||||
.map(|entry| {
|
||||
let terms =
|
||||
if len < (entry.0).0.len() {
|
||||
(entry.0).0.drain(len ..).collect()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let queue =
|
||||
if queue_len < entry.1.len() {
|
||||
entry.1.drain(queue_len ..).collect()
|
||||
} else {
|
||||
VecDeque::new()
|
||||
};
|
||||
|
||||
(Predicate(terms), queue)
|
||||
})
|
||||
.unwrap_or((Predicate::new(), VecDeque::new()))
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn add_in_situ_result(
|
||||
&mut self,
|
||||
result: &CompiledResult,
|
||||
in_situ_code_dir: &mut InSituCodeDir,
|
||||
in_situ_module_dir: &mut ModuleStubDir,
|
||||
non_counted_bt_preds: &IndexSet<PredicateKey>,
|
||||
) -> Result<(), SessionError> {
|
||||
let (ref decl, ref queue) = result;
|
||||
let (name, arity) = decl
|
||||
.0
|
||||
.first()
|
||||
.and_then(|cl| {
|
||||
let arity = cl.arity();
|
||||
cl.name().map(|name| (name, arity))
|
||||
})
|
||||
.ok_or(SessionError::NamelessEntry)?;
|
||||
|
||||
let non_counted_bt = non_counted_bt_preds.contains(&(name.clone(), arity));
|
||||
let module_name = name.owning_module();
|
||||
|
||||
let p = self.in_situ_code.len();
|
||||
|
||||
match in_situ_module_dir.get_mut(&module_name) {
|
||||
Some(ref mut module_stub) if name.has_table(&module_stub.atom_tbl) => {
|
||||
module_stub.in_situ_code_dir.insert((name, arity), p);
|
||||
}
|
||||
_ => {
|
||||
in_situ_code_dir.insert((name, arity), p);
|
||||
}
|
||||
}
|
||||
|
||||
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
|
||||
let mut decl_code = cg.compile_predicate(&decl.0)?;
|
||||
|
||||
compile_appendix(&mut decl_code, queue, non_counted_bt)?;
|
||||
|
||||
Ok(self.in_situ_code.extend(decl_code.into_iter()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn size_of_cached_query(&self) -> usize {
|
||||
self.cached_query.len()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn take_in_situ_code(&mut self) -> Code {
|
||||
mem::replace(&mut self.in_situ_code, Code::new())
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn lookup_instr<'a>(
|
||||
&'a self,
|
||||
last_call: bool,
|
||||
p: &CodePtr,
|
||||
) -> Option<RefOrOwned<'a, Line>> {
|
||||
match p {
|
||||
&CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) => {
|
||||
if p < self.goal_expanders.len() {
|
||||
Some(RefOrOwned::Borrowed(&self.goal_expanders[p]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
&CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) => {
|
||||
if p < self.term_expanders.len() {
|
||||
Some(RefOrOwned::Borrowed(&self.term_expanders[p]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
&CodePtr::Local(LocalCodePtr::TopLevel(_, p)) => {
|
||||
if p < self.cached_query.len() {
|
||||
Some(RefOrOwned::Borrowed(&self.cached_query[p]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
&CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) => {
|
||||
Some(RefOrOwned::Borrowed(&self.in_situ_code[p]))
|
||||
}
|
||||
&CodePtr::Local(LocalCodePtr::DirEntry(p)) => Some(RefOrOwned::Borrowed(&self.code[p])),
|
||||
&CodePtr::REPL(..) => None,
|
||||
&CodePtr::BuiltInClause(ref built_in, _) => {
|
||||
let call_clause = call_clause!(
|
||||
ClauseType::BuiltIn(built_in.clone()),
|
||||
built_in.arity(),
|
||||
0,
|
||||
last_call
|
||||
);
|
||||
Some(RefOrOwned::Owned(call_clause))
|
||||
}
|
||||
&CodePtr::CallN(arity, _, last_call) => {
|
||||
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
|
||||
Some(RefOrOwned::Owned(call_clause))
|
||||
}
|
||||
&CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])),
|
||||
&CodePtr::DynamicTransaction(..) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
81
src/machine/code_walker.rs
Normal file
81
src/machine/code_walker.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
use crate::instructions::*;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
fn scan_for_trust_me(code: &Code, jmp_offsets: &mut VecDeque<usize>, after_idx: &mut usize) {
|
||||
for (idx, instr) in code[*after_idx..].iter().enumerate() {
|
||||
match instr {
|
||||
&Line::Choice(ChoiceInstruction::TrustMe)
|
||||
| &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
|
||||
*after_idx += idx;
|
||||
return;
|
||||
}
|
||||
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
|
||||
jmp_offsets.push_back(*after_idx + idx + offset)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
|
||||
loop {
|
||||
match &code[*last_idx] {
|
||||
&Line::Choice(ChoiceInstruction::TryMeElse(..))
|
||||
| &Line::IndexedChoice(IndexedChoiceInstruction::Try(..)) => {
|
||||
*last_idx += 1;
|
||||
scan_for_trust_me(code, queue, last_idx);
|
||||
}
|
||||
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
|
||||
queue.push_back(*last_idx + offset);
|
||||
*last_idx += 1;
|
||||
}
|
||||
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
|
||||
queue.push_back(*last_idx + offset);
|
||||
break;
|
||||
}
|
||||
&Line::Control(ControlInstruction::Proceed)
|
||||
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) =>
|
||||
break,
|
||||
_ =>
|
||||
*last_idx += 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/* This function walks the code of a single predicate, supposed to
|
||||
* begin in code at the offset p. Each instruction is passed to the
|
||||
* walker function.
|
||||
*/
|
||||
pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
|
||||
{
|
||||
let mut queue = VecDeque::from(vec![p]);
|
||||
|
||||
while let Some(first_idx) = queue.pop_front() {
|
||||
let mut last_idx = first_idx;
|
||||
|
||||
capture_next_range(code, &mut queue, &mut last_idx);
|
||||
|
||||
for instr in &code[first_idx .. last_idx + 1] {
|
||||
walker(instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* A function for code walking that might result in modification to
|
||||
* the code. Otherwise identical to walk_code.
|
||||
*/
|
||||
pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
|
||||
{
|
||||
let mut queue = VecDeque::from(vec![p]);
|
||||
|
||||
while let Some(first_idx) = queue.pop_front() {
|
||||
let mut last_idx = first_idx;
|
||||
|
||||
capture_next_range(code, &mut queue, &mut last_idx);
|
||||
|
||||
for instr in &mut code[first_idx .. last_idx + 1] {
|
||||
walker(instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
1459
src/machine/compile.rs
Normal file
1459
src/machine/compile.rs
Normal file
File diff suppressed because it is too large
Load Diff
314
src/machine/copier.rs
Normal file
314
src/machine/copier.rs
Normal file
@@ -0,0 +1,314 @@
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::stack::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::IndexMut;
|
||||
|
||||
type Trail = Vec<(Ref, HeapCellValue)>;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AttrVarPolicy {
|
||||
DeepCopy,
|
||||
StripAttributes
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||
fn deref(&self, val: Addr) -> Addr;
|
||||
fn push(&mut self, val: HeapCellValue);
|
||||
fn stack(&mut self) -> &mut Stack;
|
||||
fn store(&self, val: Addr) -> Addr;
|
||||
fn threshold(&self) -> usize;
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn copy_term<T: CopierTarget>(target: T, addr: Addr, attr_var_policy: AttrVarPolicy) {
|
||||
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
||||
copy_term_state.copy_term_impl(addr);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CopyTermState<T: CopierTarget> {
|
||||
trail: Trail,
|
||||
scan: usize,
|
||||
old_h: usize,
|
||||
target: T,
|
||||
attr_var_policy: AttrVarPolicy,
|
||||
}
|
||||
|
||||
impl<T: CopierTarget> CopyTermState<T> {
|
||||
fn new(target: T, attr_var_policy: AttrVarPolicy) -> Self {
|
||||
CopyTermState {
|
||||
trail: Trail::new(),
|
||||
scan: 0,
|
||||
old_h: target.threshold(),
|
||||
target,
|
||||
attr_var_policy
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn value_at_scan(&mut self) -> &mut HeapCellValue {
|
||||
let scan = self.scan;
|
||||
&mut self.target[scan]
|
||||
}
|
||||
|
||||
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
HeapCellValue::Addr(Addr::Lis(threshold)),
|
||||
);
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
trail_item,
|
||||
));
|
||||
}
|
||||
|
||||
fn copy_list(&mut self, addr: usize) {
|
||||
for offset in 0 .. 2 {
|
||||
if let Addr::Lis(h) = self.target[addr + offset].as_addr(addr + offset) {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(h));
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
|
||||
|
||||
for i in 0 .. 2 {
|
||||
let hcv = self.target[addr + i].context_free_clone();
|
||||
self.target.push(hcv);
|
||||
}
|
||||
|
||||
let cdr = self.target.store(self.target.deref(Addr::HeapCell(addr + 1)));
|
||||
|
||||
if !cdr.is_ref() {
|
||||
self.trail_list_cell(addr + 1, threshold);
|
||||
} else {
|
||||
let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
|
||||
|
||||
if !car.is_ref() {
|
||||
self.trail_list_cell(addr, threshold);
|
||||
}
|
||||
}
|
||||
|
||||
self.scan += 1;
|
||||
}
|
||||
|
||||
fn copy_partial_string(&mut self, addr: usize, n: usize) {
|
||||
if let &HeapCellValue::Addr(Addr::PStrLocation(h, _)) = &self.target[addr] {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(h, 0));
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() =
|
||||
HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
|
||||
|
||||
self.scan += 1;
|
||||
|
||||
let (pstr, has_tail) =
|
||||
match &self.target[addr] {
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
(pstr.clone_from_offset(n), has_tail)
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
self.target.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||
|
||||
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, 0));
|
||||
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
replacement,
|
||||
);
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
trail_item,
|
||||
));
|
||||
|
||||
if has_tail {
|
||||
let tail_addr = self.target[addr + 1].as_addr(addr + 1);
|
||||
self.target.push(HeapCellValue::Addr(tail_addr));
|
||||
}
|
||||
}
|
||||
|
||||
fn reinstantiate_var(&mut self, addr: Addr, frontier: usize) {
|
||||
match addr {
|
||||
Addr::HeapCell(h) => {
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(h),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h)),
|
||||
));
|
||||
}
|
||||
Addr::StackCell(fr, sc) => {
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(frontier));
|
||||
self.target.stack().index_and_frame_mut(fr)[sc] = Addr::HeapCell(frontier);
|
||||
|
||||
self.trail.push((
|
||||
Ref::StackCell(fr, sc),
|
||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
||||
));
|
||||
}
|
||||
Addr::AttrVar(h) => {
|
||||
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||
self.target.threshold()
|
||||
} else {
|
||||
frontier
|
||||
};
|
||||
|
||||
self.target[frontier] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||
self.target[h] = HeapCellValue::Addr(Addr::HeapCell(threshold));
|
||||
|
||||
self.trail.push((
|
||||
Ref::AttrVar(h),
|
||||
HeapCellValue::Addr(Addr::AttrVar(h)),
|
||||
));
|
||||
|
||||
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||
self.target.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
|
||||
|
||||
let list_val = self.target[h + 1].context_free_clone();
|
||||
self.target.push(list_val);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_var(&mut self, addr: Addr) {
|
||||
let rd = self.target.store(self.target.deref(addr));
|
||||
|
||||
match rd {
|
||||
Addr::AttrVar(h) | Addr::HeapCell(h) if h >= self.old_h => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||
self.scan += 1;
|
||||
}
|
||||
_ if addr == rd => {
|
||||
self.reinstantiate_var(addr, self.scan);
|
||||
self.scan += 1;
|
||||
}
|
||||
_ => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_structure(&mut self, addr: usize) {
|
||||
match self.target[addr].context_free_clone() {
|
||||
HeapCellValue::NamedStr(arity, name, fixity) => {
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
|
||||
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
HeapCellValue::Addr(Addr::Str(threshold)),
|
||||
);
|
||||
|
||||
self.trail.push((
|
||||
Ref::HeapCell(addr),
|
||||
trail_item,
|
||||
));
|
||||
|
||||
self.target.push(HeapCellValue::NamedStr(arity, name, fixity));
|
||||
|
||||
for i in 0..arity {
|
||||
let hcv = self.target[addr + 1 + i].context_free_clone();
|
||||
self.target.push(hcv);
|
||||
}
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Str(addr)) => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
self.scan += 1;
|
||||
}
|
||||
|
||||
fn copy_term_impl(&mut self, addr: Addr) {
|
||||
self.scan = self.target.threshold();
|
||||
self.target.push(HeapCellValue::Addr(addr));
|
||||
|
||||
while self.scan < self.target.threshold() {
|
||||
match self.value_at_scan() {
|
||||
&mut HeapCellValue::Addr(addr) => {
|
||||
match addr {
|
||||
Addr::Con(h) => {
|
||||
let addr = self.target[h].as_addr(h);
|
||||
|
||||
if addr == Addr::Con(h) {
|
||||
*self.value_at_scan() = self.target[h].context_free_clone();
|
||||
} else {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(addr);
|
||||
}
|
||||
}
|
||||
Addr::Lis(h) => {
|
||||
if h >= self.old_h {
|
||||
self.scan += 1;
|
||||
} else {
|
||||
self.copy_list(h);
|
||||
}
|
||||
}
|
||||
addr @ Addr::AttrVar(_) |
|
||||
addr @ Addr::HeapCell(_) |
|
||||
addr @ Addr::StackCell(..) => {
|
||||
self.copy_var(addr);
|
||||
}
|
||||
Addr::Str(addr) => {
|
||||
self.copy_structure(addr);
|
||||
}
|
||||
Addr::PStrLocation(addr, n) => {
|
||||
self.copy_partial_string(addr, n);
|
||||
}
|
||||
Addr::Stream(h) => {
|
||||
*self.value_at_scan() = self.target[h].context_free_clone();
|
||||
}
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.unwind_trail();
|
||||
}
|
||||
|
||||
fn unwind_trail(&mut self) {
|
||||
for (r, value) in self.trail.drain(0..) {
|
||||
match r {
|
||||
Ref::AttrVar(h) | Ref::HeapCell(h) =>
|
||||
self.target[h] = value,
|
||||
Ref::StackCell(fr, sc) =>
|
||||
self.target.stack().index_and_frame_mut(fr)[sc] = value.as_addr(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
376
src/machine/dynamic_database.rs
Normal file
376
src/machine/dynamic_database.rs
Normal file
@@ -0,0 +1,376 @@
|
||||
use crate::prolog_parser::ast::*;
|
||||
|
||||
use crate::heap_print::*;
|
||||
use crate::machine::*;
|
||||
use crate::machine::compile::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::streams::*;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
impl Machine {
|
||||
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
|
||||
match name {
|
||||
&ClauseName::User(ref rc) => rc.table.clone(),
|
||||
_ => self.indices.atom_tbl(),
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_into_machine(
|
||||
&mut self,
|
||||
src: Stream,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
) -> EvalSession {
|
||||
match name.owning_module().as_str() {
|
||||
"user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
|
||||
Some(idx) => {
|
||||
let module = idx.0.borrow().1.clone();
|
||||
|
||||
match module.as_str() {
|
||||
"user" => compile_user_module(self, src, true, ListingSource::User),
|
||||
_ => compile_into_module(self, module, src, name)
|
||||
}
|
||||
}
|
||||
None => compile_user_module(self, src, true, ListingSource::User),
|
||||
},
|
||||
_ => compile_into_module(self, name.owning_module(), src, name),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey {
|
||||
let name = self.machine_st[name].clone();
|
||||
let arity = self.machine_st[arity].clone();
|
||||
|
||||
let name = match self.machine_st.store(self.machine_st.deref(name)) {
|
||||
Addr::Con(h) =>
|
||||
if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
|
||||
name.clone()
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
|
||||
Addr::Con(h) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::Integer(ref arity) => {
|
||||
arity.to_usize().unwrap()
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||
usize::try_from(*arity).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::Usize(n) => {
|
||||
n
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
(name, arity)
|
||||
}
|
||||
|
||||
fn print_new_dynamic_clause(
|
||||
&self,
|
||||
addrs: VecDeque<Addr>,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
) -> String {
|
||||
let mut output = PrinterOutputter::new();
|
||||
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
|
||||
|
||||
for addr in addrs {
|
||||
let mut printer = HCPrinter::new(&self.machine_st, &self.indices.op_dir, output);
|
||||
printer.quoted = true;
|
||||
|
||||
output = printer.print(addr);
|
||||
output.append(". ");
|
||||
}
|
||||
|
||||
output.result()
|
||||
}
|
||||
|
||||
fn make_undefined(&mut self, name: ClauseName, arity: usize) {
|
||||
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
|
||||
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
|
||||
}
|
||||
}
|
||||
|
||||
fn make_undefined_in_module(&mut self, module_name: ClauseName, name: ClauseName, arity: usize) {
|
||||
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
|
||||
if idx.module_name() == module_name {
|
||||
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) {
|
||||
let (name, arity) = self.get_predicate_key(name, arity);
|
||||
|
||||
self.make_undefined(name.clone(), arity);
|
||||
|
||||
self.indices.remove_code_index((name.clone(), arity));
|
||||
self.indices.remove_clause_subsection(name.owning_module(), name, arity);
|
||||
}
|
||||
|
||||
fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
|
||||
let (name, arity) = self.get_predicate_key(name, arity);
|
||||
let module_addr = self.machine_st[module].clone();
|
||||
|
||||
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
||||
Addr::Con(h) =>
|
||||
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
|
||||
match self.indices.modules.get_mut(module) {
|
||||
Some(ref mut module) => {
|
||||
module.code_dir.remove(&(name.clone(), arity));
|
||||
module.module_decl.name.clone()
|
||||
}
|
||||
_ => {
|
||||
self.machine_st.fail = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
self.make_undefined_in_module(module_name.clone(), name.clone(), arity);
|
||||
|
||||
self.indices.remove_code_index((name.clone(), arity));
|
||||
self.indices.remove_clause_subsection(module_name, name, arity);
|
||||
}
|
||||
|
||||
fn handle_eval_result_from_dynamic_compile(
|
||||
&mut self,
|
||||
pred_str: String,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
src: ClauseName,
|
||||
) {
|
||||
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
|
||||
|
||||
let result = self.compile_into_machine(
|
||||
Stream::from(pred_str),
|
||||
name,
|
||||
arity,
|
||||
);
|
||||
|
||||
self.machine_st = machine_st;
|
||||
|
||||
if let EvalSession::Error(err) = result {
|
||||
let h = self.machine_st.heap.h();
|
||||
let stub = MachineError::functor_stub(src, 1);
|
||||
let err = MachineError::session_error(h, err);
|
||||
let err = self.machine_st.error_form(err, stub);
|
||||
|
||||
self.machine_st.throw_exception(err);
|
||||
}
|
||||
}
|
||||
|
||||
fn recompile_dynamic_predicate_impl(
|
||||
&mut self,
|
||||
place: DynamicAssertPlace,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
) {
|
||||
let stub = MachineError::functor_stub(place.predicate_name(), 1);
|
||||
let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
|
||||
Ok(addrs) => {
|
||||
let mut addrs = VecDeque::from(addrs);
|
||||
let added_clause = self.machine_st[temp_v!(1)].clone();
|
||||
|
||||
place.push_to_queue(&mut addrs, added_clause);
|
||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||
}
|
||||
Err(err) => {
|
||||
return self.machine_st.throw_exception(err);
|
||||
}
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(
|
||||
pred_str,
|
||||
name,
|
||||
arity,
|
||||
place.predicate_name(),
|
||||
);
|
||||
}
|
||||
|
||||
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
|
||||
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
|
||||
Addr::Con(h) =>
|
||||
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
|
||||
match self.indices.modules.get(module) {
|
||||
Some(ref module) => module.atom_tbl.clone(),
|
||||
None => {
|
||||
self.machine_st.fail = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.machine_st.fail = true;
|
||||
return false;
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if let &mut ClauseName::User(ref mut rc) = name {
|
||||
rc.table = atom_tbl;
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn recompile_dynamic_predicate_in_module(&mut self, place: DynamicAssertPlace) {
|
||||
let (mut name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
|
||||
let module_addr = self.machine_st[temp_v!(5)].clone();
|
||||
|
||||
if self.set_module_atom_tbl(module_addr, &mut name) {
|
||||
self.recompile_dynamic_predicate_impl(place, name, arity);
|
||||
}
|
||||
}
|
||||
|
||||
fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace) {
|
||||
let (name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
|
||||
self.recompile_dynamic_predicate_impl(place, name, arity);
|
||||
}
|
||||
|
||||
fn retract_from_dynamic_predicate_in_module(&mut self) {
|
||||
let index = self.machine_st[temp_v!(3)].clone();
|
||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||
Addr::Con(h) =>
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::Integer(ref arity) => {
|
||||
arity.to_usize().unwrap()
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||
usize::try_from(*arity).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
||||
let module_addr = self.machine_st[temp_v!(5)].clone();
|
||||
|
||||
if self.set_module_atom_tbl(module_addr, &mut name) {
|
||||
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
|
||||
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
|
||||
Ok(addrs) => {
|
||||
let mut addrs = VecDeque::from(addrs);
|
||||
addrs.remove(index);
|
||||
|
||||
if addrs.is_empty() {
|
||||
self.make_undefined(name.clone(), arity);
|
||||
}
|
||||
|
||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||
}
|
||||
Err(err) => {
|
||||
return self.machine_st.throw_exception(err);
|
||||
}
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(
|
||||
pred_str,
|
||||
name,
|
||||
arity,
|
||||
clause_name!("retract"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn retract_from_dynamic_predicate(&mut self) {
|
||||
let index = self.machine_st[temp_v!(3)].clone();
|
||||
let index = match self.machine_st.store(self.machine_st.deref(index)) {
|
||||
Addr::Con(h) => {
|
||||
match &self.machine_st.heap[h] {
|
||||
HeapCellValue::Integer(ref arity) => {
|
||||
arity.to_usize().unwrap()
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
|
||||
usize::try_from(*arity).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::Usize(n) => {
|
||||
n
|
||||
}
|
||||
Addr::Fixnum(n) => {
|
||||
usize::try_from(n).unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
|
||||
|
||||
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
|
||||
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
|
||||
Ok(addrs) => {
|
||||
let mut addrs = VecDeque::from(addrs);
|
||||
addrs.remove(index);
|
||||
|
||||
if addrs.is_empty() {
|
||||
self.make_undefined(name.clone(), arity);
|
||||
}
|
||||
|
||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||
}
|
||||
Err(err) => {
|
||||
return self.machine_st.throw_exception(err);
|
||||
}
|
||||
};
|
||||
|
||||
self.handle_eval_result_from_dynamic_compile(
|
||||
pred_str,
|
||||
name,
|
||||
arity,
|
||||
clause_name!("retract"),
|
||||
);
|
||||
}
|
||||
|
||||
pub(super) fn dynamic_transaction(
|
||||
&mut self,
|
||||
trans_type: DynamicTransactionType,
|
||||
p: LocalCodePtr,
|
||||
) {
|
||||
match trans_type {
|
||||
DynamicTransactionType::Abolish => {
|
||||
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2))
|
||||
}
|
||||
DynamicTransactionType::Assert(place) => {
|
||||
self.recompile_dynamic_predicate(place)
|
||||
}
|
||||
DynamicTransactionType::ModuleAbolish => {
|
||||
self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(3))
|
||||
}
|
||||
DynamicTransactionType::ModuleAssert(place) => {
|
||||
self.recompile_dynamic_predicate_in_module(place)
|
||||
}
|
||||
DynamicTransactionType::ModuleRetract => {
|
||||
self.retract_from_dynamic_predicate_in_module()
|
||||
}
|
||||
DynamicTransactionType::Retract => {
|
||||
self.retract_from_dynamic_predicate()
|
||||
}
|
||||
}
|
||||
|
||||
self.machine_st.p = CodePtr::Local(p);
|
||||
}
|
||||
}
|
||||
544
src/machine/heap.rs
Normal file
544
src/machine/heap.rs
Normal file
@@ -0,0 +1,544 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::prolog_parser::ast::Constant;
|
||||
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::partial_string::*;
|
||||
use crate::machine::raw_block::*;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StandardHeapTraits {}
|
||||
|
||||
impl RawBlockTraits for StandardHeapTraits {
|
||||
#[inline]
|
||||
fn init_size() -> usize {
|
||||
256 * mem::size_of::<HeapCellValue>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
mem::align_of::<HeapCellValue>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HeapTemplate<T: RawBlockTraits> {
|
||||
buf: RawBlock<T>,
|
||||
_marker: PhantomData<HeapCellValue>,
|
||||
}
|
||||
|
||||
pub(crate) type Heap = HeapTemplate<StandardHeapTraits>;
|
||||
|
||||
impl<T: RawBlockTraits> Drop for HeapTemplate<T> {
|
||||
fn drop(&mut self) {
|
||||
self.clear();
|
||||
self.buf.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate)
|
||||
struct HeapIntoIter<T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: RawBlock<T>,
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Drop for HeapIntoIter<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut heap =
|
||||
HeapTemplate { buf: self.buf.take(), _marker: PhantomData };
|
||||
|
||||
heap.truncate(self.offset / mem::size_of::<HeapCellValue>());
|
||||
heap.buf.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Iterator for HeapIntoIter<T> {
|
||||
type Item = HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let ptr = self.buf.base as usize + self.offset;
|
||||
self.offset += mem::size_of::<HeapCellValue>();
|
||||
|
||||
if ptr < self.buf.top as usize {
|
||||
unsafe {
|
||||
Some(ptr::read(ptr as *const HeapCellValue))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate)
|
||||
struct HeapIter<'a, T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: &'a RawBlock<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
|
||||
pub(crate)
|
||||
fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
|
||||
HeapIter { buf, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
|
||||
type Item = &'a HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let ptr = self.buf.base as usize + self.offset;
|
||||
self.offset += mem::size_of::<HeapCellValue>();
|
||||
|
||||
if ptr < self.buf.top as usize {
|
||||
unsafe {
|
||||
Some(&*(ptr as *const _))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate)
|
||||
fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
|
||||
for (index, term) in heap.enumerate() {
|
||||
println!("{} : {}", h + index, term);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate)
|
||||
struct HeapIterMut<'a, T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: &'a mut RawBlock<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> HeapIterMut<'a, T> {
|
||||
pub(crate)
|
||||
fn new(buf: &'a mut RawBlock<T>, offset: usize) -> Self {
|
||||
HeapIterMut { buf, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIterMut<'a, T> {
|
||||
type Item = &'a mut HeapCellValue;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let ptr = self.buf.base as usize + self.offset;
|
||||
self.offset += mem::size_of::<HeapCellValue>();
|
||||
|
||||
if ptr < self.buf.top as usize {
|
||||
unsafe {
|
||||
Some(&mut *(ptr as *mut _))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn new() -> Self {
|
||||
HeapTemplate { buf: RawBlock::new(), _marker: PhantomData }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn clone(&self, h: usize) -> HeapCellValue {
|
||||
match &self[h] {
|
||||
&HeapCellValue::Addr(addr) => {
|
||||
HeapCellValue::Addr(addr)
|
||||
}
|
||||
&HeapCellValue::Atom(ref name, ref op) => {
|
||||
HeapCellValue::Atom(name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::DBRef(ref db_ref) => {
|
||||
HeapCellValue::DBRef(db_ref.clone())
|
||||
}
|
||||
&HeapCellValue::Integer(ref n) => {
|
||||
HeapCellValue::Integer(n.clone())
|
||||
}
|
||||
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::PartialString(..) => {
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
}
|
||||
&HeapCellValue::Rational(ref r) => {
|
||||
HeapCellValue::Rational(r.clone())
|
||||
}
|
||||
&HeapCellValue::Stream(_) => {
|
||||
HeapCellValue::Addr(Addr::Stream(h))
|
||||
}
|
||||
&HeapCellValue::TcpListener(_) => {
|
||||
HeapCellValue::Addr(Addr::TcpListener(h))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn put_complete_string(&mut self, s: &str) -> Addr {
|
||||
if s.is_empty() {
|
||||
return Addr::EmptyList;
|
||||
}
|
||||
|
||||
let addr = self.allocate_pstr(s);
|
||||
self.pop();
|
||||
|
||||
let h = self.h();
|
||||
|
||||
match &mut self[h - 1] {
|
||||
&mut HeapCellValue::PartialString(_, ref mut has_tail) => {
|
||||
*has_tail = false;
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn put_constant(&mut self, c: Constant) -> Addr {
|
||||
match c {
|
||||
Constant::Atom(name, op) => {
|
||||
Addr::Con(self.push(HeapCellValue::Atom(name, op)))
|
||||
}
|
||||
Constant::Char(c) => {
|
||||
Addr::Char(c)
|
||||
}
|
||||
Constant::EmptyList => {
|
||||
Addr::EmptyList
|
||||
}
|
||||
Constant::Fixnum(n) => {
|
||||
Addr::Fixnum(n)
|
||||
}
|
||||
Constant::Integer(n) => {
|
||||
Addr::Con(self.push(HeapCellValue::Integer(n)))
|
||||
}
|
||||
Constant::Rational(r) => {
|
||||
Addr::Con(self.push(HeapCellValue::Rational(r)))
|
||||
}
|
||||
Constant::Float(f) => {
|
||||
Addr::Float(f)
|
||||
}
|
||||
Constant::String(s) => {
|
||||
if s.is_empty() {
|
||||
Addr::EmptyList
|
||||
} else {
|
||||
self.put_complete_string(&s)
|
||||
}
|
||||
}
|
||||
Constant::Usize(n) => {
|
||||
Addr::Usize(n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn pop(&mut self) {
|
||||
let h = self.h();
|
||||
|
||||
if h > 0 {
|
||||
self.truncate(h - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn push(&mut self, val: HeapCellValue) -> usize {
|
||||
let h = self.h();
|
||||
|
||||
unsafe {
|
||||
let new_top = self.buf.new_block(mem::size_of::<HeapCellValue>());
|
||||
ptr::write(self.buf.top as *mut _, val);
|
||||
self.buf.top = new_top;
|
||||
}
|
||||
|
||||
h
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn atom_at(&self, h: usize) -> bool {
|
||||
if let HeapCellValue::Atom(..) = &self[h] {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
|
||||
match non_heap_value {
|
||||
HeapCellValue::Addr(addr) => {
|
||||
addr
|
||||
}
|
||||
val @ HeapCellValue::Atom(..) |
|
||||
val @ HeapCellValue::Integer(_) |
|
||||
val @ HeapCellValue::DBRef(_) |
|
||||
val @ HeapCellValue::Rational(_) => {
|
||||
Addr::Con(self.push(val))
|
||||
}
|
||||
val @ HeapCellValue::NamedStr(..) => {
|
||||
Addr::Str(self.push(val))
|
||||
}
|
||||
HeapCellValue::PartialString(pstr, has_tail) => {
|
||||
let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||
|
||||
if has_tail {
|
||||
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
}
|
||||
|
||||
Addr::Con(h)
|
||||
}
|
||||
val @ HeapCellValue::Stream(..) => {
|
||||
Addr::Stream(self.push(val))
|
||||
}
|
||||
val @ HeapCellValue::TcpListener(..) => {
|
||||
Addr::TcpListener(self.push(val))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn allocate_pstr(&mut self, src: &str) -> Addr {
|
||||
self.write_pstr(src)
|
||||
.unwrap_or_else(|| Addr::EmptyList)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_pstr(&mut self, mut src: &str) -> Option<Addr> {
|
||||
let orig_h = self.h();
|
||||
|
||||
loop {
|
||||
if src == "" {
|
||||
return if orig_h == self.h() {
|
||||
None
|
||||
} else {
|
||||
let tail_h = self.h() - 1;
|
||||
self[tail_h] = HeapCellValue::Addr(Addr::HeapCell(tail_h));
|
||||
|
||||
Some(Addr::PStrLocation(orig_h, 0))
|
||||
};
|
||||
}
|
||||
|
||||
let h = self.h();
|
||||
|
||||
let (pstr, rest_src) =
|
||||
match PartialString::new(src) {
|
||||
Some(tuple) => {
|
||||
tuple
|
||||
}
|
||||
None => {
|
||||
if src.len() > '\u{0}'.len_utf8() {
|
||||
src = &src['\u{0}'.len_utf8() ..];
|
||||
continue;
|
||||
} else if orig_h == h {
|
||||
return None;
|
||||
} else {
|
||||
self[h - 1] = HeapCellValue::Addr(Addr::HeapCell(h - 1));
|
||||
return Some(Addr::PStrLocation(orig_h, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
self.push(HeapCellValue::PartialString(pstr, true));
|
||||
|
||||
if rest_src != "" {
|
||||
self.push(HeapCellValue::Addr(Addr::PStrLocation(h + 2, 0)));
|
||||
src = rest_src;
|
||||
} else {
|
||||
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
|
||||
return Some(Addr::PStrLocation(orig_h, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn take(&mut self) -> Self {
|
||||
HeapTemplate {
|
||||
buf: self.buf.take(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn truncate(&mut self, h: usize) {
|
||||
let new_top = h * mem::size_of::<HeapCellValue>() + self.buf.base as usize;
|
||||
let mut h = new_top;
|
||||
|
||||
unsafe {
|
||||
while h as *const _ < self.buf.top {
|
||||
let val = h as *mut HeapCellValue;
|
||||
ptr::drop_in_place(val);
|
||||
h += mem::size_of::<HeapCellValue>();
|
||||
}
|
||||
}
|
||||
|
||||
self.buf.top = new_top as *const _;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn h(&self) -> usize {
|
||||
(self.buf.top as usize - self.buf.base as usize) / mem::size_of::<HeapCellValue>()
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn append(&mut self, vals: Vec<HeapCellValue>) {
|
||||
for val in vals {
|
||||
self.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn clear(&mut self) {
|
||||
if !self.buf.base.is_null() {
|
||||
self.truncate(0);
|
||||
self.buf.top = self.buf.base;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn to_list<Iter, SrcT>(&mut self, values: Iter) -> usize
|
||||
where Iter: Iterator<Item = SrcT>,
|
||||
SrcT: Into<HeapCellValue>
|
||||
{
|
||||
let head_addr = self.h();
|
||||
let mut h = head_addr;
|
||||
|
||||
for value in values.map(|v| v.into()) {
|
||||
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
self.push(value);
|
||||
|
||||
h += 2;
|
||||
}
|
||||
|
||||
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
|
||||
head_addr
|
||||
}
|
||||
|
||||
/* Create an iterator starting from the passed offset. */
|
||||
pub(crate)
|
||||
fn iter_from<'a>(&'a self, offset: usize) -> HeapIter<'a, T> {
|
||||
HeapIter::new(&self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn iter_mut_from<'a>(&'a mut self, offset: usize) -> HeapIterMut<'a, T> {
|
||||
HeapIterMut::new(&mut self.buf, offset * mem::size_of::<HeapCellValue>())
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn into_iter(mut self) -> HeapIntoIter<T> {
|
||||
HeapIntoIter { buf: self.buf.take(), offset: 0 }
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn extend<Iter: Iterator<Item = HeapCellValue>>(&mut self, iter: Iter) {
|
||||
for hcv in iter {
|
||||
self.push(hcv);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn to_local_code_ptr(&self, addr: &Addr) -> Option<LocalCodePtr> {
|
||||
let extract_integer = |s: usize| -> Option<usize> {
|
||||
match &self[s] {
|
||||
&HeapCellValue::Addr(Addr::Fixnum(n)) => usize::try_from(n).ok(),
|
||||
&HeapCellValue::Integer(ref n) => n.to_usize(),
|
||||
_ => None
|
||||
}
|
||||
};
|
||||
|
||||
match addr {
|
||||
Addr::Str(s) => {
|
||||
match &self[*s] {
|
||||
HeapCellValue::NamedStr(arity, ref name, _) => {
|
||||
match (name.as_str(), *arity) {
|
||||
("dir_entry", 1) => {
|
||||
extract_integer(s+1).map(LocalCodePtr::DirEntry)
|
||||
}
|
||||
("in_situ_dir_entry", 1) => {
|
||||
extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
|
||||
}
|
||||
("top_level", 2) => {
|
||||
if let Some(chunk_num) = extract_integer(s+1) {
|
||||
if let Some(p) = extract_integer(s+2) {
|
||||
return Some(LocalCodePtr::TopLevel(chunk_num, p));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
("user_goal_expansion", 1) => {
|
||||
extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion)
|
||||
}
|
||||
("user_term_expansion", 1) => {
|
||||
extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub
|
||||
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
|
||||
match addr {
|
||||
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
|
||||
RefOrOwned::Borrowed(&self[h])
|
||||
}
|
||||
addr => {
|
||||
RefOrOwned::Owned(HeapCellValue::Addr(*addr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
|
||||
&*(ptr as *const HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> IndexMut<usize> for HeapTemplate<T> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + index * mem::size_of::<HeapCellValue>();
|
||||
&mut *(ptr as *mut HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
844
src/machine/machine_errors.rs
Normal file
844
src/machine/machine_errors.rs
Normal file
@@ -0,0 +1,844 @@
|
||||
use crate::prolog_parser::ast::*;
|
||||
|
||||
use crate::forms::{ModuleSource, Number, PredicateKey};
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::machine_state::*;
|
||||
use crate::rug::Integer;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) type MachineStub = Vec<HeapCellValue>;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum ErrorProvenance {
|
||||
Constructed, // if constructed, offset the addresses.
|
||||
Received, // otherwise, preserve the addresses.
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct MachineError {
|
||||
stub: MachineStub,
|
||||
location: Option<(usize, usize)>, // line_num, col_num
|
||||
from: ErrorProvenance,
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
trait TypeError {
|
||||
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError;
|
||||
}
|
||||
|
||||
impl TypeError for Addr {
|
||||
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
[atom(valid_type.as_str()), addr(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeError for HeapCellValue {
|
||||
fn type_error(self, _: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
[atom(valid_type.as_str()), value(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeError for MachineStub {
|
||||
fn type_error(self, h: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
[atom(valid_type.as_str()), aux(h, 0)],
|
||||
[self]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeError for Number {
|
||||
fn type_error(self, _h: usize, valid_type: ValidType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"type_error",
|
||||
[atom(valid_type.as_str()), number(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
trait PermissionError {
|
||||
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError;
|
||||
}
|
||||
|
||||
impl PermissionError for Addr {
|
||||
fn permission_error(self, _: usize, index_str: &'static str, perm: Permission) -> MachineError {
|
||||
let stub = functor!(
|
||||
"permission_error",
|
||||
[atom(perm.as_str()), atom(index_str), addr(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PermissionError for MachineStub {
|
||||
fn permission_error(self, h: usize, index_str: &'static str, perm: Permission) -> MachineError {
|
||||
let stub = functor!(
|
||||
"permission_error",
|
||||
[atom(perm.as_str()), atom(index_str), aux(h, 0)],
|
||||
[self]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
trait DomainError {
|
||||
fn domain_error(self, error: DomainErrorType) -> MachineError;
|
||||
}
|
||||
|
||||
impl DomainError for Addr {
|
||||
fn domain_error(self, error: DomainErrorType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"domain_error",
|
||||
[atom(error.as_str()), addr(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DomainError for Number {
|
||||
fn domain_error(self, error: DomainErrorType) -> MachineError {
|
||||
let stub = functor!(
|
||||
"domain_error",
|
||||
[atom(error.as_str()), number(self)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineError {
|
||||
pub(super)
|
||||
fn functor_stub(name: ClauseName, arity: usize) -> MachineStub {
|
||||
functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[clause_name(name), integer(arity)]
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn interrupt_error() -> Self {
|
||||
let stub = functor!("$interrupt_thrown");
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn evaluation_error(eval_error: EvalError) -> Self {
|
||||
let stub = functor!("evaluation_error", [atom(eval_error.as_str())]);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn type_error<T: TypeError>(h: usize, valid_type: ValidType, culprit: T) -> Self {
|
||||
culprit.type_error(h, valid_type)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn module_resolution_error(
|
||||
h: usize,
|
||||
mod_name: ClauseName,
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
) -> Self {
|
||||
let res_stub = functor!(
|
||||
":",
|
||||
SharedOpDesc::new(600, XFY),
|
||||
[clause_name(mod_name), clause_name(name)]
|
||||
);
|
||||
|
||||
let ind_stub = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[aux(h + 2, 0), integer(arity)],
|
||||
[res_stub]
|
||||
);
|
||||
|
||||
let stub = functor!(
|
||||
"evaluation_error",
|
||||
[aux(h, 0)],
|
||||
[ind_stub]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn existence_error(h: usize, err: ExistenceError) -> Self {
|
||||
match err {
|
||||
ExistenceError::Module(name) => {
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("source_sink"), clause_name(name)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
ExistenceError::Procedure(name, arity) => {
|
||||
let culprit = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[clause_name(name), integer(arity)]
|
||||
);
|
||||
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("procedure"), aux(h, 0)],
|
||||
[culprit]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
ExistenceError::ModuleSource(source) => {
|
||||
let source_stub = source.as_functor_stub();
|
||||
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("source_sink"), aux(h, 0)],
|
||||
[source_stub]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
ExistenceError::SourceSink(culprit) => {
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("source_sink"), addr(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
ExistenceError::Stream(culprit) => {
|
||||
let stub = functor!(
|
||||
"existence_error",
|
||||
[atom("stream"), addr(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn permission_error<T: PermissionError>(
|
||||
h: usize,
|
||||
err: Permission,
|
||||
index_str: &'static str,
|
||||
culprit: T,
|
||||
) -> Self {
|
||||
culprit.permission_error(
|
||||
h,
|
||||
index_str,
|
||||
err,
|
||||
)
|
||||
}
|
||||
|
||||
fn arithmetic_error(h: usize, err: ArithmeticError) -> Self {
|
||||
match err {
|
||||
ArithmeticError::UninstantiatedVar => {
|
||||
Self::instantiation_error()
|
||||
}
|
||||
ArithmeticError::NonEvaluableFunctor(name, arity) => {
|
||||
let culprit = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[constant(h, &name), integer(arity)]
|
||||
);
|
||||
|
||||
Self::type_error(h, ValidType::Evaluable, culprit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn domain_error<T: DomainError>(error: DomainErrorType, culprit: T) -> Self {
|
||||
culprit.domain_error(error)
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn instantiation_error() -> Self {
|
||||
let stub = functor!("instantiation_error");
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn uninstantiation_error(culprit: Addr) -> Self {
|
||||
let stub = functor!(
|
||||
"uninstantiation_error",
|
||||
[addr(culprit)]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn session_error(h: usize, err: SessionError) -> Self {
|
||||
match err {
|
||||
SessionError::CannotOverwriteBuiltIn(pred_str) |
|
||||
SessionError::CannotOverwriteImport(pred_str) => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Modify,
|
||||
"private_procedure",
|
||||
functor!(clause_name(pred_str)),
|
||||
)
|
||||
}
|
||||
SessionError::ExistenceError(err) => {
|
||||
Self::existence_error(h, err)
|
||||
}
|
||||
SessionError::InvalidFileName(filename) => {
|
||||
Self::existence_error(h, ExistenceError::Module(filename))
|
||||
}
|
||||
SessionError::ModuleDoesNotContainExport(..) => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Access,
|
||||
"private_procedure",
|
||||
functor!("module_does_not_contain_claimed_export"),
|
||||
)
|
||||
}
|
||||
SessionError::NamelessEntry => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Create,
|
||||
"static_procedure",
|
||||
functor!("nameless_procedure")
|
||||
)
|
||||
}
|
||||
SessionError::OpIsInfixAndPostFix(op) => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Create,
|
||||
"operator",
|
||||
functor!(clause_name(op)),
|
||||
)
|
||||
}
|
||||
SessionError::ParserError(err) => {
|
||||
Self::syntax_error(h, err)
|
||||
}
|
||||
SessionError::QueryCannotBeDefinedAsFact => {
|
||||
Self::permission_error(
|
||||
h,
|
||||
Permission::Create,
|
||||
"static_procedure",
|
||||
functor!("query_cannot_be_defined_as_fact")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn syntax_error(h: usize, err: ParserError) -> Self {
|
||||
if let ParserError::Arithmetic(err) = err {
|
||||
return Self::arithmetic_error(h, err);
|
||||
}
|
||||
|
||||
let location = err.line_and_col_num();
|
||||
let stub = functor!(err.as_str());
|
||||
|
||||
let stub = functor!(
|
||||
"syntax_error",
|
||||
[aux(h, 0)],
|
||||
[stub]
|
||||
);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location,
|
||||
from: ErrorProvenance::Constructed,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn representation_error(flag: RepFlag) -> Self {
|
||||
let stub = functor!("representation_error", [atom(flag.as_str())]);
|
||||
|
||||
MachineError {
|
||||
stub,
|
||||
location: None,
|
||||
from: ErrorProvenance::Received,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_iter(self, offset: usize) -> Box<dyn Iterator<Item = HeapCellValue>> {
|
||||
match self.from {
|
||||
ErrorProvenance::Constructed => {
|
||||
Box::new(self.stub.into_iter().map(move |hcv| match hcv {
|
||||
HeapCellValue::Addr(addr) => HeapCellValue::Addr(addr + offset),
|
||||
hcv => hcv,
|
||||
}))
|
||||
}
|
||||
ErrorProvenance::Received => Box::new(self.stub.into_iter()),
|
||||
}
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
self.stub.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Permission {
|
||||
Access,
|
||||
Create,
|
||||
InputStream,
|
||||
Modify,
|
||||
Open,
|
||||
OutputStream,
|
||||
Reposition,
|
||||
}
|
||||
|
||||
impl Permission {
|
||||
#[inline]
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Permission::Access => "access",
|
||||
Permission::Create => "create",
|
||||
Permission::InputStream => "input",
|
||||
Permission::Modify => "modify",
|
||||
Permission::Open => "open",
|
||||
Permission::OutputStream => "output",
|
||||
Permission::Reposition => "reposition",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 b) of 13211-1:1995
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ValidType {
|
||||
Atom,
|
||||
Atomic,
|
||||
// Boolean,
|
||||
Byte,
|
||||
Callable,
|
||||
Character,
|
||||
Compound,
|
||||
Evaluable,
|
||||
Float,
|
||||
InByte,
|
||||
InCharacter,
|
||||
Integer,
|
||||
List,
|
||||
Number,
|
||||
Pair,
|
||||
// PredicateIndicator,
|
||||
// Variable
|
||||
TcpListener,
|
||||
}
|
||||
|
||||
impl ValidType {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
ValidType::Atom => "atom",
|
||||
ValidType::Atomic => "atomic",
|
||||
// ValidType::Boolean => "boolean",
|
||||
ValidType::Byte => "byte",
|
||||
ValidType::Callable => "callable",
|
||||
ValidType::Character => "character",
|
||||
ValidType::Compound => "compound",
|
||||
ValidType::Evaluable => "evaluable",
|
||||
ValidType::Float => "float",
|
||||
ValidType::InByte => "in_byte",
|
||||
ValidType::InCharacter => "in_character",
|
||||
ValidType::Integer => "integer",
|
||||
ValidType::List => "list",
|
||||
ValidType::Number => "number",
|
||||
ValidType::Pair => "pair",
|
||||
// ValidType::PredicateIndicator => "predicate_indicator",
|
||||
// ValidType::Variable => "variable"
|
||||
ValidType::TcpListener => "tcp_listener",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DomainErrorType {
|
||||
IOMode,
|
||||
NotLessThanZero,
|
||||
Order,
|
||||
SourceSink,
|
||||
Stream,
|
||||
StreamOrAlias,
|
||||
}
|
||||
|
||||
impl DomainErrorType {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
DomainErrorType::IOMode => "io_mode",
|
||||
DomainErrorType::NotLessThanZero => "not_less_than_zero",
|
||||
DomainErrorType::Order => "order",
|
||||
DomainErrorType::SourceSink => "source_sink",
|
||||
DomainErrorType::Stream => "stream",
|
||||
DomainErrorType::StreamOrAlias => "stream_or_alias",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 f) of 13211-1:1995
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum RepFlag {
|
||||
// Character,
|
||||
CharacterCode,
|
||||
InCharacterCode,
|
||||
MaxArity,
|
||||
// MaxInteger,
|
||||
// MinInteger
|
||||
}
|
||||
|
||||
impl RepFlag {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
// RepFlag::Character => "character",
|
||||
RepFlag::CharacterCode => "character_code",
|
||||
RepFlag::InCharacterCode => "in_character_code",
|
||||
RepFlag::MaxArity => "max_arity",
|
||||
// RepFlag::MaxInteger => "max_integer",
|
||||
// RepFlag::MinInteger => "min_integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from 7.12.2 g) of 13211-1:1995
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EvalError {
|
||||
FloatOverflow,
|
||||
Undefined,
|
||||
// Underflow,
|
||||
ZeroDivisor,
|
||||
}
|
||||
|
||||
impl EvalError {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
EvalError::FloatOverflow => "float_overflow",
|
||||
EvalError::Undefined => "undefined",
|
||||
// EvalError::FloatUnderflow => "underflow",
|
||||
EvalError::ZeroDivisor => "zero_divisor",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// used by '$skip_max_list'.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(super) enum CycleSearchResult {
|
||||
EmptyList,
|
||||
NotList,
|
||||
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
|
||||
ProperList(usize), // the list length.
|
||||
PStrLocation(usize, usize, usize), // the list length (up to max), the heap offset, byte offset into the string.
|
||||
UntouchedList(usize), // the address of an uniterated Addr::Lis(address).
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
// see 8.4.3 of Draft Technical Corrigendum 2.
|
||||
pub(super)
|
||||
fn check_sort_errors(&self) -> CallResult {
|
||||
let stub = MachineError::functor_stub(clause_name!("sort"), 2);
|
||||
let list = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
match self.detect_cycles(list.clone()) {
|
||||
CycleSearchResult::PartialList(..) => {
|
||||
return Err(self.error_form(MachineError::instantiation_error(), stub))
|
||||
}
|
||||
CycleSearchResult::NotList => {
|
||||
return Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
match self.detect_cycles(sorted.clone()) {
|
||||
CycleSearchResult::NotList if !sorted.is_ref() => {
|
||||
Err(self.error_form(MachineError::type_error(0, ValidType::List, sorted), stub))
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_for_list_pairs(&self, list: Addr) -> CallResult {
|
||||
let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
|
||||
|
||||
match self.detect_cycles(list.clone()) {
|
||||
CycleSearchResult::NotList if !list.is_ref() => {
|
||||
Err(self.error_form(MachineError::type_error(0, ValidType::List, list), stub))
|
||||
}
|
||||
_ => {
|
||||
let mut addr = list;
|
||||
|
||||
while let Addr::Lis(l) = self.store(self.deref(addr)) {
|
||||
let mut new_l = l;
|
||||
|
||||
loop {
|
||||
match self.heap.clone(new_l) {
|
||||
HeapCellValue::Addr(Addr::Str(l)) => {
|
||||
new_l = l;
|
||||
}
|
||||
HeapCellValue::NamedStr(2, ref name, Some(_))
|
||||
if name.as_str() == "-" => {
|
||||
break;
|
||||
}
|
||||
HeapCellValue::Addr(Addr::HeapCell(_)) => {
|
||||
break;
|
||||
}
|
||||
HeapCellValue::Addr(Addr::StackCell(..)) => {
|
||||
break;
|
||||
}
|
||||
_ => {
|
||||
return Err(self.error_form(
|
||||
MachineError::type_error(0, ValidType::Pair, Addr::HeapCell(l)),
|
||||
stub,
|
||||
))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
addr = Addr::HeapCell(l + 1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// see 8.4.4 of Draft Technical Corrigendum 2.
|
||||
pub(super)
|
||||
fn check_keysort_errors(&self) -> CallResult {
|
||||
let stub = MachineError::functor_stub(clause_name!("keysort"), 2);
|
||||
|
||||
let pairs = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||
let sorted = self.store(self.deref(self[temp_v!(2)].clone()));
|
||||
|
||||
match self.detect_cycles(pairs.clone()) {
|
||||
CycleSearchResult::PartialList(..) => {
|
||||
Err(self.error_form(MachineError::instantiation_error(), stub))
|
||||
}
|
||||
CycleSearchResult::NotList => {
|
||||
Err(self.error_form(MachineError::type_error(0, ValidType::List, pairs), stub))
|
||||
}
|
||||
_ => Ok(()),
|
||||
}?;
|
||||
|
||||
self.check_for_list_pairs(sorted)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn type_error<T: TypeError>(
|
||||
&self,
|
||||
valid_type: ValidType,
|
||||
culprit: T,
|
||||
caller: ClauseName,
|
||||
arity: usize,
|
||||
) -> MachineStub {
|
||||
let stub = MachineError::functor_stub(caller, arity);
|
||||
let err = MachineError::type_error(
|
||||
self.heap.h(),
|
||||
valid_type,
|
||||
culprit,
|
||||
);
|
||||
|
||||
return self.error_form(err, stub);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn representation_error(
|
||||
&self,
|
||||
rep_flag: RepFlag,
|
||||
caller: ClauseName,
|
||||
arity: usize,
|
||||
) -> MachineStub {
|
||||
let stub = MachineError::functor_stub(caller, arity);
|
||||
let err = MachineError::representation_error(
|
||||
rep_flag,
|
||||
);
|
||||
|
||||
return self.error_form(err, stub);
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn error_form(&self, err: MachineError, src: MachineStub) -> MachineStub {
|
||||
let location = err.location;
|
||||
let err_len = err.len();
|
||||
|
||||
let h = self.heap.h();
|
||||
let mut stub = vec![
|
||||
HeapCellValue::NamedStr(2, clause_name!("error"), None),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3)),
|
||||
HeapCellValue::Addr(Addr::HeapCell(h + 3 + err_len)),
|
||||
];
|
||||
|
||||
stub.extend(err.into_iter(3));
|
||||
|
||||
if let Some((line_num, _)) = location {
|
||||
let colon_op_desc = Some(SharedOpDesc::new(600, XFY));
|
||||
|
||||
stub.push(HeapCellValue::NamedStr(2, clause_name!(":"), colon_op_desc));
|
||||
stub.push(HeapCellValue::Addr(Addr::HeapCell(h + 6 + err_len)));
|
||||
stub.push(HeapCellValue::Integer(Rc::new(Integer::from(line_num))));
|
||||
}
|
||||
|
||||
stub.extend(src.into_iter());
|
||||
stub
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn throw_exception(&mut self, err: MachineStub) {
|
||||
let h = self.heap.h();
|
||||
|
||||
self.ball.boundary = 0;
|
||||
self.ball.stub.truncate(0);
|
||||
|
||||
self.heap.append(err);
|
||||
|
||||
self.registers[1] = Addr::HeapCell(h);
|
||||
|
||||
self.set_ball();
|
||||
self.unwind_stack();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ExistenceError {
|
||||
Module(ClauseName),
|
||||
ModuleSource(ModuleSource),
|
||||
Procedure(ClauseName, usize),
|
||||
SourceSink(Addr),
|
||||
Stream(Addr),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SessionError {
|
||||
CannotOverwriteBuiltIn(ClauseName),
|
||||
CannotOverwriteImport(ClauseName),
|
||||
ExistenceError(ExistenceError),
|
||||
InvalidFileName(ClauseName),
|
||||
ModuleDoesNotContainExport(ClauseName, PredicateKey),
|
||||
NamelessEntry,
|
||||
OpIsInfixAndPostFix(ClauseName),
|
||||
QueryCannotBeDefinedAsFact,
|
||||
ParserError(ParserError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EvalSession {
|
||||
EntrySuccess,
|
||||
Error(SessionError),
|
||||
}
|
||||
|
||||
impl From<SessionError> for EvalSession {
|
||||
fn from(err: SessionError) -> Self {
|
||||
EvalSession::Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParserError> for SessionError {
|
||||
fn from(err: ParserError) -> Self {
|
||||
SessionError::ParserError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ParserError> for EvalSession {
|
||||
fn from(err: ParserError) -> Self {
|
||||
EvalSession::from(SessionError::ParserError(err))
|
||||
}
|
||||
|
||||
}
|
||||
1132
src/machine/machine_indices.rs
Normal file
1132
src/machine/machine_indices.rs
Normal file
File diff suppressed because it is too large
Load Diff
1820
src/machine/machine_state.rs
Normal file
1820
src/machine/machine_state.rs
Normal file
File diff suppressed because it is too large
Load Diff
3356
src/machine/machine_state_impl.rs
Normal file
3356
src/machine/machine_state_impl.rs
Normal file
File diff suppressed because it is too large
Load Diff
1112
src/machine/mod.rs
Normal file
1112
src/machine/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
371
src/machine/modules.rs
Normal file
371
src/machine/modules.rs
Normal file
@@ -0,0 +1,371 @@
|
||||
use crate::prolog_parser::ast::*;
|
||||
use crate::prolog_parser::tabled_rc::*;
|
||||
|
||||
use crate::forms::*;
|
||||
use crate::machine::code_repo::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::mem;
|
||||
|
||||
// Module's and related types are defined in forms.
|
||||
impl Module {
|
||||
pub fn new(
|
||||
module_decl: ModuleDecl,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
listing_src: ListingSource,
|
||||
) -> Self
|
||||
{
|
||||
Module {
|
||||
atom_tbl,
|
||||
module_decl,
|
||||
term_dir: TermDir::new(),
|
||||
user_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||
user_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||
term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||
goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||
local_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||
local_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
|
||||
code_dir: CodeDir::new(),
|
||||
op_dir: default_op_dir(),
|
||||
inserted_expansions: false,
|
||||
is_impromptu_module: false,
|
||||
listing_src,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_expansions(
|
||||
&self,
|
||||
code_repo: &mut CodeRepo,
|
||||
) -> Result<(), ParserError> {
|
||||
{
|
||||
let te = code_repo
|
||||
.term_dir
|
||||
.entry((clause_name!("term_expansion"), 2))
|
||||
.or_insert((Predicate::new(), VecDeque::from(vec![])));
|
||||
|
||||
(te.0)
|
||||
.0
|
||||
.extend((self.user_term_expansions.0).0.iter().cloned());
|
||||
|
||||
te.1.extend(self.user_term_expansions.1.iter().cloned());
|
||||
}
|
||||
|
||||
{
|
||||
let ge = code_repo
|
||||
.term_dir
|
||||
.entry((clause_name!("goal_expansion"), 2))
|
||||
.or_insert((Predicate::new(), VecDeque::from(vec![])));
|
||||
|
||||
(ge.0)
|
||||
.0
|
||||
.extend((self.user_goal_expansions.0).0.iter().cloned());
|
||||
|
||||
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
|
||||
}
|
||||
|
||||
code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
|
||||
code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_expansion_record(
|
||||
&mut self,
|
||||
hook: CompileTimeHook,
|
||||
clause: PredicateClause,
|
||||
queue: VecDeque<TopLevel>,
|
||||
) {
|
||||
match hook {
|
||||
CompileTimeHook::TermExpansion | CompileTimeHook::UserTermExpansion => {
|
||||
(self.term_expansions.0).0.push(clause);
|
||||
self.term_expansions.1.extend(queue.into_iter());
|
||||
}
|
||||
CompileTimeHook::GoalExpansion | CompileTimeHook::UserGoalExpansion => {
|
||||
(self.goal_expansions.0).0.push(clause);
|
||||
self.goal_expansions.1.extend(queue.into_iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_local_expansion(
|
||||
&mut self,
|
||||
hook: CompileTimeHook,
|
||||
clause: PredicateClause,
|
||||
queue: VecDeque<TopLevel>,
|
||||
) {
|
||||
match hook {
|
||||
CompileTimeHook::TermExpansion => {
|
||||
(self.local_term_expansions.0).0.push(clause);
|
||||
self.local_term_expansions.1.extend(queue.into_iter());
|
||||
}
|
||||
CompileTimeHook::GoalExpansion => {
|
||||
(self.local_goal_expansions.0).0.push(clause);
|
||||
self.local_goal_expansions.1.extend(queue.into_iter());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_local_expansions(&mut self) -> Vec<(Predicate, VecDeque<TopLevel>)>
|
||||
{
|
||||
let term_expansions =
|
||||
mem::replace(&mut self.local_term_expansions, (Predicate::new(), VecDeque::new()));
|
||||
let goal_expansions =
|
||||
mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
|
||||
|
||||
vec![term_expansions, goal_expansions]
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SubModuleUser {
|
||||
fn atom_tbl(&self) -> TabledData<Atom>;
|
||||
fn op_dir(&mut self) -> &mut OpDir;
|
||||
fn remove_code_index(&mut self, _: PredicateKey);
|
||||
fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option<CodeIndex>;
|
||||
|
||||
fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex);
|
||||
|
||||
fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option<ClauseName> {
|
||||
self.op_dir()
|
||||
.get(&(name, fixity))
|
||||
.map(|op_val| op_val.owning_module())
|
||||
}
|
||||
|
||||
fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
|
||||
for export in module.module_decl.exports.iter().cloned() {
|
||||
match export {
|
||||
ModuleExport::PredicateKey((name, arity)) => {
|
||||
let name = name.defrock_brackets();
|
||||
|
||||
match self.get_code_index((name.clone(), arity), mod_name.clone()) {
|
||||
Some(CodeIndex(ref code_idx)) => {
|
||||
if &code_idx.borrow().1 != &module.module_decl.name {
|
||||
continue;
|
||||
}
|
||||
|
||||
self.remove_code_index((name.clone(), arity));
|
||||
|
||||
// remove or respecify ops.
|
||||
if arity == 2 {
|
||||
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
|
||||
if mod_name == module.module_decl.name {
|
||||
self.op_dir().remove(&(name.clone(), Fixity::In));
|
||||
}
|
||||
}
|
||||
} else if arity == 1 {
|
||||
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
|
||||
if mod_name == module.module_decl.name {
|
||||
self.op_dir().remove(&(name.clone(), Fixity::Pre));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
|
||||
{
|
||||
if mod_name == module.module_decl.name {
|
||||
self.op_dir().remove(&(name.clone(), Fixity::Post));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
},
|
||||
ModuleExport::OpDecl(op_decl) => {
|
||||
let op_dir = self.op_dir();
|
||||
op_dir.remove(&(op_decl.name(), op_decl.fixity()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns true on successful import.
|
||||
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
|
||||
let name = name.defrock_brackets();
|
||||
|
||||
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
|
||||
let name = name.with_table(submodule.atom_tbl.clone());
|
||||
let atom_tbl = self.atom_tbl();
|
||||
|
||||
atom_tbl.borrow_mut().insert(name.to_rc());
|
||||
|
||||
self.insert_dir_entry(name, arity, code_data.clone());
|
||||
true
|
||||
} else {
|
||||
submodule.is_impromptu_module
|
||||
}
|
||||
}
|
||||
|
||||
fn use_qualified_module(
|
||||
&mut self,
|
||||
_: &mut CodeRepo,
|
||||
_: MachineFlags,
|
||||
_: &Module,
|
||||
_: &Vec<ModuleExport>,
|
||||
) -> Result<(), SessionError>;
|
||||
|
||||
fn use_module(
|
||||
&mut self,
|
||||
_: &mut CodeRepo,
|
||||
_: MachineFlags,
|
||||
_: &Module
|
||||
) -> Result<(), SessionError>;
|
||||
}
|
||||
|
||||
pub fn use_qualified_module<User>(
|
||||
user: &mut User,
|
||||
submodule: &Module,
|
||||
exports: &Vec<ModuleExport>,
|
||||
) -> Result<(), SessionError>
|
||||
where
|
||||
User: SubModuleUser,
|
||||
{
|
||||
for export in exports.iter().cloned() {
|
||||
match export {
|
||||
ModuleExport::PredicateKey((name, arity)) => {
|
||||
if !submodule
|
||||
.module_decl
|
||||
.exports
|
||||
.contains(&ModuleExport::PredicateKey((name.clone(), arity)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if !user.import_decl(name.clone(), arity, submodule) {
|
||||
let submodule_name = submodule.module_decl.name.clone();
|
||||
|
||||
return Err(SessionError::ModuleDoesNotContainExport(
|
||||
submodule_name,
|
||||
(name, arity)
|
||||
));
|
||||
}
|
||||
},
|
||||
ModuleExport::OpDecl(op_decl) => {
|
||||
if !submodule
|
||||
.module_decl
|
||||
.exports
|
||||
.contains(&ModuleExport::OpDecl(op_decl.clone()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let op_dir = user.op_dir();
|
||||
let prec = op_decl.0;
|
||||
|
||||
op_decl.insert_into_op_dir(
|
||||
submodule.module_decl.name.clone(),
|
||||
op_dir,
|
||||
prec,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn use_module<User: SubModuleUser>(
|
||||
user: &mut User,
|
||||
submodule: &Module,
|
||||
) -> Result<(), SessionError> {
|
||||
for export in submodule.module_decl.exports.iter().cloned() {
|
||||
match export {
|
||||
ModuleExport::PredicateKey((name, arity)) => {
|
||||
if !user.import_decl(name.clone(), arity, submodule) {
|
||||
let submodule_name = submodule.module_decl.name.clone();
|
||||
|
||||
return Err(SessionError::ModuleDoesNotContainExport(
|
||||
submodule_name,
|
||||
(name, arity)
|
||||
));
|
||||
}
|
||||
}
|
||||
ModuleExport::OpDecl(op_decl) => {
|
||||
let op_dir = user.op_dir();
|
||||
let prec = op_decl.0;
|
||||
|
||||
op_decl.insert_into_op_dir(
|
||||
submodule.module_decl.name.clone(),
|
||||
op_dir,
|
||||
prec,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl SubModuleUser for Module {
|
||||
fn atom_tbl(&self) -> TabledData<Atom> {
|
||||
self.atom_tbl.clone()
|
||||
}
|
||||
|
||||
fn op_dir(&mut self) -> &mut OpDir {
|
||||
&mut self.op_dir
|
||||
}
|
||||
|
||||
fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
|
||||
self.code_dir.get(&key).cloned()
|
||||
}
|
||||
|
||||
fn remove_code_index(&mut self, key: PredicateKey) {
|
||||
self.code_dir.remove(&key);
|
||||
}
|
||||
|
||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
|
||||
self.code_dir.insert((name, arity), idx);
|
||||
}
|
||||
|
||||
fn use_qualified_module(
|
||||
&mut self,
|
||||
_: &mut CodeRepo,
|
||||
_: MachineFlags,
|
||||
submodule: &Module,
|
||||
exports: &Vec<ModuleExport>,
|
||||
) -> Result<(), SessionError> {
|
||||
use_qualified_module(self, submodule, exports)?;
|
||||
|
||||
(self.user_term_expansions.0)
|
||||
.0
|
||||
.extend((submodule.term_expansions.0).0.iter().cloned());
|
||||
self.user_term_expansions
|
||||
.1
|
||||
.extend(submodule.term_expansions.1.iter().cloned());
|
||||
|
||||
(self.user_goal_expansions.0)
|
||||
.0
|
||||
.extend((submodule.goal_expansions.0).0.iter().cloned());
|
||||
self.user_goal_expansions
|
||||
.1
|
||||
.extend(submodule.goal_expansions.1.iter().cloned());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn use_module(
|
||||
&mut self,
|
||||
_: &mut CodeRepo,
|
||||
_: MachineFlags,
|
||||
submodule: &Module,
|
||||
) -> Result<(), SessionError> {
|
||||
use_module(self, submodule)?;
|
||||
|
||||
(self.user_term_expansions.0)
|
||||
.0
|
||||
.extend((submodule.term_expansions.0).0.iter().cloned());
|
||||
self.user_term_expansions
|
||||
.1
|
||||
.extend(submodule.term_expansions.1.iter().cloned());
|
||||
|
||||
(self.user_goal_expansions.0)
|
||||
.0
|
||||
.extend((submodule.goal_expansions.0).0.iter().cloned());
|
||||
self.user_goal_expansions
|
||||
.1
|
||||
.extend(submodule.goal_expansions.1.iter().cloned());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
202
src/machine/partial_string.rs
Normal file
202
src/machine/partial_string.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use std::alloc;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::ops::RangeFrom;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PartialString {
|
||||
buf: *const u8,
|
||||
len: usize,
|
||||
_marker: PhantomData<[u8]>,
|
||||
}
|
||||
|
||||
impl Drop for PartialString {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
|
||||
alloc::dealloc(self.buf as *mut u8, layout);
|
||||
|
||||
self.buf = ptr::null();
|
||||
self.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for PartialString {
|
||||
#[inline]
|
||||
fn clone(&self) -> Self {
|
||||
self.clone_from_offset(0)
|
||||
}
|
||||
}
|
||||
|
||||
fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
|
||||
let mut terminator_idx = 0;
|
||||
|
||||
for c in iter {
|
||||
if c == '\u{0}' && terminator_idx != 0 {
|
||||
return terminator_idx;
|
||||
}
|
||||
|
||||
terminator_idx += c.len_utf8();
|
||||
}
|
||||
|
||||
terminator_idx
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PStrIter {
|
||||
buf: *const u8,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
impl PStrIter {
|
||||
#[inline]
|
||||
fn from(buf: *const u8, len: usize, idx: usize) -> Self {
|
||||
PStrIter {
|
||||
buf: (buf as usize + idx) as *const _,
|
||||
len: len - idx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for PStrIter {
|
||||
type Item = char;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
unsafe {
|
||||
let slice = slice::from_raw_parts(self.buf, self.len);
|
||||
let s = str::from_utf8(slice).unwrap();
|
||||
|
||||
if let Some(c) = s.chars().next() {
|
||||
self.buf = self.buf.offset(c.len_utf8() as isize);
|
||||
self.len -= c.len_utf8();
|
||||
|
||||
Some(c)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialString {
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn new(src: &str) -> Option<(Self, &str)> {
|
||||
let pstr = PartialString {
|
||||
buf: ptr::null_mut(),
|
||||
len: 0,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
pstr.append_chars(src)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
|
||||
let terminator_idx = scan_for_terminator(src.chars());
|
||||
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
terminator_idx + '\u{0}'.len_utf8(),
|
||||
mem::align_of::<u8>(),
|
||||
);
|
||||
|
||||
self.buf = alloc::alloc(layout) as *const _;
|
||||
self.len = terminator_idx + '\u{0}'.len_utf8();
|
||||
|
||||
ptr::copy(
|
||||
src.as_ptr(),
|
||||
self.buf as *mut _,
|
||||
terminator_idx,
|
||||
);
|
||||
|
||||
self.write_terminator_at(terminator_idx);
|
||||
|
||||
Some(if terminator_idx != src.as_bytes().len() {
|
||||
(self, &src[terminator_idx ..])
|
||||
} else {
|
||||
(self, "")
|
||||
})
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn clone_from_offset(&self, n: usize) -> Self {
|
||||
let len =
|
||||
if self.len - '\u{0}'.len_utf8() > n {
|
||||
self.len - n - '\u{0}'.len_utf8()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let mut pstr = PartialString {
|
||||
buf: ptr::null_mut(),
|
||||
len: len + '\u{0}'.len_utf8(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
len + '\u{0}'.len_utf8(),
|
||||
mem::align_of::<u8>(),
|
||||
);
|
||||
|
||||
pstr.buf = alloc::alloc(layout);
|
||||
|
||||
if len > 0 {
|
||||
ptr::copy(
|
||||
(self.buf as usize + n) as *const u8,
|
||||
pstr.buf as *mut _,
|
||||
len,
|
||||
);
|
||||
}
|
||||
|
||||
pstr.write_terminator_at(len);
|
||||
}
|
||||
|
||||
pstr
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super)
|
||||
fn write_terminator_at(&mut self, index: usize) {
|
||||
unsafe {
|
||||
ptr::write(
|
||||
(self.buf as usize + index) as *mut u8,
|
||||
0u8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
|
||||
if self.len >= '\u{0}'.len_utf8() {
|
||||
PStrIter::from(self.buf, self.len - '\u{0}'.len_utf8(), index.start)
|
||||
} else {
|
||||
PStrIter::from(self.buf, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn at_end(&self, end_n: usize) -> bool {
|
||||
end_n + 1 == self.len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_str_from(&self, n: usize) -> &str {
|
||||
unsafe {
|
||||
let slice = slice::from_raw_parts(
|
||||
self.buf,
|
||||
self.len - '\u{0}'.len_utf8(),
|
||||
);
|
||||
|
||||
let s = str::from_utf8(slice).unwrap();
|
||||
|
||||
&s[n ..]
|
||||
}
|
||||
}
|
||||
}
|
||||
110
src/machine/project_attributes.pl
Normal file
110
src/machine/project_attributes.pl
Normal file
@@ -0,0 +1,110 @@
|
||||
:- module('$project_atts', [copy_term/3]).
|
||||
|
||||
'$attribute_goals_driver'(QueryVars, AttrVars) :-
|
||||
gather_modules(AttrVars, Modules0, _),
|
||||
sort(Modules0, Modules),
|
||||
call_project_attributes(Modules, QueryVars, AttrVars),
|
||||
call_attribute_goals(Modules, call_query_var_goals, QueryVars),
|
||||
call_attribute_goals(Modules, call_attr_var_goals, AttrVars).
|
||||
|
||||
enqueue_goals(Goals0) :-
|
||||
nonvar(Goals0),
|
||||
Goals0 = [Goal | Goals],
|
||||
nonvar(Goal),
|
||||
!,
|
||||
'$enqueue_attribute_goal'(Goal),
|
||||
enqueue_goals(Goals).
|
||||
enqueue_goals(_).
|
||||
|
||||
'$print_project_attributes_exception'(Module, E) :-
|
||||
( E = error(evaluation_error((Module:project_attributes)/2), project_attributes/2) ->
|
||||
true
|
||||
; write_term('caught: ', [quoted(false)]),
|
||||
writeq(E),
|
||||
nl
|
||||
).
|
||||
|
||||
call_project_attributes([], _, _).
|
||||
call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
|
||||
( catch(Module:project_attributes(QueryVars, AttrVars),
|
||||
E,
|
||||
'$print_project_attributes_exception'(Module, E)
|
||||
)
|
||||
-> true
|
||||
; true
|
||||
),
|
||||
call_project_attributes(Modules, QueryVars, AttrVars).
|
||||
|
||||
call_attribute_goals([], _, _).
|
||||
call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
|
||||
call(GoalCaller, AttrVars, Module, Goals),
|
||||
enqueue_goals(Goals),
|
||||
call_attribute_goals(Modules, GoalCaller, AttrVars).
|
||||
|
||||
'$print_attribute_goals_exception'(Module, E) :-
|
||||
( E = error(evaluation_error((Module:attribute_goals)/3), attribute_goals/3)
|
||||
-> true
|
||||
; write_term('caught: ', [quoted(false)]),
|
||||
writeq(E),
|
||||
nl
|
||||
).
|
||||
|
||||
call_query_var_goals([], _, []).
|
||||
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
||||
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0)
|
||||
, atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
|
||||
),
|
||||
E,
|
||||
( '$print_attribute_goals_exception'(Module, E),
|
||||
atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
|
||||
))
|
||||
-> true
|
||||
; atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
|
||||
),
|
||||
call_query_var_goals(AttrVars, Module, RGoals).
|
||||
|
||||
call_attr_var_goals([], _, []).
|
||||
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
|
||||
( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
|
||||
E,
|
||||
'$print_attribute_goals_exception'(Module, E)
|
||||
)
|
||||
-> true
|
||||
; true
|
||||
),
|
||||
call_attr_var_goals(AttrVars, Module, RGoals).
|
||||
|
||||
gather_modules([], [], _).
|
||||
gather_modules([AttrVar|AttrVars], Modules, Modules0) :-
|
||||
'$get_attr_list'(AttrVar, Attrs),
|
||||
gather_modules_for_attrs(Attrs, Modules, Modules0),
|
||||
gather_modules(AttrVars, Modules0, _).
|
||||
|
||||
gather_modules_for_attrs(Attrs, Modules, Modules) :-
|
||||
var(Attrs), !.
|
||||
gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
|
||||
'$module_of'(Module, Attr),
|
||||
gather_modules_for_attrs(Attrs, Modules, Modules0).
|
||||
|
||||
module_prefixed_goals([], _, Gs, Gs).
|
||||
module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :-
|
||||
( G = _:_ -> MG = G
|
||||
; MG = Module:G
|
||||
),
|
||||
module_prefixed_goals(Gs, Module, MGs, TailGs).
|
||||
|
||||
call_attribute_goals_with_module_prefix([], _, _, []).
|
||||
call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars, Goals) :-
|
||||
call(GoalCaller, AttrVars, Module, Goals0),
|
||||
enqueue_goals(Goals0),
|
||||
module_prefixed_goals(Goals0, Module, Goals, Gs),
|
||||
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
|
||||
|
||||
copy_term(Source, Dest, Goals) :-
|
||||
'$term_attributed_variables'(Source, Vars),
|
||||
gather_modules(Vars, Modules0, _),
|
||||
sort(Modules0, Modules),
|
||||
call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0),
|
||||
sort(Goals0, Goals1),
|
||||
!,
|
||||
'$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).
|
||||
109
src/machine/raw_block.rs
Normal file
109
src/machine/raw_block.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use std::alloc;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
pub(crate) trait RawBlockTraits {
|
||||
fn init_size() -> usize;
|
||||
fn align() -> usize;
|
||||
|
||||
#[inline]
|
||||
fn base_offset(base: *const u8) -> *const u8 {
|
||||
base
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct RawBlock<T: RawBlockTraits> {
|
||||
pub(crate) size: usize,
|
||||
pub(crate) base: *const u8,
|
||||
pub(crate) top: *const u8,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> RawBlock<T> {
|
||||
pub(crate)
|
||||
fn new() -> Self {
|
||||
let mut block = RawBlock { size: 0,
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
_marker: PhantomData };
|
||||
|
||||
unsafe {
|
||||
block.grow();
|
||||
}
|
||||
|
||||
block
|
||||
}
|
||||
|
||||
unsafe fn init_at_size(&mut self, cap: usize) {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
|
||||
|
||||
self.base = alloc::alloc(layout) as *const _;
|
||||
self.size = cap;
|
||||
|
||||
self.top = T::base_offset(self.base);
|
||||
}
|
||||
|
||||
pub(super)
|
||||
unsafe fn grow(&mut self) {
|
||||
if self.size == 0 {
|
||||
self.init_at_size(T::init_size());
|
||||
} else {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(T::init_size(), T::align());
|
||||
let top_dist = self.top as usize - self.base as usize;
|
||||
|
||||
self.base = alloc::realloc(self.base as *mut _, layout, self.size*2) as *const _;
|
||||
self.top = (self.base as usize + top_dist) as *const _;
|
||||
self.size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_block() -> Self {
|
||||
RawBlock { size: 0,
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
_marker: PhantomData }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn take(&mut self) -> Self {
|
||||
mem::replace(self, Self::empty_block())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn free_space(&self) -> usize {
|
||||
debug_assert!(self.top >= self.base,
|
||||
"self.top = {:?} < {:?} = self.base",
|
||||
self.top, self.base);
|
||||
|
||||
self.size - (self.top as usize - self.base as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate)
|
||||
unsafe fn new_block(&mut self, size: usize) -> *const u8 {
|
||||
loop {
|
||||
if self.free_space() >= size {
|
||||
return (self.top as usize + size) as *const _;
|
||||
} else {
|
||||
self.grow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate)
|
||||
fn deallocate(&mut self) {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.size, T::align());
|
||||
|
||||
alloc::dealloc(self.base as *mut u8, layout);
|
||||
|
||||
self.top = ptr::null();
|
||||
self.base = ptr::null();
|
||||
self.size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
280
src/machine/stack.rs
Normal file
280
src/machine/stack.rs
Normal file
@@ -0,0 +1,280 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::raw_block::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StackTraits {}
|
||||
|
||||
impl RawBlockTraits for StackTraits {
|
||||
#[inline]
|
||||
fn init_size() -> usize {
|
||||
10 * 1024 * 1024
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
mem::align_of::<Addr>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn base_offset(base: *const u8) -> *const u8 {
|
||||
unsafe {
|
||||
base.offset(Self::align() as isize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const fn prelude_size<Prelude>() -> usize {
|
||||
let size = mem::size_of::<Prelude>();
|
||||
let align = mem::align_of::<Addr>();
|
||||
|
||||
(size & !(align - 1)) + align
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Stack {
|
||||
buf: RawBlock<StackTraits>,
|
||||
_marker: PhantomData<Addr>,
|
||||
}
|
||||
|
||||
impl Drop for Stack {
|
||||
fn drop(&mut self) {
|
||||
self.drop_in_place();
|
||||
self.buf.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FramePrelude {
|
||||
pub num_cells: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AndFramePrelude {
|
||||
pub univ_prelude: FramePrelude,
|
||||
pub e: usize,
|
||||
pub cp: LocalCodePtr,
|
||||
pub interrupt_cp: LocalCodePtr,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AndFrame {
|
||||
pub prelude: AndFramePrelude,
|
||||
}
|
||||
|
||||
impl AndFrame {
|
||||
pub fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for AndFrame {
|
||||
type Output = Addr;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&*(ptr as *const Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for AndFrame {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&mut *(ptr as *mut Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrFramePrelude {
|
||||
pub univ_prelude: FramePrelude,
|
||||
pub e: usize,
|
||||
pub cp: LocalCodePtr,
|
||||
pub b: usize,
|
||||
pub bp: LocalCodePtr,
|
||||
pub tr: usize,
|
||||
pub pstr_tr: usize,
|
||||
pub h: usize,
|
||||
pub b0: usize,
|
||||
pub attr_var_init_queue_b: usize,
|
||||
pub attr_var_init_bindings_b: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OrFrame {
|
||||
pub prelude: OrFramePrelude,
|
||||
}
|
||||
|
||||
impl Index<usize> for OrFrame {
|
||||
type Output = Addr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
let index_offset = index * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&*(ptr as *const Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for OrFrame {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
let index_offset = index * mem::size_of::<Addr>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&mut *(ptr as *mut Addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OrFrame {
|
||||
pub fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Stack {
|
||||
pub fn new() -> Self {
|
||||
Stack { buf: RawBlock::new(), _marker: PhantomData }
|
||||
}
|
||||
|
||||
pub fn allocate_and_frame(&mut self, num_cells: usize) -> usize {
|
||||
let frame_size = AndFrame::size_of(num_cells);
|
||||
|
||||
unsafe {
|
||||
let new_top = self.buf.new_block(frame_size);
|
||||
let e = self.buf.top as usize - self.buf.base as usize;
|
||||
|
||||
for idx in 0 .. num_cells {
|
||||
let offset = prelude_size::<AndFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||
ptr::write(
|
||||
(self.buf.top as usize + offset) as *mut Addr,
|
||||
Addr::StackCell(e, idx + 1),
|
||||
);
|
||||
}
|
||||
|
||||
let and_frame = &mut *(self.buf.top as *mut AndFrame);
|
||||
and_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
self.buf.top = new_top;
|
||||
|
||||
e
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
|
||||
let frame_size = OrFrame::size_of(num_cells);
|
||||
|
||||
unsafe {
|
||||
let new_top = self.buf.new_block(frame_size);
|
||||
let b = self.buf.top as usize - self.buf.base as usize;
|
||||
|
||||
for idx in 0 .. num_cells {
|
||||
let offset = prelude_size::<OrFramePrelude>() + idx * mem::size_of::<Addr>();
|
||||
ptr::write(
|
||||
(self.buf.top as usize + offset) as *mut Addr,
|
||||
Addr::StackCell(b, idx),
|
||||
);
|
||||
}
|
||||
|
||||
let or_frame = &mut *(self.buf.top as *mut OrFrame);
|
||||
or_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
self.buf.top = new_top;
|
||||
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_and_frame(&self, e: usize) -> &AndFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + e;
|
||||
&*(ptr as *const AndFrame)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + e;
|
||||
&mut *(ptr as *mut AndFrame)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_or_frame(&self, b: usize) -> &OrFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + b;
|
||||
&*(ptr as *const OrFrame)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + b;
|
||||
&mut *(ptr as *mut OrFrame)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take(&mut self) -> Self {
|
||||
Stack { buf: self.buf.take(), _marker: PhantomData }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn truncate(&mut self, b: usize) {
|
||||
if b == 0 {
|
||||
self.inner_truncate(mem::align_of::<Addr>());
|
||||
} else {
|
||||
self.inner_truncate(b);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn inner_truncate(&mut self, b: usize) {
|
||||
let base = b + self.buf.base as usize;
|
||||
|
||||
if base < self.buf.top as usize {
|
||||
self.buf.top = base as *const _;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn drop_in_place(&mut self) {
|
||||
self.truncate(mem::align_of::<Addr>());
|
||||
|
||||
debug_assert!(if self.buf.top.is_null() {
|
||||
self.buf.top == self.buf.base
|
||||
} else {
|
||||
self.buf.top as usize == self.buf.base as usize + mem::align_of::<Addr>()
|
||||
});
|
||||
}
|
||||
}
|
||||
1137
src/machine/streams.rs
Normal file
1137
src/machine/streams.rs
Normal file
File diff suppressed because it is too large
Load Diff
5620
src/machine/system_calls.rs
Normal file
5620
src/machine/system_calls.rs
Normal file
File diff suppressed because it is too large
Load Diff
394
src/machine/term_expansion.rs
Normal file
394
src/machine/term_expansion.rs
Normal file
@@ -0,0 +1,394 @@
|
||||
use crate::prolog_parser::ast::*;
|
||||
use crate::prolog_parser::parser::*;
|
||||
|
||||
use crate::machine::machine_indices::HeapCellValue;
|
||||
use crate::machine::*;
|
||||
use crate::rug::ops::Pow;
|
||||
use crate::rug::Integer;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::iter::Rev;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
|
||||
where
|
||||
I: DoubleEndedIterator<Item = Term>,
|
||||
{
|
||||
for prec in terms.rev() {
|
||||
term = Term::Clause(
|
||||
Cell::default(),
|
||||
sym.clone(),
|
||||
vec![Box::new(prec), Box::new(term)],
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
term
|
||||
}
|
||||
|
||||
fn extract_from_list(
|
||||
head: Box<Term>,
|
||||
tail: Box<Term>,
|
||||
) -> Result<Rev<IntoIter<Term>>, ParserError>
|
||||
{
|
||||
let mut terms = vec![*head];
|
||||
let mut tail = *tail;
|
||||
|
||||
while let Term::Cons(_, head, next_tail) = tail {
|
||||
terms.push(*head);
|
||||
tail = *next_tail;
|
||||
}
|
||||
|
||||
if let Term::Constant(_, Constant::EmptyList) = tail {
|
||||
Ok(terms.into_iter().rev())
|
||||
} else {
|
||||
Err(ParserError::ExpectedTopLevelTerm)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TermStream<'a> {
|
||||
stack: Vec<Term>,
|
||||
pub(crate) wam: &'a mut Machine,
|
||||
parser: Parser<'a, Stream>,
|
||||
pub(crate) flags: MachineFlags,
|
||||
term_expansion_lens: (usize, usize),
|
||||
goal_expansion_lens: (usize, usize),
|
||||
top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExpansionAdditionResult {
|
||||
term_expansion_additions: (Predicate, VecDeque<TopLevel>),
|
||||
goal_expansion_additions: (Predicate, VecDeque<TopLevel>),
|
||||
}
|
||||
|
||||
impl ExpansionAdditionResult {
|
||||
pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
|
||||
let tes = mem::replace(&mut self.term_expansion_additions.0, Predicate::new());
|
||||
let teqs = mem::replace(&mut self.term_expansion_additions.1, VecDeque::from(vec![]));
|
||||
|
||||
(tes, teqs)
|
||||
}
|
||||
|
||||
pub fn take_goal_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
|
||||
let ges = mem::replace(&mut self.goal_expansion_additions.0, Predicate::new());
|
||||
let geqs = mem::replace(&mut self.goal_expansion_additions.1, VecDeque::from(vec![]));
|
||||
|
||||
(ges, geqs)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for TermStream<'a> {
|
||||
fn drop(&mut self) {
|
||||
self.wam.indices.in_situ_code_dir.clear();
|
||||
self.wam.indices.in_situ_module_dir.clear();
|
||||
|
||||
self.wam.code_repo.in_situ_code.clear();
|
||||
discard_result!(self.rollback_expansion_code());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TermStream<'a> {
|
||||
pub fn new(
|
||||
src: &'a mut ParsingStream<Stream>,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
flags: MachineFlags,
|
||||
wam: &'a mut Machine,
|
||||
) -> Self {
|
||||
TermStream {
|
||||
stack: Vec::new(),
|
||||
term_expansion_lens: wam
|
||||
.code_repo
|
||||
.term_dir_entry_len((clause_name!("term_expansion"), 2)),
|
||||
goal_expansion_lens: wam
|
||||
.code_repo
|
||||
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
|
||||
wam,
|
||||
parser: Parser::new(src, atom_tbl, flags),
|
||||
flags,
|
||||
top_level_terms: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> {
|
||||
mem::replace(&mut self.top_level_terms, vec![])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
|
||||
match hook {
|
||||
CompileTimeHook::UserTermExpansion => {
|
||||
self.term_expansion_lens.0 += len;
|
||||
self.term_expansion_lens.1 += queue_len;
|
||||
}
|
||||
CompileTimeHook::UserGoalExpansion => {
|
||||
self.goal_expansion_lens.0 += len;
|
||||
self.goal_expansion_lens.1 += queue_len;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn line_num(&self) -> usize {
|
||||
self.parser.line_num()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn col_num(&self) -> usize {
|
||||
self.parser.col_num()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn update_expansion_lens(&mut self) {
|
||||
let te_key = (clause_name!("term_expansion"), 2);
|
||||
let ge_key = (clause_name!("goal_expansion"), 2);
|
||||
|
||||
let (tes_len, tes_q_len) = self.wam.code_repo.term_dir_entry_len(te_key);
|
||||
|
||||
self.term_expansion_lens.0 = tes_len;
|
||||
self.term_expansion_lens.1 = tes_q_len;
|
||||
|
||||
let (ges_len, ges_q_len) = self.wam.code_repo.term_dir_entry_len(ge_key);
|
||||
|
||||
self.goal_expansion_lens.0 = ges_len;
|
||||
self.goal_expansion_lens.1 = ges_q_len;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
|
||||
self.parser.set_atom_tbl(atom_tbl);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn eof(&mut self) -> Result<bool, ParserError> {
|
||||
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
|
||||
Ok(self.stack.is_empty() && self.parser.eof()?)
|
||||
}
|
||||
|
||||
pub fn rollback_expansion_code(&mut self) -> Result<ExpansionAdditionResult, ParserError> {
|
||||
let te_len = self.term_expansion_lens.0;
|
||||
let te_queue_len = self.term_expansion_lens.1;
|
||||
|
||||
let ge_len = self.goal_expansion_lens.0;
|
||||
let ge_queue_len = self.goal_expansion_lens.1;
|
||||
|
||||
let term_expansion_additions = self.wam.code_repo.truncate_terms(
|
||||
(clause_name!("term_expansion"), 2),
|
||||
te_len,
|
||||
te_queue_len,
|
||||
);
|
||||
|
||||
let goal_expansion_additions = self.wam.code_repo.truncate_terms(
|
||||
(clause_name!("goal_expansion"), 2),
|
||||
ge_len,
|
||||
ge_queue_len,
|
||||
);
|
||||
|
||||
self.wam
|
||||
.code_repo
|
||||
.compile_hook(CompileTimeHook::TermExpansion)?;
|
||||
self.wam
|
||||
.code_repo
|
||||
.compile_hook(CompileTimeHook::GoalExpansion)?;
|
||||
|
||||
Ok(ExpansionAdditionResult {
|
||||
term_expansion_additions,
|
||||
goal_expansion_additions,
|
||||
})
|
||||
}
|
||||
|
||||
fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
|
||||
match term {
|
||||
Term::Cons(_, head, tail) => {
|
||||
let iter = extract_from_list(head, tail)?;
|
||||
Ok(self.stack.extend(iter))
|
||||
}
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
|
||||
Ok(self.stack.push(term))
|
||||
}
|
||||
_ => {
|
||||
Err(ParserError::ExpectedTopLevelTerm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expansion_output(
|
||||
&self,
|
||||
term_string: &str,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<Term, ParserError> {
|
||||
let mut stream = parsing_stream(term_string.trim().as_bytes())?;
|
||||
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
|
||||
|
||||
parser.read_term(composite_op!(
|
||||
false,
|
||||
&self.wam.indices.op_dir,
|
||||
op_dir
|
||||
))
|
||||
}
|
||||
|
||||
pub fn expand_term(&mut self, term: Term, op_dir: &OpDir) -> Result<Term, ParserError> {
|
||||
let mut machine_st = MachineState::new();
|
||||
|
||||
self.stack.push(term);
|
||||
|
||||
while let Some(term) = self.stack.pop() {
|
||||
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) {
|
||||
Some(term_string) => {
|
||||
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
|
||||
self.enqueue_term(term)?;
|
||||
}
|
||||
None => {
|
||||
return Ok(term);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> {
|
||||
loop {
|
||||
if let Some(term) = self.stack.pop() {
|
||||
return Ok(self.expand_term(term, op_dir)?);
|
||||
}
|
||||
|
||||
self.parser.reset();
|
||||
|
||||
let line_num = self.line_num();
|
||||
let col_num = self.col_num();
|
||||
|
||||
let term = self.parser.read_term(composite_op!(
|
||||
false,
|
||||
&self.wam.indices.op_dir,
|
||||
op_dir
|
||||
))?;
|
||||
|
||||
// preserve a copy of the original unexpanded term for warning scans,
|
||||
// if that stage is reached.
|
||||
self.top_level_terms.push((term.clone(), line_num, col_num));
|
||||
self.stack.push(term);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super)
|
||||
fn expand_goals(
|
||||
&mut self,
|
||||
machine_st: &mut MachineState,
|
||||
op_dir: &OpDir,
|
||||
mut terms: VecDeque<Term>,
|
||||
) -> Result<Vec<Term>, ParserError> {
|
||||
let mut results = vec![];
|
||||
|
||||
while let Some(term) = terms.pop_front() {
|
||||
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::GoalExpansion) {
|
||||
Some(term_string) => {
|
||||
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
|
||||
|
||||
match term {
|
||||
Term::Cons(_, head, tail) => {
|
||||
for term in extract_from_list(head, tail)? {
|
||||
terms.push_front(term);
|
||||
}
|
||||
}
|
||||
term => terms.push_front(term),
|
||||
};
|
||||
}
|
||||
None => results.push(term),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super)
|
||||
fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
|
||||
let output = PrinterOutputter::new();
|
||||
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
||||
let mut max_var_length = 0;
|
||||
|
||||
for var in self.heap_locs.keys() {
|
||||
max_var_length = std::cmp::max(var.len(), max_var_length);
|
||||
}
|
||||
|
||||
printer.quoted = true;
|
||||
printer.numbervars = true;
|
||||
|
||||
// the purpose of the offset is to avoid clashes with variable
|
||||
// names that might occur after the addresses in the expanded
|
||||
// term are substituted with the variable names in the
|
||||
// pre-expansion term. This formula ensures that all generated
|
||||
// "numbervars"- style variable names will be longer than the
|
||||
// keys of the var_dict, and therefore not equal to any of
|
||||
// them.
|
||||
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
|
||||
printer.print_strings_as_strs = true;
|
||||
printer.drop_toplevel_spec();
|
||||
|
||||
printer.see_all_locs();
|
||||
|
||||
let mut output = printer.print(addr);
|
||||
|
||||
output.push_char('.');
|
||||
output
|
||||
}
|
||||
|
||||
// reset the machine, but keep the heap contents as they were.
|
||||
// this prevents clashes between underscored variable names in the
|
||||
// same query.
|
||||
fn reset_with_heap_preservation(&mut self) {
|
||||
let heap = self.heap.take();
|
||||
self.reset();
|
||||
self.heap = heap;
|
||||
}
|
||||
|
||||
fn try_expand_term(
|
||||
&mut self,
|
||||
wam: &mut Machine,
|
||||
term: &Term,
|
||||
hook: CompileTimeHook,
|
||||
) -> Option<String> {
|
||||
let term_write_result = write_term_to_heap(term, self);
|
||||
let h = self.heap.h();
|
||||
|
||||
self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
|
||||
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||
self[temp_v!(2)] = Addr::HeapCell(h);
|
||||
|
||||
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
|
||||
wam.code_repo.cached_query = code;
|
||||
|
||||
self.cp = LocalCodePtr::TopLevel(0, 0);
|
||||
|
||||
self.at_end_of_expansion = false;
|
||||
self.flags.double_quotes = DoubleQuotes::Chars;
|
||||
|
||||
self.query_stepper(
|
||||
&mut wam.indices,
|
||||
&mut MachinePolicies::default(),
|
||||
&mut wam.code_repo,
|
||||
&mut readline::input_stream(),
|
||||
&mut Stream::stdout(),
|
||||
);
|
||||
|
||||
if self.fail || self.at_end_of_expansion {
|
||||
self.reset_with_heap_preservation();
|
||||
None
|
||||
} else {
|
||||
let TermWriteResult { var_dict, .. } = term_write_result;
|
||||
|
||||
self.heap_locs = var_dict;
|
||||
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
|
||||
|
||||
self.reset_with_heap_preservation();
|
||||
|
||||
Some(output.result())
|
||||
}
|
||||
}
|
||||
}
|
||||
1335
src/machine/toplevel.rs
Normal file
1335
src/machine/toplevel.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user