Merge branch 'rebis-dev' into 0.9.0 release
This commit is contained in:
@@ -1,53 +1,57 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::temp_v;
|
||||
use crate::parser::ast::*;
|
||||
use crate::temp_v;
|
||||
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::targets::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) trait Allocator<'a> {
|
||||
pub(crate) trait Allocator {
|
||||
fn new() -> Self;
|
||||
|
||||
fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Vec<Target>)
|
||||
where
|
||||
Target: CompilationTarget<'a>;
|
||||
fn mark_non_var<Target>(
|
||||
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
_: Level,
|
||||
_: GenContext,
|
||||
_: &'a Cell<RegType>,
|
||||
_: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>;
|
||||
fn mark_reserved_var<Target>(
|
||||
lvl: Level,
|
||||
context: GenContext,
|
||||
code: &mut Code,
|
||||
);
|
||||
|
||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
_: Rc<Var>,
|
||||
_: Level,
|
||||
_: &'a Cell<VarReg>,
|
||||
_: GenContext,
|
||||
_: &mut Vec<Target>,
|
||||
_: RegType,
|
||||
_: bool,
|
||||
) where
|
||||
Target: CompilationTarget<'a>;
|
||||
fn mark_var<Target>(
|
||||
lvl: Level,
|
||||
context: GenContext,
|
||||
cell: &'a Cell<RegType>,
|
||||
code: &mut Code,
|
||||
);
|
||||
|
||||
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
_: Rc<Var>,
|
||||
_: Level,
|
||||
_: &'a Cell<VarReg>,
|
||||
_: GenContext,
|
||||
_: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>;
|
||||
var_name: Rc<String>,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
code: &mut Code,
|
||||
r: RegType,
|
||||
is_new_var: bool,
|
||||
);
|
||||
|
||||
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
var_name: Rc<String>,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
context: GenContext,
|
||||
code: &mut Code,
|
||||
);
|
||||
|
||||
fn reset(&mut self);
|
||||
fn reset_contents(&mut self) {}
|
||||
fn reset_arg(&mut self, _: usize);
|
||||
fn reset_at_head(&mut self, _: &Vec<Box<Term>>);
|
||||
fn reset_arg(&mut self, arg_num: usize);
|
||||
fn reset_at_head(&mut self, args: &Vec<Term>);
|
||||
|
||||
fn advance_arg(&mut self);
|
||||
|
||||
@@ -56,7 +60,7 @@ pub(crate) trait Allocator<'a> {
|
||||
|
||||
fn take_bindings(self) -> AllocVarDict;
|
||||
|
||||
fn drain_var_data(
|
||||
fn drain_var_data<'a>(
|
||||
&mut self,
|
||||
vs: VariableFixtures<'a>,
|
||||
num_of_chunks: usize,
|
||||
@@ -83,17 +87,17 @@ pub(crate) trait Allocator<'a> {
|
||||
perm_vs
|
||||
}
|
||||
|
||||
fn get(&self, var: Rc<Var>) -> RegType {
|
||||
fn get(&self, var: Rc<String>) -> RegType {
|
||||
self.bindings()
|
||||
.get(&var)
|
||||
.map_or(temp_v!(0), |v| v.as_reg_type())
|
||||
}
|
||||
|
||||
fn is_unbound(&self, var: Rc<Var>) -> bool {
|
||||
fn is_unbound(&self, var: Rc<String>) -> bool {
|
||||
self.get(var).reg_num() == 0
|
||||
}
|
||||
|
||||
fn record_register(&mut self, var: Rc<Var>, r: RegType) {
|
||||
fn record_register(&mut self, var: Rc<String>, r: RegType) {
|
||||
match self.bindings_mut().get_mut(&var).unwrap() {
|
||||
&mut VarData::Temp(_, ref mut s, _) => *s = r.reg_num(),
|
||||
&mut VarData::Perm(ref mut s) => *s = r.reg_num(),
|
||||
|
||||
801
src/arena.rs
Normal file
801
src/arena.rs
Normal file
@@ -0,0 +1,801 @@
|
||||
use crate::machine::loader::LiveLoadState;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::streams::*;
|
||||
use crate::read::*;
|
||||
|
||||
use modular_bitfield::prelude::*;
|
||||
use ordered_float::OrderedFloat;
|
||||
use rug::{Integer, Rational};
|
||||
|
||||
use std::alloc;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::net::TcpListener;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::ptr;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! arena_alloc {
|
||||
($e:expr, $arena:expr) => {{
|
||||
let result = $e;
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe { $arena.alloc(result) }
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
|
||||
#[bits = 7]
|
||||
pub enum ArenaHeaderTag {
|
||||
F64 = 0b01,
|
||||
Integer = 0b10,
|
||||
Rational = 0b11,
|
||||
OssifiedOpDir = 0b0000100,
|
||||
LiveLoadState = 0b0001000,
|
||||
InactiveLoadState = 0b1011000,
|
||||
InputFileStream = 0b10000,
|
||||
OutputFileStream = 0b10100,
|
||||
NamedTcpStream = 0b011100,
|
||||
NamedTlsStream = 0b100000,
|
||||
ReadlineStream = 0b110000,
|
||||
StaticStringStream = 0b110100,
|
||||
ByteStream = 0b111000,
|
||||
StandardOutputStream = 0b1100,
|
||||
StandardErrorStream = 0b11000,
|
||||
NullStream = 0b111100,
|
||||
TcpListener = 0b1000000,
|
||||
Dropped = 0b1000100,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ArenaHeader {
|
||||
size: B56,
|
||||
m: bool,
|
||||
tag: ArenaHeaderTag,
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<ArenaHeader>() == 8);
|
||||
|
||||
impl ArenaHeader {
|
||||
#[inline]
|
||||
pub fn build_with(size: u64, tag: ArenaHeaderTag) -> Self {
|
||||
ArenaHeader::new()
|
||||
.with_size(size)
|
||||
.with_tag(tag)
|
||||
.with_m(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tag(self) -> ArenaHeaderTag {
|
||||
self.tag()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord)]
|
||||
pub struct TypedArenaPtr<T: ?Sized>(ptr::NonNull<T>);
|
||||
|
||||
impl<T: ?Sized + PartialEq> PartialEq for TypedArenaPtr<T> {
|
||||
fn eq(&self, other: &TypedArenaPtr<T>) -> bool {
|
||||
self.0 == other.0 || &**self == &**other
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized + PartialEq> Eq for TypedArenaPtr<T> {}
|
||||
|
||||
impl<T: ?Sized + Hash> Hash for TypedArenaPtr<T> {
|
||||
#[inline(always)]
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
(&*self as &T).hash(hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Clone for TypedArenaPtr<T> {
|
||||
fn clone(&self) -> Self {
|
||||
TypedArenaPtr(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Copy for TypedArenaPtr<T> {}
|
||||
|
||||
impl<T: ?Sized> Deref for TypedArenaPtr<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> DerefMut for TypedArenaPtr<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for TypedArenaPtr<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", **self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> TypedArenaPtr<T> {
|
||||
#[inline]
|
||||
pub const fn new(data: *mut T) -> Self {
|
||||
unsafe { TypedArenaPtr(ptr::NonNull::new_unchecked(data)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ptr(&self) -> *mut T {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn header_ptr(&self) -> *const ArenaHeader {
|
||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
||||
ptr as *const ArenaHeader
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn header_ptr_mut(&mut self) -> *mut ArenaHeader {
|
||||
let mut ptr = self.as_ptr() as *const u8 as usize;
|
||||
ptr -= mem::size_of::<*const ArenaHeader>();
|
||||
ptr as *mut ArenaHeader
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mark_bit(&self) -> bool {
|
||||
unsafe { (*self.header_ptr()).m() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_tag(&mut self, tag: ArenaHeaderTag) {
|
||||
unsafe { (*self.header_ptr_mut()).set_tag(tag); }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tag(&self) -> ArenaHeaderTag {
|
||||
unsafe { (*self.header_ptr()).get_tag() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mark(&mut self) {
|
||||
unsafe {
|
||||
(*self.header_ptr_mut()).set_m(true);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn unmark(&mut self) {
|
||||
unsafe {
|
||||
(*self.header_ptr_mut()).set_m(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ArenaAllocated {
|
||||
type PtrToAllocated;
|
||||
|
||||
fn tag() -> ArenaHeaderTag;
|
||||
fn size(&self) -> usize;
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct F64Ptr(pub TypedArenaPtr<OrderedFloat<f64>>);
|
||||
|
||||
impl fmt::Display for F64Ptr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for F64Ptr {
|
||||
type Target = TypedArenaPtr<OrderedFloat<f64>>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for F64Ptr {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for OrderedFloat<f64> {
|
||||
type PtrToAllocated = F64Ptr;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::F64
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
F64Ptr(TypedArenaPtr::new(dst as *mut Self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for Integer {
|
||||
type PtrToAllocated = TypedArenaPtr<Integer>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::Integer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for Rational {
|
||||
type PtrToAllocated = TypedArenaPtr<Rational>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::Rational
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for OssifiedOpDir {
|
||||
type PtrToAllocated = TypedArenaPtr<OssifiedOpDir>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::OssifiedOpDir
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for LiveLoadState {
|
||||
type PtrToAllocated = TypedArenaPtr<LiveLoadState>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::LiveLoadState
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaAllocated for TcpListener {
|
||||
type PtrToAllocated = TypedArenaPtr<TcpListener>;
|
||||
|
||||
#[inline]
|
||||
fn tag() -> ArenaHeaderTag {
|
||||
ArenaHeaderTag::TcpListener
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size(&self) -> usize {
|
||||
mem::size_of::<Self>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_to_arena(self, dst: *mut Self) -> Self::PtrToAllocated {
|
||||
unsafe {
|
||||
ptr::write(dst, self);
|
||||
TypedArenaPtr::new(dst as *mut Self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct AllocSlab {
|
||||
next: *mut AllocSlab,
|
||||
header: ArenaHeader,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Arena(*mut AllocSlab);
|
||||
|
||||
unsafe impl Send for Arena {}
|
||||
unsafe impl Sync for Arena {}
|
||||
|
||||
impl Arena {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Arena(ptr::null_mut())
|
||||
}
|
||||
|
||||
pub unsafe fn alloc<T: ArenaAllocated>(&mut self, value: T) -> T::PtrToAllocated {
|
||||
let size = value.size() + mem::size_of::<AllocSlab>();
|
||||
|
||||
let align = mem::align_of::<AllocSlab>();
|
||||
let layout = alloc::Layout::from_size_align_unchecked(size, align);
|
||||
|
||||
let slab = alloc::alloc(layout) as *mut AllocSlab;
|
||||
|
||||
(*slab).next = self.0;
|
||||
(*slab).header = ArenaHeader::build_with(value.size() as u64, T::tag());
|
||||
|
||||
let offset = (*slab).payload_offset();
|
||||
let result = value.copy_to_arena(offset as *mut T);
|
||||
|
||||
self.0 = slab;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn drop_slab_in_place(value: &mut AllocSlab) {
|
||||
use crate::parser::char_reader::CharReader;
|
||||
|
||||
match value.header.tag() {
|
||||
ArenaHeaderTag::Integer => {
|
||||
ptr::drop_in_place(value.payload_offset::<Integer>());
|
||||
}
|
||||
ArenaHeaderTag::Rational => {
|
||||
ptr::drop_in_place(value.payload_offset::<Rational>());
|
||||
}
|
||||
ArenaHeaderTag::InputFileStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<InputFileStream>>>());
|
||||
}
|
||||
ArenaHeaderTag::OutputFileStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<OutputFileStream>>());
|
||||
}
|
||||
ArenaHeaderTag::NamedTcpStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTcpStream>>>());
|
||||
}
|
||||
ArenaHeaderTag::NamedTlsStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<NamedTlsStream>>>());
|
||||
}
|
||||
ArenaHeaderTag::ReadlineStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<ReadlineStream>>());
|
||||
}
|
||||
ArenaHeaderTag::StaticStringStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<StaticStringStream>>());
|
||||
}
|
||||
ArenaHeaderTag::ByteStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<CharReader<ByteStream>>>());
|
||||
}
|
||||
ArenaHeaderTag::OssifiedOpDir => {
|
||||
ptr::drop_in_place(value.payload_offset::<OssifiedOpDir>());
|
||||
}
|
||||
ArenaHeaderTag::LiveLoadState | ArenaHeaderTag::InactiveLoadState => {
|
||||
ptr::drop_in_place(value.payload_offset::<LiveLoadState>());
|
||||
}
|
||||
ArenaHeaderTag::Dropped => {
|
||||
}
|
||||
ArenaHeaderTag::TcpListener => {
|
||||
ptr::drop_in_place(value.payload_offset::<TcpListener>());
|
||||
}
|
||||
ArenaHeaderTag::StandardOutputStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardOutputStream>>());
|
||||
}
|
||||
ArenaHeaderTag::StandardErrorStream => {
|
||||
ptr::drop_in_place(value.payload_offset::<StreamLayout<StandardErrorStream>>());
|
||||
}
|
||||
ArenaHeaderTag::F64 | ArenaHeaderTag::NullStream => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Arena {
|
||||
fn drop(&mut self) {
|
||||
let mut ptr = self.0;
|
||||
|
||||
while !ptr.is_null() {
|
||||
unsafe {
|
||||
let ptr_r = &*ptr;
|
||||
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
ptr_r.slab_size(),
|
||||
mem::align_of::<AllocSlab>(),
|
||||
);
|
||||
|
||||
drop_slab_in_place(&mut *ptr);
|
||||
|
||||
let next_ptr = ptr_r.next;
|
||||
alloc::dealloc(ptr as *mut u8, layout);
|
||||
ptr = next_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
self.0 = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<AllocSlab>() == 16);
|
||||
|
||||
impl AllocSlab {
|
||||
#[inline]
|
||||
fn slab_size(&self) -> usize {
|
||||
self.header.size() as usize + mem::size_of::<AllocSlab>()
|
||||
}
|
||||
|
||||
fn payload_offset<T>(&self) -> *mut T {
|
||||
let mut ptr = (self as *const AllocSlab) as usize;
|
||||
ptr += mem::size_of::<AllocSlab>();
|
||||
ptr as *mut T
|
||||
}
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::machine::mock_wam::*;
|
||||
use crate::machine::partial_string::*;
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
use rug::{Integer, Rational};
|
||||
|
||||
#[test]
|
||||
fn float_ptr_cast() {
|
||||
let mut wam = MockWAM::new();
|
||||
|
||||
let f = OrderedFloat(0f64);
|
||||
let mut fp = arena_alloc!(f, &mut wam.machine_st.arena);
|
||||
let cell = HeapCellValue::from(fp);
|
||||
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
|
||||
assert_eq!(fp.get_mark_bit(), false);
|
||||
assert_eq!(**fp, f);
|
||||
|
||||
fp.mark();
|
||||
|
||||
assert_eq!(fp.get_mark_bit(), true);
|
||||
|
||||
read_heap_cell!(cell,
|
||||
(HeapCellValueTag::F64, ptr) => {
|
||||
assert_eq!(**ptr, f)
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn heap_cell_value_const_cast() {
|
||||
let mut wam = MockWAM::new();
|
||||
let const_value = HeapCellValue::from(ConsPtr::build_with(
|
||||
0x0000_5555_ff00_0431 as *const _,
|
||||
ConsPtrMaskTag::Cons,
|
||||
));
|
||||
|
||||
match const_value.to_untyped_arena_ptr() {
|
||||
Some(arena_ptr) => {
|
||||
assert_eq!(arena_ptr.into_bytes(), const_value.into_bytes());
|
||||
}
|
||||
None => {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
let stream = Stream::from_static_string("test", &mut wam.machine_st.arena);
|
||||
let stream_cell =
|
||||
HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons));
|
||||
|
||||
match stream_cell.to_untyped_arena_ptr() {
|
||||
Some(arena_ptr) => {
|
||||
assert_eq!(arena_ptr.into_bytes(), stream_cell.into_bytes());
|
||||
}
|
||||
None => {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn heap_put_literal_tests() {
|
||||
let mut wam = MockWAM::new();
|
||||
|
||||
// integer
|
||||
|
||||
let big_int = 2 * Integer::from(1u64 << 63);
|
||||
let big_int_ptr: TypedArenaPtr<Integer> = arena_alloc!(big_int, &mut wam.machine_st.arena);
|
||||
|
||||
assert!(!big_int_ptr.as_ptr().is_null());
|
||||
|
||||
let cell = HeapCellValue::from(Literal::Integer(big_int_ptr));
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||
|
||||
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
|
||||
Some(ptr) => ptr,
|
||||
None => {
|
||||
assert!(false);
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
match_untyped_arena_ptr!(untyped_arena_ptr,
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
|
||||
}
|
||||
_ => unreachable!()
|
||||
);
|
||||
|
||||
read_heap_cell!(cell,
|
||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||
match_untyped_arena_ptr!(cons_ptr,
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
assert_eq!(&*n, &(2 * Integer::from(1u64 << 63)))
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
)
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
// rational
|
||||
|
||||
let big_rat = 2 * Rational::from(1u64 << 63);
|
||||
let big_rat_ptr: TypedArenaPtr<Rational> = arena_alloc!(big_rat, &mut wam.machine_st.arena);
|
||||
|
||||
assert!(!big_rat_ptr.as_ptr().is_null());
|
||||
|
||||
let rat_cell = typed_arena_ptr_as_cell!(big_rat_ptr);
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||
|
||||
match rat_cell.to_untyped_arena_ptr() {
|
||||
Some(untyped_arena_ptr) => {
|
||||
assert_eq!(
|
||||
Some(big_rat_ptr.header_ptr()),
|
||||
Some(untyped_arena_ptr.into()),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
assert!(false); // we fail.
|
||||
}
|
||||
}
|
||||
|
||||
// assert_eq!(wam.machine_st.heap[1usize].get_tag(), HeapCellValueTag::Cons);
|
||||
|
||||
read_heap_cell!(rat_cell,
|
||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||
match_untyped_arena_ptr!(cons_ptr,
|
||||
(ArenaHeaderTag::Rational, n) => {
|
||||
assert_eq!(&*n, &(2 * Rational::from(1u64 << 63)));
|
||||
}
|
||||
_ => unreachable!()
|
||||
)
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
// atom
|
||||
|
||||
let f_atom = atom!("f");
|
||||
let g_atom = atom!("g");
|
||||
|
||||
assert_eq!(f_atom.as_str(), "f");
|
||||
assert_eq!(g_atom.as_str(), "g");
|
||||
|
||||
let f_atom_cell = atom_as_cell!(f_atom);
|
||||
let g_atom_cell = atom_as_cell!(g_atom);
|
||||
|
||||
assert_eq!(f_atom_cell.get_tag(), HeapCellValueTag::Atom);
|
||||
|
||||
match f_atom_cell.to_atom() {
|
||||
Some(atom) => {
|
||||
assert_eq!(f_atom, atom);
|
||||
assert_eq!(atom.as_str(), "f");
|
||||
}
|
||||
None => {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
read_heap_cell!(f_atom_cell,
|
||||
(HeapCellValueTag::Atom, (atom, arity)) => {
|
||||
assert_eq!(f_atom, atom);
|
||||
assert_eq!(arity, 0);
|
||||
assert_eq!(atom.as_str(), "f");
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
read_heap_cell!(g_atom_cell,
|
||||
(HeapCellValueTag::Atom, (atom, arity)) => {
|
||||
assert_eq!(g_atom, atom);
|
||||
assert_eq!(arity, 0);
|
||||
assert_eq!(atom.as_str(), "g");
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
// complete string
|
||||
|
||||
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "ronan", &mut wam.machine_st.atom_tbl);
|
||||
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
|
||||
|
||||
assert_eq!(pstr_cell.get_tag(), HeapCellValueTag::PStr);
|
||||
|
||||
match pstr_cell.to_pstr() {
|
||||
Some(pstr) => {
|
||||
assert_eq!(pstr.as_str_from(0), "ronan");
|
||||
}
|
||||
None => {
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
||||
read_heap_cell!(pstr_cell,
|
||||
(HeapCellValueTag::PStr, pstr_atom) => {
|
||||
let pstr = PartialString::from(pstr_atom);
|
||||
assert_eq!(pstr.as_str_from(0), "ronan");
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
// fixnum
|
||||
|
||||
let fixnum_cell = fixnum_as_cell!(Fixnum::build_with(3));
|
||||
|
||||
assert_eq!(fixnum_cell.get_tag(), HeapCellValueTag::Fixnum);
|
||||
|
||||
match fixnum_cell.to_fixnum() {
|
||||
Some(n) => assert_eq!(n.get_num(), 3),
|
||||
None => assert!(false),
|
||||
}
|
||||
|
||||
read_heap_cell!(fixnum_cell,
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
assert_eq!(n.get_num(), 3);
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 55));
|
||||
|
||||
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
|
||||
|
||||
match fixnum_b_cell.to_fixnum() {
|
||||
Some(n) => assert_eq!(n.get_num(), 1 << 55),
|
||||
None => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(1 << 57) {
|
||||
Ok(_) => assert!(false),
|
||||
_ => assert!(true),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(i64::MAX) {
|
||||
Ok(_) => assert!(false),
|
||||
_ => assert!(true),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(i64::MIN) {
|
||||
Ok(_) => assert!(false),
|
||||
_ => assert!(true),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(-1) {
|
||||
Ok(n) => assert_eq!(n.get_num(), -1),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked((1 << 56) - 1) {
|
||||
Ok(n) => assert_eq!(n.get_num(), (1 << 56) - 1),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(-(1 << 56)) {
|
||||
Ok(n) => assert_eq!(n.get_num(), -(1 << 56)),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(-(1 << 56) - 1) {
|
||||
Ok(_n) => assert!(false),
|
||||
_ => assert!(true),
|
||||
}
|
||||
|
||||
match Fixnum::build_with_checked(-1) {
|
||||
Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
// float
|
||||
|
||||
let float = OrderedFloat(3.1415926f64);
|
||||
let float_ptr = arena_alloc!(float, &mut wam.machine_st.arena);
|
||||
|
||||
assert!(!float_ptr.as_ptr().is_null());
|
||||
|
||||
let float_cell = typed_arena_ptr_as_cell!(float_ptr);
|
||||
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
|
||||
|
||||
match float_cell.to_untyped_arena_ptr() {
|
||||
Some(untyped_arena_ptr) => {
|
||||
assert_eq!(Some(float_ptr.header_ptr()), Some(untyped_arena_ptr.into()),);
|
||||
}
|
||||
None => {
|
||||
assert!(false); // we fail.
|
||||
}
|
||||
}
|
||||
|
||||
// char
|
||||
|
||||
let c = 'c';
|
||||
let char_cell = char_as_cell!(c);
|
||||
|
||||
read_heap_cell!(char_cell,
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
assert_eq!(c, 'c');
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
let c = 'Ћ';
|
||||
let cyrillic_char_cell = char_as_cell!(c);
|
||||
|
||||
read_heap_cell!(cyrillic_char_cell,
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
assert_eq!(c, 'Ћ');
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
|
||||
// empty list
|
||||
|
||||
let cell = empty_list_as_cell!();
|
||||
|
||||
read_heap_cell!(cell,
|
||||
(HeapCellValueTag::Atom, (el, _arity)) => {
|
||||
assert_eq!(el.flat_index() as usize, empty_list_as_cell!().get_value());
|
||||
assert_eq!(el.as_str(), "[]");
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,19 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::{atom, clause_name};
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::allocator::*;
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::types::*;
|
||||
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::rug::ops::PowAssign;
|
||||
use crate::parser::rug::{Assign, Integer, Rational};
|
||||
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
use crate::rug::ops::PowAssign;
|
||||
use crate::rug::{Assign, Integer, Rational};
|
||||
use ordered_float::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
@@ -20,10 +21,33 @@ use std::cmp::{max, min, Ordering};
|
||||
use std::convert::TryFrom;
|
||||
use std::f64;
|
||||
use std::num::FpCategory;
|
||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
||||
use std::ops::Div;
|
||||
use std::rc::Rc;
|
||||
use std::vec::Vec;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum ArithmeticTerm {
|
||||
Reg(RegType),
|
||||
Interm(usize),
|
||||
Number(Number),
|
||||
}
|
||||
|
||||
impl ArithmeticTerm {
|
||||
pub(crate) fn interm_or(&self, interm: usize) -> usize {
|
||||
if let &ArithmeticTerm::Interm(interm) = self {
|
||||
interm
|
||||
} else {
|
||||
interm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ArithmeticTerm {
|
||||
fn default() -> Self {
|
||||
ArithmeticTerm::Number(Number::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArithInstructionIterator<'a> {
|
||||
state_stack: Vec<TermIterState<'a>>,
|
||||
@@ -37,31 +61,30 @@ impl<'a> ArithInstructionIterator<'a> {
|
||||
.push(TermIterState::subterm_to_state(lvl, term));
|
||||
}
|
||||
|
||||
fn new(term: &'a Term) -> Result<Self, ArithmeticError> {
|
||||
fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
|
||||
let state = match term {
|
||||
&Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
|
||||
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
|
||||
match ClauseType::from(name.clone(), terms.len(), fixity.clone()) {
|
||||
ct @ ClauseType::Named(..) | ct @ ClauseType::Op(..) => {
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
|
||||
let ct = ClauseType::Named(clause_name!("float"), 1, CodeIndex::default());
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Constant::Atom(name.clone(), fixity.clone()),
|
||||
terms.len(),
|
||||
)),
|
||||
}?
|
||||
Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
|
||||
Term::Clause(cell, name, terms) => match ClauseType::from(*name, terms.len()) {
|
||||
ct @ ClauseType::Named(..) => {
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
|
||||
let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
|
||||
Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
|
||||
}
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Literal::Atom(*name),
|
||||
terms.len(),
|
||||
)),
|
||||
}?,
|
||||
Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
|
||||
Term::Cons(..) | Term::PartialString(..) => {
|
||||
return Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Literal::Atom(atom!(".")),
|
||||
2,
|
||||
))
|
||||
}
|
||||
&Term::Constant(ref cell, ref cons) => {
|
||||
TermIterState::Constant(Level::Shallow, cell, cons)
|
||||
}
|
||||
&Term::Cons(_, _, _) => {
|
||||
return Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))
|
||||
}
|
||||
&Term::Var(ref cell, ref var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
|
||||
Term::Var(cell, var) => TermIterState::Var(Level::Shallow, cell, var.clone()),
|
||||
};
|
||||
|
||||
Ok(ArithInstructionIterator {
|
||||
@@ -72,9 +95,9 @@ impl<'a> ArithInstructionIterator<'a> {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ArithTermRef<'a> {
|
||||
Constant(&'a Constant),
|
||||
Op(ClauseName, usize), // name, arity.
|
||||
Var(&'a Cell<VarReg>, Rc<Var>),
|
||||
Literal(&'a Literal),
|
||||
Op(Atom, usize), // name, arity.
|
||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
@@ -97,14 +120,23 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
ct,
|
||||
subterms,
|
||||
));
|
||||
self.push_subterm(lvl, subterms[child_num].as_ref());
|
||||
|
||||
self.push_subterm(lvl, &subterms[child_num]);
|
||||
}
|
||||
}
|
||||
TermIterState::Constant(_, _, c) => return Some(Ok(ArithTermRef::Constant(c))),
|
||||
TermIterState::Var(_, cell, var) => {
|
||||
return Some(Ok(ArithTermRef::Var(cell, var.clone())))
|
||||
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
|
||||
TermIterState::Var(lvl, cell, var) => {
|
||||
// the expression is the second argument of an
|
||||
// is/2 but the iterator can't see that, so the
|
||||
// level needs to be demoted manually.
|
||||
return Some(Ok(ArithTermRef::Var(lvl.child_level(), cell, var.clone())));
|
||||
}
|
||||
_ => {
|
||||
return Some(Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Literal::Atom(atom!(".")),
|
||||
2,
|
||||
)));
|
||||
}
|
||||
_ => return Some(Err(ArithmeticError::NonEvaluableFunctor(atom!("'.'"), 2))),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -113,8 +145,8 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ArithmeticEvaluator<'a> {
|
||||
bindings: &'a AllocVarDict,
|
||||
pub(crate) struct ArithmeticEvaluator<'a, TermMarker> {
|
||||
marker: &'a mut TermMarker,
|
||||
interm: Vec<ArithmeticTerm>,
|
||||
interm_c: usize,
|
||||
}
|
||||
@@ -129,82 +161,99 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
|
||||
type Iter = ArithInstructionIterator<'a>;
|
||||
|
||||
fn iter(self) -> Result<Self::Iter, ArithmeticError> {
|
||||
ArithInstructionIterator::new(self)
|
||||
ArithInstructionIterator::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ArithmeticEvaluator<'a> {
|
||||
pub(crate) fn new(bindings: &'a AllocVarDict, target_int: usize) -> Self {
|
||||
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
|
||||
match c {
|
||||
Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
|
||||
Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
|
||||
Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(***n))),
|
||||
Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
|
||||
Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::consts::E)),
|
||||
)),
|
||||
Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::consts::PI)),
|
||||
)),
|
||||
Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
|
||||
Number::Float(OrderedFloat(f64::EPSILON)),
|
||||
)),
|
||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'a, TermMarker: Allocator> ArithmeticEvaluator<'a, TermMarker> {
|
||||
pub(crate) fn new(marker: &'a mut TermMarker, target_int: usize) -> Self {
|
||||
ArithmeticEvaluator {
|
||||
bindings,
|
||||
marker,
|
||||
interm: Vec::new(),
|
||||
interm_c: target_int,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_unary_instr(
|
||||
name: ClauseName,
|
||||
&self,
|
||||
name: Atom,
|
||||
a1: ArithmeticTerm,
|
||||
t: usize,
|
||||
) -> Result<ArithmeticInstruction, ArithmeticError> {
|
||||
match name.as_str() {
|
||||
"abs" => Ok(ArithmeticInstruction::Abs(a1, t)),
|
||||
"-" => Ok(ArithmeticInstruction::Neg(a1, t)),
|
||||
"+" => Ok(ArithmeticInstruction::Plus(a1, t)),
|
||||
"cos" => Ok(ArithmeticInstruction::Cos(a1, t)),
|
||||
"sin" => Ok(ArithmeticInstruction::Sin(a1, t)),
|
||||
"tan" => Ok(ArithmeticInstruction::Tan(a1, t)),
|
||||
"log" => Ok(ArithmeticInstruction::Log(a1, t)),
|
||||
"exp" => Ok(ArithmeticInstruction::Exp(a1, t)),
|
||||
"sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)),
|
||||
"acos" => Ok(ArithmeticInstruction::ACos(a1, t)),
|
||||
"asin" => Ok(ArithmeticInstruction::ASin(a1, t)),
|
||||
"atan" => Ok(ArithmeticInstruction::ATan(a1, t)),
|
||||
"float" => Ok(ArithmeticInstruction::Float(a1, t)),
|
||||
"truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)),
|
||||
"round" => Ok(ArithmeticInstruction::Round(a1, t)),
|
||||
"ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
|
||||
"floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
|
||||
"sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
|
||||
"\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Constant::Atom(name, None),
|
||||
1,
|
||||
)),
|
||||
) -> Result<Instruction, ArithmeticError> {
|
||||
match name {
|
||||
atom!("abs") => Ok(Instruction::Abs(a1, t)),
|
||||
atom!("-") => Ok(Instruction::Neg(a1, t)),
|
||||
atom!("+") => Ok(Instruction::Plus(a1, t)),
|
||||
atom!("cos") => Ok(Instruction::Cos(a1, t)),
|
||||
atom!("sin") => Ok(Instruction::Sin(a1, t)),
|
||||
atom!("tan") => Ok(Instruction::Tan(a1, t)),
|
||||
atom!("log") => Ok(Instruction::Log(a1, t)),
|
||||
atom!("exp") => Ok(Instruction::Exp(a1, t)),
|
||||
atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
|
||||
atom!("acos") => Ok(Instruction::ACos(a1, t)),
|
||||
atom!("asin") => Ok(Instruction::ASin(a1, t)),
|
||||
atom!("atan") => Ok(Instruction::ATan(a1, t)),
|
||||
atom!("float") => Ok(Instruction::Float(a1, t)),
|
||||
atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
|
||||
atom!("round") => Ok(Instruction::Round(a1, t)),
|
||||
atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
|
||||
atom!("floor") => Ok(Instruction::Floor(a1, t)),
|
||||
atom!("sign") => Ok(Instruction::Sign(a1, t)),
|
||||
atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_binary_instr(
|
||||
name: ClauseName,
|
||||
&self,
|
||||
name: Atom,
|
||||
a1: ArithmeticTerm,
|
||||
a2: ArithmeticTerm,
|
||||
t: usize,
|
||||
) -> Result<ArithmeticInstruction, ArithmeticError> {
|
||||
match name.as_str() {
|
||||
"+" => Ok(ArithmeticInstruction::Add(a1, a2, t)),
|
||||
"-" => Ok(ArithmeticInstruction::Sub(a1, a2, t)),
|
||||
"/" => Ok(ArithmeticInstruction::Div(a1, a2, t)),
|
||||
"//" => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
|
||||
"max" => Ok(ArithmeticInstruction::Max(a1, a2, t)),
|
||||
"min" => Ok(ArithmeticInstruction::Min(a1, a2, t)),
|
||||
"div" => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)),
|
||||
"rdiv" => Ok(ArithmeticInstruction::RDiv(a1, a2, t)),
|
||||
"*" => Ok(ArithmeticInstruction::Mul(a1, a2, t)),
|
||||
"**" => Ok(ArithmeticInstruction::Pow(a1, a2, t)),
|
||||
"^" => Ok(ArithmeticInstruction::IntPow(a1, a2, t)),
|
||||
">>" => Ok(ArithmeticInstruction::Shr(a1, a2, t)),
|
||||
"<<" => Ok(ArithmeticInstruction::Shl(a1, a2, t)),
|
||||
"/\\" => Ok(ArithmeticInstruction::And(a1, a2, t)),
|
||||
"\\/" => Ok(ArithmeticInstruction::Or(a1, a2, t)),
|
||||
"xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
|
||||
"mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
|
||||
"rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
|
||||
"gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
|
||||
"atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Constant::Atom(name, None),
|
||||
2,
|
||||
)),
|
||||
) -> Result<Instruction, ArithmeticError> {
|
||||
match name {
|
||||
atom!("+") => Ok(Instruction::Add(a1, a2, t)),
|
||||
atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
|
||||
atom!("/") => Ok(Instruction::Div(a1, a2, t)),
|
||||
atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
|
||||
atom!("max") => Ok(Instruction::Max(a1, a2, t)),
|
||||
atom!("min") => Ok(Instruction::Min(a1, a2, t)),
|
||||
atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
|
||||
atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
|
||||
atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
|
||||
atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
|
||||
atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
|
||||
atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
|
||||
atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
|
||||
atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
|
||||
atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
|
||||
atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
|
||||
atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
|
||||
atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
|
||||
atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
|
||||
atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,9 +268,9 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
|
||||
fn instr_from_clause(
|
||||
&mut self,
|
||||
name: ClauseName,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
) -> Result<ArithmeticInstruction, ArithmeticError> {
|
||||
) -> Result<Instruction, ArithmeticError> {
|
||||
match arity {
|
||||
1 => {
|
||||
let a1 = self.interm.pop().unwrap();
|
||||
@@ -233,7 +282,7 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
a1.interm_or(0)
|
||||
};
|
||||
|
||||
Self::get_unary_instr(name, a1, ninterm)
|
||||
self.get_unary_instr(name, a1, ninterm)
|
||||
}
|
||||
2 => {
|
||||
let a2 = self.interm.pop().unwrap();
|
||||
@@ -257,67 +306,55 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
min_interm
|
||||
};
|
||||
|
||||
Self::get_binary_instr(name, a1, a2, ninterm)
|
||||
self.get_binary_instr(name, a1, a2, ninterm)
|
||||
}
|
||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||
Constant::Atom(name, None),
|
||||
Literal::Atom(name),
|
||||
arity,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_constant(&mut self, c: &Constant) -> Result<(), ArithmeticError> {
|
||||
match c {
|
||||
&Constant::Fixnum(n) => self.interm.push(ArithmeticTerm::Number(Number::Fixnum(n))),
|
||||
&Constant::Integer(ref n) => self
|
||||
.interm
|
||||
.push(ArithmeticTerm::Number(Number::Integer(n.clone()))),
|
||||
&Constant::Float(ref n) => self
|
||||
.interm
|
||||
.push(ArithmeticTerm::Number(Number::Float(n.clone()))),
|
||||
&Constant::Rational(ref n) => self
|
||||
.interm
|
||||
.push(ArithmeticTerm::Number(Number::Rational(n.clone()))),
|
||||
&Constant::Atom(ref name, _) if name.as_str() == "e" => {
|
||||
self.interm
|
||||
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
|
||||
f64::consts::E,
|
||||
))))
|
||||
}
|
||||
&Constant::Atom(ref name, _) if name.as_str() == "pi" => {
|
||||
self.interm
|
||||
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
|
||||
f64::consts::PI,
|
||||
))))
|
||||
}
|
||||
&Constant::Atom(ref name, _) if name.as_str() == "epsilon" => {
|
||||
self.interm
|
||||
.push(ArithmeticTerm::Number(Number::Float(OrderedFloat(
|
||||
f64::EPSILON,
|
||||
))))
|
||||
}
|
||||
_ => return Err(ArithmeticError::NonEvaluableFunctor(c.clone(), 0)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn eval<Iter>(&mut self, src: Iter) -> Result<ArithCont, ArithmeticError>
|
||||
where
|
||||
Iter: ArithmeticTermIter<'a>,
|
||||
pub(crate) fn eval(
|
||||
&mut self,
|
||||
src: &'a Term,
|
||||
term_loc: GenContext,
|
||||
) -> Result<ArithCont, ArithmeticError>
|
||||
{
|
||||
let mut code = vec![];
|
||||
let mut iter = src.iter()?;
|
||||
|
||||
for term_ref in src.iter()? {
|
||||
while let Some(term_ref) = iter.next() {
|
||||
match term_ref? {
|
||||
ArithTermRef::Constant(c) => self.push_constant(c)?,
|
||||
ArithTermRef::Var(cell, name) => {
|
||||
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
|
||||
ArithTermRef::Var(lvl, cell, name) => {
|
||||
let r = if cell.get().norm().reg_num() == 0 {
|
||||
match self.bindings.get(&name) {
|
||||
Some(&VarData::Temp(_, t, _)) if t != 0 => RegType::Temp(t),
|
||||
Some(&VarData::Perm(p)) if p != 0 => RegType::Perm(p),
|
||||
_ => return Err(ArithmeticError::UninstantiatedVar),
|
||||
}
|
||||
let mut getter = || {
|
||||
use crate::targets::QueryInstruction;
|
||||
|
||||
loop {
|
||||
match self.marker.bindings().get(&name) {
|
||||
Some(&VarData::Temp(_, t, _)) if t != 0 =>
|
||||
return RegType::Temp(t),
|
||||
Some(&VarData::Perm(p)) if p != 0 =>
|
||||
return RegType::Perm(p),
|
||||
_ => {
|
||||
self.marker.mark_var::<QueryInstruction>(
|
||||
name.clone(),
|
||||
lvl,
|
||||
cell,
|
||||
term_loc,
|
||||
&mut code,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
getter()
|
||||
/*
|
||||
_ => return Err(ArithmeticError::UninstantiatedVar),
|
||||
*/
|
||||
} else {
|
||||
cell.get().norm()
|
||||
};
|
||||
@@ -325,7 +362,7 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
self.interm.push(ArithmeticTerm::Reg(r));
|
||||
}
|
||||
ArithTermRef::Op(name, arity) => {
|
||||
code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
|
||||
code.push(self.instr_from_clause(name, arity)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -335,27 +372,31 @@ impl<'a> ArithmeticEvaluator<'a> {
|
||||
}
|
||||
|
||||
// integer division rounding function -- 9.1.3.1.
|
||||
pub(crate) fn rnd_i<'a>(n: &'a Number) -> RefOrOwned<'a, Number> {
|
||||
pub(crate) fn rnd_i<'a>(n: &'a Number, arena: &mut Arena) -> Number {
|
||||
match n {
|
||||
&Number::Integer(_) => RefOrOwned::Borrowed(n),
|
||||
&Number::Float(OrderedFloat(f)) => RefOrOwned::Owned(Number::from(
|
||||
Integer::from_f64(f.floor()).unwrap_or_else(|| Integer::from(0)),
|
||||
)),
|
||||
&Number::Fixnum(n) => RefOrOwned::Owned(Number::from(n)),
|
||||
&Number::Integer(_) | &Number::Fixnum(_) => *n,
|
||||
&Number::Float(OrderedFloat(f)) => fixnum!(Number, f.floor() as i64, arena),
|
||||
&Number::Rational(ref r) => {
|
||||
let r_ref = r.fract_floor_ref();
|
||||
let (mut fract, mut floor) = (Rational::new(), Integer::new());
|
||||
(&mut fract, &mut floor).assign(r_ref);
|
||||
|
||||
RefOrOwned::Owned(Number::from(floor))
|
||||
Number::Integer(arena_alloc!(floor, arena))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Fixnum> for Integer {
|
||||
#[inline]
|
||||
fn from(n: Fixnum) -> Integer {
|
||||
Integer::from(n.get_num())
|
||||
}
|
||||
}
|
||||
|
||||
// floating point rounding function -- 9.1.4.1.
|
||||
pub(crate) fn rnd_f(n: &Number) -> f64 {
|
||||
match n {
|
||||
&Number::Fixnum(n) => n as f64,
|
||||
&Number::Fixnum(n) => n.get_num() as f64,
|
||||
&Number::Integer(ref n) => n.to_f64(),
|
||||
&Number::Float(OrderedFloat(f)) => f,
|
||||
&Number::Rational(ref r) => r.to_f64(),
|
||||
@@ -392,27 +433,27 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn float_fn_to_f(n: isize) -> Result<f64, EvalError> {
|
||||
pub(crate) fn float_fn_to_f(n: i64) -> Result<f64, EvalError> {
|
||||
classify_float(n as f64, rnd_f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
||||
pub(crate) fn float_i_to_f(n: &Integer) -> Result<f64, EvalError> {
|
||||
classify_float(n.to_f64(), rnd_f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
||||
pub(crate) fn float_r_to_f(r: &Rational) -> Result<f64, EvalError> {
|
||||
classify_float(r.to_f64(), rnd_f)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
pub(crate) fn add_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
Ok(OrderedFloat(classify_float(f1 + f2, rnd_f)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
pub(crate) fn mul_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
Ok(OrderedFloat(classify_float(f1 * f2, rnd_f)?))
|
||||
}
|
||||
|
||||
@@ -425,161 +466,36 @@ fn div_f(f1: f64, f2: f64) -> Result<OrderedFloat<f64>, EvalError> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Number> for Number {
|
||||
type Output = Result<Number, EvalError>;
|
||||
|
||||
fn add(self, rhs: Number) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||
Ok(if let Some(result) = n1.checked_add(n2) {
|
||||
Number::Fixnum(result)
|
||||
} else {
|
||||
Number::from(Integer::from(n1) + Integer::from(n2))
|
||||
})
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Integer(n2))
|
||||
| (Number::Integer(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Integer::from(n1) + &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Rational(n2))
|
||||
| (Number::Rational(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Rational::from(n1) + &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
|
||||
Ok(Number::Float(add_f(float_fn_to_f(n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
Ok(Number::from(Integer::from(&*n1) + &*n2)) // add_i
|
||||
}
|
||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||
Ok(Number::Float(add_f(float_i_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Rational(n2))
|
||||
| (Number::Rational(n2), Number::Integer(n1)) => {
|
||||
Ok(Number::from(Rational::from(&*n1) + &*n2))
|
||||
}
|
||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||
Ok(Number::Float(add_f(float_r_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||
Ok(Number::Float(add_f(f1, f2)?))
|
||||
}
|
||||
(Number::Rational(r1), Number::Rational(r2)) => {
|
||||
Ok(Number::from(Rational::from(&*r1) + &*r2))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Number {
|
||||
type Output = Number;
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
match self {
|
||||
Number::Fixnum(n) => {
|
||||
if let Some(n) = n.checked_neg() {
|
||||
Number::Fixnum(n)
|
||||
} else {
|
||||
Number::from(-Integer::from(n))
|
||||
}
|
||||
}
|
||||
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
|
||||
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
|
||||
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Number> for Number {
|
||||
type Output = Result<Number, EvalError>;
|
||||
|
||||
fn sub(self, rhs: Number) -> Self::Output {
|
||||
self.add(-rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul<Number> for Number {
|
||||
type Output = Result<Number, EvalError>;
|
||||
|
||||
fn mul(self, rhs: Number) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||
Ok(if let Some(result) = n1.checked_mul(n2) {
|
||||
Number::Fixnum(result)
|
||||
} else {
|
||||
Number::from(Integer::from(n1) * Integer::from(n2))
|
||||
})
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Integer(n2))
|
||||
| (Number::Integer(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Integer::from(n1) * &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Rational(n2))
|
||||
| (Number::Rational(n2), Number::Fixnum(n1)) => {
|
||||
Ok(Number::from(Rational::from(n1) * &*n2))
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Fixnum(n1)) => {
|
||||
Ok(Number::Float(mul_f(float_fn_to_f(n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
Ok(Number::Integer(Rc::new(Integer::from(&*n1) * &*n2))) // mul_i
|
||||
}
|
||||
(Number::Integer(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Integer(n1)) => {
|
||||
Ok(Number::Float(mul_f(float_i_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Rational(n2))
|
||||
| (Number::Rational(n2), Number::Integer(n1)) => {
|
||||
Ok(Number::Rational(Rc::new(Rational::from(&*n1) * &*n2)))
|
||||
}
|
||||
(Number::Rational(n1), Number::Float(OrderedFloat(n2)))
|
||||
| (Number::Float(OrderedFloat(n2)), Number::Rational(n1)) => {
|
||||
Ok(Number::Float(mul_f(float_r_to_f(&n1)?, n2)?))
|
||||
}
|
||||
(Number::Float(OrderedFloat(f1)), Number::Float(OrderedFloat(f2))) => {
|
||||
Ok(Number::Float(mul_f(f1, f2)?))
|
||||
}
|
||||
(Number::Rational(r1), Number::Rational(r2)) => {
|
||||
Ok(Number::Rational(Rc::new(Rational::from(&*r1) * &*r2)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Div<Number> for Number {
|
||||
type Output = Result<Number, EvalError>;
|
||||
|
||||
fn div(self, rhs: Number) -> Self::Output {
|
||||
match (self, rhs) {
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
float_fn_to_f(n2)?,
|
||||
float_fn_to_f(n1.get_num())?,
|
||||
float_fn_to_f(n2.get_num())?,
|
||||
)?)),
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
float_fn_to_f(n1.get_num())?,
|
||||
float_i_to_f(&n2)?,
|
||||
)?)),
|
||||
(Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
|
||||
float_i_to_f(&n1)?,
|
||||
float_fn_to_f(n2)?,
|
||||
float_fn_to_f(n2.get_num())?,
|
||||
)?)),
|
||||
(Number::Fixnum(n1), Number::Rational(n2)) => Ok(Number::Float(div_f(
|
||||
float_fn_to_f(n1)?,
|
||||
float_fn_to_f(n1.get_num())?,
|
||||
float_r_to_f(&n2)?,
|
||||
)?)),
|
||||
(Number::Rational(n1), Number::Fixnum(n2)) => Ok(Number::Float(div_f(
|
||||
float_r_to_f(&n1)?,
|
||||
float_fn_to_f(n2)?,
|
||||
float_fn_to_f(n2.get_num())?,
|
||||
)?)),
|
||||
(Number::Fixnum(n1), Number::Float(OrderedFloat(n2))) => {
|
||||
Ok(Number::Float(div_f(float_fn_to_f(n1)?, n2)?))
|
||||
Ok(Number::Float(div_f(float_fn_to_f(n1.get_num())?, n2)?))
|
||||
}
|
||||
(Number::Float(OrderedFloat(n1)), Number::Fixnum(n2)) => {
|
||||
Ok(Number::Float(div_f(n1, float_fn_to_f(n2)?)?))
|
||||
Ok(Number::Float(div_f(n1, float_fn_to_f(n2.get_num())?)?))
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => Ok(Number::Float(div_f(
|
||||
float_i_to_f(&n1)?,
|
||||
@@ -620,14 +536,14 @@ impl PartialEq for Number {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
match (self, rhs) {
|
||||
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.eq(&n2),
|
||||
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.eq(&**n2),
|
||||
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
|
||||
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.eq(&**n2),
|
||||
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2),
|
||||
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).eq(&n2),
|
||||
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2 as f64)),
|
||||
(&Number::Fixnum(n1), &Number::Integer(ref n2)) => n1.get_num().eq(&**n2),
|
||||
(&Number::Integer(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
|
||||
(&Number::Fixnum(n1), &Number::Rational(ref n2)) => n1.get_num().eq(&**n2),
|
||||
(&Number::Rational(ref n1), &Number::Fixnum(n2)) => (&**n1).eq(&n2.get_num()),
|
||||
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).eq(&n2),
|
||||
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.eq(&OrderedFloat(n2.get_num() as f64)),
|
||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.eq(n2),
|
||||
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(&n2),
|
||||
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).eq(n2),
|
||||
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.eq(&OrderedFloat(n2.to_f64())),
|
||||
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
|
||||
#[cfg(feature = "num")]
|
||||
@@ -659,6 +575,46 @@ impl PartialEq for Number {
|
||||
|
||||
impl Eq for Number {}
|
||||
|
||||
impl PartialOrd<usize> for Number {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, rhs: &usize) -> Option<Ordering> {
|
||||
match self {
|
||||
Number::Fixnum(n) => {
|
||||
let n = n.get_num();
|
||||
|
||||
if n < 0i64 {
|
||||
Some(Ordering::Less)
|
||||
} else {
|
||||
(n as usize).partial_cmp(rhs)
|
||||
}
|
||||
}
|
||||
Number::Integer(n) => (&**n).partial_cmp(rhs),
|
||||
Number::Rational(r) => (&**r).partial_cmp(rhs),
|
||||
Number::Float(f) => f.partial_cmp(&OrderedFloat(*rhs as f64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<usize> for Number {
|
||||
#[inline]
|
||||
fn eq(&self, rhs: &usize) -> bool {
|
||||
match self {
|
||||
Number::Fixnum(n) => {
|
||||
let n = n.get_num();
|
||||
|
||||
if n < 0i64 {
|
||||
false
|
||||
} else {
|
||||
(n as usize).eq(rhs)
|
||||
}
|
||||
}
|
||||
Number::Integer(n) => (&**n).eq(rhs),
|
||||
Number::Rational(r) => (&**r).eq(rhs),
|
||||
Number::Float(f) => f.eq(&OrderedFloat(*rhs as f64)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Number {
|
||||
fn partial_cmp(&self, rhs: &Number) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
@@ -668,92 +624,78 @@ impl PartialOrd for Number {
|
||||
impl Ord for Number {
|
||||
fn cmp(&self, rhs: &Number) -> Ordering {
|
||||
match (self, rhs) {
|
||||
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.cmp(&n2),
|
||||
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1).cmp(&*n2),
|
||||
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2)),
|
||||
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1).cmp(&*n2),
|
||||
(Number::Rational(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Rational::from(n2)),
|
||||
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1 as f64).cmp(&n2),
|
||||
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2 as f64)),
|
||||
(&Number::Integer(ref n1), &Number::Integer(ref n2)) => n1.cmp(n2),
|
||||
(&Number::Integer(ref n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
|
||||
(&Number::Fixnum(n1), &Number::Fixnum(n2)) => n1.get_num().cmp(&n2.get_num()),
|
||||
(&Number::Fixnum(n1), Number::Integer(n2)) => Integer::from(n1.get_num()).cmp(&*n2),
|
||||
(Number::Integer(n1), &Number::Fixnum(n2)) => (&**n1).cmp(&Integer::from(n2.get_num())),
|
||||
(&Number::Fixnum(n1), Number::Rational(n2)) => Rational::from(n1.get_num()).cmp(&*n2),
|
||||
(Number::Rational(n1), &Number::Fixnum(n2)) => {
|
||||
(&**n1).cmp(&Rational::from(n2.get_num()))
|
||||
}
|
||||
(&Number::Fixnum(n1), &Number::Float(n2)) => OrderedFloat(n1.get_num() as f64).cmp(&n2),
|
||||
(&Number::Float(n1), &Number::Fixnum(n2)) => n1.cmp(&OrderedFloat(n2.get_num() as f64)),
|
||||
(&Number::Integer(n1), &Number::Integer(n2)) => (*n1).cmp(&*n2),
|
||||
(&Number::Integer(n1), Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(n2),
|
||||
(&Number::Float(n1), &Number::Integer(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
|
||||
(&Number::Integer(ref n1), &Number::Rational(ref n2)) => {
|
||||
(&Number::Integer(n1), &Number::Rational(n2)) => {
|
||||
#[cfg(feature = "num")]
|
||||
{
|
||||
Rational::from(&**n1).cmp(n2)
|
||||
}
|
||||
#[cfg(not(feature = "num"))]
|
||||
{
|
||||
(&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
|
||||
(&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less)
|
||||
}
|
||||
}
|
||||
(&Number::Rational(ref n1), &Number::Integer(ref n2)) => {
|
||||
(&Number::Rational(n1), &Number::Integer(n2)) => {
|
||||
#[cfg(feature = "num")]
|
||||
{
|
||||
(&**n1).cmp(&Rational::from(&**n2))
|
||||
}
|
||||
#[cfg(not(feature = "num"))]
|
||||
{
|
||||
(&**n1).partial_cmp(&**n2).unwrap_or(Ordering::Less)
|
||||
(&*n1).partial_cmp(&*n2).unwrap_or(Ordering::Less)
|
||||
}
|
||||
}
|
||||
(&Number::Rational(ref n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
|
||||
(&Number::Float(n1), &Number::Rational(ref n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
|
||||
(&Number::Rational(n1), &Number::Float(n2)) => OrderedFloat(n1.to_f64()).cmp(&n2),
|
||||
(&Number::Float(n1), &Number::Rational(n2)) => n1.cmp(&OrderedFloat(n2.to_f64())),
|
||||
(&Number::Float(f1), &Number::Float(f2)) => f1.cmp(&f2),
|
||||
(&Number::Rational(ref r1), &Number::Rational(ref r2)) => r1.cmp(&r2),
|
||||
(&Number::Rational(r1), &Number::Rational(r2)) => (*r1).cmp(&*r2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<(Addr, &'a Heap)> for Number {
|
||||
impl TryFrom<HeapCellValue> for Number {
|
||||
type Error = ();
|
||||
|
||||
fn try_from((addr, heap): (Addr, &'a Heap)) -> Result<Number, Self::Error> {
|
||||
match addr {
|
||||
Addr::Fixnum(n) => Ok(Number::from(n)),
|
||||
Addr::Float(n) => Ok(Number::Float(n)),
|
||||
Addr::Usize(n) => {
|
||||
if let Ok(n) = isize::try_from(n) {
|
||||
Ok(Number::from(n))
|
||||
} else {
|
||||
Ok(Number::from(Integer::from(n)))
|
||||
}
|
||||
}
|
||||
Addr::Con(h) => Number::try_from(&heap[h]),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a HeapCellValue> for Number {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &'a HeapCellValue) -> Result<Number, Self::Error> {
|
||||
match value {
|
||||
HeapCellValue::Addr(addr) => match addr {
|
||||
&Addr::Fixnum(n) => Ok(Number::from(n)),
|
||||
&Addr::Float(n) => Ok(Number::Float(n)),
|
||||
&Addr::Usize(n) => {
|
||||
if let Ok(n) = isize::try_from(n) {
|
||||
Ok(Number::from(n))
|
||||
} else {
|
||||
Ok(Number::from(Integer::from(n)))
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
},
|
||||
HeapCellValue::Integer(n) => Ok(Number::Integer(n.clone())),
|
||||
HeapCellValue::Rational(n) => Ok(Number::Rational(n.clone())),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Integer> for Number {
|
||||
#[inline]
|
||||
fn from(src: &'a Integer) -> Self {
|
||||
Number::Integer(Rc::new(Integer::from(src)))
|
||||
fn try_from(value: HeapCellValue) -> Result<Number, Self::Error> {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::Cons, c) => {
|
||||
match_untyped_arena_ptr!(c,
|
||||
(ArenaHeaderTag::F64, n) => {
|
||||
Ok(Number::Float(*n))
|
||||
}
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
Ok(Number::Integer(n))
|
||||
}
|
||||
(ArenaHeaderTag::Rational, n) => {
|
||||
Ok(Number::Rational(n))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
)
|
||||
}
|
||||
(HeapCellValueTag::F64, n) => {
|
||||
Ok(Number::Float(**n))
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
Ok(Number::Fixnum(n))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
366
src/atom_table.rs
Normal file
366
src/atom_table.rs
Normal file
@@ -0,0 +1,366 @@
|
||||
use crate::parser::ast::MAX_ARITY;
|
||||
use crate::raw_block::*;
|
||||
use crate::types::*;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
use std::cmp::Ordering;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::slice;
|
||||
use std::str;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use modular_bitfield::prelude::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Atom {
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<Atom>() == 8);
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
|
||||
|
||||
impl<'a> From<&'a Atom> for Atom {
|
||||
#[inline]
|
||||
fn from(atom: &'a Atom) -> Self {
|
||||
*atom
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for Atom {
|
||||
#[inline]
|
||||
fn from(value: bool) -> Self {
|
||||
if value { atom!("true") } else { atom!("false") }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use std::cell::RefCell;
|
||||
|
||||
const ATOM_TABLE_INIT_SIZE: usize = 1 << 16;
|
||||
const ATOM_TABLE_ALIGN: usize = 8;
|
||||
|
||||
#[cfg(test)]
|
||||
thread_local! {
|
||||
static ATOM_TABLE_BUF_BASE: RefCell<*const u8> = RefCell::new(ptr::null_mut());
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
static mut ATOM_TABLE_BUF_BASE: *const u8 = ptr::null_mut();
|
||||
|
||||
#[cfg(test)]
|
||||
fn set_atom_tbl_buf_base(ptr: *const u8) {
|
||||
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| {
|
||||
*atom_table_buf_base.borrow_mut() = ptr;
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
|
||||
ATOM_TABLE_BUF_BASE.with(|atom_table_buf_base| *atom_table_buf_base.borrow())
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
fn set_atom_tbl_buf_base(ptr: *const u8) {
|
||||
unsafe {
|
||||
ATOM_TABLE_BUF_BASE = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub(crate) fn get_atom_tbl_buf_base() -> *const u8 {
|
||||
unsafe { ATOM_TABLE_BUF_BASE }
|
||||
}
|
||||
|
||||
impl RawBlockTraits for AtomTable {
|
||||
#[inline]
|
||||
fn init_size() -> usize {
|
||||
ATOM_TABLE_INIT_SIZE
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
ATOM_TABLE_ALIGN
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct AtomHeader {
|
||||
#[allow(unused)] m: bool,
|
||||
len: B50,
|
||||
#[allow(unused)] padding: B13,
|
||||
}
|
||||
|
||||
impl AtomHeader {
|
||||
fn build_with(len: u64) -> Self {
|
||||
AtomHeader::new().with_len(len).with_m(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<str> for Atom {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Atom {
|
||||
#[inline]
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
self.as_str().hash(hasher)
|
||||
// hasher.write_usize(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_char {
|
||||
($s:expr) => {
|
||||
!$s.is_empty() && $s.chars().nth(1).is_none()
|
||||
};
|
||||
}
|
||||
|
||||
impl Atom {
|
||||
#[inline]
|
||||
pub fn buf(self) -> *const u8 {
|
||||
let ptr = self.as_ptr();
|
||||
|
||||
if ptr.is_null() {
|
||||
return ptr::null();
|
||||
}
|
||||
|
||||
(ptr as usize + mem::size_of::<AtomHeader>()) as *const u8
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_static(self) -> bool {
|
||||
self.index < STRINGS.len() << 3
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn as_ptr(self) -> *const u8 {
|
||||
if self.is_static() {
|
||||
ptr::null()
|
||||
} else {
|
||||
(get_atom_tbl_buf_base() as usize + self.index - (STRINGS.len() << 3)) as *const u8
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from(index: usize) -> Self {
|
||||
Self { index }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn len(self) -> usize {
|
||||
if self.is_static() {
|
||||
STRINGS[self.index >> 3].len()
|
||||
} else {
|
||||
unsafe { ptr::read(self.as_ptr() as *const AtomHeader).len() as _ }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flat_index(self) -> u64 {
|
||||
(self.index >> 3) as u64
|
||||
}
|
||||
|
||||
pub fn as_char(self) -> Option<char> {
|
||||
let s = self.as_str();
|
||||
let mut it = s.chars();
|
||||
|
||||
let c1 = it.next();
|
||||
let c2 = it.next();
|
||||
|
||||
if c2.is_none() { c1 } else { None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn chars(&self) -> str::Chars {
|
||||
self.as_str().chars()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
unsafe {
|
||||
let ptr = self.as_ptr();
|
||||
|
||||
if ptr.is_null() {
|
||||
return STRINGS[self.index >> 3];
|
||||
}
|
||||
|
||||
let header = ptr::read::<AtomHeader>(ptr as *const _);
|
||||
let len = header.len() as usize;
|
||||
let buf = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
|
||||
|
||||
str::from_utf8_unchecked(slice::from_raw_parts(buf, len))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn defrock_brackets(&self, atom_tbl: &mut AtomTable) -> Self {
|
||||
let s = self.as_str();
|
||||
|
||||
let s = if s.starts_with('(') && s.ends_with(')') {
|
||||
&s['('.len_utf8()..s.len() - ')'.len_utf8()]
|
||||
} else {
|
||||
return *self;
|
||||
};
|
||||
|
||||
atom_tbl.build_with(s)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn write_to_ptr(string: &str, ptr: *mut u8) {
|
||||
ptr::write(ptr as *mut _, AtomHeader::build_with(string.len() as u64));
|
||||
let str_ptr = (ptr as usize + mem::size_of::<AtomHeader>()) as *mut u8;
|
||||
ptr::copy_nonoverlapping(string.as_ptr(), str_ptr as *mut u8, string.len());
|
||||
}
|
||||
|
||||
impl PartialOrd for Atom {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &Atom) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Atom {
|
||||
#[inline]
|
||||
fn cmp(&self, other: &Atom) -> Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AtomTable {
|
||||
block: RawBlock<AtomTable>,
|
||||
pub table: IndexSet<Atom>,
|
||||
}
|
||||
|
||||
impl Drop for AtomTable {
|
||||
fn drop(&mut self) {
|
||||
self.block.deallocate();
|
||||
}
|
||||
}
|
||||
|
||||
impl AtomTable {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
let table = Self {
|
||||
block: RawBlock::new(),
|
||||
table: IndexSet::new(),
|
||||
};
|
||||
|
||||
set_atom_tbl_buf_base(table.block.base);
|
||||
table
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn buf(&self) -> *const u8 {
|
||||
self.block.base as *const u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn top(&self) -> *const u8 {
|
||||
self.block.top
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn lookup_str(&self, string: &str) -> Option<Atom> {
|
||||
STATIC_ATOMS_MAP.get(string).or_else(|| self.table.get(string)).cloned()
|
||||
}
|
||||
|
||||
pub fn build_with(&mut self, string: &str) -> Atom {
|
||||
if let Some(atom) = self.lookup_str(string) {
|
||||
return atom;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let size = mem::size_of::<AtomHeader>() + string.len();
|
||||
let align_offset = 8 * mem::align_of::<AtomHeader>();
|
||||
let size = (size & !(align_offset - 1)) + align_offset;
|
||||
|
||||
let len_ptr = {
|
||||
let mut ptr;
|
||||
|
||||
loop {
|
||||
ptr = self.block.alloc(size);
|
||||
|
||||
if ptr.is_null() {
|
||||
self.block.grow();
|
||||
set_atom_tbl_buf_base(self.block.base);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ptr
|
||||
};
|
||||
|
||||
let ptr_base = self.block.base as usize;
|
||||
|
||||
write_to_ptr(string, len_ptr);
|
||||
|
||||
let atom = Atom {
|
||||
index: (STRINGS.len() << 3) + len_ptr as usize - ptr_base,
|
||||
};
|
||||
|
||||
self.table.insert(atom);
|
||||
|
||||
atom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AtomCell {
|
||||
name: B46,
|
||||
arity: B10,
|
||||
#[allow(unused)] f: bool,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] tag: B6,
|
||||
}
|
||||
|
||||
impl AtomCell {
|
||||
#[inline]
|
||||
pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self {
|
||||
if arity > 0 {
|
||||
debug_assert!(arity as usize <= MAX_ARITY);
|
||||
|
||||
AtomCell::new()
|
||||
.with_name(name)
|
||||
.with_arity(arity)
|
||||
.with_f(false)
|
||||
.with_tag(tag as u8)
|
||||
} else {
|
||||
AtomCell::new()
|
||||
.with_name(name)
|
||||
.with_f(false)
|
||||
.with_tag(tag as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_index(self) -> usize {
|
||||
self.name() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_name(self) -> Atom {
|
||||
Atom::from(self.get_index() << 3)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_arity(self) -> usize {
|
||||
self.arity() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_name_and_arity(self) -> (Atom, usize) {
|
||||
(Atom::from(self.get_index() << 3), self.get_arity())
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,12 @@
|
||||
fn main() {
|
||||
use nix::sys::signal;
|
||||
use scryer_prolog::read::readline;
|
||||
use scryer_prolog::*;
|
||||
|
||||
let handler = signal::SigHandler::Handler(handle_sigint);
|
||||
unsafe { signal::signal(signal::Signal::SIGINT, handler) }.unwrap();
|
||||
|
||||
let mut wam = machine::Machine::new(
|
||||
readline::input_stream(),
|
||||
machine::Stream::stdout(),
|
||||
machine::Stream::stderr(),
|
||||
);
|
||||
let mut wam = machine::Machine::new();
|
||||
|
||||
wam.run_top_level();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,994 +0,0 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::{clause_name, temp_v};
|
||||
|
||||
use crate::forms::Number;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::rug::rand::RandState;
|
||||
|
||||
use ref_thread_local::{ref_thread_local, RefThreadLocal};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub(crate) enum CompareNumberQT {
|
||||
GreaterThan,
|
||||
LessThan,
|
||||
GreaterThanOrEqual,
|
||||
LessThanOrEqual,
|
||||
NotEqual,
|
||||
Equal,
|
||||
}
|
||||
|
||||
impl CompareNumberQT {
|
||||
fn name(self) -> &'static str {
|
||||
match self {
|
||||
CompareNumberQT::GreaterThan => ">",
|
||||
CompareNumberQT::LessThan => "<",
|
||||
CompareNumberQT::GreaterThanOrEqual => ">=",
|
||||
CompareNumberQT::LessThanOrEqual => "=<",
|
||||
CompareNumberQT::NotEqual => "=\\=",
|
||||
CompareNumberQT::Equal => "=:=",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) enum CompareTermQT {
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
GreaterThanOrEqual,
|
||||
GreaterThan,
|
||||
}
|
||||
|
||||
impl CompareTermQT {
|
||||
fn name<'a>(self) -> &'a str {
|
||||
match self {
|
||||
CompareTermQT::GreaterThan => "@>",
|
||||
CompareTermQT::LessThan => "@<",
|
||||
CompareTermQT::GreaterThanOrEqual => "@>=",
|
||||
CompareTermQT::LessThanOrEqual => "@=<",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum ArithmeticTerm {
|
||||
Reg(RegType),
|
||||
Interm(usize),
|
||||
Number(Number),
|
||||
}
|
||||
|
||||
impl ArithmeticTerm {
|
||||
pub(crate) fn interm_or(&self, interm: usize) -> usize {
|
||||
if let &ArithmeticTerm::Interm(interm) = self {
|
||||
interm
|
||||
} else {
|
||||
interm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum InlinedClauseType {
|
||||
CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
|
||||
IsAtom(RegType),
|
||||
IsAtomic(RegType),
|
||||
IsCompound(RegType),
|
||||
IsInteger(RegType),
|
||||
IsNumber(RegType),
|
||||
IsRational(RegType),
|
||||
IsFloat(RegType),
|
||||
IsNonVar(RegType),
|
||||
IsVar(RegType),
|
||||
}
|
||||
|
||||
ref_thread_local! {
|
||||
pub(crate)static managed RANDOM_STATE: RandState<'static> = RandState::new();
|
||||
}
|
||||
|
||||
ref_thread_local! {
|
||||
pub(crate)static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = {
|
||||
let mut m = BTreeMap::new();
|
||||
|
||||
let r1 = temp_v!(1);
|
||||
let r2 = temp_v!(2);
|
||||
|
||||
m.insert((">", 2),
|
||||
ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThan, ar_reg!(r1), ar_reg!(r2))));
|
||||
m.insert(("<", 2),
|
||||
ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThan, ar_reg!(r1), ar_reg!(r2))));
|
||||
m.insert((">=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::GreaterThanOrEqual, ar_reg!(r1), ar_reg!(r2))));
|
||||
m.insert(("=<", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::LessThanOrEqual, ar_reg!(r1), ar_reg!(r2))));
|
||||
m.insert(("=:=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::Equal, ar_reg!(r1), ar_reg!(r2))));
|
||||
m.insert(("=\\=", 2), ClauseType::Inlined(InlinedClauseType::CompareNumber(CompareNumberQT::NotEqual, ar_reg!(r1), ar_reg!(r2))));
|
||||
m.insert(("atom", 1), ClauseType::Inlined(InlinedClauseType::IsAtom(r1)));
|
||||
m.insert(("atomic", 1), ClauseType::Inlined(InlinedClauseType::IsAtomic(r1)));
|
||||
m.insert(("compound", 1), ClauseType::Inlined(InlinedClauseType::IsCompound(r1)));
|
||||
m.insert(("integer", 1), ClauseType::Inlined(InlinedClauseType::IsInteger(r1)));
|
||||
m.insert(("number", 1), ClauseType::Inlined(InlinedClauseType::IsNumber(r1)));
|
||||
m.insert(("rational", 1), ClauseType::Inlined(InlinedClauseType::IsRational(r1)));
|
||||
m.insert(("float", 1), ClauseType::Inlined(InlinedClauseType::IsFloat(r1)));
|
||||
m.insert(("nonvar", 1), ClauseType::Inlined(InlinedClauseType::IsNonVar(r1)));
|
||||
m.insert(("var", 1), ClauseType::Inlined(InlinedClauseType::IsVar(r1)));
|
||||
m.insert(("acyclic_term", 1), ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm));
|
||||
m.insert(("arg", 3), ClauseType::BuiltIn(BuiltInClauseType::Arg));
|
||||
m.insert(("compare", 3), ClauseType::BuiltIn(BuiltInClauseType::Compare));
|
||||
m.insert(("@>", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThan)));
|
||||
m.insert(("@<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThan)));
|
||||
m.insert(("@>=", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::GreaterThanOrEqual)));
|
||||
m.insert(("@=<", 2), ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(CompareTermQT::LessThanOrEqual)));
|
||||
m.insert(("copy_term", 2), ClauseType::BuiltIn(BuiltInClauseType::CopyTerm));
|
||||
m.insert(("==", 2), ClauseType::BuiltIn(BuiltInClauseType::Eq));
|
||||
m.insert(("functor", 3), ClauseType::BuiltIn(BuiltInClauseType::Functor));
|
||||
m.insert(("ground", 1), ClauseType::BuiltIn(BuiltInClauseType::Ground));
|
||||
m.insert(("is", 2), ClauseType::BuiltIn(BuiltInClauseType::Is(r1, ar_reg!(r2))));
|
||||
m.insert(("keysort", 2), ClauseType::BuiltIn(BuiltInClauseType::KeySort));
|
||||
m.insert(("\\==", 2), ClauseType::BuiltIn(BuiltInClauseType::NotEq));
|
||||
m.insert(("read", 2), ClauseType::BuiltIn(BuiltInClauseType::Read));
|
||||
m.insert(("sort", 2), ClauseType::BuiltIn(BuiltInClauseType::Sort));
|
||||
|
||||
m
|
||||
};
|
||||
}
|
||||
|
||||
impl InlinedClauseType {
|
||||
pub(crate) fn name(&self) -> &'static str {
|
||||
match self {
|
||||
&InlinedClauseType::CompareNumber(qt, ..) => qt.name(),
|
||||
&InlinedClauseType::IsAtom(..) => "atom",
|
||||
&InlinedClauseType::IsAtomic(..) => "atomic",
|
||||
&InlinedClauseType::IsCompound(..) => "compound",
|
||||
&InlinedClauseType::IsNumber(..) => "number",
|
||||
&InlinedClauseType::IsInteger(..) => "integer",
|
||||
&InlinedClauseType::IsRational(..) => "rational",
|
||||
&InlinedClauseType::IsFloat(..) => "float",
|
||||
&InlinedClauseType::IsNonVar(..) => "nonvar",
|
||||
&InlinedClauseType::IsVar(..) => "var",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum SystemClauseType {
|
||||
AtomChars,
|
||||
AtomCodes,
|
||||
AtomLength,
|
||||
BindFromRegister,
|
||||
CallContinuation,
|
||||
CharCode,
|
||||
CharType,
|
||||
CharsToNumber,
|
||||
CodesToNumber,
|
||||
CopyTermWithoutAttrVars,
|
||||
CheckCutPoint,
|
||||
Close,
|
||||
CopyToLiftedHeap,
|
||||
CreatePartialString,
|
||||
CurrentHostname,
|
||||
CurrentInput,
|
||||
CurrentOutput,
|
||||
DirectoryFiles,
|
||||
FileSize,
|
||||
FileExists,
|
||||
DirectoryExists,
|
||||
DirectorySeparator,
|
||||
MakeDirectory,
|
||||
MakeDirectoryPath,
|
||||
DeleteFile,
|
||||
RenameFile,
|
||||
DeleteDirectory,
|
||||
WorkingDirectory,
|
||||
PathCanonical,
|
||||
FileTime,
|
||||
DeleteAttribute,
|
||||
DeleteHeadAttribute,
|
||||
DynamicModuleResolution(usize),
|
||||
EnqueueAttributedVar,
|
||||
FetchGlobalVar,
|
||||
FirstStream,
|
||||
FlushOutput,
|
||||
GetByte,
|
||||
GetChar,
|
||||
GetNChars,
|
||||
GetCode,
|
||||
GetSingleChar,
|
||||
ResetAttrVarState,
|
||||
TruncateIfNoLiftedHeapGrowthDiff,
|
||||
TruncateIfNoLiftedHeapGrowth,
|
||||
GetAttributedVariableList,
|
||||
GetAttrVarQueueDelimiter,
|
||||
GetAttrVarQueueBeyond,
|
||||
GetBValue,
|
||||
GetContinuationChunk,
|
||||
GetNextDBRef,
|
||||
GetNextOpDBRef,
|
||||
IsPartialString,
|
||||
LookupDBRef,
|
||||
LookupOpDBRef,
|
||||
Halt,
|
||||
GetLiftedHeapFromOffset,
|
||||
GetLiftedHeapFromOffsetDiff,
|
||||
GetSCCCleaner,
|
||||
HeadIsDynamic,
|
||||
InstallSCCCleaner,
|
||||
InstallInferenceCounter,
|
||||
LiftedHeapLength,
|
||||
LoadLibraryAsStream,
|
||||
ModuleExists,
|
||||
NextEP,
|
||||
NoSuchPredicate,
|
||||
NumberToChars,
|
||||
NumberToCodes,
|
||||
OpDeclaration,
|
||||
Open,
|
||||
SetStreamOptions,
|
||||
NextStream,
|
||||
PartialStringTail,
|
||||
PeekByte,
|
||||
PeekChar,
|
||||
PeekCode,
|
||||
PointsToContinuationResetMarker,
|
||||
PutByte,
|
||||
PutChar,
|
||||
PutChars,
|
||||
PutCode,
|
||||
REPL(REPLCodePtr),
|
||||
ReadQueryTerm,
|
||||
ReadTerm,
|
||||
RedoAttrVarBinding,
|
||||
RemoveCallPolicyCheck,
|
||||
RemoveInferenceCounter,
|
||||
ResetContinuationMarker,
|
||||
RestoreCutPolicy,
|
||||
SetCutPoint(RegType),
|
||||
SetInput,
|
||||
SetOutput,
|
||||
StoreBacktrackableGlobalVar,
|
||||
StoreGlobalVar,
|
||||
StreamProperty,
|
||||
SetStreamPosition,
|
||||
InferenceLevel,
|
||||
CleanUpBlock,
|
||||
EraseBall,
|
||||
Fail,
|
||||
GetBall,
|
||||
GetCurrentBlock,
|
||||
GetCutPoint,
|
||||
GetDoubleQuotes,
|
||||
InstallNewBlock,
|
||||
Maybe,
|
||||
CpuNow,
|
||||
CurrentTime,
|
||||
QuotedToken,
|
||||
ReadTermFromChars,
|
||||
ResetBlock,
|
||||
ReturnFromVerifyAttr,
|
||||
SetBall,
|
||||
SetCutPointByDefault(RegType),
|
||||
SetDoubleQuotes,
|
||||
SetSeed,
|
||||
SkipMaxList,
|
||||
Sleep,
|
||||
SocketClientOpen,
|
||||
SocketServerOpen,
|
||||
SocketServerAccept,
|
||||
SocketServerClose,
|
||||
TLSAcceptClient,
|
||||
TLSClientConnect,
|
||||
Succeed,
|
||||
TermAttributedVariables,
|
||||
TermVariables,
|
||||
TruncateLiftedHeapTo,
|
||||
UnifyWithOccursCheck,
|
||||
UnwindEnvironments,
|
||||
UnwindStack,
|
||||
Variant,
|
||||
WAMInstructions,
|
||||
WriteTerm,
|
||||
WriteTermToChars,
|
||||
ScryerPrologVersion,
|
||||
CryptoRandomByte,
|
||||
CryptoDataHash,
|
||||
CryptoDataHKDF,
|
||||
CryptoPasswordHash,
|
||||
CryptoDataEncrypt,
|
||||
CryptoDataDecrypt,
|
||||
CryptoCurveScalarMult,
|
||||
Ed25519Sign,
|
||||
Ed25519Verify,
|
||||
Ed25519NewKeyPair,
|
||||
Ed25519KeyPairPublicKey,
|
||||
Curve25519ScalarMult,
|
||||
FirstNonOctet,
|
||||
LoadHTML,
|
||||
LoadXML,
|
||||
GetEnv,
|
||||
SetEnv,
|
||||
UnsetEnv,
|
||||
Shell,
|
||||
PID,
|
||||
CharsBase64,
|
||||
DevourWhitespace,
|
||||
IsSTOEnabled,
|
||||
SetSTOAsUnify,
|
||||
SetNSTOAsUnify,
|
||||
SetSTOWithErrorAsUnify,
|
||||
HomeDirectory,
|
||||
DebugHook,
|
||||
PopCount
|
||||
}
|
||||
|
||||
impl SystemClauseType {
|
||||
pub(crate) fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
||||
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
||||
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
||||
&SystemClauseType::BindFromRegister => clause_name!("$bind_from_register"),
|
||||
&SystemClauseType::CallContinuation => clause_name!("$call_continuation"),
|
||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||
&SystemClauseType::CharType => clause_name!("$char_type"),
|
||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
||||
&SystemClauseType::CopyTermWithoutAttrVars => {
|
||||
clause_name!("$copy_term_without_attr_vars")
|
||||
}
|
||||
&SystemClauseType::CreatePartialString => clause_name!("$create_partial_string"),
|
||||
&SystemClauseType::CurrentInput => clause_name!("$current_input"),
|
||||
&SystemClauseType::CurrentHostname => clause_name!("$current_hostname"),
|
||||
&SystemClauseType::CurrentOutput => clause_name!("$current_output"),
|
||||
&SystemClauseType::DirectoryFiles => clause_name!("$directory_files"),
|
||||
&SystemClauseType::FileSize => clause_name!("$file_size"),
|
||||
&SystemClauseType::FileExists => clause_name!("$file_exists"),
|
||||
&SystemClauseType::DirectoryExists => clause_name!("$directory_exists"),
|
||||
&SystemClauseType::DirectorySeparator => clause_name!("$directory_separator"),
|
||||
&SystemClauseType::MakeDirectory => clause_name!("$make_directory"),
|
||||
&SystemClauseType::MakeDirectoryPath => clause_name!("$make_directory_path"),
|
||||
&SystemClauseType::DeleteFile => clause_name!("$delete_file"),
|
||||
&SystemClauseType::RenameFile => clause_name!("$rename_file"),
|
||||
&SystemClauseType::DeleteDirectory => clause_name!("$delete_directory"),
|
||||
&SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
|
||||
&SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
|
||||
&SystemClauseType::FileTime => clause_name!("$file_time"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => {
|
||||
clause_name!("$add_discontiguous_predicate")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => {
|
||||
clause_name!("$add_dynamic_predicate")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => {
|
||||
clause_name!("$add_multifile_predicate")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => {
|
||||
clause_name!("$add_goal_expansion_clause")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => {
|
||||
clause_name!("$add_term_expansion_clause")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => {
|
||||
clause_name!("$clause_to_evacuable")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => {
|
||||
clause_name!("$scoped_clause_to_evacuable")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => clause_name!("$conclude_load"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::DeclareModule) => clause_name!("$declare_module"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => {
|
||||
clause_name!("$load_compiled_library")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => {
|
||||
clause_name!("$push_load_state_payload")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule) => {
|
||||
clause_name!("$add_in_situ_filename_module")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::Asserta) => clause_name!("$asserta"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::Assertz) => clause_name!("$assertz"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::Retract) => clause_name!("$retract_clause"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => {
|
||||
clause_name!("$push_load_context")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => {
|
||||
clause_name!("$pop_load_context")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => {
|
||||
clause_name!("$pop_load_state_payload")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => {
|
||||
clause_name!("$prolog_lc_source")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => {
|
||||
clause_name!("$prolog_lc_file")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => {
|
||||
clause_name!("$prolog_lc_dir")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => {
|
||||
clause_name!("$prolog_lc_module")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => {
|
||||
clause_name!("$prolog_lc_stream")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => {
|
||||
clause_name!("$cpp_meta_predicate_property")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => {
|
||||
clause_name!("$cpp_built_in_property")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => {
|
||||
clause_name!("$cpp_dynamic_property")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => {
|
||||
clause_name!("$cpp_multifile_property")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => {
|
||||
clause_name!("$cpp_discontiguous_property")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AbolishClause) => clause_name!("$abolish_clause"),
|
||||
&SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => {
|
||||
clause_name!("$is_consistent_with_term_queue")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => {
|
||||
clause_name!("$flush_term_queue")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => {
|
||||
clause_name!("$remove_module_exports")
|
||||
}
|
||||
&SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => {
|
||||
clause_name!("$add_non_counted_backtracking")
|
||||
}
|
||||
&SystemClauseType::Close => clause_name!("$close"),
|
||||
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
|
||||
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
|
||||
&SystemClauseType::DeleteHeadAttribute => clause_name!("$del_attr_head"),
|
||||
&SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
|
||||
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
||||
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
|
||||
&SystemClauseType::FirstStream => clause_name!("$first_stream"),
|
||||
&SystemClauseType::FlushOutput => clause_name!("$flush_output"),
|
||||
&SystemClauseType::GetByte => clause_name!("$get_byte"),
|
||||
&SystemClauseType::GetChar => clause_name!("$get_char"),
|
||||
&SystemClauseType::GetNChars => clause_name!("$get_n_chars"),
|
||||
&SystemClauseType::GetCode => clause_name!("$get_code"),
|
||||
&SystemClauseType::GetSingleChar => clause_name!("$get_single_char"),
|
||||
&SystemClauseType::ResetAttrVarState => clause_name!("$reset_attr_var_state"),
|
||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
||||
clause_name!("$truncate_if_no_lh_growth")
|
||||
}
|
||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
|
||||
clause_name!("$truncate_if_no_lh_growth_diff")
|
||||
}
|
||||
&SystemClauseType::GetAttributedVariableList => clause_name!("$get_attr_list"),
|
||||
&SystemClauseType::GetAttrVarQueueDelimiter => {
|
||||
clause_name!("$get_attr_var_queue_delim")
|
||||
}
|
||||
&SystemClauseType::GetAttrVarQueueBeyond => clause_name!("$get_attr_var_queue_beyond"),
|
||||
&SystemClauseType::GetContinuationChunk => clause_name!("$get_cont_chunk"),
|
||||
&SystemClauseType::GetLiftedHeapFromOffset => clause_name!("$get_lh_from_offset"),
|
||||
&SystemClauseType::GetLiftedHeapFromOffsetDiff => {
|
||||
clause_name!("$get_lh_from_offset_diff")
|
||||
}
|
||||
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
|
||||
// &SystemClauseType::GetClause => clause_name!("$get_clause"),
|
||||
&SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
|
||||
&SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
|
||||
&SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"),
|
||||
&SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"),
|
||||
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
|
||||
// &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
|
||||
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
|
||||
&SystemClauseType::Halt => clause_name!("$halt"),
|
||||
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
|
||||
&SystemClauseType::Open => clause_name!("$open"),
|
||||
&SystemClauseType::SetStreamOptions => clause_name!("$set_stream_options"),
|
||||
&SystemClauseType::OpDeclaration => clause_name!("$op"),
|
||||
&SystemClauseType::InstallSCCCleaner => clause_name!("$install_scc_cleaner"),
|
||||
&SystemClauseType::InstallInferenceCounter => {
|
||||
clause_name!("$install_inference_counter")
|
||||
}
|
||||
&SystemClauseType::IsPartialString => clause_name!("$is_partial_string"),
|
||||
&SystemClauseType::PartialStringTail => clause_name!("$partial_string_tail"),
|
||||
&SystemClauseType::PeekByte => clause_name!("$peek_byte"),
|
||||
&SystemClauseType::PeekChar => clause_name!("$peek_char"),
|
||||
&SystemClauseType::PeekCode => clause_name!("$peek_code"),
|
||||
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
||||
&SystemClauseType::Maybe => clause_name!("maybe"),
|
||||
&SystemClauseType::CpuNow => clause_name!("$cpu_now"),
|
||||
&SystemClauseType::CurrentTime => clause_name!("$current_time"),
|
||||
// &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
||||
// clause_name!("$module_asserta")
|
||||
// }
|
||||
// &SystemClauseType::ModuleAssertDynamicPredicateToBack => {
|
||||
// clause_name!("$module_assertz")
|
||||
// }
|
||||
// &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
||||
&SystemClauseType::ModuleExists => clause_name!("$module_exists"),
|
||||
&SystemClauseType::NextStream => clause_name!("$next_stream"),
|
||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||
&SystemClauseType::PointsToContinuationResetMarker => {
|
||||
clause_name!("$points_to_cont_reset_marker")
|
||||
}
|
||||
&SystemClauseType::PutByte => {
|
||||
clause_name!("$put_byte")
|
||||
}
|
||||
&SystemClauseType::PutChar => {
|
||||
clause_name!("$put_char")
|
||||
}
|
||||
&SystemClauseType::PutChars => {
|
||||
clause_name!("$put_chars")
|
||||
}
|
||||
&SystemClauseType::PutCode => {
|
||||
clause_name!("$put_code")
|
||||
}
|
||||
&SystemClauseType::QuotedToken => {
|
||||
clause_name!("$quoted_token")
|
||||
}
|
||||
&SystemClauseType::RedoAttrVarBinding => clause_name!("$redo_attr_var_binding"),
|
||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
|
||||
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
|
||||
&SystemClauseType::SetInput => clause_name!("$set_input"),
|
||||
&SystemClauseType::SetOutput => clause_name!("$set_output"),
|
||||
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
|
||||
&SystemClauseType::StreamProperty => clause_name!("$stream_property"),
|
||||
&SystemClauseType::SetStreamPosition => clause_name!("$set_stream_position"),
|
||||
&SystemClauseType::StoreBacktrackableGlobalVar => {
|
||||
clause_name!("$store_back_trackable_global_var")
|
||||
}
|
||||
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
|
||||
&SystemClauseType::InferenceLevel => clause_name!("$inference_level"),
|
||||
&SystemClauseType::CleanUpBlock => clause_name!("$clean_up_block"),
|
||||
&SystemClauseType::EraseBall => clause_name!("$erase_ball"),
|
||||
&SystemClauseType::Fail => clause_name!("$fail"),
|
||||
&SystemClauseType::GetBall => clause_name!("$get_ball"),
|
||||
&SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
|
||||
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
|
||||
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
|
||||
&SystemClauseType::NextEP => clause_name!("$nextEP"),
|
||||
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
|
||||
&SystemClauseType::ReadTerm => clause_name!("$read_term"),
|
||||
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
|
||||
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
||||
&SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
|
||||
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
||||
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
||||
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
||||
&SystemClauseType::SetDoubleQuotes => clause_name!("$set_double_quotes"),
|
||||
&SystemClauseType::SkipMaxList => clause_name!("$skip_max_list"),
|
||||
&SystemClauseType::Sleep => clause_name!("$sleep"),
|
||||
&SystemClauseType::SocketClientOpen => clause_name!("$socket_client_open"),
|
||||
&SystemClauseType::SocketServerOpen => clause_name!("$socket_server_open"),
|
||||
&SystemClauseType::SocketServerAccept => clause_name!("$socket_server_accept"),
|
||||
&SystemClauseType::SocketServerClose => clause_name!("$socket_server_close"),
|
||||
&SystemClauseType::TLSAcceptClient => clause_name!("$tls_accept_client"),
|
||||
&SystemClauseType::TLSClientConnect => clause_name!("$tls_client_connect"),
|
||||
&SystemClauseType::Succeed => clause_name!("$succeed"),
|
||||
&SystemClauseType::TermAttributedVariables => {
|
||||
clause_name!("$term_attributed_variables")
|
||||
}
|
||||
&SystemClauseType::TermVariables => clause_name!("$term_variables"),
|
||||
&SystemClauseType::TruncateLiftedHeapTo => clause_name!("$truncate_lh_to"),
|
||||
&SystemClauseType::UnifyWithOccursCheck => clause_name!("$unify_with_occurs_check"),
|
||||
&SystemClauseType::UnwindEnvironments => clause_name!("$unwind_environments"),
|
||||
&SystemClauseType::UnwindStack => clause_name!("$unwind_stack"),
|
||||
&SystemClauseType::Variant => clause_name!("$variant"),
|
||||
&SystemClauseType::WAMInstructions => clause_name!("$wam_instructions"),
|
||||
&SystemClauseType::WriteTerm => clause_name!("$write_term"),
|
||||
&SystemClauseType::WriteTermToChars => clause_name!("$write_term_to_chars"),
|
||||
&SystemClauseType::ScryerPrologVersion => clause_name!("$scryer_prolog_version"),
|
||||
&SystemClauseType::CryptoRandomByte => clause_name!("$crypto_random_byte"),
|
||||
&SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
|
||||
&SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
|
||||
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
||||
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
||||
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
|
||||
&SystemClauseType::CryptoCurveScalarMult => clause_name!("$crypto_curve_scalar_mult"),
|
||||
&SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
|
||||
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
|
||||
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
|
||||
&SystemClauseType::Ed25519KeyPairPublicKey => {
|
||||
clause_name!("$ed25519_keypair_public_key")
|
||||
}
|
||||
&SystemClauseType::Curve25519ScalarMult => clause_name!("$curve25519_scalar_mult"),
|
||||
&SystemClauseType::FirstNonOctet => clause_name!("$first_non_octet"),
|
||||
&SystemClauseType::LoadHTML => clause_name!("$load_html"),
|
||||
&SystemClauseType::LoadXML => clause_name!("$load_xml"),
|
||||
&SystemClauseType::GetEnv => clause_name!("$getenv"),
|
||||
&SystemClauseType::SetEnv => clause_name!("$setenv"),
|
||||
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
|
||||
&SystemClauseType::Shell => clause_name!("$shell"),
|
||||
&SystemClauseType::PID => clause_name!("$pid"),
|
||||
&SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
|
||||
&SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"),
|
||||
&SystemClauseType::DevourWhitespace => clause_name!("$devour_whitespace"),
|
||||
&SystemClauseType::IsSTOEnabled => clause_name!("$is_sto_enabled"),
|
||||
&SystemClauseType::SetSTOAsUnify => clause_name!("$set_sto_as_unify"),
|
||||
&SystemClauseType::SetNSTOAsUnify => clause_name!("$set_nsto_as_unify"),
|
||||
&SystemClauseType::HomeDirectory => clause_name!("$home_directory"),
|
||||
&SystemClauseType::SetSTOWithErrorAsUnify => {
|
||||
clause_name!("$set_sto_with_error_as_unify")
|
||||
}
|
||||
&SystemClauseType::DebugHook => clause_name!("$debug_hook"),
|
||||
&SystemClauseType::PopCount => clause_name!("$popcount"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
|
||||
match (name, arity) {
|
||||
("$abolish_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)),
|
||||
("$add_dynamic_predicate", 4) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate))
|
||||
}
|
||||
("$add_multifile_predicate", 4) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate))
|
||||
}
|
||||
("$add_discontiguous_predicate", 4) => Some(SystemClauseType::REPL(
|
||||
REPLCodePtr::AddDiscontiguousPredicate,
|
||||
)),
|
||||
("$add_goal_expansion_clause", 3) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause))
|
||||
}
|
||||
("$add_term_expansion_clause", 2) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause))
|
||||
}
|
||||
("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
|
||||
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
|
||||
("$atom_length", 2) => Some(SystemClauseType::AtomLength),
|
||||
("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
|
||||
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
|
||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||
("$char_type", 2) => Some(SystemClauseType::CharType),
|
||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
||||
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
||||
("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
|
||||
("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
|
||||
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
|
||||
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
|
||||
("$close", 2) => Some(SystemClauseType::Close),
|
||||
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
|
||||
("$current_input", 1) => Some(SystemClauseType::CurrentInput),
|
||||
("$current_output", 1) => Some(SystemClauseType::CurrentOutput),
|
||||
("$first_stream", 1) => Some(SystemClauseType::FirstStream),
|
||||
("$next_stream", 2) => Some(SystemClauseType::NextStream),
|
||||
("$flush_output", 1) => Some(SystemClauseType::FlushOutput),
|
||||
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
|
||||
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
|
||||
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
|
||||
("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef),
|
||||
("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
|
||||
("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
|
||||
("$module_call", _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
|
||||
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
||||
("$partial_string_tail", 2) => Some(SystemClauseType::PartialStringTail),
|
||||
("$peek_byte", 2) => Some(SystemClauseType::PeekByte),
|
||||
("$peek_char", 2) => Some(SystemClauseType::PeekChar),
|
||||
("$peek_code", 2) => Some(SystemClauseType::PeekCode),
|
||||
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
|
||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||
("$get_byte", 2) => Some(SystemClauseType::GetByte),
|
||||
("$get_char", 2) => Some(SystemClauseType::GetChar),
|
||||
("$get_n_chars", 3) => Some(SystemClauseType::GetNChars),
|
||||
("$get_code", 2) => Some(SystemClauseType::GetCode),
|
||||
("$get_single_char", 1) => Some(SystemClauseType::GetSingleChar),
|
||||
("$points_to_cont_reset_marker", 1) => {
|
||||
Some(SystemClauseType::PointsToContinuationResetMarker)
|
||||
}
|
||||
("$put_byte", 2) => Some(SystemClauseType::PutByte),
|
||||
("$put_char", 2) => Some(SystemClauseType::PutChar),
|
||||
("$put_chars", 2) => Some(SystemClauseType::PutChars),
|
||||
("$put_code", 2) => Some(SystemClauseType::PutCode),
|
||||
("$reset_attr_var_state", 0) => Some(SystemClauseType::ResetAttrVarState),
|
||||
("$truncate_if_no_lh_growth", 1) => {
|
||||
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
|
||||
}
|
||||
("$truncate_if_no_lh_growth_diff", 2) => {
|
||||
Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff)
|
||||
}
|
||||
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
|
||||
("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
|
||||
("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
|
||||
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
|
||||
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
|
||||
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
|
||||
("$halt", 1) => Some(SystemClauseType::Halt),
|
||||
("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic),
|
||||
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
|
||||
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
|
||||
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
|
||||
("$maybe", 0) => Some(SystemClauseType::Maybe),
|
||||
("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
|
||||
("$current_time", 1) => Some(SystemClauseType::CurrentTime),
|
||||
("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
|
||||
("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate),
|
||||
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
|
||||
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
|
||||
("$op", 3) => Some(SystemClauseType::OpDeclaration),
|
||||
("$open", 7) => Some(SystemClauseType::Open),
|
||||
("$set_stream_options", 5) => Some(SystemClauseType::SetStreamOptions),
|
||||
("$redo_attr_var_binding", 2) => Some(SystemClauseType::RedoAttrVarBinding),
|
||||
("$remove_call_policy_check", 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
|
||||
("$remove_inference_counter", 2) => Some(SystemClauseType::RemoveInferenceCounter),
|
||||
("$restore_cut_policy", 0) => Some(SystemClauseType::RestoreCutPolicy),
|
||||
("$set_cp", 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
|
||||
("$set_input", 1) => Some(SystemClauseType::SetInput),
|
||||
("$set_output", 1) => Some(SystemClauseType::SetOutput),
|
||||
("$stream_property", 3) => Some(SystemClauseType::StreamProperty),
|
||||
("$set_stream_position", 2) => Some(SystemClauseType::SetStreamPosition),
|
||||
("$inference_level", 2) => Some(SystemClauseType::InferenceLevel),
|
||||
("$clean_up_block", 1) => Some(SystemClauseType::CleanUpBlock),
|
||||
("$erase_ball", 0) => Some(SystemClauseType::EraseBall),
|
||||
("$fail", 0) => Some(SystemClauseType::Fail),
|
||||
("$get_attr_var_queue_beyond", 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
|
||||
("$get_attr_var_queue_delim", 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
|
||||
("$get_ball", 1) => Some(SystemClauseType::GetBall),
|
||||
("$get_cont_chunk", 3) => Some(SystemClauseType::GetContinuationChunk),
|
||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||
("$quoted_token", 1) => Some(SystemClauseType::QuotedToken),
|
||||
("$nextEP", 3) => Some(SystemClauseType::NextEP),
|
||||
("$read_query_term", 5) => Some(SystemClauseType::ReadQueryTerm),
|
||||
("$read_term", 5) => Some(SystemClauseType::ReadTerm),
|
||||
("$read_term_from_chars", 2) => Some(SystemClauseType::ReadTermFromChars),
|
||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
|
||||
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
|
||||
("$set_ball", 1) => Some(SystemClauseType::SetBall),
|
||||
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
|
||||
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
|
||||
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
|
||||
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
||||
("$sleep", 1) => Some(SystemClauseType::Sleep),
|
||||
("$socket_client_open", 7) => Some(SystemClauseType::SocketClientOpen),
|
||||
("$socket_server_open", 3) => Some(SystemClauseType::SocketServerOpen),
|
||||
("$socket_server_accept", 7) => Some(SystemClauseType::SocketServerAccept),
|
||||
("$socket_server_close", 1) => Some(SystemClauseType::SocketServerClose),
|
||||
("$tls_accept_client", 4) => Some(SystemClauseType::TLSAcceptClient),
|
||||
("$tls_client_connect", 3) => Some(SystemClauseType::TLSClientConnect),
|
||||
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
|
||||
("$store_backtrackable_global_var", 2) => {
|
||||
Some(SystemClauseType::StoreBacktrackableGlobalVar)
|
||||
}
|
||||
("$term_attributed_variables", 2) => Some(SystemClauseType::TermAttributedVariables),
|
||||
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||
("$unwind_environments", 0) => Some(SystemClauseType::UnwindEnvironments),
|
||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||
("$unify_with_occurs_check", 2) => Some(SystemClauseType::UnifyWithOccursCheck),
|
||||
("$directory_files", 2) => Some(SystemClauseType::DirectoryFiles),
|
||||
("$file_size", 2) => Some(SystemClauseType::FileSize),
|
||||
("$file_exists", 1) => Some(SystemClauseType::FileExists),
|
||||
("$directory_exists", 1) => Some(SystemClauseType::DirectoryExists),
|
||||
("$directory_separator", 1) => Some(SystemClauseType::DirectorySeparator),
|
||||
("$make_directory", 1) => Some(SystemClauseType::MakeDirectory),
|
||||
("$make_directory_path", 1) => Some(SystemClauseType::MakeDirectoryPath),
|
||||
("$delete_file", 1) => Some(SystemClauseType::DeleteFile),
|
||||
("$rename_file", 2) => Some(SystemClauseType::RenameFile),
|
||||
("$delete_directory", 1) => Some(SystemClauseType::DeleteDirectory),
|
||||
("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
|
||||
("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
|
||||
("$file_time", 3) => Some(SystemClauseType::FileTime),
|
||||
("$clause_to_evacuable", 2) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable))
|
||||
}
|
||||
("$scoped_clause_to_evacuable", 3) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable))
|
||||
}
|
||||
("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)),
|
||||
("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
|
||||
("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)),
|
||||
("$load_compiled_library", 3) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary))
|
||||
}
|
||||
("$push_load_state_payload", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload))
|
||||
}
|
||||
("$add_in_situ_filename_module", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule))
|
||||
}
|
||||
("$asserta", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)),
|
||||
("$assertz", 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)),
|
||||
("$retract_clause", 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)),
|
||||
("$is_consistent_with_term_queue", 4) => Some(SystemClauseType::REPL(
|
||||
REPLCodePtr::IsConsistentWithTermQueue,
|
||||
)),
|
||||
("$flush_term_queue", 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)),
|
||||
("$remove_module_exports", 2) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports))
|
||||
}
|
||||
("$add_non_counted_backtracking", 3) => Some(SystemClauseType::REPL(
|
||||
REPLCodePtr::AddNonCountedBacktracking,
|
||||
)),
|
||||
("$variant", 2) => Some(SystemClauseType::Variant),
|
||||
("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions),
|
||||
("$write_term", 7) => Some(SystemClauseType::WriteTerm),
|
||||
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
|
||||
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
|
||||
("$crypto_random_byte", 1) => Some(SystemClauseType::CryptoRandomByte),
|
||||
("$crypto_data_hash", 4) => Some(SystemClauseType::CryptoDataHash),
|
||||
("$crypto_data_hkdf", 7) => Some(SystemClauseType::CryptoDataHKDF),
|
||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||
("$crypto_data_encrypt", 7) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||
("$crypto_data_decrypt", 6) => Some(SystemClauseType::CryptoDataDecrypt),
|
||||
("$crypto_curve_scalar_mult", 5) => Some(SystemClauseType::CryptoCurveScalarMult),
|
||||
("$ed25519_sign", 4) => Some(SystemClauseType::Ed25519Sign),
|
||||
("$ed25519_verify", 4) => Some(SystemClauseType::Ed25519Verify),
|
||||
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
|
||||
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
|
||||
("$curve25519_scalar_mult", 3) => Some(SystemClauseType::Curve25519ScalarMult),
|
||||
("$first_non_octet", 2) => Some(SystemClauseType::FirstNonOctet),
|
||||
("$load_html", 3) => Some(SystemClauseType::LoadHTML),
|
||||
("$load_xml", 3) => Some(SystemClauseType::LoadXML),
|
||||
("$getenv", 2) => Some(SystemClauseType::GetEnv),
|
||||
("$setenv", 2) => Some(SystemClauseType::SetEnv),
|
||||
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
|
||||
("$shell", 2) => Some(SystemClauseType::Shell),
|
||||
("$pid", 1) => Some(SystemClauseType::PID),
|
||||
("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
|
||||
("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream),
|
||||
("$push_load_context", 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)),
|
||||
("$pop_load_state_payload", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload))
|
||||
}
|
||||
("$pop_load_context", 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)),
|
||||
("$prolog_lc_source", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource))
|
||||
}
|
||||
("$prolog_lc_file", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)),
|
||||
("$prolog_lc_dir", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory))
|
||||
}
|
||||
("$prolog_lc_module", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule))
|
||||
}
|
||||
("$prolog_lc_stream", 1) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream))
|
||||
}
|
||||
("$cpp_meta_predicate_property", 4) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty))
|
||||
}
|
||||
("$cpp_built_in_property", 2) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty))
|
||||
}
|
||||
("$cpp_dynamic_property", 3) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty))
|
||||
}
|
||||
("$cpp_multifile_property", 3) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty))
|
||||
}
|
||||
("$cpp_discontiguous_property", 3) => {
|
||||
Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty))
|
||||
}
|
||||
("$devour_whitespace", 1) => Some(SystemClauseType::DevourWhitespace),
|
||||
("$is_sto_enabled", 1) => Some(SystemClauseType::IsSTOEnabled),
|
||||
("$set_sto_as_unify", 0) => Some(SystemClauseType::SetSTOAsUnify),
|
||||
("$set_nsto_as_unify", 0) => Some(SystemClauseType::SetNSTOAsUnify),
|
||||
("$set_sto_with_error_as_unify", 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify),
|
||||
("$home_directory", 1) => Some(SystemClauseType::HomeDirectory),
|
||||
("$debug_hook", 0) => Some(SystemClauseType::DebugHook),
|
||||
("$popcount", 2) => Some(SystemClauseType::PopCount),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub(crate) enum BuiltInClauseType {
|
||||
AcyclicTerm,
|
||||
Arg,
|
||||
Compare,
|
||||
CompareTerm(CompareTermQT),
|
||||
CopyTerm,
|
||||
Eq,
|
||||
Functor,
|
||||
Ground,
|
||||
Is(RegType, ArithmeticTerm),
|
||||
KeySort,
|
||||
NotEq,
|
||||
Read,
|
||||
Sort,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) enum ClauseType {
|
||||
BuiltIn(BuiltInClauseType),
|
||||
CallN,
|
||||
Inlined(InlinedClauseType),
|
||||
Named(ClauseName, usize, CodeIndex), // name, arity, index.
|
||||
Op(ClauseName, SharedOpDesc, CodeIndex),
|
||||
System(SystemClauseType),
|
||||
}
|
||||
|
||||
impl BuiltInClauseType {
|
||||
pub(crate) fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&BuiltInClauseType::AcyclicTerm => clause_name!("acyclic_term"),
|
||||
&BuiltInClauseType::Arg => clause_name!("arg"),
|
||||
&BuiltInClauseType::Compare => clause_name!("compare"),
|
||||
&BuiltInClauseType::CompareTerm(qt) => clause_name!(qt.name()),
|
||||
&BuiltInClauseType::CopyTerm => clause_name!("copy_term"),
|
||||
&BuiltInClauseType::Eq => clause_name!("=="),
|
||||
&BuiltInClauseType::Functor => clause_name!("functor"),
|
||||
&BuiltInClauseType::Ground => clause_name!("ground"),
|
||||
&BuiltInClauseType::Is(..) => clause_name!("is"),
|
||||
&BuiltInClauseType::KeySort => clause_name!("keysort"),
|
||||
&BuiltInClauseType::NotEq => clause_name!("\\=="),
|
||||
&BuiltInClauseType::Read => clause_name!("read"),
|
||||
&BuiltInClauseType::Sort => clause_name!("sort"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn arity(&self) -> usize {
|
||||
match self {
|
||||
&BuiltInClauseType::AcyclicTerm => 1,
|
||||
&BuiltInClauseType::Arg => 3,
|
||||
&BuiltInClauseType::Compare => 2,
|
||||
&BuiltInClauseType::CompareTerm(_) => 2,
|
||||
&BuiltInClauseType::CopyTerm => 2,
|
||||
&BuiltInClauseType::Eq => 2,
|
||||
&BuiltInClauseType::Functor => 3,
|
||||
&BuiltInClauseType::Ground => 1,
|
||||
&BuiltInClauseType::Is(..) => 2,
|
||||
&BuiltInClauseType::KeySort => 2,
|
||||
&BuiltInClauseType::NotEq => 2,
|
||||
&BuiltInClauseType::Read => 2,
|
||||
&BuiltInClauseType::Sort => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ClauseType {
|
||||
pub(crate) fn spec(&self) -> Option<SharedOpDesc> {
|
||||
match self {
|
||||
&ClauseType::Op(_, ref spec, _) => Some(spec.clone()),
|
||||
&ClauseType::Inlined(InlinedClauseType::CompareNumber(..))
|
||||
| &ClauseType::BuiltIn(BuiltInClauseType::Is(..))
|
||||
| &ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(_))
|
||||
| &ClauseType::BuiltIn(BuiltInClauseType::NotEq)
|
||||
| &ClauseType::BuiltIn(BuiltInClauseType::Eq) => Some(SharedOpDesc::new(700, XFX)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn name(&self) -> ClauseName {
|
||||
match self {
|
||||
&ClauseType::BuiltIn(ref built_in) => built_in.name(),
|
||||
&ClauseType::CallN => clause_name!("$call"),
|
||||
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
|
||||
&ClauseType::Op(ref name, ..) => name.clone(),
|
||||
&ClauseType::Named(ref name, ..) => name.clone(),
|
||||
&ClauseType::System(ref system) => system.name(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from(name: ClauseName, arity: usize, spec: Option<SharedOpDesc>) -> Self {
|
||||
CLAUSE_TYPE_FORMS
|
||||
.borrow()
|
||||
.get(&(name.as_str(), arity))
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
SystemClauseType::from(name.as_str(), arity)
|
||||
.map(ClauseType::System)
|
||||
.unwrap_or_else(|| {
|
||||
if let Some(spec) = spec {
|
||||
ClauseType::Op(name, spec, CodeIndex::default())
|
||||
} else if name.as_str() == "$call" {
|
||||
ClauseType::CallN
|
||||
} else {
|
||||
ClauseType::Named(name, arity, CodeIndex::default())
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<InlinedClauseType> for ClauseType {
|
||||
fn from(inlined_ct: InlinedClauseType) -> Self {
|
||||
ClauseType::Inlined(inlined_ct)
|
||||
}
|
||||
}
|
||||
696
src/codegen.rs
696
src/codegen.rs
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,16 @@
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::temp_v;
|
||||
|
||||
use crate::allocator::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::forms::Level;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::targets::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::targets::CompilationTarget;
|
||||
|
||||
use crate::temp_v;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::BTreeSet;
|
||||
@@ -15,23 +18,23 @@ use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DebrayAllocator {
|
||||
bindings: IndexMap<Rc<Var>, VarData>,
|
||||
bindings: IndexMap<Rc<String>, VarData, FxBuildHasher>,
|
||||
arg_c: usize,
|
||||
temp_lb: usize,
|
||||
arity: usize, // 0 if not at head.
|
||||
contents: IndexMap<usize, Rc<Var>>,
|
||||
contents: IndexMap<usize, Rc<String>, FxBuildHasher>,
|
||||
in_use: BTreeSet<usize>,
|
||||
}
|
||||
|
||||
impl DebrayAllocator {
|
||||
fn is_curr_arg_distinct_from(&self, var: &Var) -> bool {
|
||||
fn is_curr_arg_distinct_from(&self, var: &String) -> bool {
|
||||
match self.contents.get(&self.arg_c) {
|
||||
Some(t_var) if **t_var != *var => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn occurs_shallowly_in_head(&self, var: &Var, r: usize) -> bool {
|
||||
fn occurs_shallowly_in_head(&self, var: &String, r: usize) -> bool {
|
||||
match self.bindings.get(var).unwrap() {
|
||||
&VarData::Temp(_, _, ref tvd) => tvd.use_set.contains(&(GenContext::Head, r)),
|
||||
_ => false,
|
||||
@@ -44,7 +47,7 @@ impl DebrayAllocator {
|
||||
in_use_range || self.in_use.contains(&r)
|
||||
}
|
||||
|
||||
fn alloc_with_cr(&self, var: &Var) -> usize {
|
||||
fn alloc_with_cr(&self, var: &String) -> usize {
|
||||
match self.bindings.get(var) {
|
||||
Some(&VarData::Temp(_, _, ref tvd)) => {
|
||||
for &(_, reg) in tvd.use_set.iter() {
|
||||
@@ -70,7 +73,7 @@ impl DebrayAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_with_ca(&self, var: &Var) -> usize {
|
||||
fn alloc_with_ca(&self, var: &String) -> usize {
|
||||
match self.bindings.get(var) {
|
||||
Some(&VarData::Temp(_, _, ref tvd)) => {
|
||||
for &(_, reg) in tvd.use_set.iter() {
|
||||
@@ -98,7 +101,7 @@ impl DebrayAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<Var>, usize)> {
|
||||
fn alloc_in_last_goal_hint(&self, chunk_num: usize) -> Option<(Rc<String>, usize)> {
|
||||
// we want to allocate a register to the k^{th} parameter, par_k.
|
||||
// par_k may not be a temporary variable.
|
||||
let k = self.arg_c;
|
||||
@@ -123,10 +126,11 @@ impl DebrayAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
|
||||
where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
fn evacuate_arg<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
chunk_num: usize,
|
||||
code: &mut Code,
|
||||
) {
|
||||
match self.alloc_in_last_goal_hint(chunk_num) {
|
||||
Some((var, r)) => {
|
||||
let k = self.arg_c;
|
||||
@@ -134,7 +138,7 @@ impl DebrayAllocator {
|
||||
if r != k {
|
||||
let r = RegType::Temp(r);
|
||||
|
||||
target.push(Target::move_to_register(r, k));
|
||||
code.push(Target::move_to_register(r, k));
|
||||
|
||||
self.contents.swap_remove(&k);
|
||||
self.contents.insert(r.reg_num(), var.clone());
|
||||
@@ -149,10 +153,10 @@ impl DebrayAllocator {
|
||||
|
||||
fn alloc_reg_to_var<'a, Target>(
|
||||
&mut self,
|
||||
var: &Var,
|
||||
var: &String,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
target: &mut Vec<Target>,
|
||||
target: &mut Vec<Instruction>,
|
||||
) -> usize
|
||||
where
|
||||
Target: CompilationTarget<'a>,
|
||||
@@ -160,7 +164,7 @@ impl DebrayAllocator {
|
||||
match term_loc {
|
||||
GenContext::Head => {
|
||||
if let Level::Shallow = lvl {
|
||||
self.evacuate_arg(0, target);
|
||||
self.evacuate_arg::<Target>(0, target);
|
||||
self.alloc_with_cr(var)
|
||||
} else {
|
||||
self.alloc_with_ca(var)
|
||||
@@ -169,7 +173,7 @@ impl DebrayAllocator {
|
||||
GenContext::Mid(_) => self.alloc_with_ca(var),
|
||||
GenContext::Last(chunk_num) => {
|
||||
if let Level::Shallow = lvl {
|
||||
self.evacuate_arg(chunk_num, target);
|
||||
self.evacuate_arg::<Target>(chunk_num, target);
|
||||
self.alloc_with_cr(var)
|
||||
} else {
|
||||
self.alloc_with_ca(var)
|
||||
@@ -193,7 +197,7 @@ impl DebrayAllocator {
|
||||
final_index
|
||||
}
|
||||
|
||||
fn in_place(&self, var: &Var, term_loc: GenContext, r: RegType, k: usize) -> bool {
|
||||
fn in_place(&self, var: &String, term_loc: GenContext, r: RegType, k: usize) -> bool {
|
||||
match term_loc {
|
||||
GenContext::Head if !r.is_perm() => r.reg_num() == k,
|
||||
_ => match self.bindings().get(var).unwrap() {
|
||||
@@ -204,49 +208,49 @@ impl DebrayAllocator {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
impl Allocator for DebrayAllocator {
|
||||
fn new() -> DebrayAllocator {
|
||||
DebrayAllocator {
|
||||
arity: 0,
|
||||
arg_c: 1,
|
||||
temp_lb: 1,
|
||||
bindings: IndexMap::new(),
|
||||
contents: IndexMap::new(),
|
||||
bindings: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
contents: IndexMap::with_hasher(FxBuildHasher::default()),
|
||||
in_use: BTreeSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_anon_var<Target>(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec<Target>)
|
||||
where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
code: &mut Code,
|
||||
) {
|
||||
let r = RegType::Temp(self.alloc_reg_to_non_var());
|
||||
|
||||
match lvl {
|
||||
Level::Deep => target.push(Target::subterm_to_variable(r)),
|
||||
Level::Deep => code.push(Target::subterm_to_variable(r)),
|
||||
Level::Root | Level::Shallow => {
|
||||
let k = self.arg_c;
|
||||
|
||||
if let GenContext::Last(chunk_num) = term_loc {
|
||||
self.evacuate_arg(chunk_num, target);
|
||||
self.evacuate_arg::<Target>(chunk_num, code);
|
||||
}
|
||||
|
||||
self.arg_c += 1;
|
||||
|
||||
target.push(Target::argument_to_variable(r, k));
|
||||
code.push(Target::argument_to_variable(r, k));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn mark_non_var<Target>(
|
||||
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
lvl: Level,
|
||||
term_loc: GenContext,
|
||||
cell: &Cell<RegType>,
|
||||
target: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
cell: &'a Cell<RegType>,
|
||||
code: &mut Code,
|
||||
) {
|
||||
let r = cell.get();
|
||||
|
||||
let r = match lvl {
|
||||
@@ -254,7 +258,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
let k = self.arg_c;
|
||||
|
||||
if let GenContext::Last(chunk_num) = term_loc {
|
||||
self.evacuate_arg(chunk_num, target);
|
||||
self.evacuate_arg::<Target>(chunk_num, code);
|
||||
}
|
||||
|
||||
self.arg_c += 1;
|
||||
@@ -270,20 +274,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
cell.set(r);
|
||||
}
|
||||
|
||||
fn mark_var<Target>(
|
||||
fn mark_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
var: Rc<Var>,
|
||||
var: Rc<String>,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
target: &mut Vec<Target>,
|
||||
) where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
code: &mut Code,
|
||||
) {
|
||||
let (r, is_new_var) = match self.get(var.clone()) {
|
||||
RegType::Temp(0) => {
|
||||
// here, r is temporary *and* unassigned.
|
||||
let o = self.alloc_reg_to_var(&var, lvl, term_loc, target);
|
||||
let o = self.alloc_reg_to_var::<Target>(&var, lvl, term_loc, code);
|
||||
cell.set(VarReg::Norm(RegType::Temp(o)));
|
||||
|
||||
(RegType::Temp(o), true)
|
||||
@@ -297,27 +299,25 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
r => (r, false),
|
||||
};
|
||||
|
||||
self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);
|
||||
self.mark_reserved_var::<Target>(var, lvl, cell, term_loc, code, r, is_new_var);
|
||||
}
|
||||
|
||||
fn mark_reserved_var<Target>(
|
||||
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
|
||||
&mut self,
|
||||
var: Rc<Var>,
|
||||
var: Rc<String>,
|
||||
lvl: Level,
|
||||
cell: &'a Cell<VarReg>,
|
||||
term_loc: GenContext,
|
||||
target: &mut Vec<Target>,
|
||||
code: &mut Code,
|
||||
r: RegType,
|
||||
is_new_var: bool,
|
||||
) where
|
||||
Target: CompilationTarget<'a>,
|
||||
{
|
||||
) {
|
||||
match lvl {
|
||||
Level::Root | Level::Shallow => {
|
||||
let k = self.arg_c;
|
||||
|
||||
if self.is_curr_arg_distinct_from(&var) {
|
||||
self.evacuate_arg(term_loc.chunk_num(), target);
|
||||
self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
|
||||
}
|
||||
|
||||
self.arg_c += 1;
|
||||
@@ -326,24 +326,24 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
|
||||
if !self.in_place(&var, term_loc, r, k) {
|
||||
if is_new_var {
|
||||
target.push(Target::argument_to_variable(r, k));
|
||||
code.push(Target::argument_to_variable(r, k));
|
||||
} else {
|
||||
target.push(Target::argument_to_value(r, k));
|
||||
code.push(Target::argument_to_value(r, k));
|
||||
}
|
||||
}
|
||||
}
|
||||
Level::Deep if is_new_var => {
|
||||
if let GenContext::Head = term_loc {
|
||||
if self.occurs_shallowly_in_head(&var, r.reg_num()) {
|
||||
target.push(Target::subterm_to_value(r));
|
||||
code.push(Target::subterm_to_value(r));
|
||||
} else {
|
||||
target.push(Target::subterm_to_variable(r));
|
||||
code.push(Target::subterm_to_variable(r));
|
||||
}
|
||||
} else {
|
||||
target.push(Target::subterm_to_variable(r));
|
||||
code.push(Target::subterm_to_variable(r));
|
||||
}
|
||||
}
|
||||
Level::Deep => target.push(Target::subterm_to_value(r)),
|
||||
Level::Deep => code.push(Target::subterm_to_value(r)),
|
||||
};
|
||||
|
||||
if !r.is_perm() {
|
||||
@@ -382,12 +382,12 @@ impl<'a> Allocator<'a> for DebrayAllocator {
|
||||
self.bindings
|
||||
}
|
||||
|
||||
fn reset_at_head(&mut self, args: &Vec<Box<Term>>) {
|
||||
fn reset_at_head(&mut self, args: &Vec<Term>) {
|
||||
self.reset_arg(args.len());
|
||||
self.arity = args.len();
|
||||
|
||||
for (idx, arg) in args.iter().enumerate() {
|
||||
if let &Term::Var(_, ref var) = arg.as_ref() {
|
||||
if let &Term::Var(_, ref var) = arg {
|
||||
let r = self.get(var.clone());
|
||||
|
||||
if !r.is_perm() && r.reg_num() == 0 {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*/
|
||||
|
||||
:- module(least_time, [find_min_time/2,
|
||||
write_time_nl/1]).
|
||||
write_time_nl/1]).
|
||||
|
||||
|
||||
:- use_module(library(dcgs)).
|
||||
@@ -20,12 +20,6 @@
|
||||
:- use_module(library(reif)).
|
||||
|
||||
|
||||
permutation([], []).
|
||||
permutation([X|Xs], Ys) :-
|
||||
permutation(Xs, Yss),
|
||||
select(X, Ys, Yss).
|
||||
|
||||
|
||||
valid_time([H1,H2,M1,M2], T) :-
|
||||
memberd_t(H1, [0,1,2], TH1),
|
||||
memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
|
||||
@@ -33,10 +27,10 @@ valid_time([H1,H2,M1,M2], T) :-
|
||||
memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
|
||||
( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
|
||||
( H1 =:= 2 ->
|
||||
( H2 =< 3 ->
|
||||
T = true
|
||||
; T = false
|
||||
)
|
||||
( H2 =< 3 ->
|
||||
T = true
|
||||
; T = false
|
||||
)
|
||||
; T = true
|
||||
)
|
||||
; T = false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use prolog_parser::ast::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
@@ -84,8 +84,8 @@ type VariableFixture<'a> = (VarStatus, Vec<&'a Cell<VarReg>>);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct VariableFixtures<'a> {
|
||||
perm_vars: IndexMap<Rc<Var>, VariableFixture<'a>>,
|
||||
last_chunk_temp_vars: IndexSet<Rc<Var>>,
|
||||
perm_vars: IndexMap<Rc<String>, VariableFixture<'a>>,
|
||||
last_chunk_temp_vars: IndexSet<Rc<String>>,
|
||||
}
|
||||
|
||||
impl<'a> VariableFixtures<'a> {
|
||||
@@ -96,11 +96,11 @@ impl<'a> VariableFixtures<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, var: Rc<Var>, vs: VariableFixture<'a>) {
|
||||
pub(crate) fn insert(&mut self, var: Rc<String>, vs: VariableFixture<'a>) {
|
||||
self.perm_vars.insert(var, vs);
|
||||
}
|
||||
|
||||
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<Var>) {
|
||||
pub(crate) fn insert_last_chunk_temp_var(&mut self, var: Rc<String>) {
|
||||
self.last_chunk_temp_vars.insert(var);
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ impl<'a> VariableFixtures<'a> {
|
||||
// Compute the conflict set of u.
|
||||
|
||||
// 1.
|
||||
let mut use_sets: IndexMap<Rc<Var>, OccurrenceSet> = IndexMap::new();
|
||||
let mut use_sets: IndexMap<Rc<String>, OccurrenceSet> = IndexMap::new();
|
||||
|
||||
for (var, &mut (ref mut var_status, _)) in self.iter_mut() {
|
||||
if let &mut VarStatus::Temp(_, ref mut var_data) = var_status {
|
||||
@@ -153,11 +153,11 @@ impl<'a> VariableFixtures<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, u: Rc<Var>) -> Option<&mut VariableFixture<'a>> {
|
||||
fn get_mut(&mut self, u: Rc<String>) -> Option<&mut VariableFixture<'a>> {
|
||||
self.perm_vars.get_mut(&u)
|
||||
}
|
||||
|
||||
fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<Var>, VariableFixture<'a>> {
|
||||
fn iter_mut(&mut self) -> indexmap::map::IterMut<Rc<String>, VariableFixture<'a>> {
|
||||
self.perm_vars.iter_mut()
|
||||
}
|
||||
|
||||
@@ -218,11 +218,11 @@ impl<'a> VariableFixtures<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<Var>, VariableFixture<'a>> {
|
||||
pub(crate) fn into_iter(self) -> indexmap::map::IntoIter<Rc<String>, VariableFixture<'a>> {
|
||||
self.perm_vars.into_iter()
|
||||
}
|
||||
|
||||
fn values(&self) -> indexmap::map::Values<Rc<Var>, VariableFixture<'a>> {
|
||||
fn values(&self) -> indexmap::map::Values<Rc<String>, VariableFixture<'a>> {
|
||||
self.perm_vars.values()
|
||||
}
|
||||
|
||||
@@ -272,10 +272,10 @@ impl UnsafeVarMarker {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
|
||||
pub(crate) fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool {
|
||||
match query_instr {
|
||||
&QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
|
||||
| &QueryInstruction::SetVariable(r) => {
|
||||
&Instruction::PutVariable(r @ RegType::Temp(_), _) |
|
||||
&Instruction::SetVariable(r) => {
|
||||
self.safe_vars.insert(r);
|
||||
true
|
||||
}
|
||||
@@ -283,10 +283,10 @@ impl UnsafeVarMarker {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
|
||||
pub(crate) fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) {
|
||||
match query_instr {
|
||||
&QueryInstruction::PutValue(r @ RegType::Perm(_), _)
|
||||
| &QueryInstruction::SetValue(r) => {
|
||||
&Instruction::PutValue(r @ RegType::Perm(_), _) |
|
||||
&Instruction::SetValue(r) => {
|
||||
let p = self.unsafe_vars.entry(r).or_insert(0);
|
||||
*p = phase;
|
||||
}
|
||||
@@ -294,21 +294,21 @@ impl UnsafeVarMarker {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
|
||||
pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut Instruction, phase: usize) {
|
||||
match query_instr {
|
||||
&mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
|
||||
&mut Instruction::PutValue(RegType::Perm(i), arg) => {
|
||||
if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
|
||||
if p == phase {
|
||||
*query_instr = QueryInstruction::PutUnsafeValue(i, arg);
|
||||
*query_instr = Instruction::PutUnsafeValue(i, arg);
|
||||
self.safe_vars.insert(RegType::Perm(i));
|
||||
} else {
|
||||
self.unsafe_vars.insert(RegType::Perm(i), p);
|
||||
}
|
||||
}
|
||||
}
|
||||
&mut QueryInstruction::SetValue(r) => {
|
||||
&mut Instruction::SetValue(r) => {
|
||||
if !self.safe_vars.contains(&r) {
|
||||
*query_instr = QueryInstruction::SetLocalValue(r);
|
||||
*query_instr = Instruction::SetLocalValue(r);
|
||||
|
||||
self.safe_vars.insert(r);
|
||||
self.unsafe_vars.remove(&r);
|
||||
|
||||
544
src/forms.rs
544
src/forms.rs
@@ -1,33 +1,41 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::parser::OpDesc;
|
||||
use prolog_parser::{clause_name, is_infix, is_postfix};
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::loader::PredicateQueue;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::rug::{Integer, Rational};
|
||||
use ordered_float::OrderedFloat;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::parser::CompositeOpDesc;
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use slice_deque::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::ops::AddAssign;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) type PredicateKey = (ClauseName, usize); // name, arity.
|
||||
use crate::{is_infix, is_postfix};
|
||||
|
||||
pub(crate) type Predicate = Vec<PredicateClause>;
|
||||
pub type PredicateKey = (Atom, usize); // name, arity.
|
||||
|
||||
pub type Predicate = Vec<PredicateClause>;
|
||||
|
||||
// vars of predicate, toplevel offset. Vec<Term> is always a vector
|
||||
// of vars (we get their adjoining cells this way).
|
||||
pub(crate) type JumpStub = Vec<Term>;
|
||||
pub type JumpStub = Vec<Term>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum TopLevel {
|
||||
pub enum TopLevel {
|
||||
Fact(Term), // Term, line_num, col_num
|
||||
Predicate(Predicate),
|
||||
Query(Vec<QueryTerm>),
|
||||
@@ -35,7 +43,7 @@ pub(crate) enum TopLevel {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum AppendOrPrepend {
|
||||
pub enum AppendOrPrepend {
|
||||
Append,
|
||||
Prepend,
|
||||
}
|
||||
@@ -51,7 +59,7 @@ impl AppendOrPrepend {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum Level {
|
||||
pub enum Level {
|
||||
Deep,
|
||||
Root,
|
||||
Shallow,
|
||||
@@ -67,12 +75,12 @@ impl Level {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum QueryTerm {
|
||||
pub enum QueryTerm {
|
||||
// register, clause type, subterms, use default call policy.
|
||||
Clause(Cell<RegType>, ClauseType, Vec<Box<Term>>, bool),
|
||||
Clause(Cell<RegType>, ClauseType, Vec<Term>, bool),
|
||||
BlockedCut, // a cut which is 'blocked by letters', like the P term in P -> Q.
|
||||
UnblockedCut(Cell<VarReg>),
|
||||
GetLevelAndUnify(Cell<VarReg>, Rc<Var>),
|
||||
GetLevelAndUnify(Cell<VarReg>, Rc<String>),
|
||||
Jump(JumpStub),
|
||||
}
|
||||
|
||||
@@ -95,25 +103,25 @@ impl QueryTerm {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Rule {
|
||||
pub(crate) head: (ClauseName, Vec<Box<Term>>, QueryTerm),
|
||||
pub struct Rule {
|
||||
pub(crate) head: (Atom, Vec<Term>, QueryTerm),
|
||||
pub(crate) clauses: Vec<QueryTerm>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash)]
|
||||
pub(crate) enum ListingSource {
|
||||
pub enum ListingSource {
|
||||
DynamicallyGenerated,
|
||||
File(ClauseName, PathBuf), // filename, path
|
||||
File(Atom, PathBuf), // filename, path
|
||||
User,
|
||||
}
|
||||
|
||||
impl ListingSource {
|
||||
pub(crate) fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
|
||||
pub(crate) fn from_file_and_path(filename: Atom, path_buf: PathBuf) -> Self {
|
||||
ListingSource::File(filename, path_buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait ClauseInfo {
|
||||
pub trait ClauseInfo {
|
||||
fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
|
||||
match clauses.first() {
|
||||
Some(cl) => {
|
||||
@@ -123,14 +131,14 @@ pub(crate) trait ClauseInfo {
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> Option<ClauseName>;
|
||||
fn name(&self) -> Option<Atom>;
|
||||
fn arity(&self) -> usize;
|
||||
}
|
||||
|
||||
impl ClauseInfo for PredicateKey {
|
||||
#[inline]
|
||||
fn name(&self) -> Option<ClauseName> {
|
||||
Some(self.0.clone())
|
||||
fn name(&self) -> Option<Atom> {
|
||||
Some(self.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -140,28 +148,32 @@ impl ClauseInfo for PredicateKey {
|
||||
}
|
||||
|
||||
impl ClauseInfo for Term {
|
||||
fn name(&self) -> Option<ClauseName> {
|
||||
fn name(&self) -> Option<Atom> {
|
||||
//, atom_tbl: &AtomTable) -> Option<StringBuffer> {
|
||||
match self {
|
||||
Term::Clause(_, ref name, ref terms, _) => {
|
||||
Term::Clause(_, name, terms) => {
|
||||
// let str_buf = StringBuffer::from(*name, atom_tbl);
|
||||
|
||||
match name.as_str() {
|
||||
// str_buf.as_str() {
|
||||
":-" => {
|
||||
match terms.len() {
|
||||
1 => None, // a declaration.
|
||||
2 => terms[0].name(),
|
||||
_ => Some(clause_name!(":-")),
|
||||
1 => None, // a declaration.
|
||||
2 => terms[0].name(), //.map(|name| StringBuffer::from(name, atom_tbl)),
|
||||
_ => Some(*name),
|
||||
}
|
||||
}
|
||||
_ => Some(name.clone()),
|
||||
_ => Some(*name), //str_buf),
|
||||
}
|
||||
}
|
||||
Term::Constant(_, Constant::Atom(ref name, _)) => Some(name.clone()),
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(*name), //Some(StringBuffer::from(*name, atom_tbl)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn arity(&self) -> usize {
|
||||
match self {
|
||||
Term::Clause(_, ref name, ref terms, _) => match name.as_str() {
|
||||
Term::Clause(_, name, terms) => match name.as_str() {
|
||||
":-" => match terms.len() {
|
||||
1 => 0,
|
||||
2 => terms[0].arity(),
|
||||
@@ -175,8 +187,8 @@ impl ClauseInfo for Term {
|
||||
}
|
||||
|
||||
impl ClauseInfo for Rule {
|
||||
fn name(&self) -> Option<ClauseName> {
|
||||
Some(self.head.0.clone())
|
||||
fn name(&self) -> Option<Atom> {
|
||||
Some(self.head.0)
|
||||
}
|
||||
|
||||
fn arity(&self) -> usize {
|
||||
@@ -185,7 +197,7 @@ impl ClauseInfo for Rule {
|
||||
}
|
||||
|
||||
impl ClauseInfo for PredicateClause {
|
||||
fn name(&self) -> Option<ClauseName> {
|
||||
fn name(&self) -> Option<Atom> {
|
||||
match self {
|
||||
&PredicateClause::Fact(ref term, ..) => term.name(),
|
||||
&PredicateClause::Rule(ref rule, ..) => rule.name(),
|
||||
@@ -200,23 +212,20 @@ impl ClauseInfo for PredicateClause {
|
||||
}
|
||||
}
|
||||
|
||||
// pub(crate) type CompiledResult = (Predicate, VecDeque<TopLevel>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum PredicateClause {
|
||||
pub enum PredicateClause {
|
||||
Fact(Term),
|
||||
Rule(Rule),
|
||||
}
|
||||
|
||||
impl PredicateClause {
|
||||
// TODO: add this to `Term` in `prolog_parser` like `first_arg`.
|
||||
pub(crate) fn args(&self) -> Option<&[Box<Term>]> {
|
||||
match *self {
|
||||
PredicateClause::Fact(ref term, ..) => match term {
|
||||
Term::Clause(_, _, args, _) => Some(&args),
|
||||
pub(crate) fn args(&self) -> Option<&[Term]> {
|
||||
match self {
|
||||
PredicateClause::Fact(term, ..) => match term {
|
||||
Term::Clause(_, _, args) => Some(&args),
|
||||
_ => None,
|
||||
},
|
||||
PredicateClause::Rule(ref rule, ..) => {
|
||||
PredicateClause::Rule(rule, ..) => {
|
||||
if rule.head.1.is_empty() {
|
||||
None
|
||||
} else {
|
||||
@@ -227,37 +236,34 @@ impl PredicateClause {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClauseSpan {
|
||||
pub left: usize,
|
||||
pub right: usize,
|
||||
pub instantiated_arg_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum ModuleSource {
|
||||
Library(ClauseName),
|
||||
File(ClauseName),
|
||||
pub enum ModuleSource {
|
||||
Library(Atom),
|
||||
File(Atom),
|
||||
}
|
||||
|
||||
impl ModuleSource {
|
||||
pub(crate) fn as_functor_stub(&self) -> MachineStub {
|
||||
match self {
|
||||
ModuleSource::Library(ref name) => {
|
||||
functor!("library", [clause_name(name.clone())])
|
||||
ModuleSource::Library(name) => {
|
||||
functor!(atom!("library"), [atom(name)])
|
||||
}
|
||||
ModuleSource::File(ref name) => {
|
||||
functor!(clause_name(name.clone()))
|
||||
ModuleSource::File(name) => {
|
||||
functor!(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pub(crate) type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
|
||||
|
||||
/*
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum MultiFileIndicator {
|
||||
LocalScoped(ClauseName, usize), // name, arity
|
||||
ModuleScoped(ScopedPredicateKey),
|
||||
}
|
||||
*/
|
||||
|
||||
#[derive(Clone, Copy, Hash, Debug)]
|
||||
pub(crate) enum MetaSpec {
|
||||
pub enum MetaSpec {
|
||||
Minus,
|
||||
Plus,
|
||||
Either,
|
||||
@@ -265,71 +271,71 @@ pub(crate) enum MetaSpec {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Declaration {
|
||||
Dynamic(ClauseName, usize),
|
||||
MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs
|
||||
pub enum Declaration {
|
||||
Dynamic(Atom, usize),
|
||||
MetaPredicate(Atom, Atom, Vec<MetaSpec>), // module name, name, meta-specs
|
||||
Module(ModuleDecl),
|
||||
NonCountedBacktracking(ClauseName, usize), // name, arity
|
||||
NonCountedBacktracking(Atom, usize), // name, arity
|
||||
Op(OpDecl),
|
||||
UseModule(ModuleSource),
|
||||
UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
|
||||
pub(crate) struct OpDecl {
|
||||
pub(crate) prec: usize,
|
||||
pub(crate) spec: Specifier,
|
||||
pub(crate) name: ClauseName,
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, Ord, PartialOrd)]
|
||||
pub struct OpDecl {
|
||||
pub(crate) op_desc: OpDesc,
|
||||
pub(crate) name: Atom,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn fixity(spec: u32) -> Fixity {
|
||||
match spec {
|
||||
XFY | XFX | YFX => Fixity::In,
|
||||
XF | YF => Fixity::Post,
|
||||
FX | FY => Fixity::Pre,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl OpDecl {
|
||||
#[inline]
|
||||
pub(crate) fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
|
||||
Self { prec, spec, name }
|
||||
pub(crate) fn new(op_desc: OpDesc, name: Atom) -> Self {
|
||||
Self { op_desc, name }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn remove(&mut self, op_dir: &mut OpDir) {
|
||||
let prec = self.prec;
|
||||
self.prec = 0;
|
||||
let prec = self.op_desc.get_prec();
|
||||
self.op_desc.set(0, self.op_desc.get_spec());
|
||||
|
||||
self.insert_into_op_dir(op_dir);
|
||||
self.prec = prec;
|
||||
self.op_desc.set(prec, self.op_desc.get_spec());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn fixity(&self) -> Fixity {
|
||||
match self.spec {
|
||||
XFY | XFX | YFX => Fixity::In,
|
||||
XF | YF => Fixity::Post,
|
||||
FX | FY => Fixity::Pre,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<OpDesc> {
|
||||
let key = (self.name, fixity(self.op_desc.get_spec() as u32));
|
||||
|
||||
pub(crate) fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
|
||||
let key = (self.name.clone(), self.fixity());
|
||||
|
||||
match op_dir.get(&key) {
|
||||
match op_dir.get_mut(&key) {
|
||||
Some(cell) => {
|
||||
return Some(cell.shared_op_desc().replace((self.prec, self.spec)));
|
||||
let (old_prec, old_spec) = cell.get();
|
||||
cell.set(self.op_desc.get_prec(), self.op_desc.get_spec());
|
||||
return Some(OpDesc::build_with(old_prec, old_spec));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
op_dir
|
||||
.insert(key, OpDirValue::new(self.spec, self.prec))
|
||||
.map(|op_dir_value| op_dir_value.shared_op_desc().get())
|
||||
op_dir.insert(key, self.op_desc)
|
||||
}
|
||||
|
||||
pub(crate) fn submit(
|
||||
&self,
|
||||
existing_desc: Option<OpDesc>,
|
||||
existing_desc: Option<CompositeOpDesc>,
|
||||
op_dir: &mut OpDir,
|
||||
) -> Result<(), SessionError> {
|
||||
let (spec, name) = (self.spec, self.name.clone());
|
||||
let (spec, name) = (self.op_desc.get_spec(), self.name.clone());
|
||||
|
||||
if is_infix!(spec) {
|
||||
if is_infix!(spec as u32) {
|
||||
if let Some(desc) = existing_desc {
|
||||
if desc.post > 0 {
|
||||
return Err(SessionError::OpIsInfixAndPostFix(name));
|
||||
@@ -337,7 +343,7 @@ impl OpDecl {
|
||||
}
|
||||
}
|
||||
|
||||
if is_postfix!(spec) {
|
||||
if is_postfix!(spec as u32) {
|
||||
if let Some(desc) = existing_desc {
|
||||
if desc.inf > 0 {
|
||||
return Err(SessionError::OpIsInfixAndPostFix(name));
|
||||
@@ -350,22 +356,51 @@ impl OpDecl {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AtomOrString {
|
||||
Atom(Atom),
|
||||
String(String),
|
||||
}
|
||||
|
||||
impl AtomOrString {
|
||||
#[inline]
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
AtomOrString::Atom(atom) if atom == &atom!("[]") => "",
|
||||
AtomOrString::Atom(atom) => atom.as_str(),
|
||||
AtomOrString::String(string) => string.as_str(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_string(self) -> String {
|
||||
match self {
|
||||
AtomOrString::Atom(atom) => {
|
||||
atom.as_str().to_owned()
|
||||
}
|
||||
AtomOrString::String(string) => {
|
||||
string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_atom_op_spec(
|
||||
name: ClauseName,
|
||||
spec: Option<SharedOpDesc>,
|
||||
name: Atom,
|
||||
spec: Option<OpDesc>,
|
||||
op_dir: &OpDir,
|
||||
) -> Option<SharedOpDesc> {
|
||||
fetch_op_spec_from_existing(name.clone(), 1, spec.clone(), op_dir)
|
||||
.or_else(|| fetch_op_spec_from_existing(name, 2, spec, op_dir))
|
||||
) -> Option<OpDesc> {
|
||||
fetch_op_spec_from_existing(name, 2, spec, op_dir)
|
||||
.or_else(|| fetch_op_spec_from_existing(name, 1, spec, op_dir))
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_op_spec_from_existing(
|
||||
name: ClauseName,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
spec: Option<SharedOpDesc>,
|
||||
op_desc: Option<OpDesc>,
|
||||
op_dir: &OpDir,
|
||||
) -> Option<SharedOpDesc> {
|
||||
if let Some(ref op_desc) = &spec {
|
||||
) -> Option<OpDesc> {
|
||||
if let Some(ref op_desc) = &op_desc {
|
||||
if op_desc.arity() != arity {
|
||||
/* it's possible to extend operator functors with
|
||||
* additional terms. When that happens,
|
||||
@@ -374,61 +409,56 @@ pub(crate) fn fetch_op_spec_from_existing(
|
||||
}
|
||||
}
|
||||
|
||||
spec.or_else(|| fetch_op_spec(name, arity, op_dir))
|
||||
op_desc.or_else(|| fetch_op_spec(name, arity, op_dir))
|
||||
}
|
||||
|
||||
pub(crate) fn fetch_op_spec(
|
||||
name: ClauseName,
|
||||
arity: usize,
|
||||
op_dir: &OpDir,
|
||||
) -> Option<SharedOpDesc> {
|
||||
pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option<OpDesc> {
|
||||
match arity {
|
||||
2 => op_dir
|
||||
.get(&(name, Fixity::In))
|
||||
.and_then(|OpDirValue(spec)| {
|
||||
if spec.prec() > 0 {
|
||||
Some(spec.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
2 => op_dir.get(&(name, Fixity::In)).and_then(|op_desc| {
|
||||
if op_desc.get_prec() > 0 {
|
||||
Some(*op_desc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}),
|
||||
1 => {
|
||||
if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
|
||||
if spec.prec() > 0 {
|
||||
return Some(spec.clone());
|
||||
if let Some(op_desc) = op_dir.get(&(name.clone(), Fixity::Pre)) {
|
||||
if op_desc.get_prec() > 0 {
|
||||
return Some(*op_desc);
|
||||
}
|
||||
}
|
||||
|
||||
op_dir
|
||||
.get(&(name.clone(), Fixity::Post))
|
||||
.and_then(|OpDirValue(spec)| {
|
||||
if spec.prec() > 0 {
|
||||
Some(spec.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
op_dir.get(&(name, Fixity::Post)).and_then(|op_desc| {
|
||||
if op_desc.get_prec() > 0 {
|
||||
Some(*op_desc)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
0 => {
|
||||
fetch_atom_op_spec(name, None, op_dir)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type ModuleDir = IndexMap<ClauseName, Module>;
|
||||
pub(crate) type ModuleDir = IndexMap<Atom, Module, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
|
||||
pub(crate) enum ModuleExport {
|
||||
pub enum ModuleExport {
|
||||
OpDecl(OpDecl),
|
||||
PredicateKey(PredicateKey),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ModuleDecl {
|
||||
pub(crate) name: ClauseName,
|
||||
pub struct ModuleDecl {
|
||||
pub(crate) name: Atom,
|
||||
pub(crate) exports: Vec<ModuleExport>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Module {
|
||||
pub struct Module {
|
||||
pub(crate) module_decl: ModuleDecl,
|
||||
pub(crate) code_dir: CodeDir,
|
||||
pub(crate) op_dir: OpDir,
|
||||
@@ -440,14 +470,19 @@ pub(crate) struct Module {
|
||||
|
||||
// Module's and related types are defined in forms.
|
||||
impl Module {
|
||||
pub(crate) fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self {
|
||||
pub(crate) fn new(
|
||||
module_decl: ModuleDecl,
|
||||
listing_src: ListingSource,
|
||||
) -> Self {
|
||||
Module {
|
||||
module_decl,
|
||||
code_dir: CodeDir::new(),
|
||||
code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
|
||||
op_dir: default_op_dir(),
|
||||
meta_predicates: MetaPredicateDir::new(),
|
||||
extensible_predicates: ExtensiblePredicates::new(),
|
||||
local_extensible_predicates: LocalExtensiblePredicates::new(),
|
||||
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
|
||||
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
|
||||
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
|
||||
FxBuildHasher::default(),
|
||||
),
|
||||
listing_src,
|
||||
}
|
||||
}
|
||||
@@ -455,71 +490,137 @@ impl Module {
|
||||
pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self {
|
||||
Module {
|
||||
module_decl,
|
||||
code_dir: CodeDir::new(),
|
||||
op_dir: OpDir::new(),
|
||||
meta_predicates: MetaPredicateDir::new(),
|
||||
extensible_predicates: ExtensiblePredicates::new(),
|
||||
local_extensible_predicates: LocalExtensiblePredicates::new(),
|
||||
code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
|
||||
op_dir: OpDir::with_hasher(FxBuildHasher::default()),
|
||||
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
|
||||
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
|
||||
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
|
||||
FxBuildHasher::default()
|
||||
),
|
||||
listing_src: ListingSource::DynamicallyGenerated,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum Number {
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Number {
|
||||
Float(OrderedFloat<f64>),
|
||||
Integer(Rc<Integer>),
|
||||
Rational(Rc<Rational>),
|
||||
Fixnum(isize),
|
||||
}
|
||||
|
||||
impl From<Integer> for Number {
|
||||
#[inline]
|
||||
fn from(n: Integer) -> Self {
|
||||
Number::Integer(Rc::new(n))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rational> for Number {
|
||||
#[inline]
|
||||
fn from(n: Rational) -> Self {
|
||||
Number::Rational(Rc::new(n))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<isize> for Number {
|
||||
#[inline]
|
||||
fn from(n: isize) -> Self {
|
||||
Number::Fixnum(n)
|
||||
}
|
||||
Integer(TypedArenaPtr<Integer>),
|
||||
Rational(TypedArenaPtr<Rational>),
|
||||
Fixnum(Fixnum),
|
||||
}
|
||||
|
||||
impl Default for Number {
|
||||
fn default() -> Self {
|
||||
Number::Float(OrderedFloat(0f64))
|
||||
Number::Fixnum(Fixnum::build_with(0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Constant> for Number {
|
||||
#[inline]
|
||||
fn into(self) -> Constant {
|
||||
impl fmt::Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Number::Fixnum(n) => Constant::Fixnum(n),
|
||||
Number::Integer(n) => Constant::Integer(n),
|
||||
Number::Float(f) => Constant::Float(f),
|
||||
Number::Rational(r) => Constant::Rational(r),
|
||||
Number::Float(fl) => write!(f, "{}", fl),
|
||||
Number::Integer(n) => write!(f, "{}", n),
|
||||
Number::Rational(r) => write!(f, "{}", r),
|
||||
Number::Fixnum(n) => write!(f, "{}", n.get_num()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<HeapCellValue> for Number {
|
||||
pub trait ArenaFrom<T> {
|
||||
fn arena_from(value: T, arena: &mut Arena) -> Self;
|
||||
}
|
||||
|
||||
impl ArenaFrom<Integer> for Number {
|
||||
#[inline]
|
||||
fn into(self) -> HeapCellValue {
|
||||
match self {
|
||||
Number::Fixnum(n) => HeapCellValue::Addr(Addr::Fixnum(n)),
|
||||
Number::Integer(n) => HeapCellValue::Integer(n),
|
||||
Number::Float(f) => HeapCellValue::Addr(Addr::Float(f)),
|
||||
Number::Rational(r) => HeapCellValue::Rational(r),
|
||||
fn arena_from(value: Integer, arena: &mut Arena) -> Number {
|
||||
Number::Integer(arena_alloc!(value, arena))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<Rational> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: Rational, arena: &mut Arena) -> Number {
|
||||
Number::Rational(arena_alloc!(value, arena))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<usize> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: usize, arena: &mut Arena) -> Number {
|
||||
match i64::try_from(value) {
|
||||
Ok(value) => Fixnum::build_with_checked(value)
|
||||
.map(Number::Fixnum)
|
||||
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))),
|
||||
Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<u64> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: u64, arena: &mut Arena) -> Number {
|
||||
match i64::try_from(value) {
|
||||
Ok(value) => Fixnum::build_with_checked(value)
|
||||
.map(Number::Fixnum)
|
||||
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena))),
|
||||
Err(_) => Number::Integer(arena_alloc!(Integer::from(value), arena)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<i64> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: i64, arena: &mut Arena) -> Number {
|
||||
Fixnum::build_with_checked(value)
|
||||
.map(Number::Fixnum)
|
||||
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<isize> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: isize, arena: &mut Arena) -> Number {
|
||||
Fixnum::build_with_checked(value as i64)
|
||||
.map(Number::Fixnum)
|
||||
.unwrap_or_else(|_| Number::Integer(arena_alloc!(Integer::from(value), arena)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<u32> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: u32, _arena: &mut Arena) -> Number {
|
||||
Number::Fixnum(Fixnum::build_with(value as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<i32> for Number {
|
||||
#[inline]
|
||||
fn arena_from(value: i32, _arena: &mut Arena) -> Number {
|
||||
Number::Fixnum(Fixnum::build_with(value as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<Number> for Literal {
|
||||
#[inline]
|
||||
fn arena_from(value: Number, arena: &mut Arena) -> Literal {
|
||||
match value {
|
||||
Number::Fixnum(n) => Literal::Fixnum(n),
|
||||
Number::Integer(n) => Literal::Integer(n),
|
||||
Number::Float(f) => Literal::Float(arena_alloc!(f, arena)),
|
||||
Number::Rational(r) => Literal::Rational(r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArenaFrom<Number> for HeapCellValue {
|
||||
#[inline]
|
||||
fn arena_from(value: Number, arena: &mut Arena) -> HeapCellValue {
|
||||
match value {
|
||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
||||
Number::Float(n) => typed_arena_ptr_as_cell!(arena_alloc!(n, arena)),
|
||||
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -528,9 +629,9 @@ impl Number {
|
||||
#[inline]
|
||||
pub(crate) fn is_positive(&self) -> bool {
|
||||
match self {
|
||||
&Number::Fixnum(n) => n > 0,
|
||||
&Number::Fixnum(n) => n.get_num() > 0,
|
||||
&Number::Integer(ref n) => &**n > &0,
|
||||
&Number::Float(OrderedFloat(f)) => f.is_sign_positive(),
|
||||
&Number::Float(f) => f.is_sign_positive(),
|
||||
&Number::Rational(ref r) => &**r > &0,
|
||||
}
|
||||
}
|
||||
@@ -538,9 +639,9 @@ impl Number {
|
||||
#[inline]
|
||||
pub(crate) fn is_negative(&self) -> bool {
|
||||
match self {
|
||||
&Number::Fixnum(n) => n < 0,
|
||||
&Number::Fixnum(n) => n.get_num() < 0,
|
||||
&Number::Integer(ref n) => &**n < &0,
|
||||
&Number::Float(OrderedFloat(f)) => f.is_sign_negative(),
|
||||
&Number::Float(OrderedFloat(f)) => f.is_sign_negative() && OrderedFloat(f) != -0f64,
|
||||
&Number::Rational(ref r) => &**r < &0,
|
||||
}
|
||||
}
|
||||
@@ -548,36 +649,28 @@ impl Number {
|
||||
#[inline]
|
||||
pub(crate) fn is_zero(&self) -> bool {
|
||||
match self {
|
||||
&Number::Fixnum(n) => n == 0,
|
||||
&Number::Fixnum(n) => n.get_num() == 0,
|
||||
&Number::Integer(ref n) => &**n == &0,
|
||||
&Number::Float(f) => f == OrderedFloat(0f64),
|
||||
&Number::Float(f) => f == OrderedFloat(0f64) || f == OrderedFloat(-0f64),
|
||||
&Number::Rational(ref r) => &**r == &0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn abs(self) -> Self {
|
||||
pub(crate) fn is_integer(&self) -> bool {
|
||||
match self {
|
||||
Number::Fixnum(n) => {
|
||||
if let Some(n) = n.checked_abs() {
|
||||
Number::from(n)
|
||||
} else {
|
||||
Number::from(Integer::from(n).abs())
|
||||
}
|
||||
}
|
||||
Number::Integer(n) => Number::from(Integer::from(n.abs_ref())),
|
||||
Number::Float(f) => Number::Float(OrderedFloat(f.abs())),
|
||||
Number::Rational(r) => Number::from(Rational::from(r.abs_ref())),
|
||||
Number::Fixnum(_) | Number::Integer(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum OptArgIndexKey {
|
||||
Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
|
||||
List(usize, usize), // index, IndexingCode location
|
||||
Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
|
||||
List(usize, usize), // index, IndexingCode location
|
||||
None,
|
||||
Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity
|
||||
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
|
||||
}
|
||||
|
||||
impl OptArgIndexKey {
|
||||
@@ -589,7 +682,7 @@ impl OptArgIndexKey {
|
||||
#[inline]
|
||||
pub(crate) fn arg_num(&self) -> usize {
|
||||
match &self {
|
||||
OptArgIndexKey::Constant(arg_num, ..)
|
||||
OptArgIndexKey::Literal(arg_num, ..)
|
||||
| OptArgIndexKey::Structure(arg_num, ..)
|
||||
| OptArgIndexKey::List(arg_num, _) => {
|
||||
// these are always at least 1.
|
||||
@@ -607,7 +700,7 @@ impl OptArgIndexKey {
|
||||
#[inline]
|
||||
pub(crate) fn switch_on_term_loc(&self) -> Option<usize> {
|
||||
match &self {
|
||||
OptArgIndexKey::Constant(_, loc, ..)
|
||||
OptArgIndexKey::Literal(_, loc, ..)
|
||||
| OptArgIndexKey::Structure(_, loc, ..)
|
||||
| OptArgIndexKey::List(_, loc) => Some(*loc),
|
||||
OptArgIndexKey::None => None,
|
||||
@@ -617,7 +710,7 @@ impl OptArgIndexKey {
|
||||
#[inline]
|
||||
pub(crate) fn set_switch_on_term_loc(&mut self, value: usize) {
|
||||
match self {
|
||||
OptArgIndexKey::Constant(_, ref mut loc, ..)
|
||||
OptArgIndexKey::Literal(_, ref mut loc, ..)
|
||||
| OptArgIndexKey::Structure(_, ref mut loc, ..)
|
||||
| OptArgIndexKey::List(_, ref mut loc) => {
|
||||
*loc = value;
|
||||
@@ -631,7 +724,7 @@ impl AddAssign<usize> for OptArgIndexKey {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, n: usize) {
|
||||
match self {
|
||||
OptArgIndexKey::Constant(_, ref mut o, ..)
|
||||
OptArgIndexKey::Literal(_, ref mut o, ..)
|
||||
| OptArgIndexKey::List(_, ref mut o)
|
||||
| OptArgIndexKey::Structure(_, ref mut o, ..) => {
|
||||
*o += n;
|
||||
@@ -700,6 +793,7 @@ pub(crate) struct LocalPredicateSkeleton {
|
||||
pub(crate) is_multifile: bool,
|
||||
pub(crate) clause_clause_locs: SliceDeque<usize>,
|
||||
pub(crate) clause_assert_margin: usize,
|
||||
pub(crate) retracted_dynamic_clauses: Option<Vec<ClauseIndexInfo>>, // always None if non-dynamic.
|
||||
}
|
||||
|
||||
impl LocalPredicateSkeleton {
|
||||
@@ -711,6 +805,7 @@ impl LocalPredicateSkeleton {
|
||||
is_multifile: false,
|
||||
clause_clause_locs: sdeq![],
|
||||
clause_assert_margin: 0,
|
||||
retracted_dynamic_clauses: Some(vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,6 +825,20 @@ impl LocalPredicateSkeleton {
|
||||
self.clause_clause_locs.clear();
|
||||
self.clause_assert_margin = 0;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn add_retracted_dynamic_clause_info(&mut self, clause_info: ClauseIndexInfo) {
|
||||
debug_assert_eq!(self.is_dynamic, true);
|
||||
|
||||
if self.retracted_dynamic_clauses.is_none() {
|
||||
self.retracted_dynamic_clauses = Some(vec![]);
|
||||
}
|
||||
|
||||
self.retracted_dynamic_clauses
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.push(clause_info);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -758,13 +867,6 @@ impl PredicateSkeleton {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.core.clause_clause_locs.clear();
|
||||
self.core.clause_assert_margin = 0;
|
||||
self.clauses.clear();
|
||||
}
|
||||
|
||||
pub(crate) fn target_pos_of_clause_clause_loc(
|
||||
&self,
|
||||
clause_clause_loc: usize,
|
||||
|
||||
2752
src/heap_iter.rs
2752
src/heap_iter.rs
File diff suppressed because it is too large
Load Diff
1835
src/heap_print.rs
1835
src/heap_print.rs
File diff suppressed because it is too large
Load Diff
383
src/indexing.rs
383
src/indexing.rs
@@ -1,33 +1,21 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::clause_name;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
|
||||
use crate::rug::Integer;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use slice_deque::{sdeq, SliceDeque};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::collections::VecDeque;
|
||||
use std::hash::Hash;
|
||||
use std::iter::once;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum IndexingCodePtr {
|
||||
External(usize), // the index points past the indexing instruction prelude.
|
||||
DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
|
||||
Fail,
|
||||
Internal(usize), // the index points into the indexing instruction prelude.
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum OptArgIndexKeyType {
|
||||
Structure,
|
||||
Constant,
|
||||
Literal,
|
||||
// List,
|
||||
}
|
||||
|
||||
@@ -35,7 +23,7 @@ impl OptArgIndexKey {
|
||||
#[inline]
|
||||
fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool {
|
||||
match (self, key_type) {
|
||||
(OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant)
|
||||
(OptArgIndexKey::Literal(..), OptArgIndexKeyType::Literal)
|
||||
| (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure)
|
||||
// | (OptArgIndexKey::List(..), OptArgIndexKeyType::List)
|
||||
=> true,
|
||||
@@ -45,11 +33,12 @@ impl OptArgIndexKey {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn search_skeleton_for_first_key_type(
|
||||
skeleton: &[ClauseIndexInfo],
|
||||
fn search_skeleton_for_first_key_type<'a>(
|
||||
skeleton: &'a [ClauseIndexInfo],
|
||||
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
|
||||
key_type: OptArgIndexKeyType,
|
||||
append_or_prepend: AppendOrPrepend,
|
||||
) -> Option<&OptArgIndexKey> {
|
||||
) -> Option<&'a OptArgIndexKey> {
|
||||
if append_or_prepend.is_append() {
|
||||
for clause_index_info in skeleton.iter().rev() {
|
||||
if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
|
||||
@@ -64,11 +53,20 @@ fn search_skeleton_for_first_key_type(
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(retracted_clauses) = retracted_dynamic_clauses {
|
||||
for clause_index_info in retracted_clauses.iter().rev() {
|
||||
if clause_index_info.opt_arg_index_key.has_key_type(key_type) {
|
||||
return Some(&clause_index_info.opt_arg_index_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
struct IndexingCodeMergingPtr<'a> {
|
||||
skeleton: &'a mut [ClauseIndexInfo],
|
||||
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
|
||||
indexing_code: &'a mut Vec<IndexingLine>,
|
||||
offset: usize,
|
||||
append_or_prepend: AppendOrPrepend,
|
||||
@@ -79,22 +77,22 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
#[inline]
|
||||
fn new(
|
||||
skeleton: &'a mut [ClauseIndexInfo],
|
||||
retracted_dynamic_clauses: &'a Option<Vec<ClauseIndexInfo>>,
|
||||
indexing_code: &'a mut Vec<IndexingLine>,
|
||||
append_or_prepend: AppendOrPrepend,
|
||||
) -> Self {
|
||||
let is_dynamic = match &indexing_code[0] {
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => {
|
||||
match v {
|
||||
IndexingCodePtr::External(_) => false,
|
||||
IndexingCodePtr::DynamicExternal(_) => true,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
|
||||
IndexingCodePtr::External(_) => false,
|
||||
IndexingCodePtr::DynamicExternal(_) => true,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Self {
|
||||
skeleton,
|
||||
retracted_dynamic_clauses,
|
||||
indexing_code,
|
||||
offset: 0,
|
||||
append_or_prepend,
|
||||
@@ -105,15 +103,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) {
|
||||
let constant_key = search_skeleton_for_first_key_type(
|
||||
self.skeleton,
|
||||
OptArgIndexKeyType::Constant,
|
||||
self.retracted_dynamic_clauses,
|
||||
OptArgIndexKeyType::Literal,
|
||||
self.append_or_prepend,
|
||||
);
|
||||
|
||||
let mut constants = IndexMap::new();
|
||||
|
||||
match constant_key {
|
||||
Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => {
|
||||
constants.insert(constant.clone(), constant_ptr);
|
||||
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
|
||||
constants.insert(*constant, constant_ptr);
|
||||
}
|
||||
_ => {
|
||||
if let IndexingCodePtr::DynamicExternal(_) = constant_ptr {
|
||||
@@ -145,7 +144,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
fn add_static_indexed_choice_for_constant(
|
||||
&mut self,
|
||||
external: usize,
|
||||
constant: Constant,
|
||||
constant: Literal,
|
||||
index: usize,
|
||||
) {
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
@@ -179,7 +178,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
fn add_dynamic_indexed_choice_for_constant(
|
||||
&mut self,
|
||||
external: usize,
|
||||
constant: Constant,
|
||||
constant: Literal,
|
||||
index: usize,
|
||||
) {
|
||||
let third_level_index = if self.append_or_prepend.is_append() {
|
||||
@@ -232,8 +231,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
|
||||
fn index_overlapping_constant(
|
||||
&mut self,
|
||||
orig_constant: &Constant,
|
||||
overlapping_constant: Constant,
|
||||
orig_constant: Literal,
|
||||
overlapping_constant: Literal,
|
||||
index: usize,
|
||||
) {
|
||||
loop {
|
||||
@@ -252,7 +251,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
}
|
||||
IndexingCodePtr::DynamicExternal(_) | IndexingCodePtr::External(_) => {
|
||||
let mut constants = IndexMap::new();
|
||||
constants.insert(orig_constant.clone(), *c);
|
||||
constants.insert(orig_constant, *c);
|
||||
|
||||
*c = IndexingCodePtr::Internal(indexing_code_len);
|
||||
|
||||
@@ -282,10 +281,18 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
);
|
||||
}
|
||||
Some(IndexingCodePtr::DynamicExternal(o)) => {
|
||||
self.add_dynamic_indexed_choice_for_constant(o, overlapping_constant, index);
|
||||
self.add_dynamic_indexed_choice_for_constant(
|
||||
o,
|
||||
overlapping_constant,
|
||||
index,
|
||||
);
|
||||
}
|
||||
Some(IndexingCodePtr::External(o)) => {
|
||||
self.add_static_indexed_choice_for_constant(o, overlapping_constant, index);
|
||||
self.add_static_indexed_choice_for_constant(
|
||||
o,
|
||||
overlapping_constant,
|
||||
index,
|
||||
);
|
||||
}
|
||||
Some(IndexingCodePtr::Internal(o)) => {
|
||||
self.offset += o;
|
||||
@@ -307,7 +314,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn index_constant(&mut self, constant: Constant, index: usize) {
|
||||
fn index_constant(&mut self, constant: Literal, index: usize) {
|
||||
loop {
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
|
||||
@@ -338,10 +345,16 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(constants)) => {
|
||||
match constants.get(&constant).cloned() {
|
||||
None | Some(IndexingCodePtr::Fail) if self.is_dynamic => {
|
||||
constants.insert(constant, IndexingCodePtr::DynamicExternal(index));
|
||||
constants.insert(
|
||||
constant,
|
||||
IndexingCodePtr::DynamicExternal(index),
|
||||
);
|
||||
}
|
||||
None | Some(IndexingCodePtr::Fail) => {
|
||||
constants.insert(constant, IndexingCodePtr::External(index));
|
||||
constants.insert(
|
||||
constant,
|
||||
IndexingCodePtr::External(index),
|
||||
);
|
||||
}
|
||||
Some(IndexingCodePtr::DynamicExternal(o)) => {
|
||||
self.add_dynamic_indexed_choice_for_constant(o, constant, index);
|
||||
@@ -372,6 +385,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) {
|
||||
let structure_key = search_skeleton_for_first_key_type(
|
||||
self.skeleton,
|
||||
self.retracted_dynamic_clauses,
|
||||
OptArgIndexKeyType::Structure,
|
||||
self.append_or_prepend,
|
||||
);
|
||||
@@ -379,8 +393,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
let mut structures = IndexMap::new();
|
||||
|
||||
match structure_key {
|
||||
Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => {
|
||||
structures.insert((name.clone(), *arity), structure_ptr);
|
||||
Some(OptArgIndexKey::Structure(_, _, name, arity)) => {
|
||||
structures.insert((*name, *arity), structure_ptr);
|
||||
}
|
||||
_ => {
|
||||
if let IndexingCodePtr::DynamicExternal(_) = structure_ptr {
|
||||
@@ -428,8 +442,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
};
|
||||
|
||||
let indexing_code_len = self.indexing_code.len();
|
||||
self.indexing_code
|
||||
.push(IndexingLine::IndexedChoice(third_level_index));
|
||||
self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index));
|
||||
|
||||
match &mut self.indexing_code[self.offset] {
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref mut structures)) => {
|
||||
@@ -599,6 +612,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
|
||||
pub(crate) fn merge_clause_index(
|
||||
target_indexing_code: &mut Vec<IndexingLine>,
|
||||
skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton.
|
||||
retracted_clauses: &Option<Vec<ClauseIndexInfo>>,
|
||||
new_clause_loc: usize, // the absolute location of the new clause in the code vector.
|
||||
append_or_prepend: AppendOrPrepend,
|
||||
) {
|
||||
@@ -609,27 +623,28 @@ pub(crate) fn merge_clause_index(
|
||||
|
||||
let mut merging_ptr = IndexingCodeMergingPtr::new(
|
||||
skeleton,
|
||||
retracted_clauses,
|
||||
target_indexing_code,
|
||||
append_or_prepend,
|
||||
);
|
||||
|
||||
match &opt_arg_index_key {
|
||||
OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => {
|
||||
OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
|
||||
let offset = new_clause_loc - index_loc + 1;
|
||||
merging_ptr.index_constant(constant.clone(), offset);
|
||||
merging_ptr.index_constant(*constant, offset);
|
||||
|
||||
for overlapping_constant in overlapping_constants {
|
||||
merging_ptr.offset = 0;
|
||||
|
||||
merging_ptr.index_overlapping_constant(
|
||||
constant,
|
||||
overlapping_constant.clone(),
|
||||
*constant,
|
||||
*overlapping_constant,
|
||||
offset,
|
||||
);
|
||||
}
|
||||
}
|
||||
OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => {
|
||||
merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1);
|
||||
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
|
||||
merging_ptr.index_structure((*name, *arity), new_clause_loc - index_loc + 1);
|
||||
}
|
||||
OptArgIndexKey::List(_, index_loc) => {
|
||||
merging_ptr.index_list(new_clause_loc - index_loc + 1);
|
||||
@@ -650,13 +665,13 @@ pub(crate) fn merge_clause_index(
|
||||
}
|
||||
|
||||
pub(crate) fn remove_constant_indices(
|
||||
constant: &Constant,
|
||||
overlapping_constants: &[Constant],
|
||||
constant: Literal,
|
||||
overlapping_constants: &[Literal],
|
||||
indexing_code: &mut Vec<IndexingLine>,
|
||||
offset: usize,
|
||||
) {
|
||||
let mut index = 0;
|
||||
let iter = once(constant).chain(overlapping_constants.iter());
|
||||
let iter = once(&constant).chain(overlapping_constants.iter());
|
||||
|
||||
match &mut indexing_code[index] {
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..)) => {
|
||||
@@ -688,11 +703,13 @@ pub(crate) fn remove_constant_indices(
|
||||
)) => {
|
||||
constants_index = index;
|
||||
|
||||
match constants.get(constant).cloned() {
|
||||
Some(IndexingCodePtr::DynamicExternal(_)) |
|
||||
Some(IndexingCodePtr::External(_)) |
|
||||
Some(IndexingCodePtr::Fail) => {
|
||||
constants.remove(constant);
|
||||
let constant = *constant;
|
||||
|
||||
match constants.get(&constant).cloned() {
|
||||
Some(IndexingCodePtr::DynamicExternal(_))
|
||||
| Some(IndexingCodePtr::External(_))
|
||||
| Some(IndexingCodePtr::Fail) => {
|
||||
constants.remove(&constant);
|
||||
break;
|
||||
}
|
||||
Some(IndexingCodePtr::Internal(o)) => {
|
||||
@@ -704,13 +721,14 @@ pub(crate) fn remove_constant_indices(
|
||||
}
|
||||
}
|
||||
IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => {
|
||||
StaticCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
|
||||
StaticCodeIndices::remove_instruction_with_offset(
|
||||
indexed_choice_instrs,
|
||||
offset,
|
||||
);
|
||||
|
||||
if indexed_choice_instrs.len() == 1 {
|
||||
if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
|
||||
let ext = IndexingCodePtr::External(
|
||||
indexed_choice_instr.offset()
|
||||
);
|
||||
let ext = IndexingCodePtr::External(indexed_choice_instr.offset());
|
||||
|
||||
match &mut indexing_code[constants_index] {
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
|
||||
@@ -724,7 +742,7 @@ pub(crate) fn remove_constant_indices(
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
||||
ref mut constants,
|
||||
)) => {
|
||||
constants.insert(constant.clone(), ext);
|
||||
constants.insert(*constant, ext);
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
@@ -736,7 +754,10 @@ pub(crate) fn remove_constant_indices(
|
||||
break;
|
||||
}
|
||||
IndexingLine::DynamicIndexedChoice(ref mut indexed_choice_instrs) => {
|
||||
DynamicCodeIndices::remove_instruction_with_offset(indexed_choice_instrs, offset);
|
||||
DynamicCodeIndices::remove_instruction_with_offset(
|
||||
indexed_choice_instrs,
|
||||
offset,
|
||||
);
|
||||
|
||||
if indexed_choice_instrs.len() == 1 {
|
||||
if let Some(indexed_choice_instr) = indexed_choice_instrs.pop_back() {
|
||||
@@ -754,7 +775,7 @@ pub(crate) fn remove_constant_indices(
|
||||
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
|
||||
ref mut constants,
|
||||
)) => {
|
||||
constants.insert(constant.clone(), ext);
|
||||
constants.insert(*constant, ext);
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
@@ -790,7 +811,7 @@ pub(crate) fn remove_constant_indices(
|
||||
}
|
||||
|
||||
pub(crate) fn remove_structure_index(
|
||||
name: &ClauseName,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
indexing_code: &mut Vec<IndexingLine>,
|
||||
offset: usize,
|
||||
@@ -825,7 +846,8 @@ pub(crate) fn remove_structure_index(
|
||||
structures_index = index;
|
||||
|
||||
match structures.get(&(name.clone(), arity)).cloned() {
|
||||
Some(IndexingCodePtr::DynamicExternal(_)) | Some(IndexingCodePtr::External(_)) => {
|
||||
Some(IndexingCodePtr::DynamicExternal(_))
|
||||
| Some(IndexingCodePtr::External(_)) => {
|
||||
structures.remove(&(name.clone(), arity));
|
||||
break;
|
||||
}
|
||||
@@ -1012,27 +1034,14 @@ pub(crate) fn remove_index(
|
||||
clause_loc: usize,
|
||||
) {
|
||||
match opt_arg_index_key {
|
||||
OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => {
|
||||
remove_constant_indices(
|
||||
constant,
|
||||
overlapping_constants,
|
||||
indexing_code,
|
||||
clause_loc,
|
||||
);
|
||||
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
|
||||
remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
|
||||
}
|
||||
OptArgIndexKey::Structure(_, _, ref name, ref arity) => {
|
||||
remove_structure_index(
|
||||
name,
|
||||
*arity,
|
||||
indexing_code,
|
||||
clause_loc,
|
||||
);
|
||||
OptArgIndexKey::Structure(_, _, name, arity) => {
|
||||
remove_structure_index(*name, *arity, indexing_code, clause_loc);
|
||||
}
|
||||
OptArgIndexKey::List(..) => {
|
||||
remove_list_index(
|
||||
indexing_code,
|
||||
clause_loc,
|
||||
);
|
||||
remove_list_index(indexing_code, clause_loc);
|
||||
}
|
||||
OptArgIndexKey::None => {
|
||||
unreachable!()
|
||||
@@ -1076,49 +1085,52 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData<Atom>) -> Vec<Constant> {
|
||||
pub(crate) fn constant_key_alternatives(
|
||||
constant: Literal,
|
||||
atom_tbl: &mut AtomTable,
|
||||
// arena: &mut Arena,
|
||||
) -> Vec<Literal> {
|
||||
let mut constants = vec![];
|
||||
|
||||
match constant {
|
||||
Constant::Atom(ref name, ref op) => {
|
||||
if name.is_char() {
|
||||
let c = name.as_str().chars().next().unwrap();
|
||||
constants.push(Constant::Char(c));
|
||||
}
|
||||
|
||||
if op.is_some() {
|
||||
constants.push(Constant::Atom(name.clone(), None));
|
||||
Literal::Atom(ref name) => {
|
||||
if let Some(c) = name.as_char() {
|
||||
constants.push(Literal::Char(c));
|
||||
}
|
||||
}
|
||||
Constant::Char(c) => {
|
||||
let atom = clause_name!(c.to_string(), atom_tbl);
|
||||
constants.push(Constant::Atom(atom, None));
|
||||
Literal::Char(c) => {
|
||||
let atom = atom_tbl.build_with(&c.to_string());
|
||||
constants.push(Literal::Atom(atom));
|
||||
}
|
||||
Constant::Fixnum(ref n) => {
|
||||
constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
|
||||
/*
|
||||
Literal::Fixnum(ref n) => {
|
||||
constants.push(Literal::Integer(arena_alloc!(n, arena))); //Rc::new(Integer::from(*n))));
|
||||
|
||||
/*
|
||||
if *n >= 0 {
|
||||
if let Ok(n) = usize::try_from(*n) {
|
||||
constants.push(Constant::Usize(n));
|
||||
constants.push(Literal::Usize(n));
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
Constant::Integer(ref n) => {
|
||||
*/
|
||||
Literal::Integer(ref n) => {
|
||||
if let Some(n) = n.to_isize() {
|
||||
constants.push(Constant::Fixnum(n));
|
||||
}
|
||||
|
||||
if let Some(n) = n.to_usize() {
|
||||
constants.push(Constant::Usize(n));
|
||||
Fixnum::build_with_checked(n as i64).map(|n| {
|
||||
constants.push(Literal::Fixnum(n));
|
||||
}).unwrap();
|
||||
}
|
||||
}
|
||||
Constant::Usize(n) => {
|
||||
constants.push(Constant::Integer(Rc::new(Integer::from(*n))));
|
||||
/*
|
||||
Literal::Usize(n) => {
|
||||
constants.push(Literal::Integer(Rc::new(Integer::from(*n))));
|
||||
|
||||
if let Ok(n) = isize::try_from(*n) {
|
||||
constants.push(Constant::Fixnum(n));
|
||||
constants.push(Literal::Fixnum(n));
|
||||
}
|
||||
}
|
||||
*/
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -1127,16 +1139,16 @@ pub(crate) fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledDat
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StaticCodeIndices {
|
||||
constants: IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>>,
|
||||
lists: SliceDeque<IndexedChoiceInstruction>,
|
||||
structures: IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>>,
|
||||
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>>,
|
||||
lists: VecDeque<IndexedChoiceInstruction>,
|
||||
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct DynamicCodeIndices {
|
||||
constants: IndexMap<Constant, SliceDeque<usize>>,
|
||||
lists: SliceDeque<usize>,
|
||||
structures: IndexMap<(ClauseName, usize), SliceDeque<usize>>,
|
||||
constants: IndexMap<Literal, VecDeque<usize>>,
|
||||
lists: VecDeque<usize>,
|
||||
structures: IndexMap<(Atom, usize), VecDeque<usize>>,
|
||||
}
|
||||
|
||||
pub(crate) trait Indexer {
|
||||
@@ -1144,32 +1156,29 @@ pub(crate) trait Indexer {
|
||||
|
||||
fn new() -> Self;
|
||||
|
||||
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<Self::ThirdLevelIndex>>;
|
||||
fn lists(&mut self) -> &mut SliceDeque<Self::ThirdLevelIndex>;
|
||||
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<Self::ThirdLevelIndex>>;
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>>;
|
||||
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
|
||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<Self::ThirdLevelIndex>>;
|
||||
|
||||
fn compute_index(is_initial_index: bool, index: usize) -> Self::ThirdLevelIndex;
|
||||
|
||||
fn second_level_index<IndexKey: Eq + Hash>(
|
||||
indices: IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
indices: IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr>;
|
||||
|
||||
fn switch_on<IndexKey: Eq + Hash>(
|
||||
instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, SliceDeque<Self::ThirdLevelIndex>>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<Self::ThirdLevelIndex>>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr;
|
||||
|
||||
fn switch_on_list(
|
||||
lists: &mut SliceDeque<Self::ThirdLevelIndex>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
lists: &mut VecDeque<Self::ThirdLevelIndex>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr;
|
||||
|
||||
fn remove_instruction_with_offset(
|
||||
code: &mut SliceDeque<Self::ThirdLevelIndex>,
|
||||
offset: usize,
|
||||
);
|
||||
fn remove_instruction_with_offset(code: &mut SliceDeque<Self::ThirdLevelIndex>, offset: usize);
|
||||
|
||||
fn var_offset_wrapper(var_offset: usize) -> IndexingCodePtr;
|
||||
}
|
||||
@@ -1181,23 +1190,23 @@ impl Indexer for StaticCodeIndices {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
constants: IndexMap::new(),
|
||||
lists: sdeq![],
|
||||
lists: VecDeque::new(),
|
||||
structures: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<IndexedChoiceInstruction>> {
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>> {
|
||||
&mut self.constants
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lists(&mut self) -> &mut SliceDeque<IndexedChoiceInstruction> {
|
||||
fn lists(&mut self) -> &mut VecDeque<IndexedChoiceInstruction> {
|
||||
&mut self.lists
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<IndexedChoiceInstruction>> {
|
||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>> {
|
||||
&mut self.structures
|
||||
}
|
||||
|
||||
@@ -1210,18 +1219,18 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
fn second_level_index<IndexKey: Eq + Hash>(
|
||||
indices: IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
indices: IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr> {
|
||||
let mut index_locs = IndexMap::new();
|
||||
|
||||
for (key, mut code) in indices.into_iter() {
|
||||
if code.len() > 1 {
|
||||
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
|
||||
cap_choice_seq_with_trust(&mut code);
|
||||
cap_choice_seq_with_trust(code.make_contiguous());
|
||||
prelude.push_back(IndexingLine::from(code));
|
||||
} else {
|
||||
code.first().map(|i| {
|
||||
code.front().map(|i| {
|
||||
index_locs.insert(key, IndexingCodePtr::External(i.offset()));
|
||||
});
|
||||
}
|
||||
@@ -1232,8 +1241,8 @@ impl Indexer for StaticCodeIndices {
|
||||
|
||||
fn switch_on<IndexKey: Eq + Hash>(
|
||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, SliceDeque<IndexedChoiceInstruction>>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<IndexedChoiceInstruction>>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr {
|
||||
let index = mem::replace(index, IndexMap::new());
|
||||
let index = Self::second_level_index(index, prelude);
|
||||
@@ -1253,25 +1262,28 @@ impl Indexer for StaticCodeIndices {
|
||||
}
|
||||
|
||||
fn switch_on_list(
|
||||
lists: &mut SliceDeque<IndexedChoiceInstruction>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
lists: &mut VecDeque<IndexedChoiceInstruction>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr {
|
||||
if lists.len() > 1 {
|
||||
cap_choice_seq_with_trust(lists);
|
||||
let lists = mem::replace(lists, sdeq![]);
|
||||
cap_choice_seq_with_trust(lists.make_contiguous());
|
||||
let lists = mem::replace(lists, VecDeque::new());
|
||||
prelude.push_back(IndexingLine::from(lists));
|
||||
|
||||
IndexingCodePtr::Internal(1)
|
||||
} else {
|
||||
lists
|
||||
.first()
|
||||
.front()
|
||||
.map(|i| IndexingCodePtr::External(i.offset()))
|
||||
.unwrap_or(IndexingCodePtr::Fail)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn remove_instruction_with_offset(code: &mut SliceDeque<IndexedChoiceInstruction>, offset: usize) {
|
||||
fn remove_instruction_with_offset(
|
||||
code: &mut SliceDeque<IndexedChoiceInstruction>,
|
||||
offset: usize,
|
||||
) {
|
||||
for (index, line) in code.iter().enumerate() {
|
||||
if offset == line.offset() {
|
||||
code.remove(index);
|
||||
@@ -1294,23 +1306,23 @@ impl Indexer for DynamicCodeIndices {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
constants: IndexMap::new(),
|
||||
lists: sdeq![],
|
||||
lists: VecDeque::new(),
|
||||
structures: IndexMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn constants(&mut self) -> &mut IndexMap<Constant, SliceDeque<usize>> {
|
||||
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>> {
|
||||
&mut self.constants
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn lists(&mut self) -> &mut SliceDeque<usize> {
|
||||
fn lists(&mut self) -> &mut VecDeque<usize> {
|
||||
&mut self.lists
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn structures(&mut self) -> &mut IndexMap<(ClauseName, usize), SliceDeque<usize>> {
|
||||
fn structures(&mut self) -> &mut IndexMap<(Atom, usize), VecDeque<usize>> {
|
||||
&mut self.structures
|
||||
}
|
||||
|
||||
@@ -1320,17 +1332,17 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
fn second_level_index<IndexKey: Eq + Hash>(
|
||||
indices: IndexMap<IndexKey, SliceDeque<usize>>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
indices: IndexMap<IndexKey, VecDeque<usize>>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexMap<IndexKey, IndexingCodePtr> {
|
||||
let mut index_locs = IndexMap::new();
|
||||
|
||||
for (key, code) in indices.into_iter() {
|
||||
if code.len() > 1 {
|
||||
index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1));
|
||||
prelude.push_back(IndexingLine::DynamicIndexedChoice(code));
|
||||
prelude.push_back(IndexingLine::DynamicIndexedChoice(code.into_iter().collect()));
|
||||
} else {
|
||||
code.first().map(|i| {
|
||||
code.front().map(|i| {
|
||||
index_locs.insert(key, IndexingCodePtr::DynamicExternal(*i));
|
||||
});
|
||||
}
|
||||
@@ -1341,8 +1353,8 @@ impl Indexer for DynamicCodeIndices {
|
||||
|
||||
fn switch_on<IndexKey: Eq + Hash>(
|
||||
mut instr_fn: impl FnMut(IndexMap<IndexKey, IndexingCodePtr>) -> IndexingInstruction,
|
||||
index: &mut IndexMap<IndexKey, SliceDeque<usize>>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
index: &mut IndexMap<IndexKey, VecDeque<usize>>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr {
|
||||
let index = mem::replace(index, IndexMap::new());
|
||||
let index = Self::second_level_index(index, prelude);
|
||||
@@ -1362,16 +1374,16 @@ impl Indexer for DynamicCodeIndices {
|
||||
}
|
||||
|
||||
fn switch_on_list(
|
||||
lists: &mut SliceDeque<usize>,
|
||||
prelude: &mut SliceDeque<IndexingLine>,
|
||||
lists: &mut VecDeque<usize>,
|
||||
prelude: &mut VecDeque<IndexingLine>,
|
||||
) -> IndexingCodePtr {
|
||||
if lists.len() > 1 {
|
||||
let lists = mem::replace(lists, sdeq![]);
|
||||
prelude.push_back(IndexingLine::DynamicIndexedChoice(lists));
|
||||
let lists = mem::replace(lists, VecDeque::new());
|
||||
prelude.push_back(IndexingLine::DynamicIndexedChoice(lists.into_iter().collect()));
|
||||
IndexingCodePtr::Internal(1)
|
||||
} else {
|
||||
lists
|
||||
.first()
|
||||
.front()
|
||||
.map(|i| IndexingCodePtr::DynamicExternal(*i))
|
||||
.unwrap_or(IndexingCodePtr::Fail)
|
||||
}
|
||||
@@ -1395,19 +1407,13 @@ impl Indexer for DynamicCodeIndices {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CodeOffsets<I: Indexer> {
|
||||
atom_tbl: TabledData<Atom>,
|
||||
indices: I,
|
||||
optimal_index: usize,
|
||||
}
|
||||
|
||||
impl<I: Indexer> CodeOffsets<I> {
|
||||
pub(crate) fn new(
|
||||
atom_tbl: TabledData<Atom>,
|
||||
indices: I,
|
||||
optimal_index: usize,
|
||||
) -> Self {
|
||||
pub(crate) fn new(indices: I, optimal_index: usize) -> Self {
|
||||
CodeOffsets {
|
||||
atom_tbl,
|
||||
indices,
|
||||
optimal_index,
|
||||
}
|
||||
@@ -1419,15 +1425,24 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
self.indices.lists().push_back(index);
|
||||
}
|
||||
|
||||
fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec<Constant> {
|
||||
let overlapping_constants = constant_key_alternatives(constant, self.atom_tbl.clone());
|
||||
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
|
||||
fn index_constant(
|
||||
&mut self,
|
||||
atom_tbl: &mut AtomTable,
|
||||
constant: Literal,
|
||||
index: usize,
|
||||
) -> Vec<Literal> {
|
||||
let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
|
||||
let code = self.indices.constants().entry(constant).or_insert(VecDeque::new());
|
||||
|
||||
let is_initial_index = code.is_empty();
|
||||
code.push_back(I::compute_index(is_initial_index, index));
|
||||
|
||||
for constant in &overlapping_constants {
|
||||
let code = self.indices.constants().entry(constant.clone()).or_insert(sdeq![]);
|
||||
let code = self
|
||||
.indices
|
||||
.constants()
|
||||
.entry(*constant)
|
||||
.or_insert(VecDeque::new());
|
||||
|
||||
let is_initial_index = code.is_empty();
|
||||
let index = I::compute_index(is_initial_index, index);
|
||||
@@ -1438,11 +1453,12 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
overlapping_constants
|
||||
}
|
||||
|
||||
fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize {
|
||||
let code = self.indices
|
||||
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
|
||||
let code = self
|
||||
.indices
|
||||
.structures()
|
||||
.entry((name.clone(), arity))
|
||||
.or_insert(sdeq![]);
|
||||
.or_insert(VecDeque::new());
|
||||
|
||||
let code_len = code.len();
|
||||
let is_initial_index = code.is_empty();
|
||||
@@ -1456,28 +1472,25 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
optimal_arg: &Term,
|
||||
index: usize,
|
||||
clause_index_info: &mut ClauseIndexInfo,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) {
|
||||
match optimal_arg {
|
||||
&Term::Clause(_, ref name, ref terms, _) => {
|
||||
&Term::Clause(_, name, ref terms) => {
|
||||
clause_index_info.opt_arg_index_key =
|
||||
OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len());
|
||||
|
||||
self.index_structure(name, terms.len(), index);
|
||||
}
|
||||
&Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => {
|
||||
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
|
||||
|
||||
self.index_list(index);
|
||||
}
|
||||
&Term::Constant(_, ref constant) => {
|
||||
let overlapping_constants = self.index_constant(constant, index);
|
||||
&Term::Literal(_, constant) => {
|
||||
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
|
||||
|
||||
clause_index_info.opt_arg_index_key = OptArgIndexKey::Constant(
|
||||
self.optimal_index,
|
||||
0,
|
||||
constant.clone(),
|
||||
overlapping_constants,
|
||||
);
|
||||
clause_index_info.opt_arg_index_key =
|
||||
OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -1496,7 +1509,7 @@ impl<I: Indexer> CodeOffsets<I> {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let mut prelude = sdeq![];
|
||||
let mut prelude = VecDeque::new();
|
||||
|
||||
let mut emitted_switch_on_structure = false;
|
||||
let mut emitted_switch_on_constant = false;
|
||||
|
||||
@@ -1,847 +0,0 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::clause_name;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::forms::*;
|
||||
use crate::indexing::IndexingCodePtr;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_errors::MachineStub;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::rug::Integer;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use slice_deque::SliceDeque;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
fn reg_type_into_functor(r: RegType) -> MachineStub {
|
||||
match r {
|
||||
RegType::Temp(r) => functor!("x", [integer(r)]),
|
||||
RegType::Perm(r) => functor!("y", [integer(r)]),
|
||||
}
|
||||
}
|
||||
|
||||
impl Level {
|
||||
fn into_functor(self) -> MachineStub {
|
||||
match self {
|
||||
Level::Root => functor!("level", [atom("root")]),
|
||||
Level::Shallow => functor!("level", [atom("shallow")]),
|
||||
Level::Deep => functor!("level", [atom("deep")]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArithmeticTerm {
|
||||
fn into_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
|
||||
&ArithmeticTerm::Interm(i) => {
|
||||
functor!("intermediate", [integer(i)])
|
||||
}
|
||||
&ArithmeticTerm::Number(ref n) => {
|
||||
vec![n.clone().into()]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum NextOrFail {
|
||||
Next(usize),
|
||||
Fail(usize),
|
||||
}
|
||||
|
||||
impl NextOrFail {
|
||||
#[inline]
|
||||
pub fn is_next(&self) -> bool {
|
||||
if let NextOrFail::Next(_) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) enum Death {
|
||||
Finite(usize),
|
||||
Infinity,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ChoiceInstruction {
|
||||
DynamicElse(usize, Death, NextOrFail),
|
||||
DynamicInternalElse(usize, Death, NextOrFail),
|
||||
DefaultRetryMeElse(usize),
|
||||
DefaultTrustMe(usize),
|
||||
RetryMeElse(usize),
|
||||
TrustMe(usize),
|
||||
TryMeElse(usize),
|
||||
}
|
||||
|
||||
impl ChoiceInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => {
|
||||
match (death, next_or_fail) {
|
||||
(Death::Infinity, NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), atom("inf"), integer(i)]
|
||||
)
|
||||
}
|
||||
(Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), atom("inf"), aux(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), integer(d), aux(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_else",
|
||||
[integer(birth), integer(d), integer(i)]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => {
|
||||
match (death, next_or_fail) {
|
||||
(Death::Infinity, NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), atom("inf"), integer(i)]
|
||||
)
|
||||
}
|
||||
(Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), atom("inf"), aux(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
let next_functor = functor!("fail", [integer(i)]);
|
||||
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), integer(d), aux(h, 0)],
|
||||
[next_functor]
|
||||
)
|
||||
}
|
||||
(Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
functor!(
|
||||
"dynamic_internal_else",
|
||||
[integer(birth), integer(d), integer(i)]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
&ChoiceInstruction::TryMeElse(offset) => {
|
||||
functor!("try_me_else", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::RetryMeElse(offset) => {
|
||||
functor!("retry_me_else", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::TrustMe(offset) => {
|
||||
functor!("trust_me", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||
functor!("default_retry_me_else", [integer(offset)])
|
||||
}
|
||||
&ChoiceInstruction::DefaultTrustMe(offset) => {
|
||||
functor!("default_trust_me", [integer(offset)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum CutInstruction {
|
||||
Cut(RegType),
|
||||
GetLevel(RegType),
|
||||
GetLevelAndUnify(RegType),
|
||||
NeckCut,
|
||||
}
|
||||
|
||||
impl CutInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&CutInstruction::Cut(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("cut", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::GetLevel(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("get_level", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::GetLevelAndUnify(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
functor!("get_level_and_unify", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&CutInstruction::NeckCut => {
|
||||
functor!("neck_cut")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum IndexedChoiceInstruction {
|
||||
Retry(usize),
|
||||
Trust(usize),
|
||||
Try(usize),
|
||||
}
|
||||
|
||||
impl IndexedChoiceInstruction {
|
||||
pub(crate) fn offset(&self) -> usize {
|
||||
match self {
|
||||
&IndexedChoiceInstruction::Retry(offset) => offset,
|
||||
&IndexedChoiceInstruction::Trust(offset) => offset,
|
||||
&IndexedChoiceInstruction::Try(offset) => offset,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&IndexedChoiceInstruction::Try(offset) => {
|
||||
functor!("try", [integer(offset)])
|
||||
}
|
||||
&IndexedChoiceInstruction::Trust(offset) => {
|
||||
functor!("trust", [integer(offset)])
|
||||
}
|
||||
&IndexedChoiceInstruction::Retry(offset) => {
|
||||
functor!("retry", [integer(offset)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `Line` is an instruction (cf. page 98 of wambook).
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum IndexingLine {
|
||||
Indexing(IndexingInstruction),
|
||||
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
|
||||
DynamicIndexedChoice(SliceDeque<usize>),
|
||||
}
|
||||
|
||||
impl From<IndexingInstruction> for IndexingLine {
|
||||
#[inline]
|
||||
fn from(instr: IndexingInstruction) -> Self {
|
||||
IndexingLine::Indexing(instr)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
|
||||
#[inline]
|
||||
fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
|
||||
IndexingLine::IndexedChoice(instrs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum Line {
|
||||
Arithmetic(ArithmeticInstruction),
|
||||
Choice(ChoiceInstruction),
|
||||
Control(ControlInstruction),
|
||||
Cut(CutInstruction),
|
||||
Fact(FactInstruction),
|
||||
IndexingCode(Vec<IndexingLine>),
|
||||
IndexedChoice(IndexedChoiceInstruction),
|
||||
DynamicIndexedChoice(usize),
|
||||
Query(QueryInstruction),
|
||||
}
|
||||
|
||||
impl Line {
|
||||
#[inline]
|
||||
pub(crate) fn is_head_instr(&self) -> bool {
|
||||
match self {
|
||||
&Line::Fact(_) => true,
|
||||
&Line::Query(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
|
||||
match self {
|
||||
&Line::Arithmetic(ref arith_instr) => functors.push(arith_instr.to_functor(h)),
|
||||
&Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
|
||||
&Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
|
||||
&Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
|
||||
&Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
|
||||
&Line::IndexingCode(ref indexing_instrs) => {
|
||||
for indexing_instr in indexing_instrs {
|
||||
match indexing_instr {
|
||||
IndexingLine::Indexing(indexing_instr) => {
|
||||
let section = indexing_instr.to_functor(h);
|
||||
h += section.len();
|
||||
functors.push(section);
|
||||
}
|
||||
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
|
||||
for indexed_choice_instr in indexed_choice_instrs {
|
||||
let section = indexed_choice_instr.to_functor();
|
||||
h += section.len();
|
||||
functors.push(section);
|
||||
}
|
||||
}
|
||||
IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
|
||||
for indexed_choice_instr in indexed_choice_instrs {
|
||||
let section = functor!("dynamic", [integer(*indexed_choice_instr)]);
|
||||
h += section.len();
|
||||
functors.push(section);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
&Line::IndexedChoice(ref indexed_choice_instr) => {
|
||||
functors.push(indexed_choice_instr.to_functor())
|
||||
}
|
||||
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
|
||||
functors.push(functor!("dynamic", [integer(*indexed_choice_instr)]));
|
||||
}
|
||||
&Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
|
||||
match line {
|
||||
Line::IndexingCode(ref mut indexing_code) => Some(indexing_code),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
|
||||
match line {
|
||||
Line::IndexingCode(ref indexing_code) => Some(indexing_code),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum ArithmeticInstruction {
|
||||
Add(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Sub(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Mul(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Pow(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
IntPow(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
IDiv(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Max(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Min(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
RDiv(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Div(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Shl(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Shr(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Xor(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
And(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Or(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Mod(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Rem(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Gcd(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Sign(ArithmeticTerm, usize),
|
||||
Cos(ArithmeticTerm, usize),
|
||||
Sin(ArithmeticTerm, usize),
|
||||
Tan(ArithmeticTerm, usize),
|
||||
Log(ArithmeticTerm, usize),
|
||||
Exp(ArithmeticTerm, usize),
|
||||
ACos(ArithmeticTerm, usize),
|
||||
ASin(ArithmeticTerm, usize),
|
||||
ATan(ArithmeticTerm, usize),
|
||||
ATan2(ArithmeticTerm, ArithmeticTerm, usize),
|
||||
Sqrt(ArithmeticTerm, usize),
|
||||
Abs(ArithmeticTerm, usize),
|
||||
Float(ArithmeticTerm, usize),
|
||||
Truncate(ArithmeticTerm, usize),
|
||||
Round(ArithmeticTerm, usize),
|
||||
Ceiling(ArithmeticTerm, usize),
|
||||
Floor(ArithmeticTerm, usize),
|
||||
Neg(ArithmeticTerm, usize),
|
||||
Plus(ArithmeticTerm, usize),
|
||||
BitwiseComplement(ArithmeticTerm, usize),
|
||||
}
|
||||
|
||||
fn arith_instr_unary_functor(
|
||||
h: usize,
|
||||
name: &'static str,
|
||||
at: &ArithmeticTerm,
|
||||
t: usize,
|
||||
) -> MachineStub {
|
||||
let at_stub = at.into_functor();
|
||||
|
||||
functor!(name, [aux(h, 0), integer(t)], [at_stub])
|
||||
}
|
||||
|
||||
fn arith_instr_bin_functor(
|
||||
h: usize,
|
||||
name: &'static str,
|
||||
at_1: &ArithmeticTerm,
|
||||
at_2: &ArithmeticTerm,
|
||||
t: usize,
|
||||
) -> MachineStub {
|
||||
let at_1_stub = at_1.into_functor();
|
||||
let at_2_stub = at_2.into_functor();
|
||||
|
||||
functor!(
|
||||
name,
|
||||
[aux(h, 0), aux(h, 1), integer(t)],
|
||||
[at_1_stub, at_2_stub]
|
||||
)
|
||||
}
|
||||
|
||||
impl ArithmeticInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "add", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "sub", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "mul", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "int_pow", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "pow", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "idiv", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Max(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "max", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Min(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "min", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "int_floor_div", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "rdiv", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Div(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "div", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "shl", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "shr", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "xor", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::And(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "and", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Or(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "or", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "mod", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "rem", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "rem", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
|
||||
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
|
||||
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
|
||||
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
|
||||
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
|
||||
&ArithmeticInstruction::Log(ref at, t) => arith_instr_unary_functor(h, "log", at, t),
|
||||
&ArithmeticInstruction::Exp(ref at, t) => arith_instr_unary_functor(h, "exp", at, t),
|
||||
&ArithmeticInstruction::ACos(ref at, t) => arith_instr_unary_functor(h, "acos", at, t),
|
||||
&ArithmeticInstruction::ASin(ref at, t) => arith_instr_unary_functor(h, "asin", at, t),
|
||||
&ArithmeticInstruction::ATan(ref at, t) => arith_instr_unary_functor(h, "atan", at, t),
|
||||
&ArithmeticInstruction::Sqrt(ref at, t) => arith_instr_unary_functor(h, "sqrt", at, t),
|
||||
&ArithmeticInstruction::Abs(ref at, t) => arith_instr_unary_functor(h, "abs", at, t),
|
||||
&ArithmeticInstruction::Float(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "float", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Truncate(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "truncate", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Round(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "round", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Ceiling(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "ceiling", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Floor(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "floor", at, t)
|
||||
}
|
||||
&ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(h, "-", at, t),
|
||||
&ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(h, "+", at, t),
|
||||
&ArithmeticInstruction::BitwiseComplement(ref at, t) => {
|
||||
arith_instr_unary_functor(h, "\\", at, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ControlInstruction {
|
||||
Allocate(usize), // num_frames.
|
||||
// name, arity, perm_vars after threshold, last call, use default call policy.
|
||||
CallClause(ClauseType, usize, usize, bool, bool),
|
||||
Deallocate,
|
||||
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
|
||||
RevJmpBy(usize), // notice the lack of context change as in
|
||||
// JmpBy. RevJmpBy is used only to patch extensible
|
||||
// predicates together.
|
||||
Proceed,
|
||||
}
|
||||
|
||||
impl ControlInstruction {
|
||||
pub(crate) fn perm_vars(&self) -> Option<usize> {
|
||||
match self {
|
||||
ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells),
|
||||
ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_functor(&self) -> MachineStub {
|
||||
match self {
|
||||
&ControlInstruction::Allocate(num_frames) => {
|
||||
functor!("allocate", [integer(num_frames)])
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
|
||||
functor!("call", [clause_name(ct.name()), integer(arity)])
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
|
||||
functor!("execute", [clause_name(ct.name()), integer(arity)])
|
||||
}
|
||||
&ControlInstruction::Deallocate => {
|
||||
functor!("deallocate")
|
||||
}
|
||||
&ControlInstruction::JmpBy(_, offset, ..) => {
|
||||
functor!("jmp_by", [integer(offset)])
|
||||
}
|
||||
&ControlInstruction::RevJmpBy(offset) => {
|
||||
functor!("rev_jmp_by", [integer(offset)])
|
||||
}
|
||||
&ControlInstruction::Proceed => {
|
||||
functor!("proceed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `IndexingInstruction` cf. page 110 of wambook.
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum IndexingInstruction {
|
||||
// The first index is the optimal argument being indexed.
|
||||
SwitchOnTerm(
|
||||
usize,
|
||||
IndexingCodePtr,
|
||||
IndexingCodePtr,
|
||||
IndexingCodePtr,
|
||||
IndexingCodePtr,
|
||||
),
|
||||
SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
|
||||
SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
|
||||
}
|
||||
|
||||
impl IndexingInstruction {
|
||||
pub(crate) fn to_functor(&self, mut h: usize) -> MachineStub {
|
||||
match self {
|
||||
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
|
||||
functor!(
|
||||
"switch_on_term",
|
||||
[
|
||||
integer(arg),
|
||||
indexing_code_ptr(h, vars),
|
||||
indexing_code_ptr(h, constants),
|
||||
indexing_code_ptr(h, lists),
|
||||
indexing_code_ptr(h, structures)
|
||||
]
|
||||
)
|
||||
}
|
||||
&IndexingInstruction::SwitchOnConstant(ref constants) => {
|
||||
let mut key_value_list_stub = vec![];
|
||||
let orig_h = h;
|
||||
|
||||
h += 2; // skip the 2-cell "switch_on_constant" functor.
|
||||
|
||||
for (c, ptr) in constants.iter() {
|
||||
let key_value_pair = functor!(
|
||||
":",
|
||||
SharedOpDesc::new(600, XFY),
|
||||
[constant(c), indexing_code_ptr(h + 3, *ptr)]
|
||||
);
|
||||
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
|
||||
h + 3 + key_value_pair.len(),
|
||||
)));
|
||||
|
||||
h += key_value_pair.len() + 3;
|
||||
key_value_list_stub.extend(key_value_pair.into_iter());
|
||||
}
|
||||
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
|
||||
functor!(
|
||||
"switch_on_constant",
|
||||
[aux(orig_h, 0)],
|
||||
[key_value_list_stub]
|
||||
)
|
||||
}
|
||||
&IndexingInstruction::SwitchOnStructure(ref structures) => {
|
||||
let mut key_value_list_stub = vec![];
|
||||
let orig_h = h;
|
||||
|
||||
h += 2; // skip the 2-cell "switch_on_constant" functor.
|
||||
|
||||
for ((name, arity), ptr) in structures.iter() {
|
||||
let predicate_indicator_stub = functor!(
|
||||
"/",
|
||||
SharedOpDesc::new(400, YFX),
|
||||
[clause_name(name.clone()), integer(*arity)]
|
||||
);
|
||||
|
||||
let key_value_pair = functor!(
|
||||
":",
|
||||
SharedOpDesc::new(600, XFY),
|
||||
[aux(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
|
||||
[predicate_indicator_stub]
|
||||
);
|
||||
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::HeapCell(
|
||||
h + 3 + key_value_pair.len(),
|
||||
)));
|
||||
|
||||
h += key_value_pair.len() + 3;
|
||||
key_value_list_stub.extend(key_value_pair.into_iter());
|
||||
}
|
||||
|
||||
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
|
||||
functor!(
|
||||
"switch_on_structure",
|
||||
[aux(orig_h, 0)],
|
||||
[key_value_list_stub]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum FactInstruction {
|
||||
GetConstant(Level, Constant, RegType),
|
||||
GetList(Level, RegType),
|
||||
GetPartialString(Level, String, RegType, bool),
|
||||
GetStructure(ClauseType, usize, RegType),
|
||||
GetValue(RegType, usize),
|
||||
GetVariable(RegType, usize),
|
||||
UnifyConstant(Constant),
|
||||
UnifyLocalValue(RegType),
|
||||
UnifyVariable(RegType),
|
||||
UnifyValue(RegType),
|
||||
UnifyVoid(usize),
|
||||
}
|
||||
|
||||
impl FactInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&FactInstruction::GetConstant(lvl, ref c, r) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"get_constant",
|
||||
[aux(h, 0), constant(h, c), aux(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetList(lvl, r) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("get_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
|
||||
}
|
||||
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"get_partial_string",
|
||||
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetStructure(ref ct, arity, r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"get_structure",
|
||||
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&FactInstruction::GetValue(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("get_value", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::GetVariable(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyConstant(ref c) => {
|
||||
functor!("unify_constant", [constant(h, c)], [])
|
||||
}
|
||||
&FactInstruction::UnifyLocalValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("unify_local_value", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyVariable(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("unify_variable", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("unify_value", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&FactInstruction::UnifyVoid(vars) => {
|
||||
functor!("unify_void", [integer(vars)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum QueryInstruction {
|
||||
GetVariable(RegType, usize),
|
||||
PutConstant(Level, Constant, RegType),
|
||||
PutList(Level, RegType),
|
||||
PutPartialString(Level, String, RegType, bool),
|
||||
PutStructure(ClauseType, usize, RegType),
|
||||
PutUnsafeValue(usize, usize),
|
||||
PutValue(RegType, usize),
|
||||
PutVariable(RegType, usize),
|
||||
SetConstant(Constant),
|
||||
SetLocalValue(RegType),
|
||||
SetVariable(RegType),
|
||||
SetValue(RegType),
|
||||
SetVoid(usize),
|
||||
}
|
||||
|
||||
impl QueryInstruction {
|
||||
pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
|
||||
match self {
|
||||
&QueryInstruction::PutUnsafeValue(norm, arg) => {
|
||||
functor!("put_unsafe_value", [integer(norm), integer(arg)])
|
||||
}
|
||||
&QueryInstruction::PutConstant(lvl, ref c, r) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"put_constant",
|
||||
[aux(h, 0), constant(h, c), aux(h, 1)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutList(lvl, r) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("put_list", [aux(h, 0), aux(h, 1)], [lvl_stub, rt_stub])
|
||||
}
|
||||
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||
let lvl_stub = lvl.into_functor();
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"put_partial_string",
|
||||
[aux(h, 0), string(h, s), aux(h, 1), boolean(has_tail)],
|
||||
[lvl_stub, rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutStructure(ref ct, arity, r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!(
|
||||
"put_structure",
|
||||
[clause_name(ct.name()), integer(arity), aux(h, 0)],
|
||||
[rt_stub]
|
||||
)
|
||||
}
|
||||
&QueryInstruction::PutValue(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("put_value", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::GetVariable(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("get_variable", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::PutVariable(r, arg) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("put_variable", [aux(h, 0), integer(arg)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetConstant(ref c) => {
|
||||
functor!("set_constant", [constant(h, c)], [])
|
||||
}
|
||||
&QueryInstruction::SetLocalValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("set_local_value", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetVariable(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("set_variable", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetValue(r) => {
|
||||
let rt_stub = reg_type_into_functor(r);
|
||||
|
||||
functor!("set_value", [aux(h, 0)], [rt_stub])
|
||||
}
|
||||
&QueryInstruction::SetVoid(vars) => {
|
||||
functor!("set_void", [integer(vars)])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type CompiledFact = Vec<FactInstruction>;
|
||||
|
||||
pub(crate) type Code = Vec<Line>;
|
||||
223
src/iterators.rs
223
src/iterators.rs
@@ -1,9 +1,8 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::rc_atom;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
@@ -16,10 +15,10 @@ use std::vec::Vec;
|
||||
pub(crate) enum TermRef<'a> {
|
||||
AnonVar(Level),
|
||||
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Box<Term>>),
|
||||
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||
Clause(Level, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
|
||||
PartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
||||
}
|
||||
|
||||
impl<'a> TermRef<'a> {
|
||||
@@ -27,7 +26,7 @@ impl<'a> TermRef<'a> {
|
||||
match self {
|
||||
TermRef::AnonVar(lvl)
|
||||
| TermRef::Cons(lvl, ..)
|
||||
| TermRef::Constant(lvl, ..)
|
||||
| TermRef::Literal(lvl, ..)
|
||||
| TermRef::Var(lvl, ..)
|
||||
| TermRef::Clause(lvl, ..) => lvl,
|
||||
TermRef::PartialString(lvl, ..) => lvl,
|
||||
@@ -38,82 +37,31 @@ impl<'a> TermRef<'a> {
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum TermIterState<'a> {
|
||||
AnonVar(Level),
|
||||
Constant(Level, &'a Cell<RegType>, &'a Constant),
|
||||
Clause(
|
||||
Level,
|
||||
usize,
|
||||
&'a Cell<RegType>,
|
||||
ClauseType,
|
||||
&'a Vec<Box<Term>>,
|
||||
),
|
||||
Literal(Level, &'a Cell<RegType>, &'a Literal),
|
||||
Clause(Level, usize, &'a Cell<RegType>, ClauseType, &'a Vec<Term>),
|
||||
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
|
||||
PartialString(Level, &'a Cell<RegType>, String, Option<&'a Term>),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<Var>),
|
||||
}
|
||||
|
||||
fn is_partial_string<'a>(head: &'a Term, mut tail: &'a Term) -> Option<(String, Option<&'a Term>)> {
|
||||
let mut string = match head {
|
||||
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
|
||||
atom.as_str().chars().next().unwrap().to_string()
|
||||
}
|
||||
&Term::Constant(_, Constant::Char(c)) => c.to_string(),
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
while let Term::Cons(_, ref head, ref succ) = tail {
|
||||
match head.as_ref() {
|
||||
&Term::Constant(_, Constant::Atom(ref atom, _)) if atom.is_char() => {
|
||||
string.push(atom.as_str().chars().next().unwrap());
|
||||
}
|
||||
&Term::Constant(_, Constant::Char(c)) => {
|
||||
string.push(c);
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
tail = succ.as_ref();
|
||||
}
|
||||
|
||||
match tail {
|
||||
Term::AnonVar | Term::Var(..) => {
|
||||
return Some((string, Some(tail)));
|
||||
}
|
||||
Term::Constant(_, Constant::EmptyList) => {
|
||||
return Some((string, None));
|
||||
}
|
||||
Term::Constant(_, Constant::String(tail)) => {
|
||||
string += &tail;
|
||||
return Some((string, None));
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
InitialPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
||||
FinalPartialString(Level, &'a Cell<RegType>, Atom, &'a Option<Box<Term>>),
|
||||
Var(Level, &'a Cell<VarReg>, Rc<String>),
|
||||
}
|
||||
|
||||
impl<'a> TermIterState<'a> {
|
||||
pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
|
||||
match term {
|
||||
&Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||
&Term::Clause(ref cell, ref name, ref subterms, ref spec) => {
|
||||
let ct = if let Some(spec) = spec {
|
||||
ClauseType::Op(name.clone(), spec.clone(), CodeIndex::default())
|
||||
} else {
|
||||
ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default())
|
||||
};
|
||||
|
||||
Term::AnonVar => TermIterState::AnonVar(lvl),
|
||||
Term::Clause(cell, name, subterms) => {
|
||||
let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default());
|
||||
TermIterState::Clause(lvl, 0, cell, ct, subterms)
|
||||
}
|
||||
&Term::Cons(ref cell, ref head, ref tail) => {
|
||||
Term::Cons(cell, head, tail) => {
|
||||
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
|
||||
}
|
||||
&Term::Constant(ref cell, ref constant) => TermIterState::Constant(lvl, cell, constant),
|
||||
&Term::Var(ref cell, ref var) => TermIterState::Var(lvl, cell, var.clone()),
|
||||
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
|
||||
Term::PartialString(cell, string_buf, tail) => {
|
||||
TermIterState::InitialPartialString(lvl, cell, *string_buf, tail)
|
||||
}
|
||||
Term::Var(cell, var) => TermIterState::Var(lvl, cell, var.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,11 +77,11 @@ impl<'a> QueryIterator<'a> {
|
||||
.push(TermIterState::subterm_to_state(lvl, term));
|
||||
}
|
||||
|
||||
fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
|
||||
fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
|
||||
let state_stack = terms
|
||||
.iter()
|
||||
.rev()
|
||||
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref()))
|
||||
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
|
||||
.collect();
|
||||
|
||||
QueryIterator { state_stack }
|
||||
@@ -141,29 +89,19 @@ impl<'a> QueryIterator<'a> {
|
||||
|
||||
fn from_term(term: &'a Term) -> Self {
|
||||
let state = match term {
|
||||
&Term::AnonVar => {
|
||||
Term::AnonVar | Term::Cons(..) | Term::Literal(..) | Term::PartialString(..) => {
|
||||
return QueryIterator {
|
||||
state_stack: vec![],
|
||||
}
|
||||
}
|
||||
&Term::Clause(ref r, ref name, ref terms, ref fixity) => TermIterState::Clause(
|
||||
Term::Clause(r, name, terms) => TermIterState::Clause(
|
||||
Level::Root,
|
||||
0,
|
||||
r,
|
||||
ClauseType::from(name.clone(), terms.len(), fixity.clone()),
|
||||
ClauseType::from(*name, terms.len()),
|
||||
terms,
|
||||
),
|
||||
&Term::Cons(..) => {
|
||||
return QueryIterator {
|
||||
state_stack: vec![],
|
||||
}
|
||||
}
|
||||
&Term::Constant(_, _) => {
|
||||
return QueryIterator {
|
||||
state_stack: vec![],
|
||||
}
|
||||
}
|
||||
&Term::Var(ref cell, ref var) => TermIterState::Var(Level::Root, cell, (*var).clone()),
|
||||
Term::Var(cell, var) => TermIterState::Var(Level::Root, cell, var.clone()),
|
||||
};
|
||||
|
||||
QueryIterator {
|
||||
@@ -173,8 +111,8 @@ impl<'a> QueryIterator<'a> {
|
||||
|
||||
fn new(term: &'a QueryTerm) -> Self {
|
||||
match term {
|
||||
&QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms, _) => {
|
||||
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms);
|
||||
&QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => {
|
||||
let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms);
|
||||
QueryIterator {
|
||||
state_stack: vec![state],
|
||||
}
|
||||
@@ -186,7 +124,7 @@ impl<'a> QueryIterator<'a> {
|
||||
}
|
||||
}
|
||||
&QueryTerm::UnblockedCut(ref cell) => {
|
||||
let state = TermIterState::Var(Level::Root, cell, rc_atom!("!"));
|
||||
let state = TermIterState::Var(Level::Root, cell, Rc::new("!".to_string()));
|
||||
QueryIterator {
|
||||
state_stack: vec![state],
|
||||
}
|
||||
@@ -225,10 +163,10 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
|
||||
if child_num == child_terms.len() {
|
||||
match ct {
|
||||
ClauseType::CallN => {
|
||||
self.push_subterm(Level::Shallow, child_terms[0].as_ref())
|
||||
ClauseType::CallN(_) => {
|
||||
self.push_subterm(Level::Shallow, &child_terms[0]);
|
||||
}
|
||||
ClauseType::Named(..) | ClauseType::Op(..) => {
|
||||
ClauseType::Named(..) => {
|
||||
return match lvl {
|
||||
Level::Root => None,
|
||||
lvl => Some(TermRef::Clause(lvl, cell, ct, child_terms)),
|
||||
@@ -247,33 +185,30 @@ impl<'a> Iterator for QueryIterator<'a> {
|
||||
child_terms,
|
||||
));
|
||||
|
||||
self.push_subterm(lvl.child_level(), child_terms[child_num].as_ref());
|
||||
self.push_subterm(lvl.child_level(), &child_terms[child_num]);
|
||||
}
|
||||
}
|
||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||
if let Some((string, tail)) = is_partial_string(head, tail) {
|
||||
self.state_stack
|
||||
.push(TermIterState::PartialString(lvl, cell, string, tail));
|
||||
self.state_stack.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
}
|
||||
} else {
|
||||
self.state_stack
|
||||
.push(TermIterState::FinalCons(lvl, cell, head, tail));
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
self.push_subterm(lvl.child_level(), head);
|
||||
}
|
||||
TermIterState::InitialPartialString(lvl, cell, string, tail) => {
|
||||
self.state_stack.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
|
||||
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(lvl.child_level(), tail);
|
||||
self.push_subterm(lvl.child_level(), head);
|
||||
}
|
||||
}
|
||||
TermIterState::PartialString(lvl, cell, string, tail) => {
|
||||
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
|
||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||
}
|
||||
TermIterState::FinalCons(lvl, cell, head, tail) => {
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
TermIterState::Constant(lvl, cell, constant) => {
|
||||
return Some(TermRef::Constant(lvl, cell, constant));
|
||||
TermIterState::Literal(lvl, cell, constant) => {
|
||||
return Some(TermRef::Literal(lvl, cell, constant));
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var) => {
|
||||
return Some(TermRef::Var(lvl, cell, var));
|
||||
@@ -297,10 +232,10 @@ impl<'a> FactIterator<'a> {
|
||||
.push_back(TermIterState::subterm_to_state(lvl, term));
|
||||
}
|
||||
|
||||
pub(crate) fn from_rule_head_clause(terms: &'a Vec<Box<Term>>) -> Self {
|
||||
pub(crate) fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
|
||||
let state_queue = terms
|
||||
.iter()
|
||||
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt.as_ref()))
|
||||
.map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
|
||||
.collect();
|
||||
|
||||
FactIterator {
|
||||
@@ -311,23 +246,31 @@ impl<'a> FactIterator<'a> {
|
||||
|
||||
fn new(term: &'a Term, iterable_root: bool) -> Self {
|
||||
let states = match term {
|
||||
&Term::AnonVar => {
|
||||
Term::AnonVar => {
|
||||
vec![TermIterState::AnonVar(Level::Root)]
|
||||
}
|
||||
&Term::Clause(ref cell, ref name, ref terms, ref fixity) => {
|
||||
let ct = ClauseType::from(name.clone(), terms.len(), fixity.clone());
|
||||
Term::Clause(cell, name, terms) => {
|
||||
let ct = ClauseType::from(*name, terms.len());
|
||||
vec![TermIterState::Clause(Level::Root, 0, cell, ct, terms)]
|
||||
}
|
||||
&Term::Cons(ref cell, ref head, ref tail) => vec![TermIterState::InitialCons(
|
||||
Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
|
||||
Level::Root,
|
||||
cell,
|
||||
head.as_ref(),
|
||||
tail.as_ref(),
|
||||
)],
|
||||
&Term::Constant(ref cell, ref constant) => {
|
||||
vec![TermIterState::Constant(Level::Root, cell, constant)]
|
||||
Term::PartialString(cell, string_buf, tail_opt) => {
|
||||
vec![TermIterState::InitialPartialString(
|
||||
Level::Root,
|
||||
cell,
|
||||
*string_buf,
|
||||
tail_opt,
|
||||
)]
|
||||
}
|
||||
&Term::Var(ref cell, ref var) => {
|
||||
Term::Literal(cell, constant) => {
|
||||
vec![TermIterState::Literal(Level::Root, cell, constant)]
|
||||
}
|
||||
Term::Var(cell, var) => {
|
||||
vec![TermIterState::Var(Level::Root, cell, var.clone())]
|
||||
}
|
||||
};
|
||||
@@ -359,21 +302,20 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
};
|
||||
}
|
||||
TermIterState::InitialCons(lvl, cell, head, tail) => {
|
||||
if let Some((string, tail)) = is_partial_string(head, tail) {
|
||||
if let Some(tail) = tail {
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
}
|
||||
self.push_subterm(Level::Deep, head);
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
|
||||
return Some(TermRef::PartialString(lvl, cell, string, tail));
|
||||
} else {
|
||||
self.push_subterm(Level::Deep, head);
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
return Some(TermRef::Cons(lvl, cell, head, tail));
|
||||
}
|
||||
TermIterState::Constant(lvl, cell, constant) => {
|
||||
return Some(TermRef::Constant(lvl, cell, constant))
|
||||
TermIterState::InitialPartialString(lvl, cell, string_buf, tail_opt) => {
|
||||
if let Some(tail) = tail_opt {
|
||||
self.push_subterm(Level::Deep, tail);
|
||||
}
|
||||
|
||||
return Some(TermRef::PartialString(lvl, cell, string_buf, tail_opt));
|
||||
}
|
||||
TermIterState::Literal(lvl, cell, constant) => {
|
||||
return Some(TermRef::Literal(lvl, cell, constant))
|
||||
}
|
||||
TermIterState::Var(lvl, cell, var) => {
|
||||
return Some(TermRef::Var(lvl, cell, var));
|
||||
@@ -386,17 +328,17 @@ impl<'a> Iterator for FactIterator<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn post_order_iter(term: &Term) -> QueryIterator {
|
||||
pub(crate) fn post_order_iter<'a>(term: &'a Term) -> QueryIterator<'a> {
|
||||
QueryIterator::from_term(term)
|
||||
}
|
||||
|
||||
pub(crate) fn breadth_first_iter(term: &Term, iterable_root: bool) -> FactIterator {
|
||||
pub(crate) fn breadth_first_iter<'a>(term: &'a Term, iterable_root: bool) -> FactIterator<'a> {
|
||||
FactIterator::new(term, iterable_root)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum ChunkedTerm<'a> {
|
||||
HeadClause(ClauseName, &'a Vec<Box<Term>>),
|
||||
HeadClause(Atom, &'a Vec<Term>),
|
||||
BodyTerm(&'a QueryTerm),
|
||||
}
|
||||
|
||||
@@ -407,7 +349,7 @@ pub(crate) fn query_term_post_order_iter<'a>(query_term: &'a QueryTerm) -> Query
|
||||
impl<'a> ChunkedTerm<'a> {
|
||||
pub(crate) fn post_order_iter(&self) -> QueryIterator<'a> {
|
||||
match self {
|
||||
&ChunkedTerm::BodyTerm(ref qt) => QueryIterator::new(qt),
|
||||
&ChunkedTerm::BodyTerm(qt) => QueryIterator::new(qt),
|
||||
&ChunkedTerm::HeadClause(_, terms) => QueryIterator::from_rule_head_clause(terms),
|
||||
}
|
||||
}
|
||||
@@ -517,7 +459,7 @@ impl<'a> ChunkedIterator<'a> {
|
||||
while let Some(term) = item {
|
||||
match term {
|
||||
ChunkedTerm::HeadClause(_, terms) => {
|
||||
if contains_cut_var(terms.iter().map(|t| t.as_ref())) {
|
||||
if contains_cut_var(terms.iter()) {
|
||||
self.cut_var_in_head = true;
|
||||
}
|
||||
|
||||
@@ -547,13 +489,16 @@ impl<'a> ChunkedIterator<'a> {
|
||||
arity = 1;
|
||||
break;
|
||||
}
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => result.push(term),
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::UnblockedCut(..)) => {
|
||||
self.deep_cut_encountered = true;
|
||||
result.push(term);
|
||||
}
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(_, ClauseType::Inlined(_), ..)) => {
|
||||
result.push(term)
|
||||
}
|
||||
ChunkedTerm::BodyTerm(&QueryTerm::Clause(
|
||||
_,
|
||||
ClauseType::CallN,
|
||||
ClauseType::CallN(_),
|
||||
ref subterms,
|
||||
_,
|
||||
)) => {
|
||||
|
||||
31
src/lib.rs
31
src/lib.rs
@@ -1,25 +1,34 @@
|
||||
#[cfg(feature = "num-rug-adapter")]
|
||||
use num_rug_adapter as rug;
|
||||
#[cfg(feature = "rug")]
|
||||
use rug;
|
||||
#![recursion_limit = "4112"]
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
extern crate static_assertions;
|
||||
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
#[macro_use]
|
||||
pub mod atom_table;
|
||||
#[macro_use]
|
||||
pub mod arena;
|
||||
#[macro_use]
|
||||
pub mod parser;
|
||||
mod allocator;
|
||||
mod arithmetic;
|
||||
mod clause_types;
|
||||
mod codegen;
|
||||
pub mod codegen;
|
||||
mod debray_allocator;
|
||||
mod fixtures;
|
||||
mod forms;
|
||||
mod heap_iter;
|
||||
mod heap_print;
|
||||
pub mod heap_print;
|
||||
mod indexing;
|
||||
mod instructions;
|
||||
#[macro_use]
|
||||
pub mod instructions {
|
||||
include!(concat!(env!("OUT_DIR"), "/instructions.rs"));
|
||||
}
|
||||
mod iterators;
|
||||
pub mod machine;
|
||||
mod raw_block;
|
||||
pub mod read;
|
||||
mod targets;
|
||||
mod write;
|
||||
pub mod types;
|
||||
|
||||
use machine::*;
|
||||
use instructions::instr;
|
||||
|
||||
@@ -94,12 +94,6 @@ number_to_rational(Eps0, Real0, Fraction) :-
|
||||
),
|
||||
!.
|
||||
|
||||
number(X) :-
|
||||
( integer(X)
|
||||
; float(X)
|
||||
; rational(X)
|
||||
).
|
||||
|
||||
stern_brocot_(Qnn/Qnd, Qpn/Qpd, A/B, C/D, Fraction) :-
|
||||
Fn1 is A + C,
|
||||
Fd1 is B + D,
|
||||
|
||||
@@ -24,30 +24,42 @@
|
||||
'$absent_from_list'(Ls, Attr).
|
||||
|
||||
'$absent_from_list'(X, Attr) :-
|
||||
( var(X) -> true
|
||||
; X = [L|Ls], L \= Attr -> '$absent_from_list'(Ls, Attr)
|
||||
( var(X) ->
|
||||
true
|
||||
; X = [L|Ls],
|
||||
L \= Attr ->
|
||||
'$absent_from_list'(Ls, Attr)
|
||||
).
|
||||
|
||||
'$get_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls), nonvar(Ls), '$get_from_list'(Ls, V, Attr).
|
||||
'$get_attr_list'(V, Ls),
|
||||
nonvar(Ls),
|
||||
'$get_from_list'(Ls, V, Attr).
|
||||
|
||||
'$get_from_list'([L|Ls], V, Attr) :-
|
||||
nonvar(L),
|
||||
( L \= Attr -> nonvar(Ls), '$get_from_list'(Ls, V, Attr)
|
||||
; L = Attr, '$enqueue_attr_var'(V)
|
||||
( L \= Attr ->
|
||||
nonvar(Ls),
|
||||
'$get_from_list'(Ls, V, Attr)
|
||||
; L = Attr,
|
||||
'$enqueue_attr_var'(V)
|
||||
).
|
||||
|
||||
'$put_attr'(V, Attr) :-
|
||||
'$get_attr_list'(V, Ls), '$add_to_list'(Ls, V, Attr).
|
||||
'$get_attr_list'(V, Ls),
|
||||
'$add_to_list'(Ls, V, Attr).
|
||||
|
||||
'$add_to_list'(Ls, V, Attr) :-
|
||||
( var(Ls) ->
|
||||
Ls = [Attr | _], '$enqueue_attr_var'(V)
|
||||
; Ls = [_ | Ls0], '$add_to_list'(Ls0, V, Attr)
|
||||
( var(Ls) ->
|
||||
Ls = [Attr | _],
|
||||
'$enqueue_attr_var'(V)
|
||||
; Ls = [_ | Ls0],
|
||||
'$add_to_list'(Ls0, V, Attr)
|
||||
).
|
||||
|
||||
'$del_attr'(Ls0, _, _) :-
|
||||
var(Ls0), !.
|
||||
var(Ls0),
|
||||
!.
|
||||
'$del_attr'(Ls0, V, Attr) :-
|
||||
Ls0 = [Att | Ls1],
|
||||
nonvar(Att),
|
||||
@@ -134,22 +146,22 @@ put_attr(Name, Arity, Module) -->
|
||||
[(put_atts(V, +Attr) :-
|
||||
!,
|
||||
functor(Attr, Head, Arity),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
(put_atts(V, Attr) :-
|
||||
!,
|
||||
functor(Attr, Head, Arity),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
functor(AttrForm, Head, Arity),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:AttrForm),
|
||||
atts:'$put_attr'(V, Module:Attr)),
|
||||
(put_atts(V, -Attr) :-
|
||||
!,
|
||||
functor(Attr, _, _),
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:Attr))].
|
||||
'$get_attr_list'(V, Ls),
|
||||
atts:'$del_attr'(Ls, V, Module:Attr))].
|
||||
|
||||
get_attr(Name, Arity, Module) -->
|
||||
{ functor(Attr, Name, Arity) },
|
||||
|
||||
@@ -12,17 +12,18 @@ between(Lower, Upper, X) :-
|
||||
( nonvar(X) ->
|
||||
Lower =< X,
|
||||
X =< Upper
|
||||
; compare(Ord, Lower, Upper),
|
||||
between_(Ord, Lower, Upper, X)
|
||||
; Lower =< Upper,
|
||||
between_(Lower, Upper, X)
|
||||
).
|
||||
|
||||
between_(<, Lower0, Upper, X) :-
|
||||
( X = Lower0
|
||||
; Lower1 is Lower0 + 1,
|
||||
compare(Ord, Lower1, Upper),
|
||||
between_(Ord, Lower1, Upper, X)
|
||||
).
|
||||
between_(=, Upper, Upper, Upper).
|
||||
between_(Lower, Upper, Lower1) :-
|
||||
Lower < Upper,
|
||||
!,
|
||||
( Lower1 = Lower
|
||||
; Lower0 is Lower + 1,
|
||||
between_(Lower0, Upper, Lower1)
|
||||
).
|
||||
between_(Lower, Lower, Lower).
|
||||
|
||||
enumerate_nats(I, I).
|
||||
enumerate_nats(I0, N) :-
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2,
|
||||
:- module(builtins, [(=)/2, (\=)/2, (\+)/1, !/0, (',')/2, (->)/2, (;)/2,
|
||||
(=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6,
|
||||
(:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12,
|
||||
abolish/1, asserta/1, assertz/1,
|
||||
@@ -59,65 +59,62 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G).
|
||||
|
||||
call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H).
|
||||
|
||||
|
||||
Module : Predicate :-
|
||||
( atom(Module) ->
|
||||
'$module_call'(Module, Predicate)
|
||||
;
|
||||
throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
|
||||
% dynamic module resolution.
|
||||
|
||||
Module : Predicate :-
|
||||
( atom(Module) -> '$module_call'(Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1) :-
|
||||
( atom(Module) -> '$module_call'(A1, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) ->
|
||||
'$module_call'(A1, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
:(Module, Predicate, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) :-
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
( atom(Module) -> '$module_call'(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Module, Predicate)
|
||||
; throw(error(type_error(atom, Module), (:)/2))
|
||||
).
|
||||
|
||||
% flags.
|
||||
@@ -205,153 +202,184 @@ repeat.
|
||||
repeat :- repeat.
|
||||
|
||||
|
||||
:- meta_predicate ','(0,0).
|
||||
|
||||
:- meta_predicate ','(0, 0).
|
||||
:- meta_predicate ;(0,0).
|
||||
|
||||
:- meta_predicate ','(0, +, +).
|
||||
|
||||
:- meta_predicate ;(0, 0).
|
||||
|
||||
:- meta_predicate ;(0, 0, +).
|
||||
|
||||
:- meta_predicate ->(0, 0).
|
||||
|
||||
:- meta_predicate ->(0, 0, +).
|
||||
:- meta_predicate ->(0,0).
|
||||
|
||||
|
||||
','(G1, G2) :-
|
||||
'$get_b_value'(B),
|
||||
( '$call_with_default_policy'(var(G1)) ->
|
||||
throw(error(instantiation_error, (',')/2))
|
||||
; '$call_with_default_policy'(','(G1, G2, B))
|
||||
).
|
||||
G1 -> G2 :- control_entry_point((G1 -> G2)).
|
||||
|
||||
|
||||
';'(G1, G2) :-
|
||||
'$get_b_value'(B),
|
||||
( '$call_with_default_policy'(var(G1)) ->
|
||||
throw(error(instantiation_error, (';')/2))
|
||||
; '$call_with_default_policy'(';'(G1, G2, B))
|
||||
).
|
||||
:- non_counted_backtracking staggered_if_then/2.
|
||||
|
||||
staggered_if_then(G1, G2) :-
|
||||
'$get_staggered_cp'(B),
|
||||
call('$call'(G1)),
|
||||
'$set_cp'(B),
|
||||
call('$call'(G2)).
|
||||
|
||||
G1 ; G2 :- control_entry_point((G1 ; G2)).
|
||||
|
||||
|
||||
G1 -> G2 :-
|
||||
'$get_b_value'(B),
|
||||
( '$call_with_default_policy'(var(G1)) ->
|
||||
throw(error(instantiation_error, (->)/2))
|
||||
; '$call_with_default_policy'(->(G1, G2, B))
|
||||
).
|
||||
:- non_counted_backtracking staggered_sc/2.
|
||||
|
||||
staggered_sc(G, _) :- call('$call'(G)).
|
||||
staggered_sc(_, G) :- call('$call'(G)).
|
||||
|
||||
|
||||
:-non_counted_backtracking call_or_cut/3.
|
||||
!.
|
||||
|
||||
call_or_cut(G, B, ErrorPI) :-
|
||||
( '$call_with_default_policy'(var(G)) ->
|
||||
throw(error(instantiation_error, ErrorPI))
|
||||
; '$call_with_default_policy'(call_or_cut(G, B))
|
||||
).
|
||||
:- non_counted_backtracking set_cp/1.
|
||||
|
||||
set_cp(B) :- '$set_cp'(B).
|
||||
|
||||
','(G1, G2) :- control_entry_point((G1, G2)).
|
||||
|
||||
:- non_counted_backtracking control_entry_point/1.
|
||||
|
||||
control_entry_point(G) :-
|
||||
functor(G, Name, Arity),
|
||||
catch(builtins:control_entry_point_(G),
|
||||
dispatch_prep_error,
|
||||
builtins:throw(error(type_error(callable, G), Name/Arity))).
|
||||
|
||||
|
||||
:- non_counted_backtracking control_functor/1.
|
||||
:- non_counted_backtracking control_entry_point_/1.
|
||||
|
||||
control_functor(_:G) :- nonvar(G), control_functor(G).
|
||||
control_functor(call(_:C)) :- C == !.
|
||||
control_functor(!).
|
||||
control_functor((_,_)).
|
||||
control_functor((_;_)).
|
||||
control_functor((_->_)).
|
||||
control_entry_point_(G) :-
|
||||
'$get_cp'(B),
|
||||
dispatch_prep(G,B,Conts),
|
||||
dispatch_call_list(Conts).
|
||||
|
||||
|
||||
:- non_counted_backtracking call_or_cut/2.
|
||||
:- non_counted_backtracking cont_list_to_goal/2.
|
||||
|
||||
call_or_cut(G, B) :-
|
||||
( nonvar(G),
|
||||
'$call_with_default_policy'(control_functor(G)) ->
|
||||
'$call_with_default_policy'(call_or_cut_interp(G, B))
|
||||
; call(G)
|
||||
).
|
||||
cont_list_goal([Cont], Cont) :- !.
|
||||
cont_list_goal(Conts, builtins:dispatch_call_list(Conts)).
|
||||
|
||||
|
||||
:- non_counted_backtracking call_or_cut_interp/2.
|
||||
:- non_counted_backtracking module_qualified_cut/1.
|
||||
|
||||
call_or_cut_interp(_ : G, B) :-
|
||||
call_or_cut_interp(G, B).
|
||||
call_or_cut_interp(call(_ : !), B) :-
|
||||
!. % '$set_cp'(B).
|
||||
call_or_cut_interp(!, B) :-
|
||||
'$set_cp'(B).
|
||||
call_or_cut_interp((G1, G2), B) :-
|
||||
'$call_with_default_policy'(','(G1, G2, B)).
|
||||
call_or_cut_interp((G1 ; G2), B) :-
|
||||
'$call_with_default_policy'(';'(G1, G2, B)).
|
||||
call_or_cut_interp((G1 -> G2), B) :-
|
||||
'$call_with_default_policy'(->(G1, G2, B)).
|
||||
module_qualified_cut(Gs) :-
|
||||
( functor(Gs, call, 1) ->
|
||||
arg(1, Gs, G1)
|
||||
; Gs = G1
|
||||
),
|
||||
functor(G1, (:), 2),
|
||||
arg(2, G1, G2),
|
||||
G2 == !.
|
||||
|
||||
|
||||
:- non_counted_backtracking (',')/3.
|
||||
:- non_counted_backtracking dispatch_prep/3.
|
||||
|
||||
','(G1, G2, B) :-
|
||||
( nonvar(G1),
|
||||
'$call_with_default_policy'(control_functor(G1)) ->
|
||||
'$call_with_default_policy'(call_or_cut_interp(G1, B)),
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
|
||||
; call(G1),
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (',')/2))
|
||||
).
|
||||
|
||||
:- non_counted_backtracking (;)/3.
|
||||
|
||||
';'(G1, G2, B) :-
|
||||
( nonvar(G1),
|
||||
'$call_with_default_policy'(control_functor(G1)) ->
|
||||
'$call_with_default_policy'(';-interp'(G1, G2, B))
|
||||
; call(G1)
|
||||
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking ';-interp'/3.
|
||||
|
||||
';-interp'((G1 -> G2), G3, B) :-
|
||||
!,
|
||||
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||
).
|
||||
';-interp'(_:(G1 -> G2), G3, B) :-
|
||||
!,
|
||||
( '$call_with_default_policy'(call_or_cut(G1, B, (->)/2)) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
; '$call_with_default_policy'(call_or_cut(G3, B, (;)/2))
|
||||
).
|
||||
';-interp'(G1, G2, B) :-
|
||||
( '$call_with_default_policy'(call_or_cut_interp(G1, B))
|
||||
; '$call_with_default_policy'(call_or_cut(G2, B, (;)/2))
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking (->)/3.
|
||||
|
||||
->(G1, G2, B) :-
|
||||
( nonvar(G1),
|
||||
'$call_with_default_policy'(control_functor(G1)) ->
|
||||
( '$call_with_default_policy'(call_or_cut_interp(G1, B)) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
dispatch_prep(Gs, B, [Cont|Conts]) :-
|
||||
( callable(Gs) ->
|
||||
( functor(Gs, ',', 2) ->
|
||||
arg(1, Gs, G1),
|
||||
arg(2, Gs, G2),
|
||||
dispatch_prep(G1, B, IConts1),
|
||||
cont_list_goal(IConts1, Cont),
|
||||
dispatch_prep(G2, B, Conts)
|
||||
; functor(Gs, ';', 2) ->
|
||||
arg(1, Gs, G1),
|
||||
arg(2, Gs, G2),
|
||||
dispatch_prep(G1, B, IConts0),
|
||||
dispatch_prep(G2, B, IConts1),
|
||||
cont_list_goal(IConts0, Cont0),
|
||||
cont_list_goal(IConts1, Cont1),
|
||||
Cont = builtins:staggered_sc(Cont0, Cont1),
|
||||
Conts = []
|
||||
; functor(Gs, ->, 2) ->
|
||||
arg(1, Gs, G1),
|
||||
arg(2, Gs, G2),
|
||||
dispatch_prep(G1, B, IConts1),
|
||||
dispatch_prep(G2, B, IConts2),
|
||||
cont_list_goal(IConts1, Cont1),
|
||||
cont_list_goal(IConts2, Cont2),
|
||||
Cont = builtins:staggered_if_then(Cont1, Cont2),
|
||||
Conts = []
|
||||
; ( Gs == ! ; module_qualified_cut(Gs) ) ->
|
||||
Cont = builtins:set_cp(B),
|
||||
Conts = []
|
||||
; Cont = Gs,
|
||||
Conts = []
|
||||
)
|
||||
; call(G1) ->
|
||||
'$call_with_default_policy'(call_or_cut(G2, B, (->)/2))
|
||||
; var(Gs) ->
|
||||
Cont = Gs,
|
||||
Conts = []
|
||||
; throw(dispatch_prep_error)
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking dispatch_call_list/1.
|
||||
|
||||
dispatch_call_list([]).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7,G8|Gs]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5),
|
||||
'$call'(G6),
|
||||
'$call'(G7),
|
||||
'$call'(G8),
|
||||
'$call_with_default_policy'(dispatch_call_list(Gs)).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5,G6,G7]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5),
|
||||
'$call'(G6),
|
||||
'$call'(G7).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5,G6]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5),
|
||||
'$call'(G6).
|
||||
dispatch_call_list([G1,G2,G3,G4,G5]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4),
|
||||
'$call'(G5).
|
||||
dispatch_call_list([G1,G2,G3,G4]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3),
|
||||
'$call'(G4).
|
||||
dispatch_call_list([G1,G2,G3]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2),
|
||||
'$call'(G3).
|
||||
dispatch_call_list([G1,G2]) :-
|
||||
!,
|
||||
'$call'(G1),
|
||||
'$call'(G2).
|
||||
dispatch_call_list([G1]) :-
|
||||
'$call'(G1).
|
||||
|
||||
|
||||
% univ.
|
||||
|
||||
:- non_counted_backtracking univ_errors/3.
|
||||
univ_errors(Term, List, N) :-
|
||||
'$skip_max_list'(N, -1, List, R),
|
||||
( var(R) ->
|
||||
( var(Term),
|
||||
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
||||
; true
|
||||
)
|
||||
'$skip_max_list'(N, _, List, R),
|
||||
( var(R) ->
|
||||
( var(Term),
|
||||
throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a)
|
||||
; true
|
||||
)
|
||||
; R \== [] ->
|
||||
throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b)
|
||||
; List = [H|T] ->
|
||||
@@ -388,9 +416,10 @@ univ_worker(Term, List, _) :-
|
||||
!,
|
||||
'$call_with_default_policy'(List = [Term]).
|
||||
univ_worker(Term, [Name|Args], N) :-
|
||||
var(Term), !,
|
||||
var(Term),
|
||||
!,
|
||||
'$call_with_default_policy'(Arity is N-1),
|
||||
'$call_with_default_policy'(functor(Term, Name, Arity)),
|
||||
'$call_with_default_policy'(functor(Term, Name, Arity)), % Term = {var}, Name = nonvar, Arity = 0.
|
||||
'$call_with_default_policy'(get_args(Args, Term, 1, Arity)).
|
||||
univ_worker(Term, List, _) :-
|
||||
'$call_with_default_policy'(functor(Term, Name, Arity)),
|
||||
@@ -415,7 +444,7 @@ get_args([Arg|Args], Func, I0, N) :-
|
||||
:- meta_predicate parse_options_list(?, 0, ?, ?, ?).
|
||||
|
||||
parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :-
|
||||
'$skip_max_list'(_, -1, Options, Tail),
|
||||
'$skip_max_list'(_, _, Options, Tail),
|
||||
( Tail == [] ->
|
||||
true
|
||||
; var(Tail) ->
|
||||
@@ -468,7 +497,7 @@ parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :-
|
||||
).
|
||||
|
||||
must_be_var_names_list(VarNames) :-
|
||||
'$skip_max_list'(_, -1, VarNames, Tail),
|
||||
'$skip_max_list'(_, _, VarNames, Tail),
|
||||
( Tail == [] ->
|
||||
must_be_var_names_list_(VarNames, VarNames)
|
||||
; var(Tail) ->
|
||||
@@ -565,7 +594,7 @@ can_be_list(List, _) :-
|
||||
var(List),
|
||||
!.
|
||||
can_be_list(List, _) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
'$skip_max_list'(_, _, List, Tail),
|
||||
( var(Tail) ->
|
||||
true
|
||||
; Tail == []
|
||||
@@ -620,9 +649,11 @@ throw(Ball) :-
|
||||
),
|
||||
'$unwind_stack'.
|
||||
|
||||
|
||||
:- non_counted_backtracking '$iterate_find_all'/4.
|
||||
|
||||
'$iterate_find_all'(Template, Goal, _, LhOffset) :-
|
||||
call(Goal),
|
||||
'$call'(Goal),
|
||||
'$copy_to_lh'(LhOffset, Template),
|
||||
'$fail'.
|
||||
'$iterate_find_all'(_, _, Solutions, LhOffset) :-
|
||||
@@ -636,7 +667,7 @@ truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength).
|
||||
:- meta_predicate findall(?, 0, ?).
|
||||
|
||||
findall(Template, Goal, Solutions) :-
|
||||
error:can_be(list, Solutions),
|
||||
'$call_with_default_policy'(error:can_be(list, Solutions)),
|
||||
'$lh_length'(LhLength),
|
||||
'$call_with_default_policy'(
|
||||
catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength),
|
||||
@@ -644,7 +675,6 @@ findall(Template, Goal, Solutions) :-
|
||||
( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))
|
||||
).
|
||||
|
||||
|
||||
:- non_counted_backtracking '$iterate_find_all_diff'/5.
|
||||
|
||||
'$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :-
|
||||
@@ -659,8 +689,8 @@ findall(Template, Goal, Solutions) :-
|
||||
:- meta_predicate findall(?, 0, ?, ?).
|
||||
|
||||
findall(Template, Goal, Solutions0, Solutions1) :-
|
||||
error:can_be(list, Solutions0),
|
||||
error:can_be(list, Solutions1),
|
||||
'$call_with_default_policy'(error:can_be(list, Solutions0)),
|
||||
'$call_with_default_policy'(error:can_be(list, Solutions1)),
|
||||
'$lh_length'(LhLength),
|
||||
'$call_with_default_policy'(
|
||||
catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0,
|
||||
@@ -679,9 +709,9 @@ set_difference([], _, []) :- !.
|
||||
set_difference(Xs, [], Xs).
|
||||
|
||||
group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :-
|
||||
iso_ext:variant(V1, V2),
|
||||
V1 = V2, % \+ \+ (V1 = V2), % (2) % iso_ext:variant(V1, V2), % (1)
|
||||
!,
|
||||
V1 = V2,
|
||||
% V1 = V2, % (3)
|
||||
group_by_variant(Pairs, V2-S2, Solutions, Pairs0).
|
||||
group_by_variant(Pairs, _, [], Pairs).
|
||||
|
||||
@@ -713,15 +743,15 @@ rightmost_power(Term, FinalTerm, Xs) :-
|
||||
|
||||
findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :-
|
||||
( nonvar(Goal),
|
||||
( Goal = _ ^ _
|
||||
; Goal = _ : (_ ^ _)
|
||||
) ->
|
||||
rightmost_power(Goal, Goal1, ExistentialVars0),
|
||||
loader:strip_module(Goal, M, Goal1),
|
||||
( Goal1 = _ ^ _ ) ->
|
||||
rightmost_power(Goal1, Goal2, ExistentialVars0),
|
||||
term_variables(ExistentialVars0, ExistentialVars),
|
||||
sort(Witnesses0, Witnesses1),
|
||||
sort(ExistentialVars, ExistentialVars1),
|
||||
set_difference(Witnesses1, ExistentialVars1, Witnesses),
|
||||
findall(Witnesses-Template, Goal1, PairedSolutions)
|
||||
expand_goal(M:Goal2, M, Goal3),
|
||||
findall(Witnesses-Template, Goal3, PairedSolutions)
|
||||
; Witnesses = Witnesses0,
|
||||
findall(Witnesses-Template, Goal, PairedSolutions)
|
||||
).
|
||||
@@ -779,11 +809,11 @@ setof(Template, Goal, Solution) :-
|
||||
( var(H) ->
|
||||
throw(error(instantiation_error, clause/2))
|
||||
; callable(H), functor(H, Name, Arity) ->
|
||||
( '$head_is_dynamic'(Module, H) ->
|
||||
( '$no_such_predicate'(Module, H) ->
|
||||
'$fail'
|
||||
; '$head_is_dynamic'(Module, H) ->
|
||||
'$clause_body_is_valid'(B),
|
||||
Module:'$clause'(H, B)
|
||||
; '$no_such_predicate'(Module, H) ->
|
||||
'$fail'
|
||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||
clause/2))
|
||||
)
|
||||
@@ -800,12 +830,11 @@ clause(H, B) :-
|
||||
arg(1, H, Module),
|
||||
arg(2, H, F),
|
||||
'$module_clause'(F, B, Module)
|
||||
; '$no_such_predicate'(user, H) ->
|
||||
'$fail'
|
||||
; '$head_is_dynamic'(user, H) ->
|
||||
'$clause_body_is_valid'(B),
|
||||
'$clause'(H, B)
|
||||
; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if
|
||||
%% H is not callable.
|
||||
'$fail'
|
||||
; throw(error(permission_error(access, private_procedure, Name/Arity),
|
||||
clause/2))
|
||||
)
|
||||
@@ -854,13 +883,14 @@ asserta_clause(Head, Body) :-
|
||||
|
||||
:- meta_predicate asserta(0).
|
||||
|
||||
asserta(Clause) :-
|
||||
asserta(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
Head = Clause,
|
||||
Body = true,
|
||||
asserta_clause(Head, Body)
|
||||
module_asserta_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
asserta_clause(Head, Body)
|
||||
module_asserta_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
module_assertz_clause(Head, Body, Module) :-
|
||||
@@ -909,13 +939,14 @@ assertz_clause(Head, Body) :-
|
||||
|
||||
:- meta_predicate assertz(0).
|
||||
|
||||
assertz(Clause) :-
|
||||
assertz(Clause0) :-
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
Head = Clause,
|
||||
Body = true,
|
||||
assertz_clause(Head, Body)
|
||||
module_assertz_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
assertz_clause(Head, Body)
|
||||
module_assertz_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
|
||||
@@ -999,13 +1030,14 @@ retract_clause(Head, Body) :-
|
||||
:- meta_predicate retract(0).
|
||||
|
||||
retract(Clause0) :-
|
||||
strip_module(Clause0, Module, Clause),
|
||||
( Clause = (Head :- Body) ->
|
||||
true
|
||||
; Head = Clause,
|
||||
Body = true
|
||||
),
|
||||
retract_clause(Module:Head, Body).
|
||||
loader:strip_module(Clause0, Module, Clause),
|
||||
( Clause \= (_ :- _) ->
|
||||
Head = Clause,
|
||||
Body = true,
|
||||
retract_module_clause(Head, Body, Module)
|
||||
; Clause = (Head :- Body) ->
|
||||
retract_module_clause(Head, Body, Module)
|
||||
).
|
||||
|
||||
|
||||
:- meta_predicate retractall(0).
|
||||
@@ -1022,8 +1054,10 @@ module_abolish(Pred, Module) :-
|
||||
; Pred = Name/Arity ->
|
||||
( var(Name) ->
|
||||
throw(error(instantiation_error, abolish/1))
|
||||
; var(Arity) ->
|
||||
throw(error(instantiation_error, abolish/1))
|
||||
; integer(Arity) ->
|
||||
( \+ atom(Name) ->
|
||||
(\+ atom(Name) ->
|
||||
throw(error(type_error(atom, Name), abolish/1))
|
||||
; Arity < 0 ->
|
||||
throw(error(domain_error(not_less_than_zero, Arity), abolish/1))
|
||||
@@ -1075,17 +1109,16 @@ abolish(Pred) :-
|
||||
; throw(error(type_error(predicate_indicator, Pred), abolish/1))
|
||||
).
|
||||
|
||||
'$iterate_db_refs'(Ref, Name/Arity) :-
|
||||
'$lookup_db_ref'(Ref, Name, Arity).
|
||||
'$iterate_db_refs'(Ref, Name/Arity) :-
|
||||
'$get_next_db_ref'(Ref, NextRef),
|
||||
'$iterate_db_refs'(NextRef, Name/Arity).
|
||||
|
||||
'$iterate_db_refs'(Name, Arity, Name/Arity). % :-
|
||||
% '$lookup_db_ref'(Ref, Name, Arity).
|
||||
'$iterate_db_refs'(RName, RArity, Name/Arity) :-
|
||||
'$get_next_db_ref'(RName, RArity, RRName, RRArity),
|
||||
'$iterate_db_refs'(RRName, RRArity, Name/Arity).
|
||||
|
||||
current_predicate(Pred) :-
|
||||
( var(Pred) ->
|
||||
'$get_next_db_ref'(Ref, _),
|
||||
'$iterate_db_refs'(Ref, Pred)
|
||||
'$get_next_db_ref'(RN, RA, _, _),
|
||||
'$iterate_db_refs'(RN, RA, Pred)
|
||||
; Pred \= _/_ ->
|
||||
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
|
||||
; Pred = Name/Arity,
|
||||
@@ -1094,15 +1127,14 @@ current_predicate(Pred) :-
|
||||
; integer(Arity), Arity < 0
|
||||
) ->
|
||||
throw(error(type_error(predicate_indicator, Pred), current_predicate/1))
|
||||
; '$get_next_db_ref'(Ref, _),
|
||||
'$iterate_db_refs'(Ref, Pred)
|
||||
; '$get_next_db_ref'(RN, RA, _, _),
|
||||
'$iterate_db_refs'(RN, RA, Pred)
|
||||
).
|
||||
|
||||
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
|
||||
'$lookup_op_db_ref'(Ref, Priority, Spec, Op).
|
||||
'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
|
||||
'$get_next_op_db_ref'(Ref, NextRef),
|
||||
'$iterate_op_db_refs'(NextRef, Priority, Spec, Op).
|
||||
'$iterate_op_db_refs'(RPriority, RSpec, ROp, _, RPriority, RSpec, ROp).
|
||||
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op) :-
|
||||
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, RRPriority, RRSpec, RROp),
|
||||
'$iterate_op_db_refs'(RRPriority, RRSpec, RROp, OssifiedOpDir, Priority, Spec, Op).
|
||||
|
||||
can_be_op_priority(Priority) :- var(Priority).
|
||||
can_be_op_priority(Priority) :- op_priority(Priority).
|
||||
@@ -1114,8 +1146,8 @@ current_op(Priority, Spec, Op) :-
|
||||
( can_be_op_priority(Priority),
|
||||
can_be_op_specifier(Spec),
|
||||
error:can_be(atom, Op) ->
|
||||
'$get_next_op_db_ref'(Ref, _),
|
||||
'$iterate_op_db_refs'(Ref, Priority, Spec, Op)
|
||||
'$get_next_op_db_ref'(RPriority, RSpec, ROp, OssifiedOpDir, _, _, Op),
|
||||
'$iterate_op_db_refs'(RPriority, RSpec, ROp, OssifiedOpDir, Priority, Spec, Op)
|
||||
).
|
||||
|
||||
list_of_op_atoms(Var) :-
|
||||
@@ -1209,7 +1241,7 @@ atom_length(Atom, Length) :-
|
||||
).
|
||||
|
||||
atom_chars(Atom, List) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
'$skip_max_list'(_, _, List, Tail),
|
||||
( ( Tail == [] ; var(Tail) ) ->
|
||||
true
|
||||
; throw(error(type_error(list, List), atom_chars/2))
|
||||
@@ -1227,7 +1259,7 @@ atom_chars(Atom, List) :-
|
||||
).
|
||||
|
||||
atom_codes(Atom, List) :-
|
||||
'$skip_max_list'(_, -1, List, Tail),
|
||||
'$skip_max_list'(_, _, List, Tail),
|
||||
( ( Tail == [] ; var(Tail) ) ->
|
||||
true
|
||||
; throw(error(type_error(list, List), atom_codes/2))
|
||||
@@ -1284,9 +1316,9 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :-
|
||||
; atom_chars(Atom, AtomChars),
|
||||
lists:append(BeforeChars, LengthAndAfterChars, AtomChars),
|
||||
lists:append(LengthChars, AfterChars, LengthAndAfterChars),
|
||||
'$skip_max_list'(Before, -1, BeforeChars, []),
|
||||
'$skip_max_list'(Length, -1, LengthChars, []),
|
||||
'$skip_max_list'(After, -1, AfterChars, []),
|
||||
'$skip_max_list'(Before, _, BeforeChars, []),
|
||||
'$skip_max_list'(Length, _, LengthChars, []),
|
||||
'$skip_max_list'(After, _, AfterChars, []),
|
||||
atom_chars(Sub_atom, LengthChars)
|
||||
).
|
||||
|
||||
@@ -1481,7 +1513,8 @@ open(SourceSink, Mode, Stream, StreamOptions) :-
|
||||
atom(SourceSink) ->
|
||||
atom_chars(SourceSink, SourceSinkString)
|
||||
; SourceSink = SourceSinkString
|
||||
), '$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||
),
|
||||
'$open'(SourceSinkString, Mode, Stream, Alias, EOFAction, Reposition, Type)
|
||||
)
|
||||
).
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
:- module(charsio, [char_type/2,
|
||||
chars_utf8bytes/2,
|
||||
get_single_char/1,
|
||||
read_n_chars/3,
|
||||
get_n_chars/3,
|
||||
read_line_to_chars/3,
|
||||
read_term_from_chars/2,
|
||||
read_from_chars/2,
|
||||
write_term_to_chars/3,
|
||||
chars_base64/3]).
|
||||
|
||||
@@ -113,18 +113,8 @@ get_single_char(C) :-
|
||||
).
|
||||
|
||||
|
||||
read_term_from_chars(Chars, Term) :-
|
||||
( var(Chars) ->
|
||||
instantiation_error(read_term_from_chars/2)
|
||||
; nonvar(Term) ->
|
||||
throw(error(uninstantiation_error(Term), read_term_from_chars/2))
|
||||
; '$skip_max_list'(_, -1, Chars, Chars0),
|
||||
Chars0 == [],
|
||||
partial_string(Chars) ->
|
||||
true
|
||||
;
|
||||
type_error(complete_string, Chars, read_term_from_chars/2)
|
||||
),
|
||||
read_from_chars(Chars, Term) :-
|
||||
must_be(chars, Chars),
|
||||
'$read_term_from_chars'(Chars, Term).
|
||||
|
||||
|
||||
@@ -205,7 +195,7 @@ read_line_to_chars(Stream, Cs0, Cs) :-
|
||||
characters read.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
read_n_chars(Stream, N, Cs) :-
|
||||
get_n_chars(Stream, N, Cs) :-
|
||||
can_be(integer, N),
|
||||
( var(N) ->
|
||||
read_to_eof(Stream, Cs),
|
||||
|
||||
@@ -6169,7 +6169,7 @@ distinct_goals_([flow_to(F,To)|Es], V) -->
|
||||
get_attr(To, lowlink, L2),
|
||||
L1 =\= L2 } ->
|
||||
{ get_attr(To, value, N) },
|
||||
[neq_num(V, N)]
|
||||
[clpz:neq_num(V, N)]
|
||||
; []
|
||||
),
|
||||
distinct_goals_(Es, V).
|
||||
@@ -6690,7 +6690,7 @@ gcc_edge_goal(arc_to(_,_,V,F), Val) -->
|
||||
get_attr(Val, lowlink, L2),
|
||||
L1 =\= L2,
|
||||
get_attr(Val, value, Value) } ->
|
||||
[neq_num(V, Value)]
|
||||
[clpz:neq_num(V, Value)]
|
||||
; []
|
||||
).
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
|
||||
Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
Predicates for cryptographic applications.
|
||||
@@ -46,6 +46,7 @@
|
||||
:- use_module(library(format)).
|
||||
:- use_module(library(charsio)).
|
||||
:- use_module(library(si)).
|
||||
:- use_module(library(iso_ext), [partial_string/3]).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
hex_bytes(?Hex, ?Bytes) is det.
|
||||
@@ -594,7 +595,9 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||
member(Encoding, [utf8,octet]),
|
||||
encoding_chars(octet, CipherText0, CipherText1),
|
||||
maplist(char_code, TagChars, Tag),
|
||||
append(CipherText1, TagChars, CipherText),
|
||||
% we append the tag very efficiently, retaining a compact
|
||||
% internal string representation of the ciphertext
|
||||
partial_string(CipherText1, CipherText, TagChars),
|
||||
( Algorithm = 'chacha20-poly1305' -> true
|
||||
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
|
||||
),
|
||||
|
||||
181
src/lib/dcgs.pl
181
src/lib/dcgs.pl
@@ -1,16 +1,26 @@
|
||||
:- module(dcgs,
|
||||
[op(1105, xfy, '|'),
|
||||
phrase/2,
|
||||
phrase/3,
|
||||
seq//1,
|
||||
seqq//1,
|
||||
... //0
|
||||
]).
|
||||
phrase/2,
|
||||
phrase/3,
|
||||
seq//1,
|
||||
seqq//1,
|
||||
... //0
|
||||
]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(lists), [append/3]).
|
||||
:- use_module(library(lists), [append/3, member/2]).
|
||||
:- use_module(library(loader), [strip_module/3]).
|
||||
|
||||
load_context(GRBody, Module, GRBody0) :-
|
||||
strip_module(GRBody, Module, GRBody0),
|
||||
( nonvar(Module) ->
|
||||
true
|
||||
; prolog_load_context(module, Module) ->
|
||||
true
|
||||
; true
|
||||
).
|
||||
|
||||
|
||||
:- meta_predicate phrase(2, ?).
|
||||
|
||||
:- meta_predicate phrase(2, ?, ?).
|
||||
@@ -18,100 +28,44 @@
|
||||
phrase(GRBody, S0) :-
|
||||
phrase(GRBody, S0, []).
|
||||
|
||||
|
||||
phrase(GRBody, S0, S) :-
|
||||
( var(GRBody) ->
|
||||
throw(error(instantiation_error, phrase/3))
|
||||
; strip_module(GRBody, Module, GRBody0),
|
||||
dcg_constr(GRBody0) ->
|
||||
( var(Module) ->
|
||||
phrase_(GRBody0, S0, S)
|
||||
; phrase_(Module:GRBody0, S0, S)
|
||||
)
|
||||
; functor(GRBody, _, _) ->
|
||||
call(GRBody, S0, S)
|
||||
; throw(error(type_error(callable, GRBody), phrase/3))
|
||||
load_context(GRBody, Module, GRBody0),
|
||||
( var(GRBody0) ->
|
||||
instantiation_error(phrase/3)
|
||||
; dcg_body(GRBody0, S0, S, GRBody1, Module) ->
|
||||
call(GRBody1)
|
||||
; type_error(callable, GRBody0, phrase/3)
|
||||
).
|
||||
|
||||
phrase_([], S, S).
|
||||
phrase_(!, S, S).
|
||||
phrase_(_:[], S, S) :- !.
|
||||
phrase_(_:!, S, S) :- !.
|
||||
phrase_((A, B), S0, S) :-
|
||||
phrase(A, S0, S1), phrase(B, S1, S).
|
||||
phrase_(M:(A, B), S0, S) :-
|
||||
!,
|
||||
phrase(M:A, S0, S1), phrase(M:B, S1, S).
|
||||
phrase_((A -> B ; C), S0, S) :-
|
||||
!,
|
||||
( phrase(A, S0, S1) ->
|
||||
phrase(B, S1, S)
|
||||
; phrase(C, S0, S)
|
||||
|
||||
module_call_qualified(M, Call, Call1) :-
|
||||
( nonvar(M) -> Call1 = M:Call
|
||||
; Call = Call1
|
||||
).
|
||||
phrase_(M:(A -> B ; C), S0, S) :-
|
||||
!,
|
||||
( phrase(M:A, S0, S1) ->
|
||||
phrase(M:B, S1, S)
|
||||
; phrase(M:C, S0, S)
|
||||
).
|
||||
phrase_((A ; B), S0, S) :-
|
||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
phrase_(M:(A ; B), S0, S) :-
|
||||
!,
|
||||
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
|
||||
phrase_((A | B), S0, S) :-
|
||||
( phrase(A, S0, S) ; phrase(B, S0, S) ).
|
||||
phrase_(M:(A | B), S0, S) :-
|
||||
!,
|
||||
( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ).
|
||||
phrase_({G}, S0, S) :-
|
||||
( call(G), S0 = S ).
|
||||
phrase_(M:{G}, S0, S) :-
|
||||
!,
|
||||
( call(M:G), S0 = S ).
|
||||
phrase_(call(G), S0, S) :-
|
||||
call(G, S0, S).
|
||||
phrase_(M:call(G), S0, S) :-
|
||||
!,
|
||||
call(M:G, S0, S).
|
||||
phrase_((A -> B), S0, S) :-
|
||||
phrase((A -> B ; fail), S0, S).
|
||||
phrase_(M:(A -> B), S0, S) :-
|
||||
!,
|
||||
phrase((M:A -> M:B ; fail), S0, S).
|
||||
phrase_(phrase(NonTerminal), S0, S) :-
|
||||
phrase(NonTerminal, S0, S).
|
||||
phrase_(M:phrase(NonTerminal), S0, S) :-
|
||||
!,
|
||||
phrase(M:NonTerminal, S0, S).
|
||||
phrase_([T|Ts], S0, S) :-
|
||||
append([T|Ts], S, S0).
|
||||
phrase_(_:[T|Ts], S0, S) :-
|
||||
append([T|Ts], S, S0).
|
||||
|
||||
|
||||
% The same version of the below two dcg_rule clauses, but with module scoping.
|
||||
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S1, Goal1),
|
||||
dcg_body(GRBody, S0, S1, Goal1, _),
|
||||
dcg_terminals(Terminals, S, S1, Goal2),
|
||||
Body = ( Goal1, Goal2 ).
|
||||
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
|
||||
NonTerminal \= ( _, _ ),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S, Body).
|
||||
dcg_body(GRBody, S0, S, Body, _).
|
||||
|
||||
% This program uses append/3 as defined in the Prolog prologue.
|
||||
% Expands a DCG rule into a Prolog rule, when no error condition applies.
|
||||
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S1, Goal1),
|
||||
dcg_body(GRBody, S0, S1, Goal1, _),
|
||||
dcg_terminals(Terminals, S, S1, Goal2),
|
||||
Body = ( Goal1, Goal2 ).
|
||||
dcg_rule(( NonTerminal --> GRBody ), ( Head :- Body )) :-
|
||||
NonTerminal \= ( _, _ ),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Head),
|
||||
dcg_body(GRBody, S0, S, Body).
|
||||
dcg_body(GRBody, S0, S, Body, _).
|
||||
|
||||
dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||
NonTerminal =.. NonTerminalUniv,
|
||||
@@ -121,18 +75,20 @@ dcg_non_terminal(NonTerminal, S0, S, Goal) :-
|
||||
dcg_terminals(Terminals, S0, S, S0 = List) :-
|
||||
append(Terminals, S, List).
|
||||
|
||||
dcg_body(Var, S0, S, Body) :-
|
||||
dcg_body(Var, S0, S, Body, M) :-
|
||||
var(Var),
|
||||
Body = phrase(Var, S0, S).
|
||||
dcg_body(GRBody, S0, S, Body) :-
|
||||
module_call_qualified(M, Var, Var1),
|
||||
Body = phrase(Var1, S0, S).
|
||||
dcg_body(GRBody, S0, S, Body, M) :-
|
||||
nonvar(GRBody),
|
||||
dcg_constr(GRBody),
|
||||
dcg_cbody(GRBody, S0, S, Body).
|
||||
dcg_body(NonTerminal, S0, S, Goal) :-
|
||||
dcg_cbody(GRBody, S0, S, Body, M).
|
||||
dcg_body(NonTerminal, S0, S, Goal1, M) :-
|
||||
nonvar(NonTerminal),
|
||||
\+ dcg_constr(NonTerminal),
|
||||
NonTerminal \= ( _ -> _ ),
|
||||
NonTerminal \= ( \+ _ ),
|
||||
module_call_qualified(M, Goal, Goal1),
|
||||
dcg_non_terminal(NonTerminal, S0, S, Goal).
|
||||
|
||||
% The following constructs in a grammar rule body
|
||||
@@ -151,37 +107,40 @@ dcg_constr((_->_)). % 7.14.12 - if-then (existence implementation dep.)
|
||||
|
||||
% The principal functor of the first argument indicates
|
||||
% the construct to be expanded.
|
||||
dcg_cbody([], S0, S, S0 = S).
|
||||
dcg_cbody([T|Ts], S0, S, Goal) :-
|
||||
dcg_cbody([], S0, S, S0 = S, _M).
|
||||
dcg_cbody([T|Ts], S0, S, Goal, _M) :-
|
||||
must_be(list, [T|Ts]),
|
||||
dcg_terminals([T|Ts], S0, S, Goal).
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second )) :-
|
||||
dcg_body(GRFirst, S0, S1, First),
|
||||
dcg_body(GRSecond, S1, S, Second).
|
||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or )) :-
|
||||
dcg_cbody(( GRFirst, GRSecond ), S0, S, ( First, Second ), M) :-
|
||||
dcg_body(GRFirst, S0, S1, First, M),
|
||||
dcg_body(GRSecond, S1, S, Second, M).
|
||||
dcg_cbody(( GREither ; GROr ), S0, S, ( Either ; Or ), M) :-
|
||||
\+ subsumes_term(( _ -> _ ), GREither),
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else )) :-
|
||||
dcg_body(GREither, S0, S, Either, M),
|
||||
dcg_body(GROr, S0, S, Or, M).
|
||||
dcg_cbody(( GRCond ; GRElse ), S0, S, ( Cond ; Else ), M) :-
|
||||
subsumes_term(( _GRIf -> _GRThen ), GRCond),
|
||||
dcg_cbody(GRCond, S0, S, Cond),
|
||||
dcg_body(GRElse, S0, S, Else).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or )) :-
|
||||
dcg_body(GREither, S0, S, Either),
|
||||
dcg_body(GROr, S0, S, Or).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal, S0 = S )).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont, S0, S)).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body, S0, S)).
|
||||
dcg_cbody(!, S0, S, ( !, S0 = S )).
|
||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody,S0,_), S0 = S )).
|
||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then )) :-
|
||||
dcg_body(GRIf, S0, S1, If),
|
||||
dcg_body(GRThen, S1, S, Then).
|
||||
dcg_cbody(GRCond, S0, S, Cond, M),
|
||||
dcg_body(GRElse, S0, S, Else, M).
|
||||
dcg_cbody(( GREither '|' GROr ), S0, S, ( Either ; Or ), M) :-
|
||||
dcg_body(GREither, S0, S, Either, M),
|
||||
dcg_body(GROr, S0, S, Or, M).
|
||||
dcg_cbody({Goal}, S0, S, ( Goal1, S0 = S ), M) :-
|
||||
module_call_qualified(M, Goal, Goal1).
|
||||
dcg_cbody(call(Cont), S0, S, call(Cont1, S0, S), M) :-
|
||||
module_call_qualified(M, Cont, Cont1).
|
||||
dcg_cbody(phrase(Body), S0, S, phrase(Body1, S0, S), M) :-
|
||||
module_call_qualified(M, Body, Body1).
|
||||
dcg_cbody(!, S0, S, ( !, S0 = S ), _M).
|
||||
dcg_cbody(\+ GRBody, S0, S, ( \+ phrase(GRBody1,S0,_), S0 = S ), M) :-
|
||||
module_call_qualified(M, GRBody, GRBody1).
|
||||
dcg_cbody(( GRIf -> GRThen ), S0, S, ( If -> Then ), M) :-
|
||||
dcg_body(GRIf, S0, S1, If, M),
|
||||
dcg_body(GRThen, S1, S, Then, M).
|
||||
|
||||
user:term_expansion(Term0, Term) :-
|
||||
nonvar(Term0),
|
||||
dcg_rule(Term0, (Head :- Body)),
|
||||
Term = (Head :- Body).
|
||||
dcg_rule(Term0, Term).
|
||||
|
||||
% Describes a sequence
|
||||
seq([]) --> [].
|
||||
@@ -193,3 +152,13 @@ seqq([Es|Ess]) --> seq(Es), seqq(Ess).
|
||||
|
||||
% Describes an arbitrary number of elements
|
||||
... --> [] | [_], ... .
|
||||
|
||||
user:goal_expansion(phrase(GRBody, S, S0), GRBody1) :-
|
||||
load_context(GRBody, M, GRBody0),
|
||||
nonvar(GRBody0),
|
||||
catch(dcgs:dcg_body(GRBody0, S, S0, GRBody1, M),
|
||||
error(E, must_be/2),
|
||||
( GRBody1 = throw(error(E, must_be/2)) )
|
||||
).
|
||||
|
||||
user:goal_expansion(phrase(GRBody, S), phrase(GRBody, S, [])).
|
||||
|
||||
@@ -80,7 +80,7 @@ character(C) :-
|
||||
atom_length(C, 1).
|
||||
|
||||
ilist(Ls) :-
|
||||
'$skip_max_list'(_, -1, Ls, Rs),
|
||||
'$skip_max_list'(_, _, Ls, Rs),
|
||||
( var(Rs) ->
|
||||
instantiation_error(must_be/2)
|
||||
; Rs == []
|
||||
@@ -124,7 +124,7 @@ can_(list, Term) :- list_or_partial_list(Term).
|
||||
can_(boolean, Term) :- boolean(Term).
|
||||
|
||||
list_or_partial_list(Ls) :-
|
||||
'$skip_max_list'(_, -1, Ls, Rs),
|
||||
'$skip_max_list'(_, _, Ls, Rs),
|
||||
( var(Rs) -> true
|
||||
; Rs == []
|
||||
).
|
||||
|
||||
@@ -174,7 +174,7 @@ file_creation_time(File, T) :-
|
||||
file_time_(File, Which, T) :-
|
||||
file_must_exist(File, file_time_/3),
|
||||
'$file_time'(File, Which, T0),
|
||||
read_term_from_chars(T0, T).
|
||||
read_from_chars(T0, T).
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written 2020, 2021 by Markus Triska (triska@metalevel.at)
|
||||
Written 2020, 2021, 2022 by Markus Triska (triska@metalevel.at)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
This library provides the nonterminal format_//2 to describe
|
||||
@@ -28,6 +28,9 @@
|
||||
if N is 0 or omitted, no decimal point is used.
|
||||
~ND like ~Nd, separating digits to the left of the decimal point
|
||||
in groups of three, using the character "," (comma)
|
||||
~NU like ~ND, using "_" (underscore) to separate groups of digits
|
||||
~NL format an integer so that at most N digits appear on a line.
|
||||
If N is 0 or omitted, it defaults to 72.
|
||||
~Nr where N is an integer between 2 and 36: format the
|
||||
next argument, which must be an integer, in radix N.
|
||||
The characters "a" to "z" are used for radices 10 to 36.
|
||||
@@ -200,14 +203,22 @@ cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
{ numeric_argument(Fs0, Num, ['D'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ number_chars(Num, NCs),
|
||||
phrase(("~",seq(NCs),"d"), FStr),
|
||||
phrase(format_(FStr, [Arg]), Cs0),
|
||||
phrase(upto_what(Bs0, .), Cs0, Ds),
|
||||
reverse(Bs0, Bs1),
|
||||
phrase(groups_of_three(Bs1), Bs2),
|
||||
reverse(Bs2, Bs),
|
||||
append(Bs, Ds, Cs) },
|
||||
{ separate_digits_fractional(Arg, ',', Num, Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
{ numeric_argument(Fs0, Num, ['U'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ separate_digits_fractional(Arg, '_', Num, Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||
cells([~|Fs0], Args0, Tab, Es, VNs) -->
|
||||
{ numeric_argument(Fs0, Num0, ['L'|Fs], Args0, [Arg|Args]) },
|
||||
!,
|
||||
{ ( Num0 =:= 0 ->
|
||||
Num = 72
|
||||
; Num = Num0
|
||||
),
|
||||
phrase(format_("~d", [Arg]), Cs0),
|
||||
phrase(split_lines_width(Cs0, Num), Cs) },
|
||||
cells(Fs, Args, Tab, [chars(Cs)|Es], VNs).
|
||||
cells([~,i|Fs], [_|Args], Tab, Es, VNs) --> !,
|
||||
cells(Fs, Args, Tab, Es, VNs).
|
||||
@@ -312,12 +323,30 @@ Cs = [a,b,c], Rest = [~,t,e,s,t].
|
||||
Cs = [a,b,c], Rest = [].
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
separate_digits_fractional(Arg, Sep, Num, Cs) :-
|
||||
number_chars(Num, NCs),
|
||||
phrase(("~",seq(NCs),"d"), FStr),
|
||||
phrase(format_(FStr, [Arg]), Cs0),
|
||||
phrase(upto_what(Bs0, .), Cs0, Ds),
|
||||
reverse(Bs0, Bs1),
|
||||
phrase(groups_of_three(Bs1,Sep), Bs2),
|
||||
reverse(Bs2, Bs),
|
||||
append(Bs, Ds, Cs).
|
||||
|
||||
upto_what([], W), [W] --> [W], !.
|
||||
upto_what([C|Cs], W) --> [C], !, upto_what(Cs, W).
|
||||
upto_what([], _) --> [].
|
||||
|
||||
groups_of_three([A,B,C,D|Rs]) --> !, [A,B,C], ",", groups_of_three([D|Rs]).
|
||||
groups_of_three(Ls) --> seq(Ls).
|
||||
groups_of_three([A,B,C,D|Rs], Sep) --> !, [A,B,C,Sep], groups_of_three([D|Rs], Sep).
|
||||
groups_of_three(Ls, _) --> seq(Ls).
|
||||
|
||||
split_lines_width(Cs, Num) -->
|
||||
( { length(Prefix, Num),
|
||||
append(Prefix, [R|Rs], Cs) } ->
|
||||
seq(Prefix), "_\n",
|
||||
split_lines_width([R|Rs], Num)
|
||||
; seq(Cs)
|
||||
).
|
||||
|
||||
cell(From, To, Es0) -->
|
||||
( { Es0 == [] } -> []
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
partial_string_tail/2,
|
||||
setup_call_cleanup/3,
|
||||
call_nth/2,
|
||||
variant/2,
|
||||
% variant/2,
|
||||
copy_term_nat/2]).
|
||||
|
||||
:- use_module(library(error), [can_be/2,
|
||||
@@ -22,10 +22,7 @@
|
||||
instantiation_error/1,
|
||||
type_error/3]).
|
||||
|
||||
|
||||
:- meta_predicate(call_cleanup(0, 0)).
|
||||
|
||||
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
|
||||
:- use_module(library(lists), [maplist/3]).
|
||||
|
||||
:- meta_predicate(forall(0, 0)).
|
||||
|
||||
@@ -55,14 +52,17 @@ bb_get(Key, Value) :-
|
||||
).
|
||||
|
||||
|
||||
% setup_call_cleanup.
|
||||
|
||||
:- meta_predicate(call_cleanup(0, 0)).
|
||||
|
||||
call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
|
||||
|
||||
|
||||
% setup_call_cleanup.
|
||||
:- meta_predicate(setup_call_cleanup(0, 0, 0)).
|
||||
|
||||
setup_call_cleanup(S, G, C) :-
|
||||
'$get_b_value'(B),
|
||||
call(S),
|
||||
'$call'(S),
|
||||
'$set_cp_by_default'(B),
|
||||
'$get_current_block'(Bb),
|
||||
( C = _:CC,
|
||||
@@ -71,6 +71,8 @@ setup_call_cleanup(S, G, C) :-
|
||||
; '$call_with_default_policy'(scc_helper(C, G, Bb))
|
||||
).
|
||||
|
||||
:- meta_predicate(scc_helper(?,0,?)).
|
||||
|
||||
:- non_counted_backtracking scc_helper/3.
|
||||
scc_helper(C, G, Bb) :-
|
||||
'$get_cp'(Cp),
|
||||
@@ -96,7 +98,8 @@ scc_helper(_, _, _) :-
|
||||
|
||||
:- non_counted_backtracking run_cleaners_with_handling/0.
|
||||
run_cleaners_with_handling :-
|
||||
'$get_scc_cleaner'(C), '$get_level'(B),
|
||||
'$get_scc_cleaner'(C),
|
||||
'$get_level'(B),
|
||||
'$call_with_default_policy'(catch(C, _, true)),
|
||||
'$set_cp_by_default'(B),
|
||||
'$call_with_default_policy'(run_cleaners_with_handling).
|
||||
@@ -134,16 +137,31 @@ handle_ile(B, E, _) :-
|
||||
:- meta_predicate(call_with_inference_limit(0, ?, ?)).
|
||||
|
||||
call_with_inference_limit(G, L, R) :-
|
||||
( integer(L) ->
|
||||
( L < 0 ->
|
||||
domain_error(not_less_than_zero, L, call_with_inference_limit/3)
|
||||
; true
|
||||
)
|
||||
; var(L) ->
|
||||
instantiation_error(call_with_inference_limit/3)
|
||||
; type_error(integer, L, call_with_inference_limit/3)
|
||||
),
|
||||
'$get_current_block'(Bb),
|
||||
'$get_b_value'(B),
|
||||
'$call_with_default_policy'(call_with_inference_limit(G, L, R, Bb, B)),
|
||||
'$remove_call_policy_check'(B).
|
||||
|
||||
install_inference_counter(B, L, Count0) :-
|
||||
'$install_inference_counter'(B, L, Count0).
|
||||
|
||||
:- meta_predicate(call_with_inference_limit(0,?,?,?,?)).
|
||||
|
||||
:- non_counted_backtracking call_with_inference_limit/5.
|
||||
|
||||
call_with_inference_limit(G, L, R, Bb, B) :-
|
||||
'$install_new_block'(NBb),
|
||||
'$install_inference_counter'(B, L, Count0),
|
||||
call(G),
|
||||
'$call'(G),
|
||||
'$inference_level'(R, B),
|
||||
'$remove_inference_counter'(B, Count1),
|
||||
'$call_with_default_policy'(is(Diff, L - (Count1 - Count0))),
|
||||
@@ -160,14 +178,12 @@ call_with_inference_limit(_, _, R, Bb, B) :-
|
||||
'$erase_ball',
|
||||
'$call_with_default_policy'(handle_ile(B, Ball, R)).
|
||||
|
||||
variant(X, Y) :- '$variant'(X, Y).
|
||||
|
||||
partial_string(String, L, L0) :-
|
||||
( String == [] ->
|
||||
L = L0
|
||||
; catch(atom_chars(Atom, String),
|
||||
error(E, _),
|
||||
throw(error(E, partial_string/3))),
|
||||
error(E, _),
|
||||
throw(error(E, partial_string/3))),
|
||||
'$create_partial_string'(Atom, L, L0)
|
||||
).
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
maplist/3, maplist/4, maplist/5, maplist/6,
|
||||
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
|
||||
sum_list/2, transpose/2, list_to_set/2, list_max/2,
|
||||
list_min/2, permutation/2]).
|
||||
list_min/2, permutation/2]).
|
||||
|
||||
/* Author: Mark Thom, Jan Wielemaker, and Richard O'Keefe
|
||||
Copyright (c) 2018-2021, Mark Thom
|
||||
@@ -50,24 +50,20 @@
|
||||
:- meta_predicate foldl(3, ?, ?, ?).
|
||||
:- meta_predicate foldl(4, ?, ?, ?, ?).
|
||||
|
||||
|
||||
length(Xs, N) :-
|
||||
var(N),
|
||||
!,
|
||||
'$skip_max_list'(M, -1, Xs, Xs0),
|
||||
( Xs0 == [] -> N = M
|
||||
; var(Xs0) -> length_addendum(Xs0, N, M)).
|
||||
length(Xs, N) :-
|
||||
integer(N),
|
||||
N >= 0, !,
|
||||
'$skip_max_list'(M, N, Xs, Xs0),
|
||||
( Xs0 == [] -> N = M
|
||||
; var(Xs0) -> R is N-M, length_rundown(Xs0, R)).
|
||||
length(Xs0, N) :-
|
||||
'$skip_max_list'(M, N, Xs0,Xs),
|
||||
!,
|
||||
( Xs == [] -> N = M
|
||||
; nonvar(Xs) -> var(N), Xs = [_|_], throw(error(resource_error(finite_memory),length/2))
|
||||
; nonvar(N) -> R is N-M, length_rundown(Xs, R)
|
||||
; N == Xs -> throw(error(resource_error(finite_memory),length/2))
|
||||
; length_addendum(Xs, N, M)
|
||||
).
|
||||
length(_, N) :-
|
||||
integer(N), !,
|
||||
domain_error(not_less_than_zero, N, length/2).
|
||||
integer(N), !,
|
||||
domain_error(not_less_than_zero, N, length/2).
|
||||
length(_, N) :-
|
||||
type_error(integer, N, length/2).
|
||||
type_error(integer, N, length/2).
|
||||
|
||||
length_addendum([], N, N).
|
||||
length_addendum([_|Xs], N, M) :-
|
||||
@@ -285,8 +281,8 @@ list_min_(N, Min0, Min) :-
|
||||
% or partial list.
|
||||
|
||||
permutation(Xs, Ys) :-
|
||||
'$skip_max_list'(Xlen, -1, Xs, XTail),
|
||||
'$skip_max_list'(Ylen, -1, Ys, YTail),
|
||||
'$skip_max_list'(Xlen, _, Xs, XTail),
|
||||
'$skip_max_list'(Ylen, _, Ys, YTail),
|
||||
( XTail == [], YTail == [] % both proper lists
|
||||
-> Xlen == Ylen
|
||||
; var(XTail), YTail == [] % partial, proper
|
||||
|
||||
@@ -89,7 +89,7 @@ because the order it relies on may have been changed.
|
||||
% setof/3.
|
||||
|
||||
is_ordset(Term) :-
|
||||
'$skip_max_list'(_, -1, Term, Tail), Tail == [], %% is_list(Term),
|
||||
'$skip_max_list'(_, _, Term, Tail), Tail == [], %% is_list(Term),
|
||||
is_ordset2(Term).
|
||||
|
||||
is_ordset2([]).
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
:- use_module(library(freeze)).
|
||||
:- use_module(library(iso_ext), [setup_call_cleanup/3, partial_string/3]).
|
||||
:- use_module(library(lists), [member/2, maplist/2]).
|
||||
:- use_module(library(charsio), [read_n_chars/3]).
|
||||
:- use_module(library(charsio), [get_n_chars/3]).
|
||||
|
||||
:- meta_predicate(phrase_from_file(2, ?)).
|
||||
:- meta_predicate(phrase_from_file(2, ?, ?)).
|
||||
@@ -62,7 +62,7 @@ reader_step(Stream, Pos, Xs0) :-
|
||||
set_stream_position(Stream, Pos),
|
||||
( at_end_of_stream(Stream)
|
||||
-> Xs0 = []
|
||||
; read_n_chars(Stream, 4096, Cs),
|
||||
; get_n_chars(Stream, 4096, Cs),
|
||||
partial_string(Cs, Xs0, Xs),
|
||||
stream_to_lazy_list(Stream, Xs)
|
||||
).
|
||||
|
||||
@@ -22,11 +22,11 @@ random(R) :-
|
||||
random_integer(Lower, Upper, R) :-
|
||||
var(R),
|
||||
( (var(Lower) ; var(Upper)) ->
|
||||
instantiation_error(random_integer/3)
|
||||
instantiation_error(random_integer/3)
|
||||
; \+ integer(Lower) ->
|
||||
domain_error(integer, Lower, random_integer/3)
|
||||
type_error(integer, Lower, random_integer/3)
|
||||
; \+ integer(Upper) ->
|
||||
domain_error(integer, Upper, random_integer/3)
|
||||
type_error(integer, Upper, random_integer/3)
|
||||
; Upper > Lower,
|
||||
random(R0),
|
||||
R is floor((Upper - Lower) * R0 + Lower)
|
||||
|
||||
@@ -79,5 +79,6 @@ tmember(P_2, [X|Xs]) :-
|
||||
|
||||
:- meta_predicate(tmember_t(2, ?, ?)).
|
||||
|
||||
tmember_t(_P_2, [], false).
|
||||
tmember_t(P_2, [X|Xs], T) :-
|
||||
if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ).
|
||||
|
||||
@@ -9,26 +9,26 @@
|
||||
syntaxes. The DCGs are presented in the order they appear in the RFC.
|
||||
While some DCGs below use `char_type/2`, the most common ones are defined
|
||||
manually in order to take advantage of Prolog's first-argument indexing.
|
||||
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
|
||||
Copyright (c) 2021, Aram Panasenco
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Written Apr 2021 by Aram Panasenco (panasenco@ucla.edu)
|
||||
Part of Scryer Prolog.
|
||||
|
||||
|
||||
`json_chars//1` can be used with [`phrase_from_file/2`](src/lib/pio.pl)
|
||||
or [`phrase/2`](src/lib/dcgs.pl) to parse and generate [JSON](https://www.json.org/json-en.html).
|
||||
|
||||
|
||||
BSD 3-Clause License
|
||||
|
||||
|
||||
Copyright (c) 2021, Aram Panasenco
|
||||
All rights reserved.
|
||||
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
@@ -44,7 +44,7 @@
|
||||
:- use_module(library(dif)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
|
||||
/* The DCGs are written to match the McKeeman form presented on the right side of https://www.json.org/json-en.html
|
||||
as closely as possible. Note that the names in the McKeeman form conflict with the pictures on the site. */
|
||||
json_chars(Internal) --> json_element(Internal).
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(pio)).
|
||||
:- use_module(library(charsio)).
|
||||
|
||||
load_html(Source, Es, Options) :-
|
||||
load_structure_(Source, Es, Options, html).
|
||||
@@ -75,15 +76,8 @@ load_structure_(file(Fs), [E], Options, What) :-
|
||||
load_(What, Cs, E, Options).
|
||||
load_structure_(stream(Stream), [E], Options, What) :-
|
||||
must_be(list, Options),
|
||||
read_to_end(Stream, Cs),
|
||||
get_n_chars(Stream, _, Cs),
|
||||
load_(What, Cs, E, Options).
|
||||
|
||||
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
|
||||
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
|
||||
|
||||
read_to_end(Stream, Cs) :-
|
||||
'$get_n_chars'(Stream, 4096, Cs0),
|
||||
( Cs0 = [] -> Cs = []
|
||||
; partial_string(Cs0, Cs, Rest),
|
||||
read_to_end(Stream, Rest)
|
||||
).
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
trie_get_all_values/2 % +Trie, -Value
|
||||
]).
|
||||
|
||||
:- use_module(library(format)).
|
||||
|
||||
:- use_module(library(assoc)).
|
||||
:- use_module(library(atts)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
@@ -49,11 +49,11 @@
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(charsio), [read_term_from_chars/2]).
|
||||
:- use_module(library(charsio), [read_from_chars/2]).
|
||||
|
||||
current_time(T) :-
|
||||
'$current_time'(T0),
|
||||
read_term_from_chars(T0, T).
|
||||
read_from_chars(T0, T).
|
||||
|
||||
format_time([], _) --> [].
|
||||
format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T).
|
||||
|
||||
630
src/lib/ugraphs.pl
Normal file
630
src/lib/ugraphs.pl
Normal file
@@ -0,0 +1,630 @@
|
||||
/* Author: R.A.O'Keefe, Vitor Santos Costa, Jan Wielemaker
|
||||
E-mail: J.Wielemaker@vu.nl
|
||||
WWW: http://www.swi-prolog.org
|
||||
Copyright (c) 1984-2021, VU University Amsterdam
|
||||
CWI, Amsterdam
|
||||
SWI-Prolog Solutions .b.v
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
:- module(ugraphs,
|
||||
[ add_edges/3, % +Graph, +Edges, -NewGraph
|
||||
add_vertices/3, % +Graph, +Vertices, -NewGraph
|
||||
complement/2, % +Graph, -NewGraph
|
||||
compose/3, % +LeftGraph, +RightGraph, -NewGraph
|
||||
del_edges/3, % +Graph, +Edges, -NewGraph
|
||||
del_vertices/3, % +Graph, +Vertices, -NewGraph
|
||||
edges/2, % +Graph, -Edges
|
||||
neighbors/3, % +Vertex, +Graph, -Vertices
|
||||
neighbours/3, % +Vertex, +Graph, -Vertices
|
||||
reachable/3, % +Vertex, +Graph, -Vertices
|
||||
top_sort/2, % +Graph, -Sort
|
||||
top_sort/3, % +Graph, -Sort0, -Sort
|
||||
transitive_closure/2, % +Graph, -Closure
|
||||
transpose_ugraph/2, % +Graph, -NewGraph
|
||||
vertices/2, % +Graph, -Vertices
|
||||
vertices_edges_to_ugraph/3, % +Vertices, +Edges, -Graph
|
||||
ugraph_union/3, % +Graph1, +Graph2, -Graph
|
||||
connect_ugraph/3 % +Graph1, -Start, -Graph
|
||||
]).
|
||||
|
||||
/** <module> Graph manipulation library
|
||||
|
||||
The S-representation of a graph is a list of (vertex-neighbours) pairs,
|
||||
where the pairs are in standard order (as produced by keysort) and the
|
||||
neighbours of each vertex are also in standard order (as produced by
|
||||
sort). This form is convenient for many calculations.
|
||||
|
||||
A new UGraph from raw data can be created using
|
||||
vertices_edges_to_ugraph/3.
|
||||
|
||||
Adapted to support some of the functionality of the SICStus ugraphs
|
||||
library by Vitor Santos Costa.
|
||||
|
||||
Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker.
|
||||
|
||||
@author R.A.O'Keefe
|
||||
@author Vitor Santos Costa
|
||||
@author Jan Wielemaker
|
||||
@license BSD-2 or Artistic 2.0
|
||||
*/
|
||||
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(pairs)).
|
||||
:- use_module(library(ordsets)).
|
||||
|
||||
%! vertices(+Graph, -Vertices)
|
||||
%
|
||||
% Unify Vertices with all vertices appearing in Graph. Example:
|
||||
%
|
||||
% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
|
||||
% L = [1, 2, 3, 4, 5]
|
||||
|
||||
vertices([], []) :- !.
|
||||
vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
|
||||
vertices(Graph, Vertices).
|
||||
|
||||
|
||||
%! vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det.
|
||||
%
|
||||
% Create a UGraph from Vertices and edges. Given a graph with a
|
||||
% set of Vertices and a set of Edges, Graph must unify with the
|
||||
% corresponding S-representation. Note that the vertices without
|
||||
% edges will appear in Vertices but not in Edges. Moreover, it is
|
||||
% sufficient for a vertice to appear in Edges.
|
||||
%
|
||||
% ==
|
||||
% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L).
|
||||
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
|
||||
% ==
|
||||
%
|
||||
% In this case all vertices are defined implicitly. The next
|
||||
% example shows three unconnected vertices:
|
||||
%
|
||||
% ==
|
||||
% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L).
|
||||
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
|
||||
% ==
|
||||
|
||||
vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
|
||||
sort(Edges, EdgeSet),
|
||||
p_to_s_vertices(EdgeSet, IVertexBag),
|
||||
append(Vertices, IVertexBag, VertexBag),
|
||||
sort(VertexBag, VertexSet),
|
||||
p_to_s_group(VertexSet, EdgeSet, Graph).
|
||||
|
||||
|
||||
%! add_vertices(+Graph, +Vertices, -NewGraph)
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by adding the list of
|
||||
% Vertices to Graph. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG).
|
||||
% NG = [0-[], 1-[3,5], 2-[], 9-[]]
|
||||
% ```
|
||||
|
||||
% replace with real msort/2 when available
|
||||
msort_(List, Sorted) :-
|
||||
pairs_keys(Pairs, List),
|
||||
keysort(Pairs, SortedPairs),
|
||||
pairs_keys(SortedPairs, Sorted).
|
||||
|
||||
add_vertices(Graph, Vertices, NewGraph) :-
|
||||
% msort/2 not available in Scryer Prolog yet: msort(Vertices, V1),
|
||||
msort_(Vertices, V1),
|
||||
add_vertices_to_s_graph(V1, Graph, NewGraph).
|
||||
|
||||
add_vertices_to_s_graph(L, [], NL) :-
|
||||
!,
|
||||
add_empty_vertices(L, NL).
|
||||
add_vertices_to_s_graph([], L, L) :- !.
|
||||
add_vertices_to_s_graph([V1|VL], [V-Edges|G], NGL) :-
|
||||
compare(Res, V1, V),
|
||||
add_vertices_to_s_graph(Res, V1, VL, V, Edges, G, NGL).
|
||||
|
||||
add_vertices_to_s_graph(=, _, VL, V, Edges, G, [V-Edges|NGL]) :-
|
||||
add_vertices_to_s_graph(VL, G, NGL).
|
||||
add_vertices_to_s_graph(<, V1, VL, V, Edges, G, [V1-[]|NGL]) :-
|
||||
add_vertices_to_s_graph(VL, [V-Edges|G], NGL).
|
||||
add_vertices_to_s_graph(>, V1, VL, V, Edges, G, [V-Edges|NGL]) :-
|
||||
add_vertices_to_s_graph([V1|VL], G, NGL).
|
||||
|
||||
add_empty_vertices([], []).
|
||||
add_empty_vertices([V|G], [V-[]|NG]) :-
|
||||
add_empty_vertices(G, NG).
|
||||
|
||||
%! del_vertices(+Graph, +Vertices, -NewGraph) is det.
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by deleting the list of
|
||||
% Vertices and all the edges that start from or go to a vertex in
|
||||
% Vertices to the Graph. Example:
|
||||
%
|
||||
% ==
|
||||
% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
|
||||
% [2,1],
|
||||
% NL).
|
||||
% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]]
|
||||
% ==
|
||||
%
|
||||
% @compat Upto 5.6.48 the argument order was (+Vertices, +Graph,
|
||||
% -NewGraph). Both YAP and SWI-Prolog have changed the argument
|
||||
% order for compatibility with recent SICStus as well as
|
||||
% consistency with del_edges/3.
|
||||
|
||||
del_vertices(Graph, Vertices, NewGraph) :-
|
||||
sort(Vertices, V1), % JW: was msort
|
||||
( V1 = []
|
||||
-> Graph = NewGraph
|
||||
; del_vertices(Graph, V1, V1, NewGraph)
|
||||
).
|
||||
|
||||
del_vertices(G, [], V1, NG) :-
|
||||
!,
|
||||
del_remaining_edges_for_vertices(G, V1, NG).
|
||||
del_vertices([], _, _, []).
|
||||
del_vertices([V-Edges|G], [V0|Vs], V1, NG) :-
|
||||
compare(Res, V, V0),
|
||||
split_on_del_vertices(Res, V,Edges, [V0|Vs], NVs, V1, NG, NGr),
|
||||
del_vertices(G, NVs, V1, NGr).
|
||||
|
||||
del_remaining_edges_for_vertices([], _, []).
|
||||
del_remaining_edges_for_vertices([V0-Edges|G], V1, [V0-NEdges|NG]) :-
|
||||
ord_subtract(Edges, V1, NEdges),
|
||||
del_remaining_edges_for_vertices(G, V1, NG).
|
||||
|
||||
split_on_del_vertices(<, V, Edges, Vs, Vs, V1, [V-NEdges|NG], NG) :-
|
||||
ord_subtract(Edges, V1, NEdges).
|
||||
split_on_del_vertices(>, V, Edges, [_|Vs], Vs, V1, [V-NEdges|NG], NG) :-
|
||||
ord_subtract(Edges, V1, NEdges).
|
||||
split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG).
|
||||
|
||||
%! add_edges(+Graph, +Edges, -NewGraph)
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by adding the list of Edges
|
||||
% to Graph. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
|
||||
% 5-[],6-[],7-[],8-[]],
|
||||
% [1-6,2-3,3-2,5-7,3-2,4-5],
|
||||
% NL).
|
||||
% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5],
|
||||
% 5-[7], 6-[], 7-[], 8-[]]
|
||||
% ```
|
||||
|
||||
add_edges(Graph, Edges, NewGraph) :-
|
||||
p_to_s_graph(Edges, G1),
|
||||
ugraph_union(Graph, G1, NewGraph).
|
||||
|
||||
%! ugraph_union(+Graph1, +Graph2, -NewGraph)
|
||||
%
|
||||
% NewGraph is the union of Graph1 and Graph2. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
|
||||
% L = [1-[2], 2-[3,4], 3-[1,2,4]]
|
||||
% ```
|
||||
|
||||
ugraph_union(Set1, [], Set1) :- !.
|
||||
ugraph_union([], Set2, Set2) :- !.
|
||||
ugraph_union([Head1-E1|Tail1], [Head2-E2|Tail2], Union) :-
|
||||
compare(Order, Head1, Head2),
|
||||
ugraph_union(Order, Head1-E1, Tail1, Head2-E2, Tail2, Union).
|
||||
|
||||
ugraph_union(=, Head-E1, Tail1, _-E2, Tail2, [Head-Es|Union]) :-
|
||||
ord_union(E1, E2, Es),
|
||||
ugraph_union(Tail1, Tail2, Union).
|
||||
ugraph_union(<, Head1, Tail1, Head2, Tail2, [Head1|Union]) :-
|
||||
ugraph_union(Tail1, [Head2|Tail2], Union).
|
||||
ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :-
|
||||
ugraph_union([Head1|Tail1], Tail2, Union).
|
||||
|
||||
%! del_edges(+Graph, +Edges, -NewGraph)
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained by removing the list of
|
||||
% Edges from Graph. Notice that no vertices are deleted. Example:
|
||||
%
|
||||
% ```
|
||||
% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
|
||||
% [1-6,2-3,3-2,5-7,3-2,4-5,1-3],
|
||||
% NL).
|
||||
% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]]
|
||||
% ```
|
||||
|
||||
del_edges(Graph, Edges, NewGraph) :-
|
||||
p_to_s_graph(Edges, G1),
|
||||
graph_subtract(Graph, G1, NewGraph).
|
||||
|
||||
%! graph_subtract(+Set1, +Set2, ?Difference)
|
||||
%
|
||||
% Is based on ord_subtract
|
||||
|
||||
graph_subtract(Set1, [], Set1) :- !.
|
||||
graph_subtract([], _, []).
|
||||
graph_subtract([Head1-E1|Tail1], [Head2-E2|Tail2], Difference) :-
|
||||
compare(Order, Head1, Head2),
|
||||
graph_subtract(Order, Head1-E1, Tail1, Head2-E2, Tail2, Difference).
|
||||
|
||||
graph_subtract(=, H-E1, Tail1, _-E2, Tail2, [H-E|Difference]) :-
|
||||
ord_subtract(E1,E2,E),
|
||||
graph_subtract(Tail1, Tail2, Difference).
|
||||
graph_subtract(<, Head1, Tail1, Head2, Tail2, [Head1|Difference]) :-
|
||||
graph_subtract(Tail1, [Head2|Tail2], Difference).
|
||||
graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :-
|
||||
graph_subtract([Head1|Tail1], Tail2, Difference).
|
||||
|
||||
%! edges(+Graph, -Edges)
|
||||
%
|
||||
% Unify Edges with all edges appearing in Graph. Example:
|
||||
%
|
||||
% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
|
||||
% L = [1-3, 1-5, 2-4, 4-5]
|
||||
|
||||
edges(Graph, Edges) :-
|
||||
s_to_p_graph(Graph, Edges).
|
||||
|
||||
p_to_s_graph(P_Graph, S_Graph) :-
|
||||
sort(P_Graph, EdgeSet),
|
||||
p_to_s_vertices(EdgeSet, VertexBag),
|
||||
sort(VertexBag, VertexSet),
|
||||
p_to_s_group(VertexSet, EdgeSet, S_Graph).
|
||||
|
||||
|
||||
p_to_s_vertices([], []).
|
||||
p_to_s_vertices([A-Z|Edges], [A,Z|Vertices]) :-
|
||||
p_to_s_vertices(Edges, Vertices).
|
||||
|
||||
|
||||
p_to_s_group([], _, []).
|
||||
p_to_s_group([Vertex|Vertices], EdgeSet, [Vertex-Neibs|G]) :-
|
||||
p_to_s_group(EdgeSet, Vertex, Neibs, RestEdges),
|
||||
p_to_s_group(Vertices, RestEdges, G).
|
||||
|
||||
|
||||
p_to_s_group([V1-X|Edges], V2, [X|Neibs], RestEdges) :- V1 == V2,
|
||||
!,
|
||||
p_to_s_group(Edges, V2, Neibs, RestEdges).
|
||||
p_to_s_group(Edges, _, [], Edges).
|
||||
|
||||
|
||||
|
||||
s_to_p_graph([], []) :- !.
|
||||
s_to_p_graph([Vertex-Neibs|G], P_Graph) :-
|
||||
s_to_p_graph(Neibs, Vertex, P_Graph, Rest_P_Graph),
|
||||
s_to_p_graph(G, Rest_P_Graph).
|
||||
|
||||
|
||||
s_to_p_graph([], _, P_Graph, P_Graph) :- !.
|
||||
s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :-
|
||||
s_to_p_graph(Neibs, Vertex, P, Rest_P).
|
||||
|
||||
%! transitive_closure(+Graph, -Closure)
|
||||
%
|
||||
% Generate the graph Closure as the transitive closure of Graph.
|
||||
% Example:
|
||||
%
|
||||
% ```
|
||||
% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L).
|
||||
% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
|
||||
% ```
|
||||
|
||||
transitive_closure(Graph, Closure) :-
|
||||
warshall(Graph, Graph, Closure).
|
||||
|
||||
warshall([], Closure, Closure) :- !.
|
||||
warshall([V-_|G], E, Closure) :-
|
||||
memberchk(V-Y, E), % Y := E(v)
|
||||
warshall(E, V, Y, NewE),
|
||||
warshall(G, NewE, Closure).
|
||||
|
||||
|
||||
warshall([X-Neibs|G], V, Y, [X-NewNeibs|NewG]) :-
|
||||
memberchk(V, Neibs),
|
||||
!,
|
||||
ord_union(Neibs, Y, NewNeibs),
|
||||
warshall(G, V, Y, NewG).
|
||||
warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :-
|
||||
!,
|
||||
warshall(G, V, Y, NewG).
|
||||
warshall([], _, _, []).
|
||||
|
||||
%! transpose_ugraph(Graph, NewGraph) is det.
|
||||
%
|
||||
% Unify NewGraph with a new graph obtained from Graph by replacing
|
||||
% all edges of the form V1-V2 by edges of the form V2-V1. The cost
|
||||
% is O(|V|*log(|V|)). Notice that an undirected graph is its own
|
||||
% transpose. Example:
|
||||
%
|
||||
% ==
|
||||
% ?- transpose([1-[3,5],2-[4],3-[],4-[5],
|
||||
% 5-[],6-[],7-[],8-[]], NL).
|
||||
% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]]
|
||||
% ==
|
||||
%
|
||||
% @compat This predicate used to be known as transpose/2.
|
||||
% Following SICStus 4, we reserve transpose/2 for matrix
|
||||
% transposition and renamed ugraph transposition to
|
||||
% transpose_ugraph/2.
|
||||
|
||||
transpose_ugraph(Graph, NewGraph) :-
|
||||
edges(Graph, Edges),
|
||||
vertices(Graph, Vertices),
|
||||
flip_edges(Edges, TransposedEdges),
|
||||
vertices_edges_to_ugraph(Vertices, TransposedEdges, NewGraph).
|
||||
|
||||
flip_edges([], []).
|
||||
flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :-
|
||||
flip_edges(Pairs, Flipped).
|
||||
|
||||
%! compose(+LeftGraph, +RightGraph, -NewGraph)
|
||||
%
|
||||
% Compose NewGraph by connecting the _drains_ of LeftGraph to the
|
||||
% _sources_ of RightGraph. Example:
|
||||
%
|
||||
% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
|
||||
% L = [1-[4], 2-[1,2,4], 3-[]]
|
||||
|
||||
compose(G1, G2, Composition) :-
|
||||
vertices(G1, V1),
|
||||
vertices(G2, V2),
|
||||
ord_union(V1, V2, V),
|
||||
compose(V, G1, G2, Composition).
|
||||
|
||||
compose([], _, _, []) :- !.
|
||||
compose([Vertex|Vertices], [Vertex-Neibs|G1], G2,
|
||||
[Vertex-Comp|Composition]) :-
|
||||
!,
|
||||
compose1(Neibs, G2, [], Comp),
|
||||
compose(Vertices, G1, G2, Composition).
|
||||
compose([Vertex|Vertices], G1, G2, [Vertex-[]|Composition]) :-
|
||||
compose(Vertices, G1, G2, Composition).
|
||||
|
||||
|
||||
compose1([V1|Vs1], [V2-N2|G2], SoFar, Comp) :-
|
||||
compare(Rel, V1, V2),
|
||||
!,
|
||||
compose1(Rel, V1, Vs1, V2, N2, G2, SoFar, Comp).
|
||||
compose1(_, _, Comp, Comp).
|
||||
|
||||
|
||||
compose1(<, _, Vs1, V2, N2, G2, SoFar, Comp) :-
|
||||
!,
|
||||
compose1(Vs1, [V2-N2|G2], SoFar, Comp).
|
||||
compose1(>, V1, Vs1, _, _, G2, SoFar, Comp) :-
|
||||
!,
|
||||
compose1([V1|Vs1], G2, SoFar, Comp).
|
||||
compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
|
||||
ord_union(N2, SoFar, Next),
|
||||
compose1(Vs1, G2, Next, Comp).
|
||||
|
||||
%! top_sort(+Graph, -Sorted) is semidet.
|
||||
%! top_sort(+Graph, -Sorted, ?Tail) is semidet.
|
||||
%
|
||||
% Sorted is a topological sorted list of nodes in Graph. A
|
||||
% toplogical sort is possible if the graph is connected and
|
||||
% acyclic. In the example we show how topological sorting works
|
||||
% for a linear graph:
|
||||
%
|
||||
% ==
|
||||
% ?- top_sort([1-[2], 2-[3], 3-[]], L).
|
||||
% L = [1, 2, 3]
|
||||
% ==
|
||||
%
|
||||
% The predicate top_sort/3 is a difference list version of
|
||||
% top_sort/2.
|
||||
|
||||
top_sort(Graph, Sorted) :-
|
||||
vertices_and_zeros(Graph, Vertices, Counts0),
|
||||
count_edges(Graph, Vertices, Counts0, Counts1),
|
||||
select_zeros(Counts1, Vertices, Zeros),
|
||||
top_sort(Zeros, Sorted, Graph, Vertices, Counts1).
|
||||
|
||||
top_sort(Graph, Sorted0, Sorted) :-
|
||||
vertices_and_zeros(Graph, Vertices, Counts0),
|
||||
count_edges(Graph, Vertices, Counts0, Counts1),
|
||||
select_zeros(Counts1, Vertices, Zeros),
|
||||
top_sort(Zeros, Sorted, Sorted0, Graph, Vertices, Counts1).
|
||||
|
||||
|
||||
vertices_and_zeros([], [], []) :- !.
|
||||
vertices_and_zeros([Vertex-_|Graph], [Vertex|Vertices], [0|Zeros]) :-
|
||||
vertices_and_zeros(Graph, Vertices, Zeros).
|
||||
|
||||
|
||||
count_edges([], _, Counts, Counts) :- !.
|
||||
count_edges([_-Neibs|Graph], Vertices, Counts0, Counts2) :-
|
||||
incr_list(Neibs, Vertices, Counts0, Counts1),
|
||||
count_edges(Graph, Vertices, Counts1, Counts2).
|
||||
|
||||
|
||||
incr_list([], _, Counts, Counts) :- !.
|
||||
incr_list([V1|Neibs], [V2|Vertices], [M|Counts0], [N|Counts1]) :-
|
||||
V1 == V2,
|
||||
!,
|
||||
N is M+1,
|
||||
incr_list(Neibs, Vertices, Counts0, Counts1).
|
||||
incr_list(Neibs, [_|Vertices], [N|Counts0], [N|Counts1]) :-
|
||||
incr_list(Neibs, Vertices, Counts0, Counts1).
|
||||
|
||||
|
||||
select_zeros([], [], []) :- !.
|
||||
select_zeros([0|Counts], [Vertex|Vertices], [Vertex|Zeros]) :-
|
||||
!,
|
||||
select_zeros(Counts, Vertices, Zeros).
|
||||
select_zeros([_|Counts], [_|Vertices], Zeros) :-
|
||||
select_zeros(Counts, Vertices, Zeros).
|
||||
|
||||
|
||||
|
||||
top_sort([], [], Graph, _, Counts) :-
|
||||
!,
|
||||
vertices_and_zeros(Graph, _, Counts).
|
||||
top_sort([Zero|Zeros], [Zero|Sorted], Graph, Vertices, Counts1) :-
|
||||
graph_memberchk(Zero-Neibs, Graph),
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
|
||||
top_sort(NewZeros, Sorted, Graph, Vertices, Counts2).
|
||||
|
||||
top_sort([], Sorted0, Sorted0, Graph, _, Counts) :-
|
||||
!,
|
||||
vertices_and_zeros(Graph, _, Counts).
|
||||
top_sort([Zero|Zeros], [Zero|Sorted], Sorted0, Graph, Vertices, Counts1) :-
|
||||
graph_memberchk(Zero-Neibs, Graph),
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zeros, NewZeros),
|
||||
top_sort(NewZeros, Sorted, Sorted0, Graph, Vertices, Counts2).
|
||||
|
||||
graph_memberchk(Element1-Edges, [Element2-Edges2|_]) :-
|
||||
Element1 == Element2,
|
||||
!,
|
||||
Edges = Edges2.
|
||||
graph_memberchk(Element, [_|Rest]) :-
|
||||
graph_memberchk(Element, Rest).
|
||||
|
||||
|
||||
decr_list([], _, Counts, Counts, Zeros, Zeros) :- !.
|
||||
decr_list([V1|Neibs], [V2|Vertices], [1|Counts1], [0|Counts2], Zi, Zo) :-
|
||||
V1 == V2,
|
||||
!,
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, [V2|Zi], Zo).
|
||||
decr_list([V1|Neibs], [V2|Vertices], [N|Counts1], [M|Counts2], Zi, Zo) :-
|
||||
V1 == V2,
|
||||
!,
|
||||
M is N-1,
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
|
||||
decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :-
|
||||
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
|
||||
|
||||
|
||||
%! neighbors(+Vertex, +Graph, -Neigbours) is det.
|
||||
%! neighbours(+Vertex, +Graph, -Neigbours) is det.
|
||||
%
|
||||
% Neigbours is a sorted list of the neighbours of Vertex in Graph.
|
||||
% Example:
|
||||
%
|
||||
% ```
|
||||
% ?- neighbours(4,[1-[3,5],2-[4],3-[],
|
||||
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
|
||||
% NL = [1,2,7,5]
|
||||
% ```
|
||||
|
||||
neighbors(Vertex, Graph, Neig) :-
|
||||
neighbours(Vertex, Graph, Neig).
|
||||
|
||||
neighbours(V,[V0-Neig|_],Neig) :-
|
||||
V == V0,
|
||||
!.
|
||||
neighbours(V,[_|G],Neig) :-
|
||||
neighbours(V,G,Neig).
|
||||
|
||||
|
||||
%! connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det.
|
||||
%
|
||||
% Adds Start as an additional vertex that is connected to all vertices
|
||||
% in UGraphIn. This can be used to create an topological sort for a
|
||||
% not connected graph. Start is before any vertex in UGraphIn in the
|
||||
% standard order of terms. No vertex in UGraphIn can be a variable.
|
||||
%
|
||||
% Can be used to order a not-connected graph as follows:
|
||||
%
|
||||
% ```
|
||||
% top_sort_unconnected(Graph, Vertices) :-
|
||||
% ( top_sort(Graph, Vertices)
|
||||
% -> true
|
||||
% ; connect_ugraph(Graph, Start, Connected),
|
||||
% top_sort(Connected, Ordered0),
|
||||
% Ordered0 = [Start|Vertices]
|
||||
% ).
|
||||
% ```
|
||||
|
||||
connect_ugraph([], 0, []) :- !.
|
||||
connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
|
||||
vertices(Graph, Vertices),
|
||||
Vertices = [First|_],
|
||||
before(First, Start).
|
||||
|
||||
%! before(+Term, -Before) is det.
|
||||
%
|
||||
% Unify Before to a term that comes before Term in the standard
|
||||
% order of terms.
|
||||
%
|
||||
% @error instantiation_error if Term is unbound.
|
||||
|
||||
before(X, _) :-
|
||||
var(X),
|
||||
!,
|
||||
instantiation_error(X).
|
||||
before(Number, Start) :-
|
||||
number(Number),
|
||||
!,
|
||||
Start is Number - 1.
|
||||
before(_, 0).
|
||||
|
||||
|
||||
%! complement(+UGraphIn, -UGraphOut)
|
||||
%
|
||||
% UGraphOut is a ugraph with an edge between all vertices that are
|
||||
% _not_ connected in UGraphIn and all edges from UGraphIn removed.
|
||||
% Example:
|
||||
%
|
||||
% ```
|
||||
% ?- complement([1-[3,5],2-[4],3-[],
|
||||
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
|
||||
% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8],
|
||||
% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8],
|
||||
% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]]
|
||||
% ```
|
||||
%
|
||||
% @tbd Simple two-step algorithm. You could be smarter, I suppose.
|
||||
|
||||
complement(G, NG) :-
|
||||
vertices(G,Vs),
|
||||
complement(G,Vs,NG).
|
||||
|
||||
complement([], _, []).
|
||||
complement([V-Ns|G], Vs, [V-INs|NG]) :-
|
||||
ord_add_element(Ns,V,Ns1),
|
||||
ord_subtract(Vs,Ns1,INs),
|
||||
complement(G, Vs, NG).
|
||||
|
||||
%! reachable(+Vertex, +UGraph, -Vertices)
|
||||
%
|
||||
% True when Vertices is an ordered set of vertices reachable in
|
||||
% UGraph, including Vertex. Example:
|
||||
%
|
||||
% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
|
||||
% V = [1, 3, 5]
|
||||
|
||||
reachable(N, G, Rs) :-
|
||||
reachable([N], G, [N], Rs).
|
||||
|
||||
reachable([], _, Rs, Rs).
|
||||
reachable([N|Ns], G, Rs0, RsF) :-
|
||||
neighbours(N, G, Nei),
|
||||
ord_union(Rs0, Nei, Rs1, D),
|
||||
append(Ns, D, Nsi),
|
||||
reachable(Nsi, G, Rs1, RsF).
|
||||
@@ -4,9 +4,9 @@
|
||||
This library provides reasoning about UUID (only version 4 right now).
|
||||
There are three predicates:
|
||||
* uuidv4/1, to generate a new UUIDv4
|
||||
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
|
||||
* uuidv4_string/1, to generate a new UUIDv4 in string hex representation
|
||||
* uuid_string/2, to converte between UUID list of bytes and UUID hex representation
|
||||
|
||||
|
||||
Examples:
|
||||
?- uuidv4(X).
|
||||
X = [42,147,248,242,117,196,79,2,129,159|...].
|
||||
@@ -30,7 +30,7 @@
|
||||
:- use_module(library(dcgs)).
|
||||
:- use_module(library(lists)).
|
||||
|
||||
/*
|
||||
/*
|
||||
An UUID is made of 16 bytes, composed of 5 sections:
|
||||
time_low - 4
|
||||
time_mid - 2
|
||||
|
||||
102
src/loader.pl
102
src/loader.pl
@@ -1,4 +1,3 @@
|
||||
|
||||
:- module(loader, [consult/1,
|
||||
expand_goal/3,
|
||||
expand_term/2,
|
||||
@@ -90,18 +89,22 @@ unload_evacuable(Evacuable) :-
|
||||
|
||||
run_initialization_goals(Module) :-
|
||||
( predicate_property(Module:'$initialization_goals'(_), dynamic) ->
|
||||
% FIXME: failing here. also, see add_module.
|
||||
findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals),
|
||||
abolish(Module:'$initialization_goals'/1),
|
||||
( maplist(Module:call, Goals) ->
|
||||
true
|
||||
; %% initialization goals can fail without thwarting the load.
|
||||
write('Warning: initialization/1 failed for: '),
|
||||
writeq(maplist(Module:call, Goals)),
|
||||
nl
|
||||
)
|
||||
maplist(loader:success_or_warning, Goals)
|
||||
; true
|
||||
).
|
||||
|
||||
success_or_warning(Goal) :-
|
||||
( call(Goal) ->
|
||||
true
|
||||
; %% initialization goals can fail without thwarting the load.
|
||||
write('Warning: initialization/1 failed for: '),
|
||||
writeq(Goal),
|
||||
nl
|
||||
).
|
||||
|
||||
run_initialization_goals :-
|
||||
prolog_load_context(module, Module),
|
||||
run_initialization_goals(user),
|
||||
@@ -258,8 +261,8 @@ expand_term_goals(Terms0, Terms) :-
|
||||
Terms = (Module:Head2 :- Body1)
|
||||
; type_error(atom, Module, load/1)
|
||||
)
|
||||
; prolog_load_context(module, Target),
|
||||
module_expanded_head_variables(Head1, HeadVars),
|
||||
; module_expanded_head_variables(Head1, HeadVars),
|
||||
prolog_load_context(module, Target),
|
||||
expand_goal(Body0, Target, Body1, HeadVars),
|
||||
Terms = (Head1 :- Body1)
|
||||
)
|
||||
@@ -316,6 +319,7 @@ compile_dispatch(user:goal_expansion(Term, Terms), Evacuable) :-
|
||||
compile_dispatch((user:goal_expansion(Term, Terms) :- Body), Evacuable) :-
|
||||
'$add_goal_expansion_clause'(user, (goal_expansion(Term, Terms) :- Body), Evacuable).
|
||||
|
||||
|
||||
remove_module(Module, Evacuable) :-
|
||||
( nonvar(Module),
|
||||
Module = library(ModuleName),
|
||||
@@ -508,7 +512,8 @@ open_file(Path, Stream) :-
|
||||
; catch(open(Path, read, Stream),
|
||||
error(existence_error(source_sink, _), _),
|
||||
( atom_concat(Path, '.pl', ExtendedPath),
|
||||
open(ExtendedPath, read, Stream) )
|
||||
open(ExtendedPath, read, Stream)
|
||||
)
|
||||
)
|
||||
).
|
||||
|
||||
@@ -540,15 +545,15 @@ use_module(Module, Exports, Evacuable) :-
|
||||
|
||||
|
||||
check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
|
||||
'$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
|
||||
'$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
|
||||
check_predicate_property(built_in, _, Name, Arity, built_in) :-
|
||||
'$cpp_built_in_property'(Name, Arity).
|
||||
'$built_in_property'(Name, Arity).
|
||||
check_predicate_property(dynamic, Module, Name, Arity, dynamic) :-
|
||||
'$cpp_dynamic_property'(Module, Name, Arity).
|
||||
'$dynamic_property'(Module, Name, Arity).
|
||||
check_predicate_property(multifile, Module, Name, Arity, multifile) :-
|
||||
'$cpp_multifile_property'(Module, Name, Arity).
|
||||
'$multifile_property'(Module, Name, Arity).
|
||||
check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :-
|
||||
'$cpp_discontiguous_property'(Module, Name, Arity).
|
||||
'$discontiguous_property'(Module, Name, Arity).
|
||||
|
||||
|
||||
|
||||
@@ -573,15 +578,13 @@ predicate_property(Callable, Property) :-
|
||||
atom(Module),
|
||||
nonvar(Callable0) ->
|
||||
functor(Callable0, Name, Arity),
|
||||
( atom(Name),
|
||||
Name \== [] ->
|
||||
( atom(Name) ->
|
||||
extract_predicate_property(Property, PropertyType),
|
||||
check_predicate_property(PropertyType, Module, Name, Arity, Property)
|
||||
; type_error(callable, Callable0, predicate_property/2)
|
||||
)
|
||||
; functor(Callable, Name, Arity),
|
||||
( atom(Name),
|
||||
Name \== [] ->
|
||||
( atom(Name) ->
|
||||
extract_predicate_property(Property, PropertyType),
|
||||
load_context(Module),
|
||||
check_predicate_property(PropertyType, Module, Name, Arity, Property)
|
||||
@@ -624,11 +627,16 @@ expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :-
|
||||
).
|
||||
|
||||
|
||||
expand_module_name(ESG0, M, ESG) :-
|
||||
expand_module_name(ESG0, MS, M, ESG) :-
|
||||
( var(ESG0) ->
|
||||
ESG = M:ESG0
|
||||
; ESG0 = _:_ ->
|
||||
ESG = ESG0
|
||||
; functor(ESG0, F, A0),
|
||||
A is A0 + MS,
|
||||
functor(EESG0, F, A),
|
||||
predicate_property(EESG0, built_in) ->
|
||||
ESG = ESG0
|
||||
; ESG = M:ESG0
|
||||
).
|
||||
|
||||
@@ -641,7 +649,7 @@ expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars
|
||||
pairs:same_key(SG, HeadVars, [_|_], _) ->
|
||||
expand_subgoal(SG, MS, M, ESG, HeadVars)
|
||||
; expand_subgoal(SG, MS, M, ESG0, HeadVars),
|
||||
expand_module_name(ESG0, M, ESG)
|
||||
expand_module_name(ESG0, MS, M, ESG)
|
||||
),
|
||||
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
|
||||
; ESG = SG,
|
||||
@@ -656,14 +664,17 @@ expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
|
||||
( GoalFunctor == (:),
|
||||
SubGoals = [M, SubGoal] ->
|
||||
expand_module_names(SubGoal, MetaSpecs, M, ExpandedSubGoal, HeadVars),
|
||||
ExpandedGoals = M:ExpandedSubGoal
|
||||
expand_module_name(ExpandedSubGoal, 0, M, ExpandedGoals)
|
||||
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
|
||||
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
|
||||
).
|
||||
|
||||
|
||||
expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
|
||||
expand_goal(UnexpandedGoals, Module, ExpandedGoals, []),
|
||||
% if a goal isn't callable, defer to call/N to report the error.
|
||||
catch('$call'(loader:expand_goal(UnexpandedGoals, Module, ExpandedGoals, [])),
|
||||
error(type_error(callable, _), _),
|
||||
'$call'(UnexpandedGoals = ExpandedGoals)),
|
||||
!.
|
||||
|
||||
expand_goal_cases((Goal0, Goals0), Module, ExpandedGoals, HeadVars) :-
|
||||
@@ -705,32 +716,29 @@ expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :-
|
||||
)
|
||||
).
|
||||
|
||||
thread_goals(Goals0, Goals1, Functor) :-
|
||||
( var(Goals0) ->
|
||||
Goals0 = Goals1
|
||||
; ( Goals0 = [G | Gs] ->
|
||||
( Gs = [] ->
|
||||
Goals1 = G
|
||||
; Goals1 =.. [Functor, G, Goals2],
|
||||
thread_goals(Gs, Goals2, Functor)
|
||||
)
|
||||
; Goals1 = Goals0
|
||||
)
|
||||
).
|
||||
|
||||
thread_goals(Goals0, Goals1, Hole, Functor) :-
|
||||
( var(Goals0) ->
|
||||
Goals1 =.. [Functor, Goals0, Hole]
|
||||
; ( Goals0 = [G | Gs] ->
|
||||
( Gs == [] ->
|
||||
Goals1 =.. [Functor, G, Hole]
|
||||
; Goals1 =.. [Functor, G, Goals2],
|
||||
thread_goals(Gs, Goals2, Hole, Functor)
|
||||
)
|
||||
; Goals1 =.. [Functor, Goals0, Hole]
|
||||
; Goals0 = [G | Gs] ->
|
||||
( Gs == [] ->
|
||||
Goals1 =.. [Functor, G, Hole]
|
||||
; Goals1 =.. [Functor, G, Goals2],
|
||||
thread_goals(Gs, Goals2, Hole, Functor)
|
||||
)
|
||||
; Goals1 =.. [Functor, Goals0, Hole]
|
||||
).
|
||||
|
||||
thread_goals(Goals0, Goals1, Functor) :-
|
||||
( var(Goals0) ->
|
||||
Goals0 = Goals1
|
||||
; Goals0 = [G | Gs] ->
|
||||
( Gs = [] ->
|
||||
Goals1 = G
|
||||
; Goals1 =.. [Functor, G, Goals2],
|
||||
thread_goals(Gs, Goals2, Functor)
|
||||
)
|
||||
; Goals1 = Goals0
|
||||
).
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%
|
||||
@@ -773,12 +781,14 @@ call_clause('$call'(G), G0) :-
|
||||
instantiation_error(call/1)
|
||||
; G = M:G1,
|
||||
!,
|
||||
callable(G1),
|
||||
functor(G1, F, _),
|
||||
atom(F),
|
||||
atom(M),
|
||||
F \== [],
|
||||
G0 = M:G1
|
||||
; !,
|
||||
callable(G),
|
||||
functor(G, F, _),
|
||||
atom(F),
|
||||
F \== [],
|
||||
@@ -788,6 +798,7 @@ call_clause('$call'(G), G0) :-
|
||||
|
||||
call_clause(G, G0) :-
|
||||
strip_module(G, M, G1),
|
||||
callable(G1),
|
||||
functor(G1, F, _),
|
||||
atom(F),
|
||||
F \== [],
|
||||
@@ -818,6 +829,7 @@ call_clause('$call'(G1), Args, N, G0) :-
|
||||
F \== [],
|
||||
append(As, Args, As1),
|
||||
G3 =.. [F | As1],
|
||||
callable(G3),
|
||||
G0 = M:G3
|
||||
; !,
|
||||
G1 =.. [F | As],
|
||||
@@ -826,6 +838,7 @@ call_clause('$call'(G1), Args, N, G0) :-
|
||||
load_context(M),
|
||||
append(As, Args, As1),
|
||||
G2 =.. [F | As1],
|
||||
callable(G2),
|
||||
G0 = M:G2
|
||||
).
|
||||
|
||||
@@ -840,6 +853,7 @@ call_clause(G, Args, _, G0) :-
|
||||
),
|
||||
append(As, Args, As1),
|
||||
G2 =.. [F | As1],
|
||||
callable(G2),
|
||||
expand_goal(call(M:G2), M, call(G0)).
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,23 @@
|
||||
use crate::heap_iter::*;
|
||||
use crate::machine::*;
|
||||
use prolog_parser::temp_v;
|
||||
use crate::parser::ast::*;
|
||||
use crate::temp_v;
|
||||
use crate::types::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
pub(super) type Bindings = Vec<(usize, Addr)>;
|
||||
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct AttrVarInitializer {
|
||||
pub(super) attr_var_queue: Vec<usize>,
|
||||
pub(super) bindings: Bindings,
|
||||
pub(super) cp: LocalCodePtr,
|
||||
pub(super) instigating_p: LocalCodePtr,
|
||||
pub(super) p: usize,
|
||||
pub(super) cp: usize,
|
||||
// pub(super) instigating_p: usize,
|
||||
pub(super) verify_attrs_loc: usize,
|
||||
}
|
||||
|
||||
@@ -23,8 +26,8 @@ impl AttrVarInitializer {
|
||||
AttrVarInitializer {
|
||||
attr_var_queue: vec![],
|
||||
bindings: vec![],
|
||||
instigating_p: LocalCodePtr::default(),
|
||||
cp: LocalCodePtr::default(),
|
||||
p: 0,
|
||||
cp: 0,
|
||||
verify_attrs_loc,
|
||||
}
|
||||
}
|
||||
@@ -37,44 +40,39 @@ impl AttrVarInitializer {
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
||||
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) {
|
||||
if self.attr_var_init.bindings.is_empty() {
|
||||
self.attr_var_init.instigating_p = self.p.local();
|
||||
// save self.p and self.cp and ensure that the next
|
||||
// instruction is InstallVerifyAttrInterrupt.
|
||||
|
||||
if self.last_call {
|
||||
self.attr_var_init.cp = self.cp;
|
||||
} else {
|
||||
self.attr_var_init.cp = self.p.local() + 1;
|
||||
}
|
||||
self.attr_var_init.p = self.p;
|
||||
self.attr_var_init.cp = self.cp;
|
||||
|
||||
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
|
||||
self.p = INSTALL_VERIFY_ATTR_INTERRUPT - 1;
|
||||
self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
|
||||
}
|
||||
|
||||
self.attr_var_init.bindings.push((h, addr));
|
||||
}
|
||||
|
||||
fn populate_var_and_value_lists(&mut self) -> (Addr, Addr) {
|
||||
fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
|
||||
let iter = self
|
||||
.attr_var_init
|
||||
.bindings
|
||||
.iter()
|
||||
.map(|(ref h, _)| HeapCellValue::Addr(Addr::AttrVar(*h)));
|
||||
.map(|(ref h, _)| attr_var_as_cell!(*h));
|
||||
|
||||
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||
let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
|
||||
|
||||
let iter = self
|
||||
.attr_var_init
|
||||
.bindings
|
||||
.drain(0..)
|
||||
.map(|(_, addr)| HeapCellValue::Addr(addr));
|
||||
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
|
||||
|
||||
let value_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, 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));
|
||||
self.heap[*h] = attr_var_as_cell!(*h);
|
||||
}
|
||||
|
||||
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
|
||||
@@ -83,69 +81,104 @@ impl MachineState {
|
||||
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();
|
||||
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
|
||||
let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() {
|
||||
vec![]
|
||||
} else {
|
||||
self.attr_var_init.attr_var_queue[b..]
|
||||
.iter()
|
||||
.filter_map(|h| {
|
||||
read_heap_cell!(self.store(self.deref(heap_loc_as_cell!(*h))),
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
Some(attr_var_as_cell!(h))
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
|
||||
attr_vars
|
||||
.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2).unwrap_or(Ordering::Less));
|
||||
attr_vars.sort_unstable_by(|a1, a2| {
|
||||
compare_term_test!(self, *a1, *a2).unwrap_or(Ordering::Less)
|
||||
});
|
||||
|
||||
self.term_dedup(&mut attr_vars);
|
||||
attr_vars.dedup();
|
||||
attr_vars.into_iter()
|
||||
}
|
||||
|
||||
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
|
||||
self.allocate(self.num_of_args + 2);
|
||||
pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) {
|
||||
self.allocate(arity + 3);
|
||||
|
||||
let e = self.e;
|
||||
self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
|
||||
let and_frame = self.stack.index_and_frame_mut(e);
|
||||
|
||||
for i in 1..self.num_of_args + 1 {
|
||||
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
|
||||
for i in 1..arity + 1 {
|
||||
and_frame[i] = self.registers[i];
|
||||
}
|
||||
|
||||
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);
|
||||
and_frame[arity + 1] =
|
||||
fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
|
||||
and_frame[arity + 2] =
|
||||
fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
|
||||
and_frame[arity + 3] =
|
||||
fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
|
||||
|
||||
self.verify_attributes();
|
||||
|
||||
self.num_of_args = 2;
|
||||
self.num_of_args = 3;
|
||||
self.b0 = self.b;
|
||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
||||
self.p = p;
|
||||
}
|
||||
|
||||
pub(super) fn attr_vars_of_term(&self, addr: Addr) -> Vec<Addr> {
|
||||
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
|
||||
let mut seen_set = IndexSet::new();
|
||||
let mut seen_vars = vec![];
|
||||
|
||||
let mut iter = self.acyclic_pre_order_iter(addr);
|
||||
let mut iter = stackful_preorder_iter(&mut self.heap, cell);
|
||||
|
||||
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;
|
||||
while let Some(value) = iter.next() {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
if seen_set.contains(&h) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = unmark_cell_bits!(value);
|
||||
|
||||
seen_vars.push(value);
|
||||
seen_set.insert(h);
|
||||
|
||||
let mut l = h + 1;
|
||||
// let mut list_elements = vec![];
|
||||
// let iter_stack_len = iter.stack_len();
|
||||
|
||||
loop {
|
||||
read_heap_cell!(iter.heap[l],
|
||||
(HeapCellValueTag::Lis) => {
|
||||
iter.push_stack(l);
|
||||
// l = elem + 1;
|
||||
break;
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
|
||||
if h == l {
|
||||
break;
|
||||
} else {
|
||||
l = h;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// iter.stack_slice_from(iter_stack_len ..).reverse();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
use crate::clause_types::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct CodeRepo {
|
||||
pub(super) code: Code,
|
||||
}
|
||||
|
||||
impl CodeRepo {
|
||||
#[inline]
|
||||
pub(super) fn new() -> Self {
|
||||
CodeRepo { code: Code::new() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn lookup_local_instr<'a>(&'a self, p: LocalCodePtr) -> RefOrOwned<'a, Line> {
|
||||
match p {
|
||||
LocalCodePtr::Halt => {
|
||||
// exit with the interrupt exit code.
|
||||
std::process::exit(1);
|
||||
}
|
||||
LocalCodePtr::DirEntry(p) => RefOrOwned::Borrowed(&self.code[p as usize]),
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => match &self.code[p] {
|
||||
&Line::IndexingCode(ref indexing_lines) => match &indexing_lines[o] {
|
||||
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
|
||||
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
|
||||
}
|
||||
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
|
||||
RefOrOwned::Owned(Line::DynamicIndexedChoice(indexed_choice_instrs[i]))
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn lookup_instr<'a>(
|
||||
&'a self,
|
||||
last_call: bool,
|
||||
p: &CodePtr,
|
||||
) -> Option<RefOrOwned<'a, Line>> {
|
||||
match p {
|
||||
&CodePtr::Local(local) => {
|
||||
return Some(self.lookup_local_instr(local));
|
||||
}
|
||||
&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])),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn find_living_dynamic_else(
|
||||
&self,
|
||||
mut p: usize,
|
||||
cc: usize,
|
||||
) -> Option<(usize, usize)> {
|
||||
loop {
|
||||
match &self.code[p] {
|
||||
&Line::Choice(ChoiceInstruction::DynamicElse(
|
||||
birth,
|
||||
death,
|
||||
NextOrFail::Next(i),
|
||||
)) => {
|
||||
if birth < cc && Death::Finite(cc) <= death {
|
||||
return Some((p, i));
|
||||
} else if i > 0 {
|
||||
p += i;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
&Line::Choice(ChoiceInstruction::DynamicElse(
|
||||
birth,
|
||||
death,
|
||||
NextOrFail::Fail(_),
|
||||
)) => {
|
||||
if birth < cc && Death::Finite(cc) <= death {
|
||||
return Some((p, 0));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
|
||||
birth,
|
||||
death,
|
||||
NextOrFail::Next(i),
|
||||
)) => {
|
||||
if birth < cc && Death::Finite(cc) <= death {
|
||||
return Some((p, i));
|
||||
} else if i > 0 {
|
||||
p += i;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
|
||||
birth,
|
||||
death,
|
||||
NextOrFail::Fail(_),
|
||||
)) => {
|
||||
if birth < cc && Death::Finite(cc) <= death {
|
||||
return Some((p, 0));
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
&Line::Control(ControlInstruction::RevJmpBy(i)) => {
|
||||
p -= i;
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn find_living_dynamic(
|
||||
&self,
|
||||
p: LocalCodePtr,
|
||||
cc: usize,
|
||||
) -> Option<(usize, usize, usize, bool)> {
|
||||
let (p, oi, mut ii) = match p {
|
||||
LocalCodePtr::IndexingBuf(p, oi, ii) => (p, oi, ii),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let indexed_choice_instrs = match &self.code[p] {
|
||||
Line::IndexingCode(ref indexing_code) => match &indexing_code[oi] {
|
||||
IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
|
||||
indexed_choice_instrs
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
loop {
|
||||
match &indexed_choice_instrs.get(ii) {
|
||||
Some(&offset) => match &self.code[p + offset - 1] {
|
||||
&Line::Choice(ChoiceInstruction::DynamicInternalElse(
|
||||
birth,
|
||||
death,
|
||||
next_or_fail,
|
||||
)) => {
|
||||
if birth < cc && Death::Finite(cc) <= death {
|
||||
return Some((offset, oi, ii, next_or_fail.is_next()));
|
||||
} else {
|
||||
ii += 1;
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
None => return None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,45 +2,47 @@ use crate::instructions::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
|
||||
fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> bool {
|
||||
match line {
|
||||
&Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
|
||||
&Instruction::TryMeElse(offset) if offset > 0 => {
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset))
|
||||
| &Line::Choice(ChoiceInstruction::RetryMeElse(offset))
|
||||
&Instruction::DefaultRetryMeElse(offset) |
|
||||
&Instruction::RetryMeElse(offset)
|
||||
if offset > 0 =>
|
||||
{
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
|
||||
&Instruction::DynamicElse(_, _, NextOrFail::Next(offset))
|
||||
if offset > 0 =>
|
||||
{
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
|
||||
&Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))
|
||||
if offset > 0 =>
|
||||
{
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
|
||||
&Instruction::JmpByCall(_, offset, _) => {
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
|
||||
&Instruction::JmpByExecute(_, offset, _) => {
|
||||
stack.push(index + offset);
|
||||
return true;
|
||||
}
|
||||
&Line::Control(ControlInstruction::Proceed)
|
||||
| &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
|
||||
&Instruction::Proceed => {
|
||||
return true;
|
||||
}
|
||||
&Line::Control(ControlInstruction::RevJmpBy(offset)) => {
|
||||
&Instruction::RevJmpBy(offset) => {
|
||||
if offset > 0 {
|
||||
stack.push(index - offset);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
instr if instr.is_execute() => {
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
||||
@@ -51,7 +53,7 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
|
||||
* begin in code at the offset p. Each instruction is passed to the
|
||||
* walker function.
|
||||
*/
|
||||
pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) {
|
||||
pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) {
|
||||
let mut stack = vec![p];
|
||||
let mut visited_indices = IndexSet::new();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::machine::stack::*;
|
||||
use crate::types::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::IndexMut;
|
||||
@@ -7,20 +8,24 @@ use std::ops::IndexMut;
|
||||
type Trail = Vec<(Ref, HeapCellValue)>;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum AttrVarPolicy {
|
||||
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);
|
||||
pub trait CopierTarget: IndexMut<usize, Output = HeapCellValue> {
|
||||
fn store(&self, value: HeapCellValue) -> HeapCellValue;
|
||||
fn deref(&self, value: HeapCellValue) -> HeapCellValue;
|
||||
fn push(&mut self, value: 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) {
|
||||
pub(crate) fn copy_term<T: CopierTarget>(
|
||||
target: T,
|
||||
addr: HeapCellValue,
|
||||
attr_var_policy: AttrVarPolicy,
|
||||
) {
|
||||
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
|
||||
copy_term_state.copy_term_impl(addr);
|
||||
}
|
||||
@@ -47,50 +52,51 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
|
||||
#[inline]
|
||||
fn value_at_scan(&mut self) -> &mut HeapCellValue {
|
||||
let scan = self.scan;
|
||||
&mut self.target[scan]
|
||||
&mut self.target[self.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));
|
||||
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
|
||||
self.trail.push((Ref::heap_cell(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;
|
||||
read_heap_cell!(self.target[addr + offset],
|
||||
(HeapCellValueTag::Lis, h) => {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = list_loc_as_cell!(h);
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Lis(threshold));
|
||||
*self.value_at_scan() = list_loc_as_cell!(threshold);
|
||||
|
||||
for i in 0..2 {
|
||||
let hcv = self.target[addr + i].context_free_clone();
|
||||
let hcv = self.target[addr + i];
|
||||
self.target.push(hcv);
|
||||
}
|
||||
|
||||
let cdr = self
|
||||
.target
|
||||
.store(self.target.deref(Addr::HeapCell(addr + 1)));
|
||||
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
|
||||
|
||||
if !cdr.is_ref() {
|
||||
if !cdr.is_var() {
|
||||
self.trail_list_cell(addr + 1, threshold);
|
||||
} else {
|
||||
let car = self.target.store(self.target.deref(Addr::HeapCell(addr)));
|
||||
let car = self
|
||||
.target
|
||||
.store(self.target.deref(heap_loc_as_cell!(addr)));
|
||||
|
||||
if !car.is_ref() {
|
||||
if !car.is_var() {
|
||||
self.trail_list_cell(addr, threshold);
|
||||
}
|
||||
}
|
||||
@@ -98,187 +104,190 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
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, n));
|
||||
fn copy_partial_string(&mut self, scan_tag: HeapCellValueTag, pstr_loc: usize) {
|
||||
read_heap_cell!(self.target[pstr_loc],
|
||||
(HeapCellValueTag::PStrLoc, h) => {
|
||||
debug_assert!(h >= self.old_h);
|
||||
|
||||
*self.value_at_scan() = match scan_tag {
|
||||
HeapCellValueTag::PStrLoc => {
|
||||
pstr_loc_as_cell!(h)
|
||||
}
|
||||
tag => {
|
||||
debug_assert_eq!(tag, HeapCellValueTag::PStrOffset);
|
||||
pstr_offset_as_cell!(h)
|
||||
}
|
||||
};
|
||||
|
||||
self.scan += 1;
|
||||
return;
|
||||
}
|
||||
(HeapCellValueTag::Var, h) => {
|
||||
debug_assert!(h >= self.old_h);
|
||||
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
|
||||
|
||||
*self.value_at_scan() = pstr_offset_as_cell!(h);
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
|
||||
let replacement = read_heap_cell!(self.target[pstr_loc],
|
||||
(HeapCellValueTag::CStr) => {
|
||||
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
|
||||
|
||||
*self.value_at_scan() = pstr_offset_as_cell!(threshold);
|
||||
self.target.push(self.target[pstr_loc]);
|
||||
|
||||
heap_loc_as_cell!(threshold)
|
||||
}
|
||||
_ => {
|
||||
*self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc {
|
||||
pstr_loc_as_cell!(threshold)
|
||||
} else {
|
||||
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
|
||||
pstr_offset_as_cell!(threshold)
|
||||
};
|
||||
|
||||
self.target.push(self.target[pstr_loc]);
|
||||
self.target.push(self.target[pstr_loc + 1]);
|
||||
|
||||
pstr_loc_as_cell!(threshold)
|
||||
}
|
||||
);
|
||||
|
||||
self.scan += 1;
|
||||
|
||||
let (pstr, has_tail) = match &self.target[addr] {
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
(pstr.clone_from_offset(0), has_tail)
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
self.target
|
||||
.push(HeapCellValue::PartialString(pstr, has_tail));
|
||||
|
||||
let replacement = HeapCellValue::Addr(Addr::PStrLocation(threshold, n));
|
||||
|
||||
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));
|
||||
}
|
||||
let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
|
||||
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
|
||||
}
|
||||
|
||||
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));
|
||||
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
|
||||
read_heap_cell!(addr,
|
||||
(HeapCellValueTag::Var, h) => {
|
||||
self.target[frontier] = heap_loc_as_cell!(frontier);
|
||||
self.target[h] = heap_loc_as_cell!(frontier);
|
||||
|
||||
self.trail
|
||||
.push((Ref::HeapCell(h), HeapCellValue::Addr(Addr::HeapCell(h))));
|
||||
self.trail.push((Ref::heap_cell(h), heap_loc_as_cell!(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);
|
||||
(HeapCellValueTag::StackVar, s) => {
|
||||
self.target[frontier] = heap_loc_as_cell!(frontier);
|
||||
self.target.stack()[s] = heap_loc_as_cell!(frontier);
|
||||
|
||||
self.trail.push((
|
||||
Ref::StackCell(fr, sc),
|
||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)),
|
||||
));
|
||||
self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
|
||||
}
|
||||
Addr::AttrVar(h) => {
|
||||
(HeapCellValueTag::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.target[frontier] = heap_loc_as_cell!(threshold);
|
||||
self.target[h] = heap_loc_as_cell!(threshold);
|
||||
|
||||
self.trail
|
||||
.push((Ref::AttrVar(h), HeapCellValue::Addr(Addr::AttrVar(h))));
|
||||
self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
|
||||
|
||||
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
|
||||
self.target
|
||||
.push(HeapCellValue::Addr(Addr::AttrVar(threshold)));
|
||||
self.target.push(attr_var_as_cell!(threshold));
|
||||
|
||||
let list_val = self.target[h + 1].context_free_clone();
|
||||
let list_val = self.target[h + 1];
|
||||
self.target.push(list_val);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn copy_var(&mut self, addr: Addr) {
|
||||
let rd = self.target.store(self.target.deref(addr));
|
||||
fn copy_var(&mut self, addr: HeapCellValue) {
|
||||
let rd = self.target.deref(addr);
|
||||
let ra = self.target.store(rd);
|
||||
|
||||
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);
|
||||
read_heap_cell!(ra,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
if h >= self.old_h {
|
||||
*self.value_at_scan() = ra;
|
||||
self.scan += 1;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
);
|
||||
|
||||
if rd == ra {
|
||||
self.reinstantiate_var(ra, self.scan);
|
||||
self.scan += 1;
|
||||
} else {
|
||||
*self.value_at_scan() = ra;
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_structure(&mut self, addr: usize) {
|
||||
match self.target[addr].context_free_clone() {
|
||||
HeapCellValue::NamedStr(arity, name, fixity) => {
|
||||
read_heap_cell!(self.target[addr],
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
let threshold = self.target.threshold();
|
||||
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(threshold));
|
||||
*self.value_at_scan() = str_loc_as_cell!(threshold);
|
||||
|
||||
let trail_item = mem::replace(
|
||||
&mut self.target[addr],
|
||||
HeapCellValue::Addr(Addr::Str(threshold)),
|
||||
str_loc_as_cell!(threshold),
|
||||
);
|
||||
|
||||
self.trail.push((Ref::HeapCell(addr), trail_item));
|
||||
|
||||
self.target
|
||||
.push(HeapCellValue::NamedStr(arity, name, fixity));
|
||||
self.trail.push((Ref::heap_cell(addr), trail_item));
|
||||
self.target.push(atom_as_cell!(name, arity));
|
||||
|
||||
for i in 0..arity {
|
||||
let hcv = self.target[addr + 1 + i].context_free_clone();
|
||||
let hcv = self.target[addr + 1 + i];
|
||||
self.target.push(hcv);
|
||||
}
|
||||
}
|
||||
HeapCellValue::Addr(Addr::Str(addr)) => {
|
||||
*self.value_at_scan() = HeapCellValue::Addr(Addr::Str(addr))
|
||||
(HeapCellValueTag::Str, h) => {
|
||||
*self.value_at_scan() = str_loc_as_cell!(h);
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
self.scan += 1;
|
||||
}
|
||||
|
||||
fn copy_term_impl(&mut self, addr: Addr) {
|
||||
fn copy_term_impl(&mut self, addr: HeapCellValue) {
|
||||
self.scan = self.target.threshold();
|
||||
self.target.push(HeapCellValue::Addr(addr));
|
||||
self.target.push(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);
|
||||
let addr = *self.value_at_scan();
|
||||
|
||||
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();
|
||||
}
|
||||
_ => {
|
||||
read_heap_cell!(addr,
|
||||
(HeapCellValueTag::Lis, h) => {
|
||||
if h >= self.old_h {
|
||||
self.scan += 1;
|
||||
} else {
|
||||
self.copy_list(h);
|
||||
}
|
||||
},
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
|
||||
self.copy_var(addr);
|
||||
}
|
||||
(HeapCellValueTag::Str, h) => {
|
||||
self.copy_structure(h);
|
||||
}
|
||||
(HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
|
||||
self.copy_partial_string(addr.get_tag(), pstr_loc);
|
||||
}
|
||||
_ => {
|
||||
self.scan += 1;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
self.unwind_trail();
|
||||
@@ -286,12 +295,117 @@ impl<T: CopierTarget> CopyTermState<T> {
|
||||
|
||||
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)
|
||||
}
|
||||
let index = r.get_value() as usize;
|
||||
|
||||
match r.get_tag() {
|
||||
RefTag::AttrVar | RefTag::HeapCell => self.target[index] = value,
|
||||
RefTag::StackCell => self.target.stack()[index] = value,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::machine::mock_wam::*;
|
||||
|
||||
#[test]
|
||||
fn copier_tests() {
|
||||
let mut wam = MockWAM::new();
|
||||
|
||||
let f_atom = atom!("f");
|
||||
let a_atom = atom!("a");
|
||||
let b_atom = atom!("b");
|
||||
|
||||
wam.machine_st.heap
|
||||
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
|
||||
|
||||
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
|
||||
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
|
||||
|
||||
{
|
||||
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
|
||||
}
|
||||
|
||||
// check that the original heap state is still intact.
|
||||
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 2));
|
||||
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
|
||||
|
||||
assert_eq!(wam.machine_st.heap[3], str_loc_as_cell!(4));
|
||||
assert_eq!(wam.machine_st.heap[4], atom_as_cell!(f_atom, 2));
|
||||
assert_eq!(wam.machine_st.heap[5], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(b_atom));
|
||||
|
||||
wam.machine_st.heap.clear();
|
||||
|
||||
let pstr_var_cell = put_partial_string(&mut wam.machine_st.heap, "abc ", &mut wam.machine_st.atom_tbl);
|
||||
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
|
||||
|
||||
let pstr_second_var_cell = put_partial_string(&mut wam.machine_st.heap, "def", &mut wam.machine_st.atom_tbl);
|
||||
let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize];
|
||||
|
||||
wam.machine_st.heap.pop();
|
||||
wam.machine_st.heap.push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1));
|
||||
|
||||
wam.machine_st.heap.push(pstr_offset_as_cell!(0));
|
||||
wam.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(0i64)));
|
||||
|
||||
{
|
||||
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
|
||||
}
|
||||
|
||||
print_heap_terms(wam.machine_st.heap[6..].iter(), 6);
|
||||
|
||||
assert_eq!(wam.machine_st.heap[0], pstr_cell);
|
||||
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(2));
|
||||
assert_eq!(wam.machine_st.heap[2], pstr_second_cell);
|
||||
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(4));
|
||||
assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0));
|
||||
assert_eq!(wam.machine_st.heap[5], fixnum_as_cell!(Fixnum::build_with(0i64)));
|
||||
|
||||
assert_eq!(wam.machine_st.heap[7], pstr_cell);
|
||||
assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(9));
|
||||
assert_eq!(wam.machine_st.heap[9], pstr_second_cell);
|
||||
assert_eq!(wam.machine_st.heap[10], pstr_loc_as_cell!(11));
|
||||
assert_eq!(wam.machine_st.heap[11], pstr_offset_as_cell!(7));
|
||||
assert_eq!(wam.machine_st.heap[12], fixnum_as_cell!(Fixnum::build_with(0i64)));
|
||||
|
||||
wam.machine_st.heap.clear();
|
||||
|
||||
wam.machine_st.heap.extend(functor!(
|
||||
f_atom,
|
||||
[
|
||||
atom(a_atom),
|
||||
atom(b_atom),
|
||||
atom(a_atom),
|
||||
cell(str_loc_as_cell!(0))
|
||||
]
|
||||
));
|
||||
|
||||
{
|
||||
let wam = TermCopyingMockWAM { wam: &mut wam };
|
||||
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
|
||||
}
|
||||
|
||||
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
|
||||
assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[2], atom_as_cell!(b_atom));
|
||||
assert_eq!(wam.machine_st.heap[3], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[4], str_loc_as_cell!(0));
|
||||
|
||||
assert_eq!(wam.machine_st.heap[5], str_loc_as_cell!(6));
|
||||
assert_eq!(wam.machine_st.heap[6], atom_as_cell!(f_atom, 4));
|
||||
assert_eq!(wam.machine_st.heap[7], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[8], atom_as_cell!(b_atom));
|
||||
assert_eq!(wam.machine_st.heap[9], atom_as_cell!(a_atom));
|
||||
assert_eq!(wam.machine_st.heap[10], str_loc_as_cell!(6));
|
||||
}
|
||||
}
|
||||
|
||||
4886
src/machine/dispatch.rs
Normal file
4886
src/machine/dispatch.rs
Normal file
File diff suppressed because it is too large
Load Diff
1100
src/machine/gc.rs
Normal file
1100
src/machine/gc.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,462 +1,282 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use prolog_parser::ast::Constant;
|
||||
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::machine::partial_string::*;
|
||||
use crate::machine::raw_block::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::types::*;
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
use rug::{Integer, Rational};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct StandardHeapTraits {}
|
||||
pub(crate) type Heap = Vec<HeapCellValue>;
|
||||
|
||||
impl RawBlockTraits for StandardHeapTraits {
|
||||
impl From<Literal> for HeapCellValue {
|
||||
#[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
|
||||
fn from(literal: Literal) -> Self {
|
||||
match literal {
|
||||
Literal::Atom(name) => atom_as_cell!(name),
|
||||
Literal::Char(c) => char_as_cell!(c),
|
||||
Literal::Fixnum(n) => fixnum_as_cell!(n),
|
||||
Literal::Integer(bigint_ptr) => {
|
||||
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||
}
|
||||
Literal::Rational(bigint_ptr) => {
|
||||
typed_arena_ptr_as_cell!(bigint_ptr)
|
||||
}
|
||||
Literal::Float(f) => HeapCellValue::from(f),
|
||||
Literal::String(s) => {
|
||||
if s == atom!("") {
|
||||
empty_list_as_cell!()
|
||||
} else {
|
||||
string_as_cstr_cell!(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HeapIter<'a, T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: &'a RawBlock<T>,
|
||||
}
|
||||
impl TryFrom<HeapCellValue> for Literal {
|
||||
type Error = ();
|
||||
|
||||
impl<'a, T: RawBlockTraits> HeapIter<'a, T> {
|
||||
pub(crate) fn new(buf: &'a RawBlock<T>, offset: usize) -> Self {
|
||||
HeapIter { buf, offset }
|
||||
fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
Ok(Literal::Atom(name))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
Ok(Literal::Char(c))
|
||||
}
|
||||
(HeapCellValueTag::Fixnum, n) => {
|
||||
Ok(Literal::Fixnum(n))
|
||||
}
|
||||
(HeapCellValueTag::F64, f) => {
|
||||
Ok(Literal::Float(f))
|
||||
}
|
||||
(HeapCellValueTag::Cons, cons_ptr) => {
|
||||
match_untyped_arena_ptr!(cons_ptr,
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
Ok(Literal::Integer(n))
|
||||
}
|
||||
(ArenaHeaderTag::Rational, n) => {
|
||||
Ok(Literal::Rational(n))
|
||||
}
|
||||
(ArenaHeaderTag::F64, f) => {
|
||||
// remove this redundancy.
|
||||
Ok(Literal::Float(F64Ptr(f)))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
)
|
||||
}
|
||||
(HeapCellValueTag::CStr, cstr_atom) => {
|
||||
Ok(Literal::String(cstr_atom))
|
||||
}
|
||||
_ => {
|
||||
Err(())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: RawBlockTraits> Iterator for HeapIter<'a, T> {
|
||||
type Item = &'a HeapCellValue;
|
||||
// sometimes we need to dereference variables that are found only in
|
||||
// the heap without access to the full WAM (e.g., while detecting
|
||||
// cycles in terms), and which therefore may only point other cells in
|
||||
// the heap (thanks to the design of the WAM).
|
||||
pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue {
|
||||
loop {
|
||||
let new_value = read_heap_cell!(value,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
heap[h]
|
||||
}
|
||||
_ => {
|
||||
value
|
||||
}
|
||||
);
|
||||
|
||||
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
|
||||
if new_value != value && new_value.is_var() {
|
||||
value = new_value;
|
||||
continue;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue {
|
||||
read_heap_cell!(value,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
heap[h]
|
||||
}
|
||||
_ => {
|
||||
value
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
|
||||
pub fn print_heap_terms<'a, I: Iterator<Item = &'a HeapCellValue>>(heap: I, h: usize) {
|
||||
for (index, term) in heap.enumerate() {
|
||||
println!("{} : {}", h + index, term);
|
||||
println!("{} : {:?}", h + index, term);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HeapIterMut<'a, T: RawBlockTraits> {
|
||||
offset: usize,
|
||||
buf: &'a mut RawBlock<T>,
|
||||
}
|
||||
#[inline]
|
||||
pub(crate) fn put_complete_string(
|
||||
heap: &mut Heap,
|
||||
s: &str,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> HeapCellValue {
|
||||
match allocate_pstr(heap, s, atom_tbl) {
|
||||
Some(h) => {
|
||||
heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr.
|
||||
|
||||
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::LoadStatePayload(_) => HeapCellValue::Addr(Addr::LoadStatePayload(h)),
|
||||
&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 is_empty(&self) -> bool {
|
||||
self.h() == 0
|
||||
}
|
||||
|
||||
#[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::LoadStatePayload(_) => Addr::LoadStatePayload(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;
|
||||
if heap.len() == h + 1 {
|
||||
let pstr_atom = cell_as_atom!(heap[h]);
|
||||
heap[h] = atom_as_cstr_cell!(pstr_atom);
|
||||
heap_loc_as_cell!(h)
|
||||
} else {
|
||||
self.push(HeapCellValue::Addr(Addr::HeapCell(h + 1)));
|
||||
return Some(Addr::PStrLocation(orig_h, 0));
|
||||
heap.push(empty_list_as_cell!());
|
||||
pstr_loc_as_cell!(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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);
|
||||
None => {
|
||||
let h = heap.len();
|
||||
heap.push(empty_list_as_cell!());
|
||||
heap_loc_as_cell!(h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
if !self.buf.base.is_null() {
|
||||
self.truncate(0);
|
||||
self.buf.top = self.buf.base;
|
||||
#[inline]
|
||||
pub(crate) fn put_partial_string(
|
||||
heap: &mut Heap,
|
||||
s: &str,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> HeapCellValue {
|
||||
match allocate_pstr(heap, s, atom_tbl) {
|
||||
Some(h) => {
|
||||
pstr_loc_as_cell!(h)
|
||||
}
|
||||
None => {
|
||||
empty_list_as_cell!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
#[inline]
|
||||
pub(crate) fn allocate_pstr(
|
||||
heap: &mut Heap,
|
||||
mut src: &str,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Option<usize> {
|
||||
let orig_h = heap.len();
|
||||
|
||||
for value in values.map(|v| v.into()) {
|
||||
self.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
self.push(value);
|
||||
loop {
|
||||
if src == "" {
|
||||
return if orig_h == heap.len() {
|
||||
None
|
||||
} else {
|
||||
let tail_h = heap.len() - 1;
|
||||
heap[tail_h] = heap_loc_as_cell!(tail_h);
|
||||
|
||||
h += 2;
|
||||
Some(orig_h)
|
||||
};
|
||||
}
|
||||
|
||||
self.push(HeapCellValue::Addr(Addr::EmptyList));
|
||||
let h = heap.len();
|
||||
|
||||
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,
|
||||
let (pstr, rest_src) = match PartialString::new(src, atom_tbl) {
|
||||
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 {
|
||||
heap[h - 1] = heap_loc_as_cell!(h - 1);
|
||||
return Some(orig_h);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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),
|
||||
/*
|
||||
("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));
|
||||
}
|
||||
}
|
||||
heap.push(string_as_pstr_cell!(pstr));
|
||||
|
||||
None
|
||||
}
|
||||
*/
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
if rest_src != "" {
|
||||
heap.push(pstr_loc_as_cell!(h + 2));
|
||||
src = rest_src;
|
||||
} else {
|
||||
heap.push(heap_loc_as_cell!(h + 1));
|
||||
return Some(orig_h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filtered_iter_to_heap_list<SrcT: Into<HeapCellValue>>(
|
||||
heap: &mut Heap,
|
||||
values: impl Iterator<Item = SrcT>,
|
||||
filter_fn: impl Fn(&Heap, HeapCellValue) -> bool,
|
||||
) -> usize {
|
||||
let head_addr = heap.len();
|
||||
let mut h = head_addr;
|
||||
|
||||
for value in values {
|
||||
let value = value.into();
|
||||
|
||||
if filter_fn(heap, value) {
|
||||
heap.push(list_loc_as_cell!(h + 1));
|
||||
heap.push(value);
|
||||
|
||||
h += 2;
|
||||
}
|
||||
}
|
||||
|
||||
heap.push(empty_list_as_cell!());
|
||||
|
||||
head_addr
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn iter_to_heap_list<Iter, SrcT>(heap: &mut Heap, values: Iter) -> usize
|
||||
where
|
||||
Iter: Iterator<Item = SrcT>,
|
||||
SrcT: Into<HeapCellValue>,
|
||||
{
|
||||
filtered_iter_to_heap_list(heap, values, |_, _| true)
|
||||
}
|
||||
|
||||
pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
|
||||
let extract_integer = |s: usize| -> Option<usize> {
|
||||
match Number::try_from(heap[s]) {
|
||||
Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
|
||||
Ok(Number::Integer(n)) => n.to_usize(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#[inline]
|
||||
pub(crate) 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])
|
||||
read_heap_cell!(addr,
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
|
||||
|
||||
if name == atom!("dir_entry") && arity == 1 {
|
||||
extract_integer(s+1)
|
||||
} else {
|
||||
panic!(
|
||||
"to_local_code_ptr crashed with p.i. {}/{}",
|
||||
name.as_str(),
|
||||
arity,
|
||||
);
|
||||
}
|
||||
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)
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,53 +1,38 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::clause_name;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::code_repo::CodeRepo;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_state::*;
|
||||
use crate::machine::partial_string::*;
|
||||
use crate::machine::raw_block::RawBlockTraits;
|
||||
use crate::machine::streams::Stream;
|
||||
use crate::machine::term_stream::LoadStatePayload;
|
||||
use crate::machine::CompilationTarget;
|
||||
use crate::rug::{Integer, Rational};
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
// use std::mem;
|
||||
use std::net::TcpListener;
|
||||
use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
|
||||
use std::collections::BTreeSet;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::types::*;
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct OrderedOpDirKey(pub(crate) ClauseName, pub(crate) Fixity);
|
||||
pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
|
||||
|
||||
pub(crate) type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>;
|
||||
pub(crate) type OssifiedOpDir = IndexMap<(Atom, Fixity), (usize, Specifier)>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum DBRef {
|
||||
NamedPred(ClauseName, usize, Option<SharedOpDesc>),
|
||||
Op(
|
||||
usize,
|
||||
Specifier,
|
||||
ClauseName,
|
||||
Rc<OssifiedOpDir>,
|
||||
SharedOpDesc,
|
||||
),
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DBRef {
|
||||
NamedPred(Atom, usize),
|
||||
Op(Atom, Fixity, TypedArenaPtr<OssifiedOpDir>),
|
||||
}
|
||||
|
||||
// 7.2
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub(crate) enum TermOrderCategory {
|
||||
pub enum TermOrderCategory {
|
||||
Variable,
|
||||
FloatingPoint,
|
||||
Integer,
|
||||
@@ -55,322 +40,45 @@ pub(crate) enum TermOrderCategory {
|
||||
Compound,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum Addr {
|
||||
AttrVar(usize),
|
||||
Char(char),
|
||||
Con(usize),
|
||||
CutPoint(usize),
|
||||
EmptyList,
|
||||
Fixnum(isize),
|
||||
Float(OrderedFloat<f64>),
|
||||
Lis(usize),
|
||||
LoadStatePayload(usize),
|
||||
HeapCell(usize),
|
||||
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
|
||||
StackCell(usize, usize),
|
||||
Str(usize),
|
||||
Stream(usize),
|
||||
TcpListener(usize),
|
||||
Usize(usize),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, PartialOrd)]
|
||||
pub(crate) enum Ref {
|
||||
AttrVar(usize),
|
||||
HeapCell(usize),
|
||||
StackCell(usize, usize),
|
||||
}
|
||||
|
||||
impl Ref {
|
||||
pub(crate) fn as_addr(self) -> Addr {
|
||||
match self {
|
||||
Ref::AttrVar(h) => Addr::AttrVar(h),
|
||||
Ref::HeapCell(h) => Addr::HeapCell(h),
|
||||
Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Ref {
|
||||
fn cmp(&self, other: &Ref) -> Ordering {
|
||||
match (self, other) {
|
||||
(Ref::AttrVar(h1), Ref::AttrVar(h2))
|
||||
| (Ref::HeapCell(h1), Ref::HeapCell(h2))
|
||||
| (Ref::HeapCell(h1), Ref::AttrVar(h2))
|
||||
| (Ref::AttrVar(h1), Ref::HeapCell(h2)) => h1.cmp(&h2),
|
||||
(Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => {
|
||||
fr1.cmp(&fr2).then_with(|| sc1.cmp(&sc2))
|
||||
}
|
||||
(Ref::StackCell(..), _) => Ordering::Greater,
|
||||
(_, Ref::StackCell(..)) => Ordering::Less,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Ref> for Addr {
|
||||
impl PartialEq<Ref> for HeapCellValue {
|
||||
fn eq(&self, r: &Ref) -> bool {
|
||||
self.as_var() == Some(*r)
|
||||
}
|
||||
}
|
||||
|
||||
// for use crate::in MachineState::bind.
|
||||
impl PartialOrd<Ref> for Addr {
|
||||
impl PartialOrd<Ref> for HeapCellValue {
|
||||
fn partial_cmp(&self, r: &Ref) -> Option<Ordering> {
|
||||
match self {
|
||||
&Addr::StackCell(fr, sc) => match *r {
|
||||
Ref::AttrVar(_) | Ref::HeapCell(_) => Some(Ordering::Greater),
|
||||
Ref::StackCell(fr1, sc1) => {
|
||||
if fr1 < fr || (fr1 == fr && sc1 < sc) {
|
||||
Some(Ordering::Greater)
|
||||
} else if fr1 == fr && sc1 == sc {
|
||||
Some(Ordering::Equal)
|
||||
} else {
|
||||
Some(Ordering::Less)
|
||||
read_heap_cell!(*self,
|
||||
(HeapCellValueTag::StackVar, s1) => {
|
||||
match r.get_tag() {
|
||||
RefTag::StackCell => {
|
||||
let s2 = r.get_value() as usize;
|
||||
s1.partial_cmp(&s2)
|
||||
}
|
||||
_ => Some(Ordering::Greater),
|
||||
}
|
||||
},
|
||||
&Addr::HeapCell(h) | &Addr::AttrVar(h) => match r {
|
||||
Ref::StackCell(..) => Some(Ordering::Less),
|
||||
Ref::AttrVar(h1) | Ref::HeapCell(h1) => h.partial_cmp(h1),
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Addr {
|
||||
#[inline]
|
||||
pub(crate) fn is_heap_bound(&self) -> bool {
|
||||
match self {
|
||||
Addr::Char(_)
|
||||
| Addr::EmptyList
|
||||
| Addr::CutPoint(_)
|
||||
| Addr::Usize(_)
|
||||
| Addr::Fixnum(_)
|
||||
| Addr::Float(_) => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Addr::HeapCell(_) | Addr::StackCell(_, _) | Addr::AttrVar(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn as_var(&self) -> Option<Ref> {
|
||||
match self {
|
||||
&Addr::AttrVar(h) => Some(Ref::AttrVar(h)),
|
||||
&Addr::HeapCell(h) => Some(Ref::HeapCell(h)),
|
||||
&Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn order_category(&self, heap: &Heap) -> Option<TermOrderCategory> {
|
||||
match Number::try_from((*self, heap)) {
|
||||
Ok(Number::Integer(_)) | Ok(Number::Fixnum(_)) | Ok(Number::Rational(_)) => {
|
||||
Some(TermOrderCategory::Integer)
|
||||
}
|
||||
Ok(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
|
||||
_ => match self {
|
||||
Addr::HeapCell(_) | Addr::AttrVar(_) | Addr::StackCell(..) => {
|
||||
Some(TermOrderCategory::Variable)
|
||||
}
|
||||
Addr::Float(_) => Some(TermOrderCategory::FloatingPoint),
|
||||
&Addr::Con(h) => match &heap[h] {
|
||||
HeapCellValue::Atom(..) => Some(TermOrderCategory::Atom),
|
||||
HeapCellValue::DBRef(_) => None,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h1) => {
|
||||
// _ if self.is_ref() => {
|
||||
// let h1 = self.get_value();
|
||||
|
||||
match r.get_tag() {
|
||||
RefTag::StackCell => Some(Ordering::Less),
|
||||
_ => {
|
||||
unreachable!()
|
||||
let h2 = r.get_value() as usize;
|
||||
h1.partial_cmp(&h2)
|
||||
}
|
||||
},
|
||||
Addr::Char(_) | Addr::EmptyList => Some(TermOrderCategory::Atom),
|
||||
Addr::Fixnum(_) | Addr::Usize(_) => Some(TermOrderCategory::Integer),
|
||||
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
|
||||
Some(TermOrderCategory::Compound)
|
||||
}
|
||||
Addr::CutPoint(_)
|
||||
| Addr::LoadStatePayload(_)
|
||||
| Addr::Stream(_)
|
||||
| Addr::TcpListener(_) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn as_constant_index(&self, machine_st: &MachineState) -> Option<Constant> {
|
||||
match self {
|
||||
&Addr::Char(c) => Some(Constant::Char(c)),
|
||||
&Addr::Con(h) => match &machine_st.heap[h] {
|
||||
&HeapCellValue::Atom(ref name, _) if name.is_char() => {
|
||||
Some(Constant::Char(name.as_str().chars().next().unwrap()))
|
||||
}
|
||||
&HeapCellValue::Atom(ref name, _) => Some(Constant::Atom(name.clone(), None)),
|
||||
&HeapCellValue::Integer(ref n) => Some(Constant::Integer(n.clone())),
|
||||
&HeapCellValue::Rational(ref n) => Some(Constant::Rational(n.clone())),
|
||||
_ => None,
|
||||
},
|
||||
&Addr::EmptyList => Some(Constant::EmptyList),
|
||||
&Addr::Fixnum(n) => Some(Constant::Fixnum(n)),
|
||||
&Addr::Float(f) => Some(Constant::Float(f)),
|
||||
&Addr::Usize(n) => Some(Constant::Usize(n)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_protected(&self, e: usize) -> bool {
|
||||
match self {
|
||||
&Addr::StackCell(addr, _) if addr >= e => false,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Addr {
|
||||
type Output = Addr;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
Addr::Stream(h) => Addr::Stream(h + rhs),
|
||||
Addr::Con(h) => Addr::Con(h + rhs),
|
||||
Addr::Lis(a) => Addr::Lis(a + rhs),
|
||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs),
|
||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs),
|
||||
Addr::Str(s) => Addr::Str(s + rhs),
|
||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs, n),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<i64> for Addr {
|
||||
type Output = Addr;
|
||||
|
||||
fn sub(self, rhs: i64) -> Self::Output {
|
||||
if rhs < 0 {
|
||||
match self {
|
||||
Addr::Stream(h) => Addr::Stream(h + rhs.abs() as usize),
|
||||
Addr::Con(h) => Addr::Con(h + rhs.abs() as usize),
|
||||
Addr::Lis(a) => Addr::Lis(a + rhs.abs() as usize),
|
||||
Addr::AttrVar(h) => Addr::AttrVar(h + rhs.abs() as usize),
|
||||
Addr::HeapCell(h) => Addr::HeapCell(h + rhs.abs() as usize),
|
||||
Addr::Str(s) => Addr::Str(s + rhs.abs() as usize),
|
||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h + rhs.abs() as usize, n),
|
||||
_ => self,
|
||||
}
|
||||
} else {
|
||||
self.sub(rhs as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<usize> for Addr {
|
||||
type Output = Addr;
|
||||
|
||||
fn sub(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
Addr::Stream(h) => Addr::Stream(h - rhs),
|
||||
Addr::Con(h) => Addr::Con(h - rhs),
|
||||
Addr::Lis(a) => Addr::Lis(a - rhs),
|
||||
Addr::AttrVar(h) => Addr::AttrVar(h - rhs),
|
||||
Addr::HeapCell(h) => Addr::HeapCell(h - rhs),
|
||||
Addr::Str(s) => Addr::Str(s - rhs),
|
||||
Addr::PStrLocation(h, n) => Addr::PStrLocation(h - rhs, n),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<usize> for Addr {
|
||||
fn sub_assign(&mut self, rhs: usize) {
|
||||
*self = self.clone() - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) enum TrailRef {
|
||||
Ref(Ref),
|
||||
AttrVarHeapLink(usize),
|
||||
AttrVarListLink(usize, usize),
|
||||
BlackboardEntry(usize),
|
||||
BlackboardOffset(usize, usize), // key atom heap location, key value heap location
|
||||
}
|
||||
|
||||
impl From<Ref> for TrailRef {
|
||||
fn from(r: Ref) -> Self {
|
||||
TrailRef::Ref(r)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum HeapCellValue {
|
||||
Addr(Addr),
|
||||
Atom(ClauseName, Option<SharedOpDesc>),
|
||||
DBRef(DBRef),
|
||||
Integer(Rc<Integer>),
|
||||
LoadStatePayload(Box<LoadStatePayload>),
|
||||
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
|
||||
Rational(Rc<Rational>),
|
||||
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
|
||||
Stream(Stream),
|
||||
TcpListener(TcpListener),
|
||||
}
|
||||
|
||||
impl HeapCellValue {
|
||||
#[inline]
|
||||
pub(crate) fn as_addr(&self, focus: usize) -> Addr {
|
||||
match self {
|
||||
HeapCellValue::Addr(ref a) => *a,
|
||||
HeapCellValue::Atom(..)
|
||||
| HeapCellValue::DBRef(..)
|
||||
| HeapCellValue::Integer(..)
|
||||
| HeapCellValue::Rational(..) => Addr::Con(focus),
|
||||
HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(focus),
|
||||
HeapCellValue::NamedStr(_, _, _) => Addr::Str(focus),
|
||||
HeapCellValue::PartialString(..) => Addr::PStrLocation(focus, 0),
|
||||
HeapCellValue::Stream(_) => Addr::Stream(focus),
|
||||
HeapCellValue::TcpListener(_) => Addr::TcpListener(focus),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn context_free_clone(&self) -> HeapCellValue {
|
||||
match self {
|
||||
&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::LoadStatePayload(_) => {
|
||||
HeapCellValue::Atom(clause_name!("$live_term_stream"), None)
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
&HeapCellValue::NamedStr(arity, ref name, ref op) => {
|
||||
HeapCellValue::NamedStr(arity, name.clone(), op.clone())
|
||||
}
|
||||
&HeapCellValue::Rational(ref r) => HeapCellValue::Rational(r.clone()),
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
HeapCellValue::PartialString(pstr.clone(), has_tail)
|
||||
}
|
||||
&HeapCellValue::Stream(ref stream) => HeapCellValue::Stream(stream.clone()),
|
||||
&HeapCellValue::TcpListener(_) => {
|
||||
HeapCellValue::Atom(clause_name!("$tcp_listener"), None)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Addr> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(value: Addr) -> HeapCellValue {
|
||||
HeapCellValue::Addr(value)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub(crate) enum IndexPtr {
|
||||
pub enum IndexPtr {
|
||||
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
|
||||
DynamicIndex(usize),
|
||||
Index(usize),
|
||||
@@ -378,7 +86,7 @@ pub(crate) enum IndexPtr {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub(crate) struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
|
||||
pub struct CodeIndex(pub(crate) Rc<Cell<IndexPtr>>);
|
||||
|
||||
impl Deref for CodeIndex {
|
||||
type Target = Cell<IndexPtr>;
|
||||
@@ -418,265 +126,25 @@ impl Default for CodeIndex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
||||
pub(crate) enum REPLCodePtr {
|
||||
AddDiscontiguousPredicate,
|
||||
AddDynamicPredicate,
|
||||
AddMultifilePredicate,
|
||||
AddGoalExpansionClause,
|
||||
AddTermExpansionClause,
|
||||
AddInSituFilenameModule,
|
||||
ClauseToEvacuable,
|
||||
ScopedClauseToEvacuable,
|
||||
ConcludeLoad,
|
||||
DeclareModule,
|
||||
LoadCompiledLibrary,
|
||||
LoadContextSource,
|
||||
LoadContextFile,
|
||||
LoadContextDirectory,
|
||||
LoadContextModule,
|
||||
LoadContextStream,
|
||||
PopLoadContext,
|
||||
PopLoadStatePayload,
|
||||
PushLoadContext,
|
||||
PushLoadStatePayload,
|
||||
UseModule,
|
||||
BuiltInProperty,
|
||||
MetaPredicateProperty,
|
||||
MultifileProperty,
|
||||
DiscontiguousProperty,
|
||||
DynamicProperty,
|
||||
AbolishClause,
|
||||
Asserta,
|
||||
Assertz,
|
||||
Retract,
|
||||
IsConsistentWithTermQueue,
|
||||
FlushTermQueue,
|
||||
RemoveModuleExports,
|
||||
AddNonCountedBacktracking,
|
||||
}
|
||||
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
|
||||
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) enum CodePtr {
|
||||
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
|
||||
CallN(usize, LocalCodePtr, bool), // arity, local, last call.
|
||||
Local(LocalCodePtr),
|
||||
// DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
|
||||
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
|
||||
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
|
||||
}
|
||||
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
|
||||
|
||||
impl CodePtr {
|
||||
pub(crate) fn local(&self) -> LocalCodePtr {
|
||||
match self {
|
||||
&CodePtr::BuiltInClause(_, ref local)
|
||||
| &CodePtr::CallN(_, ref local, _)
|
||||
| &CodePtr::Local(ref local) => local.clone(),
|
||||
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
|
||||
&CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn is_halt(&self) -> bool {
|
||||
if let CodePtr::Local(LocalCodePtr::Halt) = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub(crate) enum LocalCodePtr {
|
||||
DirEntry(usize), // offset
|
||||
Halt,
|
||||
IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
|
||||
// TopLevel(usize, usize), // chunk_num, offset
|
||||
}
|
||||
|
||||
impl LocalCodePtr {
|
||||
pub(crate) fn assign_if_local(&mut self, cp: CodePtr) {
|
||||
match cp {
|
||||
CodePtr::Local(local) => *self = local,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn abs_loc(&self) -> usize {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(ref p) => *p,
|
||||
LocalCodePtr::IndexingBuf(ref p, ..) => *p,
|
||||
LocalCodePtr::Halt => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
|
||||
match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
|
||||
Some(line) => match line.as_ref() {
|
||||
Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
|
||||
if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
None => {}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn as_functor<T: RawBlockTraits>(&self, heap: &mut HeapTemplate<T>) -> Addr {
|
||||
let addr = Addr::HeapCell(heap.h());
|
||||
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p) => {
|
||||
heap.append(functor!("dir_entry", [integer(*p)]));
|
||||
}
|
||||
LocalCodePtr::Halt => {
|
||||
heap.append(functor!("halt"));
|
||||
}
|
||||
/*
|
||||
LocalCodePtr::TopLevel(chunk_num, offset) => {
|
||||
heap.append(functor!(
|
||||
"top_level",
|
||||
[integer(*chunk_num), integer(*offset)]
|
||||
));
|
||||
}
|
||||
*/
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => {
|
||||
heap.append(functor!(
|
||||
"indexed_buf",
|
||||
[integer(*p), integer(*o), integer(*i)]
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
addr
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CodePtr {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
CodePtr::Local(LocalCodePtr::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LocalCodePtr {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
LocalCodePtr::DirEntry(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for LocalCodePtr {
|
||||
type Output = LocalCodePtr;
|
||||
|
||||
#[inline]
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs),
|
||||
LocalCodePtr::Halt => unreachable!(),
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<usize> for LocalCodePtr {
|
||||
type Output = Option<LocalCodePtr>;
|
||||
|
||||
#[inline]
|
||||
fn sub(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
|
||||
LocalCodePtr::Halt => unreachable!(),
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => i
|
||||
.checked_sub(rhs)
|
||||
.map(|r| LocalCodePtr::IndexingBuf(p, o, r)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<usize> for LocalCodePtr {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: usize) {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(ref mut p) => *p -= rhs,
|
||||
LocalCodePtr::Halt | LocalCodePtr::IndexingBuf(..) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<usize> for LocalCodePtr {
|
||||
#[inline]
|
||||
fn add_assign(&mut self, rhs: usize) {
|
||||
match self {
|
||||
&mut LocalCodePtr::DirEntry(ref mut p) /* |
|
||||
&mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs,
|
||||
&mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
|
||||
&mut LocalCodePtr::Halt => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for CodePtr {
|
||||
type Output = CodePtr;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self {
|
||||
p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
|
||||
// |
|
||||
// p @ CodePtr::DynamicTransaction(..) => {
|
||||
p
|
||||
}
|
||||
CodePtr::Local(local) => CodePtr::Local(local + rhs),
|
||||
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
|
||||
CodePtr::Local(local + rhs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<usize> for CodePtr {
|
||||
fn add_assign(&mut self, rhs: usize) {
|
||||
match self {
|
||||
&mut CodePtr::VerifyAttrInterrupt(_) => {}
|
||||
&mut CodePtr::Local(ref mut local) => *local += rhs,
|
||||
_ => *self = CodePtr::Local(self.local() + rhs),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<usize> for CodePtr {
|
||||
#[inline]
|
||||
fn sub_assign(&mut self, rhs: usize) {
|
||||
match self {
|
||||
CodePtr::Local(ref mut local) => *local -= rhs,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type HeapVarDict = IndexMap<Rc<Var>, Addr>;
|
||||
pub(crate) type AllocVarDict = IndexMap<Rc<Var>, VarData>;
|
||||
|
||||
pub(crate) type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<Addr>)>;
|
||||
|
||||
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
|
||||
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
|
||||
pub(crate) type StreamDir = BTreeSet<Stream>;
|
||||
|
||||
pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
|
||||
pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>, FxBuildHasher>;
|
||||
|
||||
pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton>;
|
||||
pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton, FxBuildHasher>;
|
||||
|
||||
pub(crate) type LocalExtensiblePredicates =
|
||||
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>;
|
||||
IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>;
|
||||
|
||||
pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct IndexStore {
|
||||
pub struct IndexStore {
|
||||
pub(super) code_dir: CodeDir,
|
||||
pub(super) extensible_predicates: ExtensiblePredicates,
|
||||
pub(super) local_extensible_predicates: LocalExtensiblePredicates,
|
||||
@@ -688,31 +156,21 @@ pub(crate) struct IndexStore {
|
||||
pub(super) stream_aliases: StreamAliasDir,
|
||||
}
|
||||
|
||||
impl Default for IndexStore {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexStore {
|
||||
pub(crate) fn get_predicate_skeleton_mut(
|
||||
&mut self,
|
||||
compilation_target: &CompilationTarget,
|
||||
key: &PredicateKey,
|
||||
) -> Option<&mut PredicateSkeleton> {
|
||||
match (key.0.as_str(), key.1) {
|
||||
// ("term_expansion", 2) => self.extensible_predicates.get_mut(key),
|
||||
_ => match compilation_target {
|
||||
CompilationTarget::User => self.extensible_predicates.get_mut(key),
|
||||
CompilationTarget::Module(ref module_name) => {
|
||||
if let Some(module) = self.modules.get_mut(module_name) {
|
||||
module.extensible_predicates.get_mut(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
match compilation_target {
|
||||
CompilationTarget::User => self.extensible_predicates.get_mut(key),
|
||||
CompilationTarget::Module(ref module_name) => {
|
||||
if let Some(module) = self.modules.get_mut(module_name) {
|
||||
module.extensible_predicates.get_mut(key)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -737,7 +195,7 @@ impl IndexStore {
|
||||
&mut self,
|
||||
mut src_compilation_target: CompilationTarget,
|
||||
local_compilation_target: CompilationTarget,
|
||||
listing_src_file_name: Option<ClauseName>,
|
||||
listing_src_file_name: Option<Atom>,
|
||||
key: PredicateKey,
|
||||
) -> Option<&mut LocalPredicateSkeleton> {
|
||||
if let Some(filename) = listing_src_file_name {
|
||||
@@ -748,8 +206,8 @@ impl IndexStore {
|
||||
CompilationTarget::User => self
|
||||
.local_extensible_predicates
|
||||
.get_mut(&(local_compilation_target, key)),
|
||||
CompilationTarget::Module(ref module_name) => {
|
||||
if let Some(module) = self.modules.get_mut(module_name) {
|
||||
CompilationTarget::Module(module_name) => {
|
||||
if let Some(module) = self.modules.get_mut(&module_name) {
|
||||
module
|
||||
.local_extensible_predicates
|
||||
.get_mut(&(local_compilation_target, key))
|
||||
@@ -764,7 +222,7 @@ impl IndexStore {
|
||||
&self,
|
||||
mut src_compilation_target: CompilationTarget,
|
||||
local_compilation_target: CompilationTarget,
|
||||
listing_src_file_name: Option<ClauseName>,
|
||||
listing_src_file_name: Option<Atom>,
|
||||
key: PredicateKey,
|
||||
) -> Option<&LocalPredicateSkeleton> {
|
||||
if let Some(filename) = listing_src_file_name {
|
||||
@@ -775,8 +233,8 @@ impl IndexStore {
|
||||
CompilationTarget::User => self
|
||||
.local_extensible_predicates
|
||||
.get(&(local_compilation_target, key)),
|
||||
CompilationTarget::Module(ref module_name) => {
|
||||
if let Some(module) = self.modules.get(module_name) {
|
||||
CompilationTarget::Module(module_name) => {
|
||||
if let Some(module) = self.modules.get(&module_name) {
|
||||
module
|
||||
.local_extensible_predicates
|
||||
.get(&(local_compilation_target, key))
|
||||
@@ -806,35 +264,30 @@ impl IndexStore {
|
||||
|
||||
pub(crate) fn get_predicate_code_index(
|
||||
&self,
|
||||
name: ClauseName,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
module: ClauseName,
|
||||
op_spec: Option<SharedOpDesc>,
|
||||
module: Atom,
|
||||
) -> Option<CodeIndex> {
|
||||
if module.as_str() == "user" {
|
||||
match ClauseType::from(name, arity, op_spec) {
|
||||
ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(),
|
||||
ClauseType::Op(name, spec, ..) => self.code_dir.get(&(name, spec.arity())).cloned(),
|
||||
if module == atom!("user") {
|
||||
match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
self.modules.get(&module).and_then(|module| {
|
||||
match ClauseType::from(name, arity, op_spec) {
|
||||
ClauseType::Named(name, arity, _) => {
|
||||
self.modules
|
||||
.get(&module)
|
||||
.and_then(|module| match ClauseType::from(name, arity) {
|
||||
ClauseType::Named(arity, name, _) => {
|
||||
module.code_dir.get(&(name, arity)).cloned()
|
||||
}
|
||||
ClauseType::Op(name, spec, ..) => {
|
||||
module.code_dir.get(&(name, spec.arity())).cloned()
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_meta_predicate_spec(
|
||||
&self,
|
||||
name: ClauseName,
|
||||
name: Atom,
|
||||
arity: usize,
|
||||
compilation_target: &CompilationTarget,
|
||||
) -> Option<&Vec<MetaSpec>> {
|
||||
@@ -850,9 +303,13 @@ impl IndexStore {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool {
|
||||
match module_name.as_str() {
|
||||
"user" => self
|
||||
pub(crate) fn is_dynamic_predicate(
|
||||
&self,
|
||||
module_name: Atom,
|
||||
key: PredicateKey,
|
||||
) -> bool {
|
||||
match module_name {
|
||||
atom!("user") => self
|
||||
.extensible_predicates
|
||||
.get(&key)
|
||||
.map(|skeleton| skeleton.core.is_dynamic)
|
||||
@@ -870,62 +327,10 @@ impl IndexStore {
|
||||
|
||||
#[inline]
|
||||
pub(super) fn new() -> Self {
|
||||
IndexStore::default()
|
||||
}
|
||||
|
||||
pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
|
||||
let r_w_h = clause_name!("run_cleaners_with_handling");
|
||||
let r_wo_h = clause_name!("run_cleaners_without_handling");
|
||||
let iso_ext = clause_name!("iso_ext");
|
||||
|
||||
let r_w_h = self
|
||||
.get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
|
||||
.and_then(|item| item.local());
|
||||
let r_wo_h = self
|
||||
.get_predicate_code_index(r_wo_h, 1, iso_ext, None)
|
||||
.and_then(|item| item.local());
|
||||
|
||||
if let Some(r_w_h) = r_w_h {
|
||||
if let Some(r_wo_h) = r_wo_h {
|
||||
return (r_w_h, r_wo_h);
|
||||
}
|
||||
}
|
||||
|
||||
return (0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
|
||||
|
||||
pub(crate) enum RefOrOwned<'a, T: 'a> {
|
||||
Borrowed(&'a T),
|
||||
Owned(T),
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed),
|
||||
&RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> RefOrOwned<'a, T> {
|
||||
pub(crate) fn as_ref(&'a self) -> &'a T {
|
||||
match self {
|
||||
&RefOrOwned::Borrowed(r) => r,
|
||||
&RefOrOwned::Owned(ref r) => r,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn to_owned(self) -> T
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
match self {
|
||||
RefOrOwned::Borrowed(item) => item.clone(),
|
||||
RefOrOwned::Owned(item) => item,
|
||||
}
|
||||
index_store!(
|
||||
CodeDir::with_hasher(FxBuildHasher::default()),
|
||||
default_op_dir(),
|
||||
ModuleDir::with_hasher(FxBuildHasher::default())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
851
src/machine/mock_wam.rs
Normal file
851
src/machine/mock_wam.rs
Normal file
@@ -0,0 +1,851 @@
|
||||
pub use crate::arena::*;
|
||||
pub use crate::atom_table::*;
|
||||
use crate::heap_print::*;
|
||||
pub use crate::machine::heap::*;
|
||||
pub use crate::machine::*;
|
||||
pub use crate::machine::machine_state::*;
|
||||
pub use crate::machine::stack::*;
|
||||
pub use crate::machine::streams::*;
|
||||
pub use crate::macros::*;
|
||||
pub use crate::parser::ast::*;
|
||||
use crate::read::*;
|
||||
pub use crate::types::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::machine::copier::CopierTarget;
|
||||
|
||||
#[cfg(test)]
|
||||
use std::ops::{Deref, DerefMut, Index, IndexMut};
|
||||
|
||||
// a mini-WAM for test purposes.
|
||||
|
||||
pub struct MockWAM {
|
||||
pub machine_st: MachineState,
|
||||
pub op_dir: OpDir,
|
||||
pub flags: MachineFlags,
|
||||
}
|
||||
|
||||
impl MockWAM {
|
||||
pub fn new() -> Self {
|
||||
let op_dir = default_op_dir();
|
||||
|
||||
Self {
|
||||
machine_st: MachineState::new(),
|
||||
op_dir,
|
||||
flags: MachineFlags::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_parsed_term_to_heap(
|
||||
&mut self,
|
||||
input_stream: Stream,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
self.machine_st.read(input_stream, &self.op_dir)
|
||||
}
|
||||
|
||||
pub fn parse_and_write_parsed_term_to_heap(
|
||||
&mut self,
|
||||
term_string: &'static str,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
let stream = Stream::from_static_string(term_string, &mut self.machine_st.arena);
|
||||
self.write_parsed_term_to_heap(stream)
|
||||
}
|
||||
|
||||
pub fn parse_and_print_term(
|
||||
&mut self,
|
||||
term_string: &'static str,
|
||||
) -> Result<String, ParserError> {
|
||||
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
|
||||
|
||||
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
|
||||
|
||||
let mut printer = HCPrinter::new(
|
||||
&mut self.machine_st.heap,
|
||||
&mut self.machine_st.arena,
|
||||
&self.op_dir,
|
||||
PrinterOutputter::new(),
|
||||
heap_loc_as_cell!(term_write_result.heap_loc),
|
||||
);
|
||||
|
||||
printer.var_names = term_write_result
|
||||
.var_dict
|
||||
.into_iter()
|
||||
.map(|(var, cell)| (cell, var))
|
||||
.collect();
|
||||
|
||||
Ok(printer.print().result())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub struct TermCopyingMockWAM<'a> {
|
||||
pub wam: &'a mut MockWAM,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
fn index(&self, index: usize) -> &HeapCellValue {
|
||||
&self.wam.machine_st.heap[index]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut HeapCellValue {
|
||||
&mut self.wam.machine_st.heap[index]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> Deref for TermCopyingMockWAM<'a> {
|
||||
type Target = MockWAM;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.wam
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> DerefMut for TermCopyingMockWAM<'a> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.wam
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
|
||||
fn store(&self, val: HeapCellValue) -> HeapCellValue {
|
||||
read_heap_cell!(val,
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
self.wam.machine_st.heap[h]
|
||||
}
|
||||
(HeapCellValueTag::StackVar, s) => {
|
||||
self.wam.machine_st.stack[s]
|
||||
}
|
||||
_ => {
|
||||
val
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn deref(&self, mut val: HeapCellValue) -> HeapCellValue {
|
||||
loop {
|
||||
let value = self.store(val);
|
||||
|
||||
if value.is_var() && value != val {
|
||||
val = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&mut self, val: HeapCellValue) {
|
||||
self.wam.machine_st.heap.push(val);
|
||||
}
|
||||
|
||||
fn stack(&mut self) -> &mut Stack {
|
||||
&mut self.wam.machine_st.stack
|
||||
}
|
||||
|
||||
fn threshold(&self) -> usize {
|
||||
self.wam.machine_st.heap.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
|
||||
for (idx, cell) in heap.iter().enumerate() {
|
||||
assert_eq!(
|
||||
cell.get_mark_bit(),
|
||||
true,
|
||||
"cell {:?} at index {} is not marked",
|
||||
cell,
|
||||
idx
|
||||
);
|
||||
assert!(
|
||||
cell.get_forwarding_bit() != Some(true),
|
||||
"cell {:?} at index {} is forwarded",
|
||||
cell,
|
||||
idx
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn all_cells_unmarked(heap: &Heap) {
|
||||
for (idx, cell) in heap.iter().enumerate() {
|
||||
assert!(
|
||||
!cell.get_mark_bit(),
|
||||
"cell {:?} at index {} is still marked",
|
||||
cell,
|
||||
idx
|
||||
);
|
||||
|
||||
assert!(
|
||||
cell.get_forwarding_bit() != Some(true),
|
||||
"cell {:?} at index {} is still forwarded",
|
||||
cell,
|
||||
idx
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn write_parsed_term_to_heap(
|
||||
machine_st: &mut MachineState,
|
||||
input_stream: Stream,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
machine_st.read(input_stream, op_dir)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn parse_and_write_parsed_term_to_heap(
|
||||
machine_st: &mut MachineState,
|
||||
term_string: &'static str,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
let stream = Stream::from_static_string(term_string, &mut machine_st.arena);
|
||||
write_parsed_term_to_heap(machine_st, stream, op_dir)
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub fn with_test_streams() -> Self {
|
||||
use ref_thread_local::RefThreadLocal;
|
||||
|
||||
let mut machine_st = MachineState::new();
|
||||
|
||||
let user_input = Stream::Null(StreamOptions::default());
|
||||
let user_output = Stream::from_owned_string("".to_owned(), &mut machine_st.arena);
|
||||
let user_error = Stream::stderr(&mut machine_st.arena);
|
||||
|
||||
let mut wam = Machine {
|
||||
machine_st,
|
||||
indices: IndexStore::new(),
|
||||
code: Code::new(),
|
||||
user_input,
|
||||
user_output,
|
||||
user_error,
|
||||
load_contexts: vec![],
|
||||
};
|
||||
|
||||
let mut lib_path = current_dir();
|
||||
|
||||
lib_path.pop();
|
||||
lib_path.push("lib");
|
||||
|
||||
wam.add_impls_to_indices();
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from_static_string(
|
||||
LIBRARIES.borrow()["ops_and_meta_predicates"],
|
||||
&mut wam.machine_st.arena,
|
||||
),
|
||||
&mut wam,
|
||||
ListingSource::from_file_and_path(
|
||||
atom!("ops_and_meta_predicates.pl"),
|
||||
lib_path.clone(),
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from_static_string(
|
||||
LIBRARIES.borrow()["builtins"],
|
||||
&mut wam.machine_st.arena,
|
||||
),
|
||||
&mut wam,
|
||||
ListingSource::from_file_and_path(atom!("builtins.pl"), lib_path.clone()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
|
||||
load_module(
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
&mut wam.indices.meta_predicates,
|
||||
&CompilationTarget::User,
|
||||
builtins,
|
||||
);
|
||||
|
||||
import_builtin_impls(&wam.indices.code_dir, builtins);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
lib_path.pop(); // remove the "lib" at the end
|
||||
|
||||
bootstrapping_compile(
|
||||
Stream::from_static_string(include_str!("../loader.pl"), &mut wam.machine_st.arena),
|
||||
&mut wam,
|
||||
ListingSource::from_file_and_path(atom!("loader.pl"), lib_path.clone()),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
wam.configure_modules();
|
||||
|
||||
if let Some(loader) = wam.indices.modules.get(&atom!("loader")) {
|
||||
load_module(
|
||||
&mut wam.indices.code_dir,
|
||||
&mut wam.indices.op_dir,
|
||||
&mut wam.indices.meta_predicates,
|
||||
&CompilationTarget::User,
|
||||
loader,
|
||||
);
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
wam.load_special_forms();
|
||||
wam.load_top_level();
|
||||
wam.configure_streams();
|
||||
|
||||
wam
|
||||
}
|
||||
|
||||
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
|
||||
use std::io::Read;
|
||||
|
||||
let stream = Stream::from_owned_string(
|
||||
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
|
||||
&mut self.machine_st.arena,
|
||||
);
|
||||
|
||||
self.load_file(file.into(), stream);
|
||||
self.user_output.bytes().map(|b| b.unwrap()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unify_tests() {
|
||||
let mut wam = MachineState::new();
|
||||
let mut op_dir = default_op_dir();
|
||||
|
||||
op_dir.insert(
|
||||
(atom!("+"), Fixity::In),
|
||||
OpDesc::build_with(500, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("-"), Fixity::In),
|
||||
OpDesc::build_with(500, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("*"), Fixity::In),
|
||||
OpDesc::build_with(500, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("/"), Fixity::In),
|
||||
OpDesc::build_with(400, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("="), Fixity::In),
|
||||
OpDesc::build_with(700, XFX as u8),
|
||||
);
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,a).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
str_loc_as_cell!(0),
|
||||
str_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(wam.fail);
|
||||
}
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.fail = false;
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
str_loc_as_cell!(1),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(!wam.fail);
|
||||
}
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.fail = false;
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(!wam.fail);
|
||||
}
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.fail = false;
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(!wam.fail);
|
||||
}
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.fail = false;
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(!wam.fail);
|
||||
}
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.fail = false;
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
unify!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(!wam.fail);
|
||||
}
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
|
||||
wam.heap.push(heap_loc_as_cell!(1));
|
||||
|
||||
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
|
||||
wam.heap.push(pstr_loc_as_cell!(4));
|
||||
|
||||
wam.heap.push(pstr_offset_as_cell!(0));
|
||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
|
||||
|
||||
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
|
||||
|
||||
assert!(!wam.fail);
|
||||
|
||||
assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.push(list_loc_as_cell!(1));
|
||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
||||
wam.heap.push(list_loc_as_cell!(3));
|
||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
||||
wam.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
wam.heap.push(list_loc_as_cell!(6));
|
||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
||||
wam.heap.push(list_loc_as_cell!(8));
|
||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
||||
wam.heap.push(heap_loc_as_cell!(5));
|
||||
|
||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||
|
||||
assert!(!wam.fail);
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.push(list_loc_as_cell!(1));
|
||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
||||
wam.heap.push(list_loc_as_cell!(3));
|
||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
||||
wam.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
wam.heap.push(list_loc_as_cell!(6));
|
||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
||||
wam.heap.push(list_loc_as_cell!(8));
|
||||
wam.heap.push(atom_as_cell!(atom!("c")));
|
||||
wam.heap.push(heap_loc_as_cell!(5));
|
||||
|
||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||
|
||||
assert!(wam.fail);
|
||||
|
||||
wam.fail = false;
|
||||
all_cells_unmarked(&wam.heap);
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.push(list_loc_as_cell!(1));
|
||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
||||
wam.heap.push(list_loc_as_cell!(3));
|
||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
||||
wam.heap.push(heap_loc_as_cell!(5));
|
||||
|
||||
wam.heap.push(list_loc_as_cell!(6));
|
||||
wam.heap.push(atom_as_cell!(atom!("a")));
|
||||
wam.heap.push(list_loc_as_cell!(8));
|
||||
wam.heap.push(atom_as_cell!(atom!("b")));
|
||||
wam.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
|
||||
|
||||
assert!(!wam.fail);
|
||||
all_cells_unmarked(&wam.heap);
|
||||
wam.heap.clear();
|
||||
|
||||
{
|
||||
let term_write_result_1 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
|
||||
|
||||
print_heap_terms(wam.heap.iter(), term_write_result_1.heap_loc);
|
||||
|
||||
unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
|
||||
|
||||
assert_eq!(wam.heap[2], str_loc_as_cell!(4));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unify_with_occurs_check() {
|
||||
let mut wam = MachineState::new();
|
||||
let mut op_dir = default_op_dir();
|
||||
|
||||
op_dir.insert(
|
||||
(atom!("+"), Fixity::In),
|
||||
OpDesc::build_with(500, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("-"), Fixity::In),
|
||||
OpDesc::build_with(500, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("*"), Fixity::In),
|
||||
OpDesc::build_with(400, YFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("/"), Fixity::In),
|
||||
OpDesc::build_with(400, YFX as u8),
|
||||
);
|
||||
|
||||
{
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
|
||||
|
||||
let term_write_result_2 =
|
||||
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
unify_with_occurs_check!(
|
||||
wam,
|
||||
str_loc_as_cell!(0),
|
||||
str_loc_as_cell!(term_write_result_2.heap_loc)
|
||||
);
|
||||
|
||||
assert!(wam.fail);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_term_compare() {
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let mut wam = MachineState::new();
|
||||
|
||||
wam.heap.push(heap_loc_as_cell!(0));
|
||||
wam.heap.push(heap_loc_as_cell!(1));
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
|
||||
Some(Ordering::Less)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(wam, wam.heap[1], wam.heap[0]),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(wam, wam.heap[0], wam.heap[0]),
|
||||
Some(Ordering::Equal)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(wam, wam.heap[1], wam.heap[1]),
|
||||
Some(Ordering::Equal)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
atom_as_cell!(atom!("atom")),
|
||||
atom_as_cstr_cell!(atom!("string"))
|
||||
),
|
||||
Some(Ordering::Less)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
atom_as_cell!(atom!("atom")),
|
||||
atom_as_cell!(atom!("atom"))
|
||||
),
|
||||
Some(Ordering::Equal)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
atom_as_cell!(atom!("atom")),
|
||||
atom_as_cell!(atom!("aaa"))
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
fixnum_as_cell!(Fixnum::build_with(6)),
|
||||
heap_loc_as_cell!(1)
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.push(atom_as_cell!(atom!("f"), 1));
|
||||
wam.heap.push(heap_loc_as_cell!(1));
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(0)
|
||||
),
|
||||
Some(Ordering::Equal)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
atom_as_cell!(atom!("a"))
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
wam.heap.clear();
|
||||
|
||||
// [1,2,3]
|
||||
wam.heap.push(list_loc_as_cell!(1));
|
||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
|
||||
wam.heap.push(list_loc_as_cell!(3));
|
||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
|
||||
wam.heap.push(list_loc_as_cell!(5));
|
||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3)));
|
||||
wam.heap.push(empty_list_as_cell!());
|
||||
|
||||
// [1,2]
|
||||
wam.heap.push(list_loc_as_cell!(8));
|
||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1)));
|
||||
wam.heap.push(list_loc_as_cell!(10));
|
||||
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2)));
|
||||
wam.heap.push(empty_list_as_cell!());
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
heap_loc_as_cell!(7),
|
||||
heap_loc_as_cell!(7)
|
||||
),
|
||||
Some(Ordering::Equal)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
heap_loc_as_cell!(0),
|
||||
heap_loc_as_cell!(7)
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
empty_list_as_cell!(),
|
||||
heap_loc_as_cell!(7)
|
||||
),
|
||||
Some(Ordering::Less)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
empty_list_as_cell!(),
|
||||
fixnum_as_cell!(Fixnum::build_with(1))
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
empty_list_as_cell!(),
|
||||
atom_as_cstr_cell!(atom!("string"))
|
||||
),
|
||||
Some(Ordering::Less)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
empty_list_as_cell!(),
|
||||
atom_as_cell!(atom!("atom"))
|
||||
),
|
||||
Some(Ordering::Less)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
atom_as_cell!(atom!("atom")),
|
||||
empty_list_as_cell!()
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
|
||||
let one_p_one = typed_arena_ptr_as_cell!(
|
||||
arena_alloc!(OrderedFloat(1.1), &mut wam.arena)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
one_p_one,
|
||||
fixnum_as_cell!(Fixnum::build_with(1))
|
||||
),
|
||||
Some(Ordering::Less)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
compare_term_test!(
|
||||
wam,
|
||||
fixnum_as_cell!(Fixnum::build_with(1)),
|
||||
one_p_one
|
||||
),
|
||||
Some(Ordering::Greater)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_cyclic_term_tests() {
|
||||
let mut wam = MachineState::new();
|
||||
|
||||
assert!(!wam.is_cyclic_term(atom_as_cell!(atom!("f"))));
|
||||
assert!(!wam.is_cyclic_term(fixnum_as_cell!(Fixnum::build_with(555))));
|
||||
|
||||
wam.heap.push(heap_loc_as_cell!(0));
|
||||
|
||||
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
|
||||
|
||||
assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.heap[2] = str_loc_as_cell!(0);
|
||||
|
||||
print_heap_terms(wam.heap.iter(), 0);
|
||||
|
||||
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.heap[2] = atom_as_cell!(atom!("b"));
|
||||
wam.heap[1] = str_loc_as_cell!(0);
|
||||
|
||||
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
assert!(wam.is_cyclic_term(heap_loc_as_cell!(1)));
|
||||
|
||||
all_cells_unmarked(&wam.heap);
|
||||
|
||||
wam.heap.clear();
|
||||
|
||||
wam.heap.push(pstr_as_cell!(atom!("a string")));
|
||||
wam.heap.push(empty_list_as_cell!());
|
||||
|
||||
assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
|
||||
}
|
||||
}
|
||||
1022
src/machine/mod.rs
1022
src/machine/mod.rs
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,10 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::tabled_rc::*;
|
||||
use prolog_parser::{atom, clause_name, rc_atom};
|
||||
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::load_state::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
@@ -30,89 +28,81 @@ pub(crate) enum CutContext {
|
||||
HasCutVariable,
|
||||
}
|
||||
|
||||
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
|
||||
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> 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 = Term::Clause(Cell::default(), sym, vec![prec, term]);
|
||||
}
|
||||
|
||||
term
|
||||
}
|
||||
|
||||
pub(crate) fn to_op_decl(
|
||||
prec: usize,
|
||||
spec: &str,
|
||||
name: ClauseName,
|
||||
prec: u16,
|
||||
spec: Atom,
|
||||
name: Atom,
|
||||
) -> Result<OpDecl, CompilationError> {
|
||||
match spec {
|
||||
"xfx" => Ok(OpDecl::new(prec, XFX, name)),
|
||||
"xfy" => Ok(OpDecl::new(prec, XFY, name)),
|
||||
"yfx" => Ok(OpDecl::new(prec, YFX, name)),
|
||||
"fx" => Ok(OpDecl::new(prec, FX, name)),
|
||||
"fy" => Ok(OpDecl::new(prec, FY, name)),
|
||||
"xf" => Ok(OpDecl::new(prec, XF, name)),
|
||||
"yf" => Ok(OpDecl::new(prec, YF, name)),
|
||||
atom!("xfx") => Ok(OpDecl::new(OpDesc::build_with(prec, XFX as u8), name)),
|
||||
atom!("xfy") => Ok(OpDecl::new(OpDesc::build_with(prec, XFY as u8), name)),
|
||||
atom!("yfx") => Ok(OpDecl::new(OpDesc::build_with(prec, YFX as u8), name)),
|
||||
atom!("fx") => Ok(OpDecl::new(OpDesc::build_with(prec, FX as u8), name)),
|
||||
atom!("fy") => Ok(OpDecl::new(OpDesc::build_with(prec, FY as u8), name)),
|
||||
atom!("xf") => Ok(OpDecl::new(OpDesc::build_with(prec, XF as u8), name)),
|
||||
atom!("yf") => Ok(OpDecl::new(OpDesc::build_with(prec, YF as u8), name)),
|
||||
_ => Err(CompilationError::InconsistentEntry),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_op_decl(
|
||||
mut terms: Vec<Box<Term>>,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<OpDecl, CompilationError> {
|
||||
let name = match *terms.pop().unwrap() {
|
||||
Term::Constant(_, Constant::Atom(name, _)) => name,
|
||||
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
|
||||
let name = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
|
||||
_ => return Err(CompilationError::InconsistentEntry),
|
||||
};
|
||||
|
||||
let spec = match *terms.pop().unwrap() {
|
||||
Term::Constant(_, Constant::Atom(name, _)) => name,
|
||||
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
|
||||
let spec = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => name,
|
||||
Term::Literal(_, Literal::Char(c)) => atom_tbl.build_with(&c.to_string()),
|
||||
_ => return Err(CompilationError::InconsistentEntry),
|
||||
};
|
||||
|
||||
let prec = match *terms.pop().unwrap() {
|
||||
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
|
||||
let prec = match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
|
||||
Ok(n) if n <= 1200 => n,
|
||||
_ => return Err(CompilationError::InconsistentEntry),
|
||||
},
|
||||
_ => return Err(CompilationError::InconsistentEntry),
|
||||
};
|
||||
|
||||
to_op_decl(prec, spec.as_str(), name)
|
||||
to_op_decl(prec, spec, name)
|
||||
}
|
||||
|
||||
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(_, ref slash, ref mut terms, Some(_))
|
||||
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
|
||||
Term::Clause(_, slash, ref mut terms)
|
||||
if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
|
||||
{
|
||||
let arity = *terms.pop().unwrap();
|
||||
let name = *terms.pop().unwrap();
|
||||
let arity = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
|
||||
let arity = arity
|
||||
.into_constant()
|
||||
.and_then(|c| match c {
|
||||
Constant::Integer(n) => n.to_usize(),
|
||||
Constant::Fixnum(n) => usize::try_from(n).ok(),
|
||||
_ => None,
|
||||
})
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
let arity = match arity {
|
||||
Term::Literal(_, Literal::Integer(n)) => n.to_usize(),
|
||||
Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
|
||||
_ => None,
|
||||
}.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
let name = name
|
||||
.into_constant()
|
||||
.and_then(|c| c.to_atom())
|
||||
.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
let name = match name {
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(name),
|
||||
_ => None,
|
||||
}.ok_or(CompilationError::InvalidModuleExport)?;
|
||||
|
||||
if slash.as_str() == "/" {
|
||||
if *slash == atom!("/") {
|
||||
Ok((name, arity))
|
||||
} else {
|
||||
Ok((name, arity + 2))
|
||||
@@ -148,13 +138,13 @@ fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKe
|
||||
|
||||
fn setup_module_export(
|
||||
mut term: Term,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<ModuleExport, CompilationError> {
|
||||
setup_predicate_indicator(&mut term)
|
||||
.map(ModuleExport::PredicateKey)
|
||||
.or_else(|_| {
|
||||
if let Term::Clause(_, name, terms, _) = term {
|
||||
if terms.len() == 3 && name.as_str() == "op" {
|
||||
if let Term::Clause(_, name, terms) = term {
|
||||
if terms.len() == 3 && name == atom!("op") {
|
||||
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
@@ -167,18 +157,18 @@ fn setup_module_export(
|
||||
|
||||
pub(super) fn setup_module_export_list(
|
||||
mut export_list: Term,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<Vec<ModuleExport>, CompilationError> {
|
||||
let mut exports = vec![];
|
||||
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
let module_export = setup_module_export(*t1, atom_tbl.clone())?;
|
||||
let module_export = setup_module_export(*t1, atom_tbl)?;
|
||||
|
||||
exports.push(module_export);
|
||||
export_list = *t2;
|
||||
}
|
||||
|
||||
if let Term::Constant(_, Constant::EmptyList) = export_list {
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
|
||||
Ok(exports)
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
@@ -186,98 +176,65 @@ pub(super) fn setup_module_export_list(
|
||||
}
|
||||
|
||||
fn setup_module_decl(
|
||||
mut terms: Vec<Box<Term>>,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<ModuleDecl, CompilationError> {
|
||||
let export_list = *terms.pop().unwrap();
|
||||
let name = terms
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_constant()
|
||||
.and_then(|c| c.to_atom())
|
||||
.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||
let export_list = terms.pop().unwrap();
|
||||
let name = terms.pop().unwrap();
|
||||
|
||||
let name = match name {
|
||||
Term::Literal(_, Literal::Atom(name)) => Some(name),
|
||||
_ => None,
|
||||
}.ok_or(CompilationError::InvalidModuleDecl)?;
|
||||
|
||||
let exports = setup_module_export_list(export_list, atom_tbl)?;
|
||||
|
||||
Ok(ModuleDecl { name, exports })
|
||||
}
|
||||
|
||||
fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, CompilationError> {
|
||||
match *terms.pop().unwrap() {
|
||||
Term::Clause(_, ref name, ref mut terms, None)
|
||||
if name.as_str() == "library" && terms.len() == 1 =>
|
||||
fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms)
|
||||
if name == atom!("library") && terms.len() == 1 =>
|
||||
{
|
||||
terms
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_constant()
|
||||
.and_then(|c| c.to_atom())
|
||||
.map(|c| ModuleSource::Library(c))
|
||||
.ok_or(CompilationError::InvalidUseModuleDecl)
|
||||
match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
|
||||
_ => Err(CompilationError::InvalidModuleDecl),
|
||||
}
|
||||
}
|
||||
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
|
||||
_ => Err(CompilationError::InvalidUseModuleDecl),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, CompilationError> {
|
||||
let dbl_quotes = *terms.pop().unwrap();
|
||||
|
||||
match terms[0].as_ref() {
|
||||
Term::Constant(_, Constant::Atom(ref name, _))
|
||||
if name.as_str() == "double_quotes" => {
|
||||
match dbl_quotes {
|
||||
Term::Constant(_, Constant::Atom(name, _)) => {
|
||||
match name.as_str() {
|
||||
"atom" => Ok(DoubleQuotes::Atom),
|
||||
"chars" => Ok(DoubleQuotes::Chars),
|
||||
"codes" => Ok(DoubleQuotes::Codes),
|
||||
_ => Err(CompilationError::InvalidDoubleQuotesDecl),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
Err(CompilationError::InvalidDoubleQuotesDecl)
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
Err(CompilationError::InvalidDoubleQuotesDecl)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
|
||||
|
||||
fn setup_qualified_import(
|
||||
mut terms: Vec<Box<Term>>,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
mut terms: Vec<Term>,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<UseModuleExport, CompilationError> {
|
||||
let mut export_list = *terms.pop().unwrap();
|
||||
let module_src = match *terms.pop().unwrap() {
|
||||
Term::Clause(_, ref name, ref mut terms, None)
|
||||
if name.as_str() == "library" && terms.len() == 1 =>
|
||||
let mut export_list = terms.pop().unwrap();
|
||||
let module_src = match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms)
|
||||
if name == atom!("library") && terms.len() == 1 =>
|
||||
{
|
||||
terms
|
||||
.pop()
|
||||
.unwrap()
|
||||
.into_constant()
|
||||
.and_then(|c| c.to_atom())
|
||||
.map(|c| ModuleSource::Library(c))
|
||||
.ok_or(CompilationError::InvalidUseModuleDecl)
|
||||
match terms.pop().unwrap() {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
|
||||
_ => Err(CompilationError::InvalidModuleDecl),
|
||||
}
|
||||
}
|
||||
Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())),
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
|
||||
_ => Err(CompilationError::InvalidUseModuleDecl),
|
||||
}?;
|
||||
|
||||
let mut exports = IndexSet::new();
|
||||
|
||||
while let Term::Cons(_, t1, t2) = export_list {
|
||||
exports.insert(setup_module_export(*t1, atom_tbl.clone())?);
|
||||
exports.insert(setup_module_export(*t1, atom_tbl)?);
|
||||
export_list = *t2;
|
||||
}
|
||||
|
||||
if let Term::Constant(_, Constant::EmptyList) = export_list {
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
|
||||
Ok((module_src, exports))
|
||||
} else {
|
||||
Err(CompilationError::InvalidModuleDecl)
|
||||
@@ -322,29 +279,29 @@ fn setup_qualified_import(
|
||||
* -
|
||||
* ?
|
||||
*/
|
||||
fn setup_meta_predicate<'a>(
|
||||
mut terms: Vec<Box<Term>>,
|
||||
load_state: &LoadState<'a>,
|
||||
) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError> {
|
||||
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
mut terms: Vec<Term>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
|
||||
fn get_name_and_meta_specs(
|
||||
name: ClauseName,
|
||||
terms: &mut [Box<Term>],
|
||||
) -> Result<(ClauseName, Vec<MetaSpec>), CompilationError> {
|
||||
name: Atom,
|
||||
terms: &mut [Term],
|
||||
) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
|
||||
let mut meta_specs = vec![];
|
||||
|
||||
for meta_spec in terms.into_iter() {
|
||||
match &**meta_spec {
|
||||
Term::Constant(_, Constant::Atom(meta_spec, _)) => {
|
||||
let meta_spec = match meta_spec.as_str() {
|
||||
"+" => MetaSpec::Plus,
|
||||
"-" => MetaSpec::Minus,
|
||||
"?" => MetaSpec::Either,
|
||||
match meta_spec {
|
||||
Term::Literal(_, Literal::Atom(meta_spec)) => {
|
||||
let meta_spec = match meta_spec {
|
||||
atom!("+") => MetaSpec::Plus,
|
||||
atom!("-") => MetaSpec::Minus,
|
||||
atom!("?") => MetaSpec::Either,
|
||||
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
};
|
||||
|
||||
meta_specs.push(meta_spec);
|
||||
}
|
||||
Term::Constant(_, Constant::Fixnum(n)) => match usize::try_from(*n) {
|
||||
Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
|
||||
Ok(n) if n <= MAX_ARITY => {
|
||||
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
|
||||
}
|
||||
@@ -361,16 +318,15 @@ fn setup_meta_predicate<'a>(
|
||||
Ok((name, meta_specs))
|
||||
}
|
||||
|
||||
match *terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms, _) if name.as_str() == ":" && terms.len() == 2 => {
|
||||
let spec = *terms.pop().unwrap();
|
||||
let module_name = *terms.pop().unwrap();
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
|
||||
let spec = terms.pop().unwrap();
|
||||
let module_name = terms.pop().unwrap();
|
||||
|
||||
match module_name {
|
||||
Term::Constant(_, Constant::Atom(module_name, _)) => match spec {
|
||||
Term::Clause(_, name, mut terms, _) => {
|
||||
Term::Literal(_, Literal::Atom(module_name)) => match spec {
|
||||
Term::Clause(_, name, mut terms) => {
|
||||
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
|
||||
|
||||
Ok((module_name, name, meta_specs))
|
||||
}
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
@@ -378,10 +334,10 @@ fn setup_meta_predicate<'a>(
|
||||
_ => Err(CompilationError::InvalidMetaPredicateDecl),
|
||||
}
|
||||
}
|
||||
Term::Clause(_, name, mut terms, _) => {
|
||||
Term::Clause(_, name, mut terms) => {
|
||||
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
|
||||
Ok((
|
||||
load_state.compilation_target.module_name(),
|
||||
loader.payload.compilation_target.module_name(),
|
||||
name,
|
||||
meta_specs,
|
||||
))
|
||||
@@ -420,11 +376,11 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
|
||||
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
|
||||
for term in terms.iter_mut() {
|
||||
match term {
|
||||
&mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
|
||||
*var = name.clone()
|
||||
&mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
|
||||
*var = name;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -433,12 +389,12 @@ fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
|
||||
|
||||
fn mark_cut_variable(term: &mut Term) -> bool {
|
||||
let cut_var_found = match term {
|
||||
&mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true,
|
||||
&mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if cut_var_found {
|
||||
*term = Term::Var(Cell::default(), rc_atom!("!"));
|
||||
*term = Term::Var(Cell::default(), Rc::new(String::from("!")));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -463,21 +419,21 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
|
||||
if name.as_str() != "->" || subterms.len() != 2 {
|
||||
if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
|
||||
if *name != atom!("->") || subterms.len() != 2 {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() {
|
||||
let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
|
||||
let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
|
||||
if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() {
|
||||
let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
|
||||
let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
|
||||
|
||||
conq_terms.push_front(Term::Constant(
|
||||
conq_terms.push_front(Term::Literal(
|
||||
Cell::default(),
|
||||
Constant::Atom(clause_name!("blocked_!"), None),
|
||||
Literal::Atom(atom!("blocked_!")),
|
||||
));
|
||||
|
||||
while let Some(term) = pre_cut_terms.pop_back() {
|
||||
@@ -489,37 +445,44 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
|
||||
terms.push(fold_by_str(
|
||||
conq_terms.into_iter(),
|
||||
tail_term,
|
||||
clause_name!(","),
|
||||
atom!(","),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn setup_declaration<'a>(
|
||||
load_state: &LoadState<'a>,
|
||||
mut terms: Vec<Box<Term>>,
|
||||
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
mut terms: Vec<Term>,
|
||||
) -> Result<Declaration, CompilationError> {
|
||||
let term = *terms.pop().unwrap();
|
||||
let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
|
||||
let term = terms.pop().unwrap();
|
||||
|
||||
match term {
|
||||
Term::Clause(_, name, mut terms, _) => match (name.as_str(), terms.len()) {
|
||||
("dynamic", 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||
Term::Clause(_, name, mut terms) => match (name, terms.len()) {
|
||||
(atom!("dynamic"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||
Ok(Declaration::Dynamic(name, arity))
|
||||
}
|
||||
("module", 2) => Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)),
|
||||
("op", 3) => Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)),
|
||||
("non_counted_backtracking", 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
|
||||
(atom!("module"), 2) => {
|
||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
||||
Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?))
|
||||
}
|
||||
(atom!("op"), 3) => {
|
||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
||||
Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?))
|
||||
}
|
||||
(atom!("non_counted_backtracking"), 1) => {
|
||||
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
|
||||
Ok(Declaration::NonCountedBacktracking(name, arity))
|
||||
}
|
||||
("use_module", 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
||||
("use_module", 2) => {
|
||||
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
|
||||
(atom!("use_module"), 2) => {
|
||||
let atom_tbl = &mut LS::machine_st(&mut loader.payload).atom_tbl;
|
||||
let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
|
||||
|
||||
Ok(Declaration::UseQualifiedModule(name, exports))
|
||||
}
|
||||
("meta_predicate", 1) => {
|
||||
let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?;
|
||||
(atom!("meta_predicate"), 1) => {
|
||||
let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
|
||||
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
|
||||
}
|
||||
_ => Err(CompilationError::InconsistentEntry),
|
||||
@@ -529,25 +492,23 @@ pub(super) fn setup_declaration<'a>(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clause_to_query_term<'a>(
|
||||
load_state: &mut LoadState<'a>,
|
||||
name: ClauseName,
|
||||
terms: Vec<Box<Term>>,
|
||||
fixity: Option<SharedOpDesc>,
|
||||
fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
name: Atom,
|
||||
terms: Vec<Term>,
|
||||
) -> QueryTerm {
|
||||
let ct = load_state.get_clause_type(name, terms.len(), fixity);
|
||||
let ct = loader.get_clause_type(name, terms.len());
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn qualified_clause_to_query_term<'a>(
|
||||
load_state: &mut LoadState<'a>,
|
||||
module_name: ClauseName,
|
||||
name: ClauseName,
|
||||
terms: Vec<Box<Term>>,
|
||||
fixity: Option<SharedOpDesc>,
|
||||
fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
module_name: Atom,
|
||||
name: Atom,
|
||||
terms: Vec<Term>,
|
||||
) -> QueryTerm {
|
||||
let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity);
|
||||
let ct = loader.get_qualified_clause_type(module_name, name, terms.len());
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, false)
|
||||
}
|
||||
|
||||
@@ -565,7 +526,7 @@ impl Preprocessor {
|
||||
|
||||
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(term),
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
||||
_ => Err(CompilationError::InadmissibleFact),
|
||||
}
|
||||
}
|
||||
@@ -579,20 +540,17 @@ impl Preprocessor {
|
||||
}
|
||||
}
|
||||
|
||||
vars.insert(rc_atom!("!"));
|
||||
vars.insert(Rc::new(String::from("!")));
|
||||
vars.into_iter()
|
||||
.map(|v| Term::Var(Cell::default(), v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
|
||||
let vars_of_head = vars.iter().cloned().map(Box::new).collect();
|
||||
let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None);
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.clone());
|
||||
let rule = vec![head_term, body_term];
|
||||
|
||||
let rule = vec![Box::new(head_term), Box::new(body_term)];
|
||||
let turnstile = clause_name!(":-");
|
||||
|
||||
Term::Clause(Cell::default(), turnstile, rule, None)
|
||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||
}
|
||||
|
||||
// the terms form the body of the rule. We create a head, by
|
||||
@@ -609,16 +567,16 @@ impl Preprocessor {
|
||||
|
||||
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
let vars = self.compute_head(&body_term);
|
||||
let results = unfold_by_str(body_term, ";")
|
||||
let results = unfold_by_str(body_term, atom!(";"))
|
||||
.into_iter()
|
||||
.map(|term| {
|
||||
let mut subterms = unfold_by_str(term, ",");
|
||||
let mut subterms = unfold_by_str(term, atom!(","));
|
||||
mark_cut_variables(&mut subterms);
|
||||
|
||||
check_for_internal_if_then(&mut subterms);
|
||||
|
||||
let term = subterms.pop().unwrap();
|
||||
let clause = fold_by_str(subterms.into_iter(), term, clause_name!(","));
|
||||
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
|
||||
|
||||
self.fabricate_rule_body(&vars, clause)
|
||||
})
|
||||
@@ -628,80 +586,78 @@ impl Preprocessor {
|
||||
}
|
||||
|
||||
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
let mut prec_seq = unfold_by_str(prec, ",");
|
||||
let comma_sym = clause_name!(",");
|
||||
let cut_sym = atom!("!");
|
||||
let mut prec_seq = unfold_by_str(prec, atom!(","));
|
||||
let comma_sym = atom!(",");
|
||||
let cut_sym = Literal::Atom(atom!("!"));
|
||||
|
||||
prec_seq.push(Term::Constant(Cell::default(), cut_sym));
|
||||
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
|
||||
|
||||
mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
|
||||
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
|
||||
|
||||
let mut conq_seq = unfold_by_str(conq, ",");
|
||||
let mut conq_seq = unfold_by_str(conq, atom!(","));
|
||||
|
||||
mark_cut_variables(&mut conq_seq);
|
||||
prec_seq.extend(conq_seq.into_iter());
|
||||
|
||||
let back_term = Box::new(prec_seq.pop().unwrap());
|
||||
let front_term = Box::new(prec_seq.pop().unwrap());
|
||||
let back_term = prec_seq.pop().unwrap();
|
||||
let front_term = prec_seq.pop().unwrap();
|
||||
|
||||
let body_term = Term::Clause(
|
||||
Cell::default(),
|
||||
comma_sym.clone(),
|
||||
comma_sym,
|
||||
vec![front_term, back_term],
|
||||
None,
|
||||
);
|
||||
|
||||
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
||||
}
|
||||
|
||||
fn to_query_term<'a>(
|
||||
fn to_query_term<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
) -> Result<QueryTerm, CompilationError> {
|
||||
match term {
|
||||
Term::Constant(_, Constant::Atom(name, fixity)) => {
|
||||
if name.as_str() == "!" || name.as_str() == "blocked_!" {
|
||||
Term::Literal(_, Literal::Atom(name)) => {
|
||||
if name == atom!("!") || name == atom!("blocked_!") {
|
||||
Ok(QueryTerm::BlockedCut)
|
||||
} else {
|
||||
Ok(clause_to_query_term(load_state, name, vec![], fixity))
|
||||
Ok(clause_to_query_term(loader, name, vec![]))
|
||||
}
|
||||
}
|
||||
Term::Constant(_, Constant::Char('!')) => Ok(QueryTerm::BlockedCut),
|
||||
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
|
||||
Term::Var(_, ref v) if v.as_str() == "!" => {
|
||||
Ok(QueryTerm::UnblockedCut(Cell::default()))
|
||||
}
|
||||
Term::Clause(r, name, mut terms, fixity) => match (name.as_str(), terms.len()) {
|
||||
(";", 2) => {
|
||||
let term = Term::Clause(r, name.clone(), terms, fixity);
|
||||
Term::Clause(r, name, mut terms) => match (name, terms.len()) {
|
||||
(atom!(";"), 2) => {
|
||||
let term = Term::Clause(r, name, terms);
|
||||
|
||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||
self.queue.push_back(clauses);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
("->", 2) => {
|
||||
let conq = *terms.pop().unwrap();
|
||||
let prec = *terms.pop().unwrap();
|
||||
(atom!("->"), 2) => {
|
||||
let conq = terms.pop().unwrap();
|
||||
let prec = terms.pop().unwrap();
|
||||
|
||||
let (stub, clauses) = self.fabricate_if_then(prec, conq);
|
||||
self.queue.push_back(clauses);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
("\\+", 1) => {
|
||||
terms.push(Box::new(Term::Constant(
|
||||
(atom!("\\+"), 1) => {
|
||||
terms.push(Term::Literal(
|
||||
Cell::default(),
|
||||
Constant::Atom(clause_name!("$fail"), None),
|
||||
)));
|
||||
Literal::Atom(atom!("$fail")),
|
||||
));
|
||||
|
||||
let conq =
|
||||
Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None));
|
||||
let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
|
||||
|
||||
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
|
||||
let terms = vec![Box::new(prec), Box::new(conq)];
|
||||
let prec = Term::Clause(Cell::default(), atom!("->"), terms);
|
||||
let terms = vec![prec, conq];
|
||||
|
||||
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
|
||||
let term = Term::Clause(Cell::default(), atom!(";"), terms);
|
||||
let (stub, clauses) = self.fabricate_disjunct(term);
|
||||
|
||||
debug_assert!(clauses.len() > 0);
|
||||
@@ -709,104 +665,102 @@ impl Preprocessor {
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
("$get_level", 1) => {
|
||||
if let Term::Var(_, ref var) = *terms[0] {
|
||||
(atom!("$get_level"), 1) => {
|
||||
if let Term::Var(_, ref var) = &terms[0] {
|
||||
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
||||
} else {
|
||||
Err(CompilationError::InadmissibleQueryTerm)
|
||||
}
|
||||
}
|
||||
(":", 2) => {
|
||||
let predicate_name = *terms.pop().unwrap();
|
||||
let module_name = *terms.pop().unwrap();
|
||||
(atom!(":"), 2) => {
|
||||
let predicate_name = terms.pop().unwrap();
|
||||
let module_name = terms.pop().unwrap();
|
||||
|
||||
match (module_name, predicate_name) {
|
||||
(
|
||||
Term::Constant(_, Constant::Atom(module_name, _)),
|
||||
Term::Constant(_, Constant::Atom(predicate_name, fixity)),
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
Term::Literal(_, Literal::Atom(predicate_name)),
|
||||
) => Ok(qualified_clause_to_query_term(
|
||||
load_state,
|
||||
loader,
|
||||
module_name,
|
||||
predicate_name,
|
||||
vec![],
|
||||
fixity,
|
||||
)),
|
||||
(
|
||||
Term::Constant(_, Constant::Atom(module_name, _)),
|
||||
Term::Clause(_, name, terms, fixity),
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
Term::Clause(_, name, terms),
|
||||
) => Ok(qualified_clause_to_query_term(
|
||||
load_state,
|
||||
loader,
|
||||
module_name,
|
||||
name,
|
||||
terms,
|
||||
fixity,
|
||||
)),
|
||||
(module_name, predicate_name) => {
|
||||
terms.push(Box::new(module_name));
|
||||
terms.push(Box::new(predicate_name));
|
||||
terms.push(module_name);
|
||||
terms.push(predicate_name);
|
||||
|
||||
Ok(clause_to_query_term(load_state, name, terms, fixity))
|
||||
Ok(clause_to_query_term(loader, name, terms))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Ok(clause_to_query_term(load_state, name, terms, fixity)),
|
||||
_ => Ok(clause_to_query_term(loader, name, terms)),
|
||||
},
|
||||
Term::Var(..) => Ok(QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::CallN,
|
||||
vec![Box::new(term)],
|
||||
ClauseType::CallN(1),
|
||||
vec![term],
|
||||
false,
|
||||
)),
|
||||
_ => Err(CompilationError::InadmissibleQueryTerm),
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_query_term<'a>(
|
||||
fn pre_query_term<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
) -> Result<QueryTerm, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(r, name, mut subterms, fixity) => {
|
||||
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
|
||||
self.to_query_term(load_state, *subterms.pop().unwrap())
|
||||
Term::Clause(r, name, mut subterms) => {
|
||||
if subterms.len() == 1 && name == atom!("$call_with_default_policy") {
|
||||
self.to_query_term(loader, subterms.pop().unwrap())
|
||||
.map(|mut query_term| {
|
||||
query_term.set_default_caller();
|
||||
query_term
|
||||
})
|
||||
} else {
|
||||
let clause = Term::Clause(r, name, subterms, fixity);
|
||||
self.to_query_term(load_state, clause)
|
||||
let clause = Term::Clause(r, name, subterms);
|
||||
self.to_query_term(loader, clause)
|
||||
}
|
||||
}
|
||||
_ => self.to_query_term(load_state, term),
|
||||
_ => self.to_query_term(loader, term),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_query<'a>(
|
||||
fn setup_query<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
terms: Vec<Box<Term>>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
terms: Vec<Term>,
|
||||
cut_context: CutContext,
|
||||
) -> Result<Vec<QueryTerm>, CompilationError> {
|
||||
let mut query_terms = vec![];
|
||||
let mut work_queue = VecDeque::from(terms);
|
||||
|
||||
while let Some(term) = work_queue.pop_front() {
|
||||
let mut term = *term;
|
||||
let mut term = term;
|
||||
|
||||
if let Term::Clause(cell, name, terms, op_spec) = term {
|
||||
if name.as_str() == "," && terms.len() == 2 {
|
||||
let term = Term::Clause(cell, name, terms, op_spec);
|
||||
let mut subterms = unfold_by_str(term, ",");
|
||||
if let Term::Clause(cell, name, terms) = term {
|
||||
if name == atom!(",") && terms.len() == 2 {
|
||||
let term = Term::Clause(cell, name, terms);
|
||||
let mut subterms = unfold_by_str(term, atom!(","));
|
||||
|
||||
while let Some(subterm) = subterms.pop() {
|
||||
work_queue.push_front(Box::new(subterm));
|
||||
work_queue.push_front(subterm);
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
term = Term::Clause(cell, name, terms, op_spec);
|
||||
term = Term::Clause(cell, name, terms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,30 +768,30 @@ impl Preprocessor {
|
||||
mark_cut_variable(&mut term);
|
||||
}
|
||||
|
||||
query_terms.push(self.pre_query_term(load_state, term)?);
|
||||
query_terms.push(self.pre_query_term(loader, term)?);
|
||||
}
|
||||
|
||||
Ok(query_terms)
|
||||
}
|
||||
|
||||
fn setup_rule<'a>(
|
||||
fn setup_rule<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
mut terms: Vec<Box<Term>>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
mut terms: Vec<Term>,
|
||||
cut_context: CutContext,
|
||||
) -> Result<Rule, CompilationError> {
|
||||
let post_head_terms: Vec<_> = terms.drain(1..).collect();
|
||||
let mut query_terms = self.setup_query(load_state, post_head_terms, cut_context)?;
|
||||
let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?;
|
||||
|
||||
let clauses = query_terms.drain(1..).collect();
|
||||
let qt = query_terms.pop().unwrap();
|
||||
|
||||
match *terms.pop().unwrap() {
|
||||
Term::Clause(_, name, terms, _) => Ok(Rule {
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, terms) => Ok(Rule {
|
||||
head: (name, terms, qt),
|
||||
clauses,
|
||||
}),
|
||||
Term::Constant(_, Constant::Atom(name, _)) => Ok(Rule {
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
|
||||
head: (name, vec![], qt),
|
||||
clauses,
|
||||
}),
|
||||
@@ -845,37 +799,37 @@ impl Preprocessor {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_term_to_query<'a>(
|
||||
fn try_term_to_query<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
terms: Vec<Box<Term>>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
terms: Vec<Term>,
|
||||
cut_context: CutContext,
|
||||
) -> Result<TopLevel, CompilationError> {
|
||||
Ok(TopLevel::Query(self.setup_query(
|
||||
load_state,
|
||||
loader,
|
||||
terms,
|
||||
cut_context,
|
||||
)?))
|
||||
}
|
||||
|
||||
pub(super) fn try_term_to_tl<'a>(
|
||||
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
cut_context: CutContext,
|
||||
) -> Result<TopLevel, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(r, name, terms, fixity) => {
|
||||
if name.as_str() == "?-" {
|
||||
self.try_term_to_query(load_state, terms, cut_context)
|
||||
} else if name.as_str() == ":-" && terms.len() == 2 {
|
||||
Term::Clause(r, name, terms) => {
|
||||
if name == atom!("?-") {
|
||||
self.try_term_to_query(loader, terms, cut_context)
|
||||
} else if name == atom!(":-") && terms.len() == 2 {
|
||||
Ok(TopLevel::Rule(self.setup_rule(
|
||||
load_state,
|
||||
loader,
|
||||
terms,
|
||||
cut_context,
|
||||
)?))
|
||||
} else {
|
||||
let term = Term::Clause(r, name, terms, fixity);
|
||||
let term = Term::Clause(r, name, terms);
|
||||
Ok(TopLevel::Fact(self.setup_fact(term)?))
|
||||
}
|
||||
}
|
||||
@@ -883,30 +837,30 @@ impl Preprocessor {
|
||||
}
|
||||
}
|
||||
|
||||
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>(
|
||||
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
terms: I,
|
||||
cut_context: CutContext,
|
||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
||||
let mut results = VecDeque::new();
|
||||
|
||||
for term in terms.into_iter() {
|
||||
results.push_back(self.try_term_to_tl(load_state, term, cut_context)?);
|
||||
results.push_back(self.try_term_to_tl(loader, term, cut_context)?);
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub(super) fn parse_queue<'a>(
|
||||
pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
load_state: &mut LoadState<'a>,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
||||
let mut queue = VecDeque::new();
|
||||
|
||||
while let Some(terms) = self.queue.pop_front() {
|
||||
let clauses = merge_clauses(&mut self.try_terms_to_tls(
|
||||
load_state,
|
||||
loader,
|
||||
terms,
|
||||
CutContext::HasCutVariable,
|
||||
)?)?;
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::raw_block::*;
|
||||
use crate::raw_block::*;
|
||||
use crate::types::*;
|
||||
|
||||
use std::mem;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::ptr;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct StackTraits {}
|
||||
|
||||
impl RawBlockTraits for StackTraits {
|
||||
impl RawBlockTraits for Stack {
|
||||
#[inline]
|
||||
fn init_size() -> usize {
|
||||
10 * 1024 * 1024
|
||||
@@ -18,31 +15,23 @@ impl RawBlockTraits for StackTraits {
|
||||
|
||||
#[inline]
|
||||
fn align() -> usize {
|
||||
mem::align_of::<Addr>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn base_offset(base: *const u8) -> *const u8 {
|
||||
unsafe { base.offset(Self::align() as isize) }
|
||||
mem::align_of::<HeapCellValue>()
|
||||
}
|
||||
}
|
||||
|
||||
const fn prelude_size<Prelude>() -> usize {
|
||||
let size = mem::size_of::<Prelude>();
|
||||
let align = mem::align_of::<Addr>();
|
||||
|
||||
(size & !(align - 1)) + align
|
||||
#[inline(always)]
|
||||
pub const fn prelude_size<Prelude>() -> usize {
|
||||
mem::size_of::<Prelude>()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Stack {
|
||||
buf: RawBlock<StackTraits>,
|
||||
_marker: PhantomData<Addr>,
|
||||
pub struct Stack {
|
||||
buf: RawBlock<Stack>,
|
||||
_marker: PhantomData<HeapCellValue>,
|
||||
}
|
||||
|
||||
impl Drop for Stack {
|
||||
fn drop(&mut self) {
|
||||
self.drop_in_place();
|
||||
self.buf.deallocate();
|
||||
}
|
||||
}
|
||||
@@ -56,8 +45,7 @@ pub(crate) struct FramePrelude {
|
||||
pub(crate) struct AndFramePrelude {
|
||||
pub(crate) univ_prelude: FramePrelude,
|
||||
pub(crate) e: usize,
|
||||
pub(crate) cp: LocalCodePtr,
|
||||
pub(crate) interrupt_cp: LocalCodePtr,
|
||||
pub(crate) cp: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -67,22 +55,22 @@ pub(crate) struct AndFrame {
|
||||
|
||||
impl AndFrame {
|
||||
pub(crate) fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
prelude_size::<AndFramePrelude>() + num_cells * mem::size_of::<HeapCellValue>()
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for AndFrame {
|
||||
type Output = Addr;
|
||||
type Output = HeapCellValue;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let prelude_offset = prelude_size::<AndFramePrelude>();
|
||||
let index_offset = (index - 1) * mem::size_of::<Addr>();
|
||||
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&*(ptr as *const Addr)
|
||||
&*(ptr as *const HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,13 +78,35 @@ impl Index<usize> for AndFrame {
|
||||
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>();
|
||||
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut AndFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&mut *(ptr as *mut Addr)
|
||||
&mut *(ptr as *mut HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<usize> for Stack {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + index;
|
||||
&*(ptr as *const HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Stack {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + index;
|
||||
&mut *(ptr as *mut HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,9 +115,11 @@ impl IndexMut<usize> for AndFrame {
|
||||
pub(crate) struct OrFramePrelude {
|
||||
pub(crate) univ_prelude: FramePrelude,
|
||||
pub(crate) e: usize,
|
||||
pub(crate) cp: LocalCodePtr,
|
||||
pub(crate) cp: usize,
|
||||
pub(crate) b: usize,
|
||||
pub(crate) bp: LocalCodePtr,
|
||||
pub(crate) bp: usize,
|
||||
pub(crate) boip: u32,
|
||||
pub(crate) biip: u32,
|
||||
pub(crate) tr: usize,
|
||||
pub(crate) h: usize,
|
||||
pub(crate) b0: usize,
|
||||
@@ -119,18 +131,18 @@ pub(crate) struct OrFrame {
|
||||
}
|
||||
|
||||
impl Index<usize> for OrFrame {
|
||||
type Output = Addr;
|
||||
type Output = HeapCellValue;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
let prelude_offset = prelude_size::<OrFramePrelude>();
|
||||
let index_offset = index * mem::size_of::<Addr>();
|
||||
let index_offset = index * mem::size_of::<HeapCellValue>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&*(ptr as *const Addr)
|
||||
&*(ptr as *const HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,20 +151,20 @@ 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>();
|
||||
let index_offset = index * mem::size_of::<HeapCellValue>();
|
||||
|
||||
unsafe {
|
||||
let ptr = mem::transmute::<&mut OrFrame, *const u8>(self);
|
||||
let ptr = ptr as usize + prelude_offset + index_offset;
|
||||
|
||||
&mut *(ptr as *mut Addr)
|
||||
&mut *(ptr as *mut HeapCellValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OrFrame {
|
||||
pub(crate) fn size_of(num_cells: usize) -> usize {
|
||||
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<Addr>()
|
||||
prelude_size::<OrFramePrelude>() + num_cells * mem::size_of::<HeapCellValue>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,26 +176,39 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
|
||||
loop {
|
||||
let ptr = self.buf.alloc(frame_size);
|
||||
|
||||
if ptr.is_null() {
|
||||
self.buf.grow();
|
||||
} else {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) 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;
|
||||
let e = self.buf.ptr as usize - self.buf.base as usize;
|
||||
let new_ptr = self.alloc(frame_size);
|
||||
let mut offset = prelude_size::<AndFramePrelude>();
|
||||
|
||||
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),
|
||||
(new_ptr as usize + offset) as *mut HeapCellValue,
|
||||
stack_loc_as_cell!(AndFrame, e, idx + 1),
|
||||
);
|
||||
|
||||
offset += mem::size_of::<HeapCellValue>();
|
||||
}
|
||||
|
||||
let and_frame = &mut *(self.buf.top as *mut AndFrame);
|
||||
let and_frame = &mut *(new_ptr as *mut AndFrame);
|
||||
and_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
self.buf.top = new_top;
|
||||
|
||||
e
|
||||
}
|
||||
}
|
||||
@@ -192,27 +217,27 @@ impl Stack {
|
||||
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;
|
||||
let b = self.buf.ptr as usize - self.buf.base as usize;
|
||||
let new_ptr = self.alloc(frame_size);
|
||||
let mut offset = prelude_size::<OrFramePrelude>();
|
||||
|
||||
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),
|
||||
(new_ptr as usize + offset) as *mut HeapCellValue,
|
||||
stack_loc_as_cell!(OrFrame, b, idx),
|
||||
);
|
||||
|
||||
offset += mem::size_of::<HeapCellValue>();
|
||||
}
|
||||
|
||||
let or_frame = &mut *(self.buf.top as *mut OrFrame);
|
||||
let or_frame = &mut *(new_ptr as *mut OrFrame);
|
||||
or_frame.prelude.univ_prelude.num_cells = num_cells;
|
||||
|
||||
self.buf.top = new_top;
|
||||
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + e;
|
||||
@@ -220,7 +245,7 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub(crate) fn index_and_frame_mut(&mut self, e: usize) -> &mut AndFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + e;
|
||||
@@ -228,7 +253,7 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + b;
|
||||
@@ -236,7 +261,7 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
|
||||
unsafe {
|
||||
let ptr = self.buf.base as usize + b;
|
||||
@@ -244,31 +269,65 @@ impl Stack {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[inline(always)]
|
||||
pub(crate) fn truncate(&mut self, b: usize) {
|
||||
if b == 0 {
|
||||
self.inner_truncate(mem::align_of::<Addr>());
|
||||
} else {
|
||||
self.inner_truncate(b);
|
||||
let base = self.buf.base as usize + b;
|
||||
|
||||
if base < self.buf.ptr as usize {
|
||||
self.buf.ptr = base as *mut _;
|
||||
}
|
||||
}
|
||||
|
||||
#[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(crate) 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>()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::machine::mock_wam::*;
|
||||
|
||||
#[test]
|
||||
fn stack_tests() {
|
||||
let mut wam = MockWAM::new();
|
||||
|
||||
let e = wam.machine_st.stack.allocate_and_frame(10); // create an AND frame!
|
||||
let and_frame = wam.machine_st.stack.index_and_frame_mut(e);
|
||||
|
||||
assert_eq!(
|
||||
e,
|
||||
0// 10 * mem::size_of::<HeapCellValue>() + prelude_size::<AndFrame>()
|
||||
);
|
||||
|
||||
assert_eq!(and_frame.prelude.univ_prelude.num_cells, 10);
|
||||
|
||||
for idx in 0..10 {
|
||||
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, e, idx + 1));
|
||||
}
|
||||
|
||||
and_frame[5] = empty_list_as_cell!();
|
||||
|
||||
assert_eq!(and_frame[5], empty_list_as_cell!());
|
||||
|
||||
let b = wam.machine_st.stack.allocate_or_frame(5);
|
||||
|
||||
let or_frame = wam.machine_st.stack.index_or_frame_mut(b);
|
||||
|
||||
for idx in 0..5 {
|
||||
assert_eq!(or_frame[idx], stack_loc_as_cell!(OrFrame, b, idx));
|
||||
}
|
||||
|
||||
let next_e = wam.machine_st.stack.allocate_and_frame(9); // create an AND frame!
|
||||
let and_frame = wam.machine_st.stack.index_and_frame_mut(next_e);
|
||||
|
||||
for idx in 0..9 {
|
||||
assert_eq!(and_frame[idx + 1], stack_loc_as_cell!(AndFrame, next_e, idx + 1));
|
||||
}
|
||||
|
||||
let and_frame = wam.machine_st.stack.index_and_frame(e);
|
||||
assert_eq!(and_frame[5], empty_list_as_cell!());
|
||||
|
||||
assert_eq!(
|
||||
wam.machine_st.stack[stack_loc!(AndFrame, e, 5)],
|
||||
empty_list_as_cell!()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,48 +1,53 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::parser::*;
|
||||
|
||||
use crate::machine::machine_errors::CompilationError;
|
||||
use crate::forms::*;
|
||||
use crate::machine::*;
|
||||
use crate::machine::load_state::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::parser::*;
|
||||
|
||||
use crate::predicate_queue;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
|
||||
pub(crate) trait TermStream: Sized {
|
||||
type Evacuable;
|
||||
pub struct LoadStatePayload<TS> {
|
||||
pub term_stream: TS,
|
||||
pub(super) compilation_target: CompilationTarget,
|
||||
pub(super) retraction_info: RetractionInfo,
|
||||
pub(super) module_op_exports: ModuleOpExports,
|
||||
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
|
||||
pub(super) predicates: PredicateQueue,
|
||||
pub(super) clause_clauses: Vec<(Term, Term)>,
|
||||
}
|
||||
|
||||
pub trait TermStream: Sized {
|
||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
|
||||
fn eof(&mut self) -> Result<bool, CompilationError>;
|
||||
fn listing_src(&self) -> &ListingSource;
|
||||
fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct BootstrappingTermStream<'a> {
|
||||
pub struct BootstrappingTermStream<'a> {
|
||||
listing_src: ListingSource,
|
||||
parser: Parser<'a, Stream>,
|
||||
pub(super) parser: Parser<'a, Stream>,
|
||||
}
|
||||
|
||||
impl<'a> BootstrappingTermStream<'a> {
|
||||
#[inline]
|
||||
pub(super) fn from_prolog_stream(
|
||||
stream: &'a mut PrologStream,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
flags: MachineFlags,
|
||||
pub(super) fn from_char_reader(
|
||||
stream: Stream,
|
||||
machine_st: &'a mut MachineState,
|
||||
listing_src: ListingSource,
|
||||
) -> Self {
|
||||
let parser = Parser::new(stream, atom_tbl, flags);
|
||||
Self {
|
||||
parser,
|
||||
listing_src,
|
||||
}
|
||||
let parser = Parser::new(stream, machine_st);
|
||||
Self { parser, listing_src }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TermStream for BootstrappingTermStream<'a> {
|
||||
type Evacuable = CompilationTarget;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||
self.parser.reset();
|
||||
@@ -61,24 +66,9 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
|
||||
fn listing_src(&self) -> &ListingSource {
|
||||
&self.listing_src
|
||||
}
|
||||
|
||||
fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
|
||||
if !loader.predicates.is_empty() {
|
||||
loader.compile_and_submit()?;
|
||||
}
|
||||
|
||||
loader
|
||||
.load_state
|
||||
.retraction_info
|
||||
.reset(loader.load_state.wam.code_repo.code.len());
|
||||
|
||||
loader.load_state.remove_module_op_exports();
|
||||
|
||||
Ok(loader.load_state.compilation_target.take())
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LiveTermStream {
|
||||
pub struct LiveTermStream {
|
||||
pub(super) term_queue: VecDeque<Term>,
|
||||
pub(super) listing_src: ListingSource,
|
||||
}
|
||||
@@ -93,28 +83,18 @@ impl LiveTermStream {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct LoadStatePayload {
|
||||
pub(super) term_stream: LiveTermStream,
|
||||
pub(super) compilation_target: CompilationTarget,
|
||||
pub(super) retraction_info: RetractionInfo,
|
||||
pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>,
|
||||
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
|
||||
pub(super) predicates: PredicateQueue,
|
||||
pub(super) clause_clauses: Vec<(Term, Term)>,
|
||||
}
|
||||
|
||||
impl fmt::Debug for LoadStatePayload {
|
||||
impl<TS> fmt::Debug for LoadStatePayload<TS> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "LoadStatePayload")
|
||||
}
|
||||
}
|
||||
|
||||
impl LoadStatePayload {
|
||||
pub(super) fn new(wam: &Machine) -> Self {
|
||||
impl<TS> LoadStatePayload<TS> {
|
||||
pub(super) fn new(code_repo_len: usize, term_stream: TS) -> Self {
|
||||
Self {
|
||||
term_stream: LiveTermStream::new(ListingSource::User),
|
||||
term_stream,
|
||||
compilation_target: CompilationTarget::default(),
|
||||
retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
|
||||
retraction_info: RetractionInfo::new(code_repo_len),
|
||||
module_op_exports: vec![],
|
||||
non_counted_bt_preds: IndexSet::new(),
|
||||
predicates: predicate_queue![],
|
||||
@@ -124,8 +104,6 @@ impl LoadStatePayload {
|
||||
}
|
||||
|
||||
impl TermStream for LiveTermStream {
|
||||
type Evacuable = LoadStatePayload;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
|
||||
Ok(self.term_queue.pop_front().unwrap())
|
||||
@@ -140,9 +118,4 @@ impl TermStream for LiveTermStream {
|
||||
fn listing_src(&self) -> &ListingSource {
|
||||
&self.listing_src
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn evacuate(loader: Loader<Self>) -> Result<LoadStatePayload, SessionError> {
|
||||
Ok(loader.to_load_state_payload())
|
||||
}
|
||||
}
|
||||
|
||||
867
src/macros.rs
867
src/macros.rs
@@ -1,9 +1,3 @@
|
||||
macro_rules! interm {
|
||||
($n: expr) => {
|
||||
ArithmeticTerm::Interm($n)
|
||||
};
|
||||
}
|
||||
|
||||
/* A simple macro to count the arguments in a variadic list
|
||||
* of token trees.
|
||||
*/
|
||||
@@ -13,53 +7,420 @@ macro_rules! count_tt {
|
||||
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
|
||||
}
|
||||
|
||||
macro_rules! char_as_cell {
|
||||
($c: expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! fixnum_as_cell {
|
||||
($n: expr) => {
|
||||
HeapCellValue::from_bytes($n.into_bytes()) //HeapCellValueTag::Fixnum, $n.get_num() as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_fixnum {
|
||||
($cell:expr) => {
|
||||
Fixnum::from_bytes($cell.into_bytes())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! integer_as_cell {
|
||||
($n: expr) => {{
|
||||
match $n {
|
||||
Number::Float(_) => unreachable!(),
|
||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||
Number::Rational(r) => typed_arena_ptr_as_cell!(r),
|
||||
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! empty_list_as_cell {
|
||||
() => {
|
||||
// the empty list atom has the fixed index of 8 (8 >> 3 == 1 in the condensed atom representation).
|
||||
atom_as_cell!(atom!("[]"))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! atom_as_cell {
|
||||
($atom:expr) => {
|
||||
HeapCellValue::from_bytes(
|
||||
AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(),
|
||||
)
|
||||
};
|
||||
($atom:expr, $arity:expr) => {
|
||||
HeapCellValue::from_bytes(
|
||||
AtomCell::build_with($atom.flat_index(), $arity as u16, HeapCellValueTag::Atom)
|
||||
.into_bytes(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_ossified_op_dir {
|
||||
($cell:expr) => {{
|
||||
let ptr_u64 = cell_as_untyped_arena_ptr!($cell);
|
||||
TypedArenaPtr::new(ptr_u64.payload_offset() as *mut OssifiedOpDir)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_string {
|
||||
($cell:expr) => {
|
||||
PartialString::from(cell_as_atom!($cell))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_atom {
|
||||
($cell:expr) => {{
|
||||
let cell = AtomCell::from_bytes($cell.into_bytes());
|
||||
let name = cell.get_index() << 3;
|
||||
|
||||
Atom::from(name as usize)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_atom_cell {
|
||||
($cell:expr) => {
|
||||
AtomCell::from_bytes($cell.into_bytes())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_f64_ptr {
|
||||
($cell:expr) => {{
|
||||
let ptr_u64 = ConsPtr::from_bytes($cell.into_bytes());
|
||||
F64Ptr(TypedArenaPtr::new(
|
||||
ptr_u64.as_ptr() as *mut OrderedFloat<f64>
|
||||
))
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_untyped_arena_ptr {
|
||||
($cell:expr) => {
|
||||
UntypedArenaPtr::from(u64::from($cell) as *const ArenaHeader)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pstr_as_cell {
|
||||
($atom:expr) => {
|
||||
HeapCellValue::from_bytes(
|
||||
AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::PStr).into_bytes(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pstr_loc_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::PStrLoc, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! pstr_offset_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::PStrOffset, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! list_loc_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::Lis, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! str_loc_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::Str, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! stack_loc {
|
||||
(OrFrame, $b:expr, $idx:expr) => ({
|
||||
$b + prelude_size::<OrFrame>() + $idx * std::mem::size_of::<HeapCellValue>()
|
||||
});
|
||||
(AndFrame, $e:expr, $idx:expr) => ({
|
||||
$e + prelude_size::<AndFrame>() + ($idx - 1) * std::mem::size_of::<HeapCellValue>()
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! stack_loc_as_cell {
|
||||
(OrFrame, $b:expr, $idx:expr) => {
|
||||
stack_loc_as_cell!(stack_loc!(OrFrame, $b, $idx))
|
||||
};
|
||||
(AndFrame, $b:expr, $idx:expr) => {
|
||||
stack_loc_as_cell!(stack_loc!(AndFrame, $b, $idx))
|
||||
};
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::StackVar, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! heap_loc_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::Var, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! attr_var_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
macro_rules! attr_var_loc_as_cell {
|
||||
($h:expr) => {
|
||||
HeapCellValue::build_with(HeapCellValueTag::AttrVar, $h as u64)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! typed_arena_ptr_as_cell {
|
||||
($ptr:expr) => {
|
||||
untyped_arena_ptr_as_cell!($ptr.header_ptr())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! untyped_arena_ptr_as_cell {
|
||||
($ptr:expr) => {
|
||||
HeapCellValue::from_bytes(unsafe { std::mem::transmute($ptr) })
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! atom_as_cstr_cell {
|
||||
($atom:expr) => {{
|
||||
let offset = $atom.flat_index();
|
||||
|
||||
HeapCellValue::from_bytes(
|
||||
AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! string_as_cstr_cell {
|
||||
($ptr:expr) => {{
|
||||
let atom: Atom = $ptr.into();
|
||||
let offset = atom.flat_index();
|
||||
|
||||
HeapCellValue::from_bytes(
|
||||
AtomCell::build_with(offset as u64, 0, HeapCellValueTag::CStr).into_bytes(),
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! string_as_pstr_cell {
|
||||
($ptr:expr) => {{
|
||||
let atom: Atom = $ptr.into();
|
||||
let offset = atom.flat_index();
|
||||
|
||||
HeapCellValue::from_bytes(
|
||||
AtomCell::build_with(offset as u64, 0, HeapCellValueTag::PStr).into_bytes(),
|
||||
)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! stream_as_cell {
|
||||
($ptr:expr) => {
|
||||
untyped_arena_ptr_as_cell!($ptr.as_ptr())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_stream {
|
||||
($cell:expr) => {{
|
||||
let ptr = cell_as_untyped_arena_ptr!($cell);
|
||||
Stream::from_tag(ptr.get_tag(), ptr.payload_offset())
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! cell_as_load_state_payload {
|
||||
($cell:expr) => { unsafe {
|
||||
let ptr = cell_as_untyped_arena_ptr!($cell);
|
||||
let ptr = std::mem::transmute::<_, *mut LiveLoadState>(ptr.payload_offset());
|
||||
|
||||
TypedArenaPtr::new(ptr)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! match_untyped_arena_ptr_pat_body {
|
||||
($ptr:ident, Integer, $n:ident, $code:expr) => {{
|
||||
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Integer>($ptr.payload_offset()) };
|
||||
let $n = TypedArenaPtr::new(payload_ptr);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($ptr:ident, F64, $n:ident, $code:expr) => {{
|
||||
let payload_ptr =
|
||||
unsafe { std::mem::transmute::<_, *mut OrderedFloat<f64>>($ptr.payload_offset()) };
|
||||
let $n = TypedArenaPtr::new(payload_ptr);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($ptr:ident, Rational, $n:ident, $code:expr) => {{
|
||||
let payload_ptr = unsafe { std::mem::transmute::<_, *mut Rational>($ptr.payload_offset()) };
|
||||
let $n = TypedArenaPtr::new(payload_ptr);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($cell:ident, OssifiedOpDir, $n:ident, $code:expr) => {{
|
||||
let $n = cell_as_ossified_op_dir!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($cell:ident, LiveLoadState, $n:ident, $code:expr) => {{
|
||||
let $n = cell_as_load_state_payload!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($ptr:ident, Stream, $s:ident, $code:expr) => {{
|
||||
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($ptr:ident, TcpListener, $listener:ident, $code:expr) => {{
|
||||
let payload_ptr = unsafe { std::mem::transmute::<_, *mut TcpListener>($ptr.payload_offset()) };
|
||||
#[allow(unused_mut)]
|
||||
let mut $listener = TypedArenaPtr::new(payload_ptr);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
($ptr:ident, $($tags:tt)|+, $s:ident, $code:expr) => {{
|
||||
let $s = Stream::from_tag($ptr.get_tag(), $ptr.payload_offset());
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! match_untyped_arena_ptr_pat {
|
||||
(Stream) => {
|
||||
ArenaHeaderTag::InputFileStream
|
||||
| ArenaHeaderTag::OutputFileStream
|
||||
| ArenaHeaderTag::NamedTcpStream
|
||||
| ArenaHeaderTag::NamedTlsStream
|
||||
| ArenaHeaderTag::ReadlineStream
|
||||
| ArenaHeaderTag::StaticStringStream
|
||||
| ArenaHeaderTag::ByteStream
|
||||
| ArenaHeaderTag::StandardOutputStream
|
||||
| ArenaHeaderTag::StandardErrorStream
|
||||
};
|
||||
($tag:ident) => {
|
||||
ArenaHeaderTag::$tag
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! match_untyped_arena_ptr {
|
||||
($ptr:expr, $( ($(ArenaHeaderTag::$tag:tt)|+, $n:ident) => $code:block $(,)?)+ $(_ => $misc_code:expr $(,)?)?) => ({
|
||||
let ptr_id = $ptr;
|
||||
|
||||
match ptr_id.get_tag() {
|
||||
$($(match_untyped_arena_ptr_pat!($tag) => {
|
||||
match_untyped_arena_ptr_pat_body!(ptr_id, $tag, $n, $code)
|
||||
})+)+
|
||||
$(_ => $misc_code)?
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! read_heap_cell_pat_body {
|
||||
($cell:ident, Cons, $n:ident, $code:expr) => ({
|
||||
let $n = cell_as_untyped_arena_ptr!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, F64, $n:ident, $code:expr) => ({
|
||||
let $n = cell_as_f64_ptr!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, Atom, ($name:ident, $arity:ident), $code:expr) => ({
|
||||
let ($name, $arity) = cell_as_atom_cell!($cell).get_name_and_arity();
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, PStr, $atom:ident, $code:expr) => ({
|
||||
let $atom = cell_as_atom!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, CStr, $atom:ident, $code:expr) => ({
|
||||
let $atom = cell_as_atom!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, CStr | PStr, $atom:ident, $code:expr) => ({
|
||||
let $atom = cell_as_atom!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, PStr | CStr, $atom:ident, $code:expr) => ({
|
||||
let $atom = cell_as_atom!($cell);
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, Fixnum, $value:ident, $code:expr) => ({
|
||||
let $value = Fixnum::from_bytes($cell.into_bytes());
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, Char, $value:ident, $code:expr) => ({
|
||||
let $value = unsafe { char::from_u32_unchecked($cell.get_value() as u32) };
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
($cell:ident, $($tags:tt)|+, $value:ident, $code:expr) => ({
|
||||
let $value = $cell.get_value() as usize;
|
||||
#[allow(unused_braces)]
|
||||
$code
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! read_heap_cell_pat {
|
||||
(($(HeapCellValueTag::$tag:tt)|+, $n:tt)) => {
|
||||
$(HeapCellValueTag::$tag)|+
|
||||
};
|
||||
(($(HeapCellValueTag::$tag:tt)|+)) => {
|
||||
$(HeapCellValueTag::$tag)|+
|
||||
};
|
||||
(_) => { _ };
|
||||
}
|
||||
|
||||
macro_rules! read_heap_cell_pat_expander {
|
||||
($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+, $n:tt), $code:block) => ({
|
||||
read_heap_cell_pat_body!($cell_id, $($tag)|+, $n, $code)
|
||||
});
|
||||
($cell_id:ident, ($(HeapCellValueTag::$tag:tt)|+), $code:block) => ({
|
||||
$code
|
||||
});
|
||||
($cell_id:ident, _, $code:block) => ({
|
||||
$code
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! read_heap_cell {
|
||||
($cell:expr, $($pat:tt $(if $guard_expr:expr)? => $code:block $(,)?)+) => ({
|
||||
let cell_id = $cell;
|
||||
|
||||
match cell_id.get_tag() {
|
||||
$(read_heap_cell_pat!($pat) $(if $guard_expr)? => {
|
||||
read_heap_cell_pat_expander!(cell_id, $pat, $code)
|
||||
})+
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! functor {
|
||||
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
||||
{
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
let arity = count_tt!($($dt) +);
|
||||
let aux_lens = [$($aux.len()),*];
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
|
||||
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
||||
|
||||
$(
|
||||
result.extend($aux.into_iter());
|
||||
)*
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
result
|
||||
}
|
||||
});
|
||||
($name:expr, $fixity:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
||||
{
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
let arity = count_tt!($($dt) +);
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), Some($fixity)),
|
||||
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
result
|
||||
}
|
||||
});
|
||||
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
|
||||
{
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
let arity = count_tt!($($dt) +);
|
||||
let aux_lens = [$($aux.len()),*];
|
||||
let arity: usize = count_tt!($($dt) +);
|
||||
|
||||
#[allow(unused_variables)]
|
||||
let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*];
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
|
||||
vec![ atom_as_cell!($name, arity as u16),
|
||||
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
|
||||
|
||||
$(
|
||||
result.extend($aux.into_iter());
|
||||
result.extend($aux.iter());
|
||||
)*
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
@@ -68,383 +429,183 @@ macro_rules! functor {
|
||||
});
|
||||
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
|
||||
{
|
||||
use crate::machine::heap::*;
|
||||
let arity: usize = count_tt!($($dt) +);
|
||||
|
||||
let arity = count_tt!($($dt) +);
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut addendum = Heap::new();
|
||||
|
||||
let mut result =
|
||||
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
|
||||
vec![ atom_as_cell!($name, arity as u16),
|
||||
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
|
||||
|
||||
result.extend(addendum.into_iter());
|
||||
result
|
||||
}
|
||||
});
|
||||
($name:expr, $fixity:expr) => (
|
||||
vec![ HeapCellValue::Atom(clause_name!($name), Some($fixity)) ]
|
||||
);
|
||||
(clause_name($name:expr)) => (
|
||||
vec![ HeapCellValue::Atom($name, None) ]
|
||||
);
|
||||
($name:expr) => (
|
||||
vec![ HeapCellValue::Atom(clause_name!($name), None) ]
|
||||
);
|
||||
($name:expr) => ({
|
||||
vec![ atom_as_cell!($name) ]
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! functor_term {
|
||||
(aux(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + 1))
|
||||
(str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
str_loc_as_cell!($arity + 1)
|
||||
});
|
||||
(aux($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
(str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + 1 + len))
|
||||
str_loc_as_cell!($arity + 1 + len)
|
||||
});
|
||||
(aux($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1))
|
||||
(str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
str_loc_as_cell!($arity + $h + 1)
|
||||
});
|
||||
(aux($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
(str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
let len: usize = $aux_lens[0 .. $e].iter().sum();
|
||||
HeapCellValue::Addr(Addr::HeapCell($arity + $h + 1 + len))
|
||||
str_loc_as_cell!($arity + $h + 1 + len)
|
||||
});
|
||||
(addr($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::Addr($e)
|
||||
(literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::from($e)
|
||||
);
|
||||
(constant($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
from_constant!($e, $h, $arity, $aux_lens, $addendum)
|
||||
(integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena)
|
||||
);
|
||||
(constant($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
from_constant!($e, 0, $arity, $aux_lens, $addendum)
|
||||
);
|
||||
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
$e.into()
|
||||
);
|
||||
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::Integer(Rc::new(Integer::from($e)))
|
||||
(fixnum($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
fixnum_as_cell!(Fixnum::build_with($e as i64))
|
||||
);
|
||||
(indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
let stub =
|
||||
match $e {
|
||||
IndexingCodePtr::DynamicExternal(o) => functor!("dynamic_external", [integer(o)]),
|
||||
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
|
||||
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
|
||||
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
|
||||
IndexingCodePtr::DynamicExternal(o) => functor!(atom!("dynamic_external"), [fixnum(o)]),
|
||||
IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
|
||||
IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
|
||||
IndexingCodePtr::Fail => {
|
||||
vec![atom_as_cell!(atom!("fail"))]
|
||||
},
|
||||
};
|
||||
|
||||
let len: usize = $aux_lens.iter().sum();
|
||||
let h = len + $arity + 1 + $addendum.h() + $h;
|
||||
let h = len + $arity + 1 + $addendum.len() + $h;
|
||||
|
||||
$addendum.extend(stub.into_iter());
|
||||
|
||||
HeapCellValue::Addr(Addr::HeapCell(h))
|
||||
str_loc_as_cell!(h)
|
||||
});
|
||||
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::Atom($e, None)
|
||||
(number($arena:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::from(($e, $arena))
|
||||
);
|
||||
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
HeapCellValue::Atom(clause_name!($e), None)
|
||||
);
|
||||
(value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
|
||||
$e
|
||||
atom_as_cell!($e)
|
||||
);
|
||||
(string($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
|
||||
let len: usize = $aux_lens.iter().sum();
|
||||
let h = len + $arity + 1 + $addendum.h() + $h;
|
||||
let h = len + $arity + 1 + $addendum.len() + $h;
|
||||
|
||||
$addendum.put_complete_string(&$e);
|
||||
let cell = string_as_pstr_cell!($e);
|
||||
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
$addendum.push(cell);
|
||||
$addendum.push(empty_list_as_cell!());
|
||||
|
||||
heap_loc_as_cell!(h)
|
||||
});
|
||||
(boolean($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ({
|
||||
if $e {
|
||||
functor_term!(atom("true"), $arity, $aux_lens, $addendum)
|
||||
functor_term!(atom(atom!("true")), $arity, $aux_lens, $addendum)
|
||||
} else {
|
||||
functor_term!(atom("false"), $arity, $aux_lens, $addendum)
|
||||
functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum)
|
||||
}
|
||||
});
|
||||
($e:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
(cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
macro_rules! from_constant {
|
||||
($e:expr, $over_h:expr, $arity:expr, $aux_lens:expr, $addendum:ident) => ({
|
||||
match $e {
|
||||
&Constant::Atom(ref name, ref op) => {
|
||||
HeapCellValue::Atom(name.clone(), op.clone())
|
||||
}
|
||||
&Constant::Char(c) => {
|
||||
HeapCellValue::Addr(Addr::Char(c))
|
||||
}
|
||||
&Constant::Fixnum(n) => {
|
||||
HeapCellValue::Addr(Addr::Fixnum(n))
|
||||
}
|
||||
&Constant::Integer(ref n) => {
|
||||
HeapCellValue::Integer(n.clone())
|
||||
}
|
||||
&Constant::Rational(ref r) => {
|
||||
HeapCellValue::Rational(r.clone())
|
||||
}
|
||||
&Constant::Float(f) => {
|
||||
HeapCellValue::Addr(Addr::Float(f))
|
||||
}
|
||||
&Constant::String(ref s) => {
|
||||
let len: usize = $aux_lens.iter().sum();
|
||||
let h = len + $arity + 1 + $addendum.h() + $over_h;
|
||||
|
||||
$addendum.put_complete_string(&s);
|
||||
|
||||
HeapCellValue::Addr(Addr::PStrLocation(h, 0))
|
||||
}
|
||||
&Constant::Usize(u) => {
|
||||
HeapCellValue::Addr(Addr::Usize(u))
|
||||
}
|
||||
&Constant::EmptyList => {
|
||||
HeapCellValue::Addr(Addr::EmptyList)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! is_atom {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_atomic {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_integer {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_compound {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_float {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_rational {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_number {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsNumber($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_nonvar {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_var {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! call_clause {
|
||||
($ct:expr, $arity:expr, $pvs:expr) => {
|
||||
Line::Control(ControlInstruction::CallClause(
|
||||
$ct, $arity, $pvs, false, false,
|
||||
))
|
||||
};
|
||||
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
|
||||
Line::Control(ControlInstruction::CallClause(
|
||||
$ct, $arity, $pvs, $lco, false,
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! call_clause_by_default {
|
||||
($ct:expr, $arity:expr, $pvs:expr) => {
|
||||
Line::Control(ControlInstruction::CallClause(
|
||||
$ct, $arity, $pvs, false, true,
|
||||
))
|
||||
};
|
||||
($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
|
||||
Line::Control(ControlInstruction::CallClause(
|
||||
$ct, $arity, $pvs, $lco, true,
|
||||
))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! proceed {
|
||||
() => {
|
||||
Line::Control(ControlInstruction::Proceed)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_call {
|
||||
($r:expr, $at:expr) => {
|
||||
call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_call_by_default {
|
||||
($r:expr, $at:expr) => {
|
||||
call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set_cp {
|
||||
($r:expr) => {
|
||||
call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! succeed {
|
||||
() => {
|
||||
call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! fail {
|
||||
() => {
|
||||
call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! compare_number_instr {
|
||||
($cmp: expr, $at_1: expr, $at_2: expr) => {{
|
||||
let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2));
|
||||
call_clause!(ct, 2, 0)
|
||||
$cmp.set_terms($at_1, $at_2);
|
||||
call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! jmp_call {
|
||||
($arity:expr, $offset:expr, $pvs:expr) => {
|
||||
Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! return_from_clause {
|
||||
($lco:expr, $machine_st:expr) => {{
|
||||
if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if $lco {
|
||||
$machine_st.p = CodePtr::Local($machine_st.cp);
|
||||
} else {
|
||||
$machine_st.p += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
macro_rules! call_clause {
|
||||
($clause_type:expr, $pvs:expr) => {{
|
||||
let mut instr = $clause_type.to_instr();
|
||||
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
|
||||
instr
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! dir_entry {
|
||||
($idx:expr) => {
|
||||
LocalCodePtr::DirEntry($idx)
|
||||
macro_rules! call_clause_by_default {
|
||||
($clause_type:expr, $pvs:expr) => {{
|
||||
let mut instr = $clause_type.to_instr().to_default();
|
||||
instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
|
||||
instr
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! interm {
|
||||
($n: expr) => {
|
||||
ArithmeticTerm::Interm($n)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! index_store {
|
||||
($code_dir:expr, $op_dir:expr, $modules:expr) => {
|
||||
IndexStore {
|
||||
code_dir: $code_dir,
|
||||
extensible_predicates: ExtensiblePredicates::new(),
|
||||
local_extensible_predicates: LocalExtensiblePredicates::new(),
|
||||
global_variables: GlobalVarDir::new(),
|
||||
meta_predicates: MetaPredicateDir::new(),
|
||||
modules: $modules,
|
||||
op_dir: $op_dir,
|
||||
streams: StreamDir::new(),
|
||||
stream_aliases: StreamAliasDir::new(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! put_constant {
|
||||
($lvl:expr, $cons:expr, $r:expr) => {
|
||||
QueryInstruction::PutConstant($lvl, $cons, $r)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! get_level_and_unify {
|
||||
($r: expr) => {
|
||||
Line::Cut(CutInstruction::GetLevelAndUnify($r))
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
macro_rules! unwind_protect {
|
||||
($e: expr, $protected: expr) => {
|
||||
match $e {
|
||||
Err(e) => {
|
||||
$protected;
|
||||
return Err(e);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
}
|
||||
*/
|
||||
/*
|
||||
macro_rules! discard_result {
|
||||
($f: expr) => {
|
||||
match $f {
|
||||
_ => (),
|
||||
}
|
||||
};
|
||||
}
|
||||
*/
|
||||
macro_rules! ar_reg {
|
||||
($r: expr) => {
|
||||
ArithmeticTerm::Reg($r)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! atom_from {
|
||||
($self:expr, $e:expr) => {
|
||||
match $e {
|
||||
Addr::Con(h) if $self.heap.atom_at(h) => {
|
||||
match &$self.heap[h] {
|
||||
HeapCellValue::Atom(ref atom, _) => {
|
||||
atom.clone()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
Addr::Char(c) => {
|
||||
clause_name!(c.to_string(), $self.atom_tbl)
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! unmark_cell_bits {
|
||||
($e:expr) => {{
|
||||
let mut result = $e;
|
||||
|
||||
macro_rules! try_or_fail {
|
||||
($s:expr, $e:expr) => {{
|
||||
match $e {
|
||||
Ok(val) => val,
|
||||
Err(msg) => {
|
||||
$s.throw_exception(msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
result.set_mark_bit(false);
|
||||
result.set_forwarding_bit(false);
|
||||
|
||||
result
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! index_store {
|
||||
($code_dir:expr, $op_dir:expr, $modules:expr) => {
|
||||
IndexStore {
|
||||
code_dir: $code_dir,
|
||||
extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
|
||||
local_extensible_predicates: LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
|
||||
global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()),
|
||||
meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
|
||||
modules: $modules,
|
||||
op_dir: $op_dir,
|
||||
streams: StreamDir::new(),
|
||||
stream_aliases: StreamAliasDir::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! unify {
|
||||
($machine_st:expr, $($value:expr),*) => {{
|
||||
$($machine_st.pdl.push($value);)*
|
||||
$machine_st.unify()
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! unify_fn {
|
||||
($machine_st:expr, $($value:expr),*) => {{
|
||||
$($machine_st.pdl.push($value);)*
|
||||
($machine_st.unify_fn)(&mut $machine_st)
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! unify_with_occurs_check {
|
||||
($machine_st:expr, $($value:expr),*) => {{
|
||||
$($machine_st.pdl.push($value);)*
|
||||
$machine_st.unify_with_occurs_check()
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! compare_term_test {
|
||||
($machine_st:expr, $e1:expr, $e2:expr) => {{
|
||||
$machine_st.pdl.push($e2);
|
||||
$machine_st.pdl.push($e1);
|
||||
|
||||
$machine_st.compare_term_test()
|
||||
}};
|
||||
}
|
||||
|
||||
632
src/parser/ast.rs
Normal file
632
src/parser/ast.rs
Normal file
@@ -0,0 +1,632 @@
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::types::HeapCellValueTag;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::io::{Error as IOError};
|
||||
use std::ops::Neg;
|
||||
use std::rc::Rc;
|
||||
use std::vec::Vec;
|
||||
|
||||
use rug::{Integer, Rational};
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexMap;
|
||||
use modular_bitfield::error::OutOfBounds;
|
||||
use modular_bitfield::prelude::*;
|
||||
|
||||
pub type Specifier = u32;
|
||||
|
||||
pub const MAX_ARITY: usize = 1023;
|
||||
|
||||
pub const XFX: u32 = 0x0001;
|
||||
pub const XFY: u32 = 0x0002;
|
||||
pub const YFX: u32 = 0x0004;
|
||||
pub const XF: u32 = 0x0010;
|
||||
pub const YF: u32 = 0x0020;
|
||||
pub const FX: u32 = 0x0040;
|
||||
pub const FY: u32 = 0x0080;
|
||||
pub const DELIMITER: u32 = 0x0100;
|
||||
pub const TERM: u32 = 0x1000;
|
||||
pub const LTERM: u32 = 0x3000;
|
||||
|
||||
pub const NEGATIVE_SIGN: u32 = 0x0200;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! fixnum {
|
||||
($wrapper:tt, $n:expr, $arena:expr) => {
|
||||
Fixnum::build_with_checked($n)
|
||||
.map(<$wrapper>::Fixnum)
|
||||
.unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_term {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::TERM) != 0
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_lterm {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::LTERM) != 0
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_op {
|
||||
($x:expr) => {
|
||||
$x as u32
|
||||
& ($crate::parser::ast::XF
|
||||
| $crate::parser::ast::YF
|
||||
| $crate::parser::ast::FX
|
||||
| $crate::parser::ast::FY
|
||||
| $crate::parser::ast::XFX
|
||||
| $crate::parser::ast::XFY
|
||||
| $crate::parser::ast::YFX)
|
||||
!= 0
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_negate {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::NEGATIVE_SIGN) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_prefix {
|
||||
($x:expr) => {
|
||||
$x as u32 & ($crate::parser::ast::FX | $crate::parser::ast::FY) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_postfix {
|
||||
($x:expr) => {
|
||||
$x as u32 & ($crate::parser::ast::XF | $crate::parser::ast::YF) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_infix {
|
||||
($x:expr) => {
|
||||
($x as u32
|
||||
& ($crate::parser::ast::XFX | $crate::parser::ast::XFY | $crate::parser::ast::YFX))
|
||||
!= 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_xfx {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::XFX) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_xfy {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::XFY) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_yfx {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::YFX) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_yf {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::YF) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_xf {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::XF) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_fx {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::FX) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! is_fy {
|
||||
($x:expr) => {
|
||||
($x as u32 & $crate::parser::ast::FY) != 0
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum RegType {
|
||||
Perm(usize),
|
||||
Temp(usize),
|
||||
}
|
||||
|
||||
impl Default for RegType {
|
||||
fn default() -> Self {
|
||||
RegType::Temp(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl RegType {
|
||||
pub fn reg_num(self) -> usize {
|
||||
match self {
|
||||
RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_perm(self) -> bool {
|
||||
matches!(self, RegType::Perm(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RegType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RegType::Perm(val) => write!(f, "Y{}", val),
|
||||
RegType::Temp(val) => write!(f, "X{}", val),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum VarReg {
|
||||
ArgAndNorm(RegType, usize),
|
||||
Norm(RegType),
|
||||
}
|
||||
|
||||
impl VarReg {
|
||||
pub fn norm(self) -> RegType {
|
||||
match self {
|
||||
VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for VarReg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
|
||||
VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
|
||||
VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg),
|
||||
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VarReg {
|
||||
fn default() -> Self {
|
||||
VarReg::Norm(RegType::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! temp_v {
|
||||
($x:expr) => {
|
||||
$crate::parser::ast::RegType::Temp($x)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! perm_v {
|
||||
($x:expr) => {
|
||||
$crate::parser::ast::RegType::Perm($x)
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum GenContext {
|
||||
Head,
|
||||
Mid(usize),
|
||||
Last(usize), // Mid & Last: chunk_num
|
||||
}
|
||||
|
||||
impl GenContext {
|
||||
pub fn chunk_num(self) -> usize {
|
||||
match self {
|
||||
GenContext::Head => 0,
|
||||
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
|
||||
pub struct OpDesc {
|
||||
prec: B11,
|
||||
spec: B8,
|
||||
#[allow(unused)] padding: B13,
|
||||
}
|
||||
|
||||
impl OpDesc {
|
||||
#[inline]
|
||||
pub fn build_with(prec: u16, spec: u8) -> Self {
|
||||
OpDesc::new().with_spec(spec).with_prec(prec)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(self) -> (u16, u8) {
|
||||
(self.prec(), self.spec())
|
||||
}
|
||||
|
||||
pub fn set(&mut self, prec: u16, spec: u8) {
|
||||
self.set_prec(prec);
|
||||
self.set_spec(spec);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_prec(self) -> u16 {
|
||||
self.prec()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_spec(self) -> u8 {
|
||||
self.spec()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn arity(self) -> usize {
|
||||
if self.spec() as u32 & (XFX | XFY | YFX) == 0 {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// name and fixity -> operator type and precedence.
|
||||
pub type OpDir = IndexMap<(Atom, Fixity), OpDesc, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct MachineFlags {
|
||||
pub double_quotes: DoubleQuotes,
|
||||
}
|
||||
|
||||
impl Default for MachineFlags {
|
||||
fn default() -> Self {
|
||||
MachineFlags {
|
||||
double_quotes: DoubleQuotes::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DoubleQuotes {
|
||||
Atom,
|
||||
Chars,
|
||||
Codes,
|
||||
}
|
||||
|
||||
impl DoubleQuotes {
|
||||
pub fn is_chars(self) -> bool {
|
||||
matches!(self, DoubleQuotes::Chars)
|
||||
}
|
||||
|
||||
pub fn is_atom(self) -> bool {
|
||||
matches!(self, DoubleQuotes::Atom)
|
||||
}
|
||||
|
||||
pub fn is_codes(self) -> bool {
|
||||
matches!(self, DoubleQuotes::Codes)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DoubleQuotes {
|
||||
fn default() -> Self {
|
||||
DoubleQuotes::Chars
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_op_dir() -> OpDir {
|
||||
let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
|
||||
|
||||
op_dir.insert(
|
||||
(atom!(":-"), Fixity::In),
|
||||
OpDesc::build_with(1200, XFX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!(":-"), Fixity::Pre),
|
||||
OpDesc::build_with(1200, FX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!("?-"), Fixity::Pre),
|
||||
OpDesc::build_with(1200, FX as u8),
|
||||
);
|
||||
op_dir.insert(
|
||||
(atom!(","), Fixity::In),
|
||||
OpDesc::build_with(1000, XFY as u8),
|
||||
);
|
||||
|
||||
op_dir
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ArithmeticError {
|
||||
NonEvaluableFunctor(Literal, usize),
|
||||
UninstantiatedVar,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ParserError {
|
||||
BackQuotedString(usize, usize),
|
||||
UnexpectedChar(char, usize, usize),
|
||||
UnexpectedEOF,
|
||||
IO(IOError),
|
||||
IncompleteReduction(usize, usize),
|
||||
InvalidSingleQuotedCharacter(char),
|
||||
MissingQuote(usize, usize),
|
||||
NonPrologChar(usize, usize),
|
||||
ParseBigInt(usize, usize),
|
||||
LexicalError(lexical::Error),
|
||||
Utf8Error(usize, usize),
|
||||
}
|
||||
|
||||
impl ParserError {
|
||||
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
|
||||
match self {
|
||||
&ParserError::BackQuotedString(line_num, col_num)
|
||||
| &ParserError::UnexpectedChar(_, line_num, col_num)
|
||||
| &ParserError::IncompleteReduction(line_num, col_num)
|
||||
| &ParserError::MissingQuote(line_num, col_num)
|
||||
| &ParserError::NonPrologChar(line_num, col_num)
|
||||
| &ParserError::ParseBigInt(line_num, col_num)
|
||||
| &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_atom(&self) -> Atom {
|
||||
match self {
|
||||
ParserError::BackQuotedString(..) => atom!("back_quoted_string"),
|
||||
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
|
||||
ParserError::UnexpectedEOF => atom!("unexpected_end_of_file"),
|
||||
ParserError::IncompleteReduction(..) => atom!("incomplete_reduction"),
|
||||
ParserError::InvalidSingleQuotedCharacter(..) => atom!("invalid_single_quoted_character"),
|
||||
ParserError::IO(_) => atom!("input_output_error"),
|
||||
ParserError::LexicalError(_) => atom!("lexical_error"), // TODO: ?
|
||||
ParserError::MissingQuote(..) => atom!("missing_quote"),
|
||||
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
|
||||
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
|
||||
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<lexical::Error> for ParserError {
|
||||
fn from(e: lexical::Error) -> ParserError {
|
||||
ParserError::LexicalError(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IOError> for ParserError {
|
||||
fn from(e: IOError) -> ParserError {
|
||||
ParserError::IO(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&IOError> for ParserError {
|
||||
fn from(error: &IOError) -> ParserError {
|
||||
if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
|
||||
ParserError::Utf8Error(0, 0)
|
||||
} else {
|
||||
ParserError::IO(error.kind().into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct CompositeOpDir<'a, 'b> {
|
||||
pub primary_op_dir: Option<&'b OpDir>,
|
||||
pub secondary_op_dir: &'a OpDir,
|
||||
}
|
||||
|
||||
impl<'a, 'b> CompositeOpDir<'a, 'b> {
|
||||
#[inline]
|
||||
pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self {
|
||||
CompositeOpDir {
|
||||
primary_op_dir,
|
||||
secondary_op_dir,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get(&self, name: Atom, fixity: Fixity) -> Option<OpDesc> {
|
||||
let entry = if let Some(ref primary_op_dir) = &self.primary_op_dir {
|
||||
primary_op_dir.get(&(name, fixity))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
entry
|
||||
.or_else(move || self.secondary_op_dir.get(&(name, fixity)))
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Fixity {
|
||||
In,
|
||||
Post,
|
||||
Pre,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Fixnum {
|
||||
num: B57,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] tag: B6,
|
||||
}
|
||||
|
||||
impl Fixnum {
|
||||
#[inline]
|
||||
pub fn build_with(num: i64) -> Self {
|
||||
Fixnum::new()
|
||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))
|
||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||
.with_m(false)
|
||||
//num as u64).with__m(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
|
||||
const UPPER_BOUND: i64 = (1 << 56) - 1;
|
||||
const LOWER_BOUND: i64 = -(1 << 56);
|
||||
|
||||
if LOWER_BOUND <= num && num <= UPPER_BOUND {
|
||||
Ok(Fixnum::new()
|
||||
.with_m(false)
|
||||
.with_tag(HeapCellValueTag::Fixnum as u8)
|
||||
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 57) - 1))) //num as u64 & ((1 << 57) - 1)))
|
||||
} else {
|
||||
Err(OutOfBounds {})
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_num(self) -> i64 {
|
||||
let n = self.num() as i64;
|
||||
let (n, overflowed) = (n << 7).overflowing_shr(7); // sign-extend the 57-bit signed fixnum.
|
||||
debug_assert_eq!(overflowed, false);
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
impl Neg for Fixnum {
|
||||
type Output = Self;
|
||||
|
||||
#[inline]
|
||||
fn neg(self) -> Self::Output {
|
||||
Fixnum::build_with(-self.get_num())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Literal {
|
||||
Atom(Atom),
|
||||
Char(char),
|
||||
Fixnum(Fixnum),
|
||||
Integer(TypedArenaPtr<Integer>),
|
||||
Rational(TypedArenaPtr<Rational>),
|
||||
Float(F64Ptr),
|
||||
String(Atom),
|
||||
}
|
||||
|
||||
impl fmt::Display for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Literal::Atom(ref atom) => {
|
||||
// if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) {
|
||||
// write!(f, "'{}'", atom)
|
||||
// } else {
|
||||
write!(f, "{}", atom.flat_index())
|
||||
// }
|
||||
}
|
||||
Literal::Char(c) => write!(f, "'{}'", *c as u32),
|
||||
Literal::Fixnum(n) => write!(f, "{}", n.get_num()),
|
||||
Literal::Integer(ref n) => write!(f, "{}", n),
|
||||
Literal::Rational(ref n) => write!(f, "{}", n),
|
||||
Literal::Float(ref n) => write!(f, "{}", *n),
|
||||
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
|
||||
// Literal::Usize(integer) => write!(f, "u{}", integer),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Literal {
|
||||
pub fn to_atom(&self, atom_tbl: &mut AtomTable) -> Option<Atom> {
|
||||
match self {
|
||||
Literal::Atom(atom) => Some(atom.defrock_brackets(atom_tbl)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Term {
|
||||
AnonVar,
|
||||
Clause(Cell<RegType>, Atom, Vec<Term>),
|
||||
Cons(Cell<RegType>, Box<Term>, Box<Term>),
|
||||
Literal(Cell<RegType>, Literal),
|
||||
PartialString(Cell<RegType>, Atom, Option<Box<Term>>),
|
||||
Var(Cell<VarReg>, Rc<String>),
|
||||
}
|
||||
|
||||
impl Term {
|
||||
pub fn into_literal(self) -> Option<Literal> {
|
||||
match self {
|
||||
Term::Literal(_, c) => Some(c),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first_arg(&self) -> Option<&Term> {
|
||||
match self {
|
||||
Term::Clause(_, _, ref terms) => terms.first(),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, new_name: Atom) {
|
||||
match self {
|
||||
Term::Literal(_, Literal::Atom(ref mut atom)) | Term::Clause(_, ref mut atom, ..) => {
|
||||
*atom = new_name;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<Atom> {
|
||||
match self {
|
||||
&Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => {
|
||||
Some(*atom)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arity(&self) -> usize {
|
||||
match self {
|
||||
Term::Clause(_, _, ref child_terms, ..) => child_terms.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
|
||||
if let Term::Clause(_, ref name, ref mut subterms) = term {
|
||||
if name == &s && subterms.len() == 2 {
|
||||
let snd = subterms.pop().unwrap();
|
||||
let fst = subterms.pop().unwrap();
|
||||
|
||||
return Some((fst, snd));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
|
||||
let mut terms = vec![];
|
||||
|
||||
while let Some((fst, snd)) = unfold_by_str_once(&mut term, s) {
|
||||
terms.push(fst);
|
||||
term = snd;
|
||||
}
|
||||
|
||||
terms.push(term);
|
||||
terms
|
||||
}
|
||||
747
src/parser/char_reader.rs
Normal file
747
src/parser/char_reader.rs
Normal file
@@ -0,0 +1,747 @@
|
||||
/*
|
||||
* CharReader is a not entirely redundant flattening/chimera of std's
|
||||
* BufReader and unicode_reader's CodePoints, introduced to allow
|
||||
* peekable buffered UTF-8 codepoints and access to the underlying
|
||||
* reader.
|
||||
*
|
||||
* Unlike CodePoints, it doesn't make the reader inaccessible by
|
||||
* wrapping it a Bytes struct.
|
||||
*
|
||||
* Unlike BufReader, its buffer is peekable as a char.
|
||||
*/
|
||||
|
||||
use smallvec::*;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::{ErrorKind, IoSliceMut, Read};
|
||||
use std::str;
|
||||
|
||||
pub struct CharReader<R> {
|
||||
inner: R,
|
||||
buf: SmallVec<[u8;4]>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
/// An error raised when parsing a UTF-8 byte stream fails.
|
||||
#[derive(Debug)]
|
||||
pub struct BadUtf8Error {
|
||||
/// The bytes that could not be parsed as a code point.
|
||||
pub bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Error for BadUtf8Error {
|
||||
fn description(&self) -> &str {
|
||||
"BadUtf8Error"
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for BadUtf8Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "Bad UTF-8: {:?}", self.bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> CharReader<R> {
|
||||
pub fn new(inner: R) -> CharReader<R> {
|
||||
Self {
|
||||
inner,
|
||||
buf: SmallVec::new(),
|
||||
pos: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner(&self) -> &R {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn inner_mut(&mut self) -> &mut R {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CharRead {
|
||||
fn read_char(&mut self) -> Option<io::Result<char>> {
|
||||
match self.peek_char() {
|
||||
Some(Ok(c)) => {
|
||||
self.consume(c.len_utf8());
|
||||
Some(Ok(c))
|
||||
}
|
||||
result => result
|
||||
}
|
||||
}
|
||||
|
||||
fn peek_char(&mut self) -> Option<io::Result<char>>;
|
||||
fn put_back_char(&mut self, c: char);
|
||||
fn consume(&mut self, nread: usize);
|
||||
}
|
||||
|
||||
impl<R> CharReader<R> {
|
||||
pub fn get_ref(&self) -> &R {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self) -> &mut R {
|
||||
&mut self.inner
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
&self.buf[self.pos..]
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> R {
|
||||
self.inner
|
||||
}
|
||||
|
||||
fn reset_buffer(&mut self) {
|
||||
self.buf.clear();
|
||||
self.pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> CharReader<R> {
|
||||
fn refresh_buffer(&mut self) -> io::Result<&[u8]> {
|
||||
// If we've reached the end of our internal buffer then we need to fetch
|
||||
// some more data from the underlying reader.
|
||||
// Branch using `>=` instead of the more correct `==`
|
||||
// to tell the compiler that the pos..cap slice is always valid.
|
||||
if self.pos >= self.buf.len() {
|
||||
debug_assert!(self.pos == self.buf.len());
|
||||
|
||||
self.buf.clear();
|
||||
|
||||
let mut word = [0u8;4];
|
||||
let nread = self.inner.read(&mut word)?;
|
||||
|
||||
self.buf.extend_from_slice(&word[..nread]);
|
||||
self.pos = 0;
|
||||
}
|
||||
|
||||
Ok(&self.buf[self.pos..])
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> CharRead for CharReader<R> {
|
||||
fn peek_char(&mut self) -> Option<io::Result<char>> {
|
||||
match self.refresh_buffer() {
|
||||
Ok(_buf) => {}
|
||||
Err(e) => return Some(Err(e)),
|
||||
}
|
||||
|
||||
loop {
|
||||
let buf = &self.buf[self.pos..];
|
||||
|
||||
if !buf.is_empty() {
|
||||
let e = match str::from_utf8(buf) {
|
||||
Ok(s) => {
|
||||
let mut chars = s.chars();
|
||||
let c = chars.next().unwrap();
|
||||
|
||||
return Some(Ok(c));
|
||||
}
|
||||
Err(e) => {
|
||||
e
|
||||
}
|
||||
};
|
||||
|
||||
if buf.len() - e.valid_up_to() >= 4 {
|
||||
// If we have 4 bytes that still don't make up
|
||||
// a valid code point, then we have garbage.
|
||||
|
||||
// We have bad data in the buffer. Remove
|
||||
// leading bytes until either the buffer is
|
||||
// empty, or we have a valid code point.
|
||||
|
||||
let mut split_point = 1;
|
||||
let mut badbytes = vec![];
|
||||
|
||||
loop {
|
||||
let (bad, rest) = buf.split_at(split_point);
|
||||
|
||||
if rest.is_empty() || str::from_utf8(rest).is_ok() {
|
||||
badbytes.extend_from_slice(bad);
|
||||
break;
|
||||
}
|
||||
|
||||
split_point += 1;
|
||||
}
|
||||
|
||||
// Raise the error. If we still have data in
|
||||
// the buffer, it will be returned on the next
|
||||
// loop.
|
||||
|
||||
return Some(Err(io::Error::new(io::ErrorKind::InvalidData,
|
||||
BadUtf8Error { bytes: badbytes })));
|
||||
} else {
|
||||
if self.pos >= self.buf.len() {
|
||||
return None;
|
||||
} else if self.buf.len() - self.pos >= 4 {
|
||||
return match str::from_utf8(&self.buf[..e.valid_up_to()]) {
|
||||
Ok(s) => {
|
||||
let mut chars = s.chars();
|
||||
let c = chars.next().unwrap();
|
||||
|
||||
Some(Ok(c))
|
||||
}
|
||||
Err(e) => {
|
||||
let badbytes = self.buf[..e.valid_up_to()].to_vec();
|
||||
|
||||
Some(Err(io::Error::new(io::ErrorKind::InvalidData,
|
||||
BadUtf8Error { bytes: badbytes })))
|
||||
}
|
||||
};
|
||||
} else {
|
||||
let buf_len = self.buf.len();
|
||||
|
||||
for (c, idx) in (self.pos..buf_len).enumerate() {
|
||||
self.buf[c] = self.buf[idx];
|
||||
}
|
||||
|
||||
self.buf.truncate(buf_len - self.pos);
|
||||
|
||||
let buf_len = self.buf.len();
|
||||
|
||||
let mut word = [0u8;4];
|
||||
let word_slice = &mut word[buf_len..4];
|
||||
|
||||
match self.inner.read(word_slice) {
|
||||
Err(e) => return Some(Err(e)),
|
||||
Ok(nread) => {
|
||||
self.buf.extend_from_slice(&word_slice[0..nread]);
|
||||
}
|
||||
}
|
||||
|
||||
self.pos = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn put_back_char(&mut self, c: char) {
|
||||
let src_len = self.buf.len() - self.pos;
|
||||
debug_assert!(src_len <= 4);
|
||||
|
||||
let c_len = c.len_utf8();
|
||||
let mut shifted_slice = [0u8; 4];
|
||||
|
||||
shifted_slice[0..src_len].copy_from_slice(&self.buf[self.pos .. self.buf.len()]);
|
||||
|
||||
self.buf.resize(c_len, 0);
|
||||
self.buf.extend_from_slice(&shifted_slice[0..src_len]);
|
||||
self.pos = 0;
|
||||
|
||||
c.encode_utf8(&mut self.buf[0..c_len]);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn consume(&mut self, nread: usize) {
|
||||
self.pos += nread;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<R: Seek> BufReader<R> {
|
||||
/// Seeks relative to the current position. If the new position lies within the buffer,
|
||||
/// the buffer will not be flushed, allowing for more efficient seeks.
|
||||
/// This method does not return the location of the underlying reader, so the caller
|
||||
/// must track this information themselves if it is required.
|
||||
#[stable(feature = "bufreader_seek_relative", since = "1.53.0")]
|
||||
pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
|
||||
let pos = self.pos as u64;
|
||||
if offset < 0 {
|
||||
if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
|
||||
self.pos = new_pos as usize;
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
if let Some(new_pos) = pos.checked_add(offset as u64) {
|
||||
if new_pos <= self.cap as u64 {
|
||||
self.pos = new_pos as usize;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.seek(SeekFrom::Current(offset)).map(drop)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<R: Read> Read for CharReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
// // If we don't have any buffered data and we're doing a massive read
|
||||
// // (larger than our internal buffer), bypass our internal buffer
|
||||
// // entirely.
|
||||
// if self.pos == self.cap && buf.len() >= self.buf.len() {
|
||||
// self.discard_buffer();
|
||||
// return self.inner.read(buf);
|
||||
// }
|
||||
|
||||
let mut inner_buf = self.refresh_buffer()?;
|
||||
let nread = inner_buf.read(buf)?;
|
||||
|
||||
// let nread = {
|
||||
// let mut rem = self.fill_buf()?;
|
||||
// rem.read(buf)?
|
||||
// };
|
||||
|
||||
self.consume(nread);
|
||||
Ok(nread)
|
||||
}
|
||||
|
||||
// Small read_exacts from a BufReader are extremely common when used with a deserializer.
|
||||
// The default implementation calls read in a loop, which results in surprisingly poor code
|
||||
// generation for the common path where the buffer has enough bytes to fill the passed-in
|
||||
// buffer.
|
||||
fn read_exact(&mut self, mut buf: &mut [u8]) -> io::Result<()> {
|
||||
if self.buffer().len() >= buf.len() {
|
||||
buf.copy_from_slice(&self.buffer()[..buf.len()]);
|
||||
self.consume(buf.len());
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
while !buf.is_empty() {
|
||||
match self.read(buf) {
|
||||
Ok(0) => break,
|
||||
Ok(n) => {
|
||||
let tmp = buf;
|
||||
buf = &mut tmp[n..];
|
||||
}
|
||||
Err(e) if e.kind() == ErrorKind::Interrupted => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
if !buf.is_empty() {
|
||||
Err(io::Error::new(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
let total_len = bufs.iter().map(|b| b.len()).sum::<usize>();
|
||||
|
||||
if self.pos == self.buf.len() && total_len >= self.buf.len() {
|
||||
self.reset_buffer(); // self.discard_buffer();
|
||||
return self.inner.read_vectored(bufs);
|
||||
}
|
||||
|
||||
let nread = {
|
||||
self.refresh_buffer()?;
|
||||
(&self.buf[self.pos..]).read_vectored(bufs)?
|
||||
};
|
||||
|
||||
self.consume(nread);
|
||||
Ok(nread)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<R: Read> BufRead for BufReader<R> {
|
||||
fn fill_buf(&mut self) -> io::Result<&[u8]> {
|
||||
// If we've reached the end of our internal buffer then we need to fetch
|
||||
// some more data from the underlying reader.
|
||||
// Branch using `>=` instead of the more correct `==`
|
||||
// to tell the compiler that the pos..cap slice is always valid.
|
||||
if self.pos >= self.cap {
|
||||
debug_assert!(self.pos == self.cap);
|
||||
self.cap = self.inner.read(&mut self.buf)?;
|
||||
self.pos = 0;
|
||||
}
|
||||
Ok(&self.buf[self.pos..self.cap])
|
||||
}
|
||||
|
||||
fn consume(&mut self, amt: usize) {
|
||||
self.pos = cmp::min(self.pos + amt, self.cap);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<R> fmt::Debug for CharReader<R>
|
||||
where
|
||||
R: fmt::Debug,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("CharReader")
|
||||
.field("reader", &self.inner)
|
||||
.field("buf", &format_args!("{}/{}", self.buf.capacity() - self.pos, self.buf.len()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<R: Seek> Seek for BufReader<R> {
|
||||
/// Seek to an offset, in bytes, in the underlying reader.
|
||||
///
|
||||
/// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
|
||||
/// position the underlying reader would be at if the `BufReader<R>` had no
|
||||
/// internal buffer.
|
||||
///
|
||||
/// Seeking always discards the internal buffer, even if the seek position
|
||||
/// would otherwise fall within it. This guarantees that calling
|
||||
/// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader
|
||||
/// at the same position.
|
||||
///
|
||||
/// To seek without discarding the internal buffer, use [`BufReader::seek_relative`].
|
||||
///
|
||||
/// See [`std::io::Seek`] for more details.
|
||||
///
|
||||
/// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
|
||||
/// where `n` minus the internal buffer length overflows an `i64`, two
|
||||
/// seeks will be performed instead of one. If the second seek returns
|
||||
/// [`Err`], the underlying reader will be left at the same position it would
|
||||
/// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
|
||||
///
|
||||
/// [`std::io::Seek`]: Seek
|
||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||
let result: u64;
|
||||
if let SeekFrom::Current(n) = pos {
|
||||
let remainder = (self.cap - self.pos) as i64;
|
||||
// it should be safe to assume that remainder fits within an i64 as the alternative
|
||||
// means we managed to allocate 8 exbibytes and that's absurd.
|
||||
// But it's not out of the realm of possibility for some weird underlying reader to
|
||||
// support seeking by i64::MIN so we need to handle underflow when subtracting
|
||||
// remainder.
|
||||
if let Some(offset) = n.checked_sub(remainder) {
|
||||
result = self.inner.seek(SeekFrom::Current(offset))?;
|
||||
} else {
|
||||
// seek backwards by our remainder, and then by the offset
|
||||
self.inner.seek(SeekFrom::Current(-remainder))?;
|
||||
self.discard_buffer();
|
||||
result = self.inner.seek(SeekFrom::Current(n))?;
|
||||
}
|
||||
} else {
|
||||
// Seeking with Start/End doesn't care about our buffer length.
|
||||
result = self.inner.seek(pos)?;
|
||||
}
|
||||
self.discard_buffer();
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Returns the current seek position from the start of the stream.
|
||||
///
|
||||
/// The value returned is equivalent to `self.seek(SeekFrom::Current(0))`
|
||||
/// but does not flush the internal buffer. Due to this optimization the
|
||||
/// function does not guarantee that calling `.into_inner()` immediately
|
||||
/// afterwards will yield the underlying reader at the same position. Use
|
||||
/// [`BufReader::seek`] instead if you require that guarantee.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This function will panic if the position of the inner reader is smaller
|
||||
/// than the amount of buffered data. That can happen if the inner reader
|
||||
/// has an incorrect implementation of [`Seek::stream_position`], or if the
|
||||
/// position has gone out of sync due to calling [`Seek::seek`] directly on
|
||||
/// the underlying reader.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::{
|
||||
/// io::{self, BufRead, BufReader, Seek},
|
||||
/// fs::File,
|
||||
/// };
|
||||
///
|
||||
/// fn main() -> io::Result<()> {
|
||||
/// let mut f = BufReader::new(File::open("foo.txt")?);
|
||||
///
|
||||
/// let before = f.stream_position()?;
|
||||
/// f.read_line(&mut String::new())?;
|
||||
/// let after = f.stream_position()?;
|
||||
///
|
||||
/// println!("The first line was {} bytes long", after - before);
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
fn stream_position(&mut self) -> io::Result<u64> {
|
||||
let remainder = (self.cap - self.pos) as u64;
|
||||
self.inner.stream_position().map(|pos| {
|
||||
pos.checked_sub(remainder).expect(
|
||||
"overflow when subtracting remaining buffer size from inner stream position",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
*/
|
||||
/*
|
||||
impl<T> SizeHint for CharReader<T> {
|
||||
fn lower_bound(&self) -> usize {
|
||||
self.buffer().len()
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::parser::char_reader::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
#[test]
|
||||
fn plain_string() {
|
||||
let mut read_string = CharReader::new(Cursor::new("a string"));
|
||||
|
||||
for c in "a string".chars() {
|
||||
assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
|
||||
}
|
||||
|
||||
assert!(read_string.read_char().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greek_string() {
|
||||
let mut read_string = CharReader::new(Cursor::new("λέξη"));
|
||||
|
||||
for c in "λέξη".chars() {
|
||||
assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
|
||||
}
|
||||
|
||||
assert!(read_string.read_char().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn russian_string() {
|
||||
let mut read_string = CharReader::new(Cursor::new("слово"));
|
||||
|
||||
for c in "слово".chars() {
|
||||
assert_eq!(read_string.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(read_string.read_char().unwrap().ok(), Some(c));
|
||||
}
|
||||
|
||||
assert!(read_string.read_char().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greek_lorem_ipsum() {
|
||||
let lorem_ipsum = "Λορεμ ιπσθμ δολορ σιτ αμετ, οφφενδιτ
|
||||
εφφιcιενδι σιτ ει, ηαρθμ λεγερε qθαερενδθμ ιθσ νε. Ηασ νο εροσ
|
||||
σιγνιφερθμqθε, σεδ ετ μθτατ jθστο, ει cθμ ελιγενδι σcριπτορεμ
|
||||
ρεπρεηενδθντ. Εοσ ατ αμετ μαλισ ελειφενδ. Ιν cθμ εριπθιτ
|
||||
νομινατι. Θσθ ιν cετεροσ μαιορθμ, μθνερε ατομορθμ ινcιδεριντ θτ
|
||||
ηασ. Αν ηασ λιβρισ πραεσεντ πατριοqθε, ηινc θτιναμ πριμισ νε
|
||||
cθμ. Cθ μοδο ερρεμ σcριβεντθρ cθμ. Ει vισ δεcορε μαλορθμ
|
||||
σεντεντιαε, σεδ νο λιβερ εvερτι μεντιτθμ. Προ φαcερ vολθτπατ
|
||||
σαπιεντεμ ιν. Cθ εροσ περσεqθερισ πρι, εα ποσσιτ cετεροσ δθο. Πρι
|
||||
εα μαλισ μθνερε.
|
||||
|
||||
Qθισ jθστο μαλορθμ cθ qθο. Νεc ατ οδιο σολετ μαιεστατισ, νε
|
||||
φορενσιβθσ σαδιπσcινγ ιθσ, αν qθι ειθσ βρθτε σαπιεντεμ. Cομμθνε
|
||||
περcιπιτθρ ιθσ αδ, μθνερε δολορθμ ιμπεδιτ ηισ νε. Νεc ετιαμ
|
||||
προπριαε vιτθπερατα ιν. Σονετ νεμορε ιθσ cθ, ιν αφφερτ ινερμισ
|
||||
cοτιδιεqθε vισ.
|
||||
|
||||
Ηασ ιδ νονθμυ δοcτθσ cοτιδιεqθε. Σινγθλισ πηιλοσοπηια εξ δθο. Εστ
|
||||
νο ιραcθνδια cονσεqθθντθρ. Τε διcτασ επιcθρει εφφιcιαντθρ δθο, εοσ
|
||||
νε νθλλα νομιναvι. Εθμ cθ ελιτρ λιβεραvισσε, σιτ περσεqθερισ
|
||||
cομπλεcτιτθρ εξ, πονδερθμ σιμιλιqθε ηασ νο.
|
||||
|
||||
Σολθμ ποσσιμ λαβιτθρ εξ ηισ, ει δομινγ εξπετενδισ vελ, διαμ μινιμ
|
||||
σcριπσεριτ ει περ. Αθδιαμ οcθρρερετ προ εξ, δομινγ vολθπταρια ετ
|
||||
qθο. Cονσθλ σανcτθσ αccθμσαν νο ιθσ, αδ εαμ αλβθcιθσ
|
||||
ηονεστατισ. Ετ vιξ φαcιλισ qθαλισqθε ερροριβθσ, ηισ εθ πθρτο
|
||||
ασσεντιορ. Ιθσ βονορθμ ηονεστατισ σcριπσεριτ ατ, ιν ναμ εσσε μοvετ
|
||||
γραεcο. Αθγθε cονσεcτετθερ εστ ατ.
|
||||
|
||||
Αδ ταλε σθασ μθνερε σεδ, vισ φεθγαιτ αντιοπαμ ιδ. Προ εθ ινερμισ
|
||||
σαλθτατθσ, σαεπε qθαεστιο θρβανιτασ cθ περ. Ιν μαλορθμ σαλθτατθσ
|
||||
δετερρθισσετ περ, νε παρτεμ vολθτπατ ινστρθcτιορ vιξ. Νο vισ
|
||||
δεμοcριτθμ εφφιcιαντθρ, επιcθρει αδολεσcενσ εστ cθ, ιδ vιξ
|
||||
λθcιλιθσ αδιπισcινγ. Σεα τε cλιτα ιραcθνδια. Σεα αν σιμθλ
|
||||
εσσεντ. Vοcιβθσ ελειφενδ cονσεqθθντθρ περ αδ, αν ναμ πονδερθμ
|
||||
vολθπταρια.
|
||||
|
||||
Λιβερ ερθδιτι αccθσαμθσ θτ ναμ. Σιτ αντιοπαμ γθβεργρεν νε. Αμετ
|
||||
ανcιλλαε ετ qθι, μεα σολθμ λαθδεμ εα. Εθ μελ παρτεμ οβλιqθε
|
||||
πηαεδρθμ. Εξ μελ jθστο αccομμοδαρε, νε νολθισσε σινγθλισ σενσιβθσ
|
||||
cθμ, vισ εθ τιμεαμ αδιπισcινγ.
|
||||
|
||||
Τε νολθισσε vολθπτατθμ εστ. Ασσθμ νομιναvι πρι νε, ει νοστρθμ
|
||||
επιcθρει μεα. Σεδ cθ ελιτ δεσερθντ, γραεcε ερροριβθσ προ θτ, περ
|
||||
νε εθισμοδ vολθπταρια. Νο εθμ διcατ ποσσιμ, νεc πρινcιπεσ
|
||||
cονcεπταμ νε. Εθ αππαρεατ ιντελλεγατ σεα. Μελ θτ ελιτ λαθδεμ, θσθ
|
||||
δολορεμ cομπλεcτιτθρ ετ, νε μεα δολορεσ μολεστιαε.
|
||||
|
||||
Θσθ λεγενδοσ vολθπτατιβθσ cθ. Qθο νε αδηθc ρεφερρεντθρ, αλια
|
||||
μεδιοcρεμ δθο νε, σεδ ερρεμ δολορθμ αccομμοδαρε νε. Ετιαμ εqθιδεμ
|
||||
δετερρθισσετ cθ μει, ετ εροσ cετεροσ σεα, εξ vιξ ενιμ cασε
|
||||
δετραξιτ. Σεδ σολθτα λιβρισ ειρμοδ τε, νοvθμ ποπθλο νε εθμ. Σθμμο
|
||||
αδμοδθμ δεσερθντ εστ εξ, εστ διcαμ εqθιδεμ cθ.
|
||||
|
||||
Ιλλθμ cορπορα ινvιδθντ εαμ ετ. Σεδ μαλισ ταcιματεσ εvερτιτθρ εα,
|
||||
μαζιμ νθλλαμ vοcιβθσ μεα ει. Μεα ορνατθσ λθπτατθμ αδιπισcινγ
|
||||
αδ. Μεα αφφερτ νοστερ ατ, ναμ αν σολεατ ερροριβθσ. Εξ σεα αεqθε
|
||||
μθνερε cετερο, εοσ ηινc ελειφενδ δεμοcριτθμ.";
|
||||
|
||||
let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
|
||||
|
||||
for c in lorem_ipsum.chars() {
|
||||
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
|
||||
}
|
||||
|
||||
assert!(lorem_ipsum_reader.read_char().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn armenian_lorem_ipsum() {
|
||||
let lorem_ipsum = "լոռեմ իպսում դոլոռ սիթ ամեթ, նովում գռաեծո
|
||||
սեա եա, աբհոռռեանթ դիսպութանդո եի քուի. իդ քուոդ ինդոծթում
|
||||
եսթ, մեա թե ծոմմոդո ծոռպոռա. եթ ծոնսուլ ադիպիսծինգ ռեֆոռմիդանս
|
||||
պեռ, ինեռմիս ֆեուգաիթ նո քուո, թալե սալե պռո եա. եթ նիբհ
|
||||
աուգուե վոլումուս դուո, նե ծում եխեռծի սալութաթուս գլոռիաթուռ,
|
||||
ծու թաթիոն պռաեսենթ մեդիոծռեմ վիս.
|
||||
|
||||
վիխ եռոս ռեֆեռռենթուռ եու. պեռսիուս վիթուպեռաթոռիբուս ութ սեա,
|
||||
վիդե ինվիդունթ պռոբաթուս նո քուո. մեի եռոս մելիուս նոմինավի
|
||||
իդ, ութ պռո քուաս քուաեսթիո. եթ նաթում պեթենթիում սուավիթաթե
|
||||
հիս. քուի ծոնսթիթութո մեդիոծռիթաթեմ թե. ծեթեռո դեթռածթո
|
||||
ծոնծեպթամ սեա եթ. դիսսենթիեթ ելոքուենթիամ թհեոպհռասթուս նեծ
|
||||
աթ, աթ ֆածեթե եռիպուիթ վիխ.
|
||||
|
||||
ասսուեվեռիթ սծռիպսեռիթ եսթ եթ, վիդիթ դեբեթ եվեռթի եխ
|
||||
եսթ. աութեմ լաուդեմ պոսիդոնիում մեի եի. ռեբում դիծամ ծեթեռոս
|
||||
եում ծու. նիհիլ եխպեթենդա ասսուեվեռիթ ուսու ան. ւիսի թաթիոն
|
||||
դելենիթ նո իուս, սեդ եխ իդքուե սիգնիֆեռումքուե, բռութե զռիլ
|
||||
ալբուծիուս ան պռի.
|
||||
|
||||
մովեթ իռիուռե սալութանդի պեռ նո, եի ոմնիս աֆֆեռթ պեռսեքուեռիս
|
||||
իուս, եթ պռաեսենթ մալուիսսեթ եսթ. եսթ պռոբո գուբեռգռեն եթ, հաս
|
||||
ին դիամ նումքուամ. ֆեուգաիթ ինվենիռե ռեպուդիանդաե աթ սեդ,
|
||||
իուվառեթ ծոնսուլաթու եֆֆիծիանթուռ ուսու եի. ութ մեա ածծումսան
|
||||
նոմինավի թինծիդունթ, մեի դիծթա ածծումսան ութ. վիմ ոմնիում
|
||||
ելիգենդի սծռիպթոռեմ եու.
|
||||
|
||||
իդ վիս եռռոռ ալիքուիպ ելոքուենթիամ, ադ դելենիթի պեռծիպիթ
|
||||
դեֆինիթիոնես իուս. վիմ իուդիծո դեմոծռիթում ծոմպռեհենսամ թե,
|
||||
ութ նիհիլ լոբոռթիս վոլուպթաթիբուս վել, դիծունթ մենթիթում
|
||||
ֆածիլիսիս եի եում. եսսե սալե մինիմ եոս նե. ագամ ոմնեսքուե ծում
|
||||
ին.
|
||||
|
||||
իուվառեթ իուդիծաբիթ ծում աթ, ուսու նիբհ աթքուի դոմինգ եխ. եի
|
||||
քուի սանծթուս սենսիբուս, նամ ուբիքուե ապպեթեռե պռոդեսսեթ
|
||||
եու. ուսու եթ աուգուե ծոնվենիռե սծռիբենթուռ. ան ոմնիում վեռեառ
|
||||
ութռոքուե դուո, եսթ եի լիբեռ մեդիոծռեմ եխպլիծառի, ոմնիս
|
||||
աուդիռե թե պռի. վիմ մունեռե սոլեաթ ծու, եռոս ինվենիռե
|
||||
դիսպութաթիոնի եի քուո, ան ալթեռա պութենթ լաբոռես պռո. անթիոպամ
|
||||
դեմոծռիթում պեռ ին.
|
||||
|
||||
նե քուի ծիբո ելիթռ. նեծ նե լիբեռ վոլուպթուա. նիսլ ծոմմունե
|
||||
եխպեթենդիս նամ եխ, իուդիծո պլածեռաթ պեռծիպիթուռ մել նո, եթ
|
||||
պառթեմ պութանթ քուի. վիմ թինծիդունթ ածծոմմոդառե աթ, նե նամ
|
||||
վիդիթ իռիուռե, պռո եա ելիգենդի պոսթուլանթ ծոնսթիթութո.
|
||||
|
||||
մել ութ ոդիո նուլլամ եխպլիծառի. պռոպռիաե թինծիդունթ
|
||||
դելիծաթիսսիմի եամ ան, մոդո քուոդսի ապեռիռի եու եսթ, պեռ աթ
|
||||
լաբոռես սենսեռիթ. վիմ ծոնգուե ռեպուդիանդաե եի, նեծ ագամ
|
||||
դիծունթ դելիծաթիսսիմի աթ. պոսսիթ լիբեռավիսսե եոս եու.
|
||||
|
||||
աթ ալիա դեբեթ ելաբոռառեթ քուո, ին ալիի ածծումսան ծոնսթիթուամ
|
||||
հաս, մել թոթա ոմիթթանթուռ ինսթռուծթիոռ նո. պեռ նե ծաուսաե
|
||||
սապիենթեմ, պաուլո ոմնեսքուե եի քուո, եխ ոռաթիո պհիլոսոպհիա
|
||||
սիթ. իգնոթա ծաուսաե աթ ուսու, եխ քուո դիծթաս քուոդսի
|
||||
ռեպուդիառե. ծոռպոռա պռոդեսսեթ ռեֆեռռենթուռ եոս եխ.
|
||||
|
||||
եու եթիամ ելեիֆենդ մել, սալե սծռիպսեռիթ հիս եու. պոռռո
|
||||
ադոլեսծենս մեի եա. ին մեա զռիլ պռոբաթուս սալութաթուս. եոս ադ
|
||||
մինիմ թեմպոռիբուս. սեա նե եթիամ.";
|
||||
|
||||
let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
|
||||
|
||||
for c in lorem_ipsum.chars() {
|
||||
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
|
||||
}
|
||||
|
||||
assert!(lorem_ipsum_reader.read_char().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn russian_lorem_ipsum() {
|
||||
let lorem_ipsum = "Лорем ипсум долор сит амет, атяуи дицам еи
|
||||
сит, ид сеа фацилис елаборарет. Меа еу яуас алияуид, те яуи
|
||||
саперет аппеллантур. Ех иус диам дицта волуптариа, еу пер
|
||||
бруте омиттам аццусата. Хис сапиентем губергрен те, яуидам
|
||||
луптатум персеяуерис ад ест.
|
||||
|
||||
Ан алияуип перицулис нам, нец апериам цотидиеяуе волуптатибус
|
||||
но. Солум тритани пер ех, меи не одио тритани рецусабо, цу при
|
||||
веро мелиоре импердиет. Ин граеци индоцтум салутатус нец, диам
|
||||
сцаевола пертинациа про те. Ут сеа дебитис лаборамус
|
||||
диссентиас, еи цум яуот лобортис.
|
||||
|
||||
Децоре сингулис вим не. Еос не риденс оффициис, еу нонумы
|
||||
лабитур еррорибус хас, вел омнис цонституто посидониум но. Вел
|
||||
персиус фастидии репрехендунт ид. Натум иллум ипсум сит ад, еа
|
||||
еам новум латине. Еос нолуиссе патриояуе елояуентиам те.
|
||||
|
||||
Стет малис яуаерендум хас ад, прима цотидиеяуе мел ан,
|
||||
трацтатос десеруиссе нам ех. Ин малорум сусципиантур вим, ех
|
||||
меа граецо тритани адолесценс. Промпта цонцлусионемяуе нам еи,
|
||||
дуо ин лаборе алтерум цотидиеяуе. Но елитр промпта сплендиде
|
||||
еум, аеяуе ассуеверит цонституам яуи ид. Ад тале еррор
|
||||
интеллегебат хас, ерудити граецис хас не, пер ут лабитур
|
||||
еуисмод. Те при суммо путант. Про утинам цоммуне урбанитас еа.
|
||||
|
||||
Идяуе репрехендунт еи нам, алии толлит легере нам не, хис еа
|
||||
виси адверсариум цонцлусионемяуе. Хас ассум омиттам луцилиус
|
||||
ет, вих цонсул малорум фастидии не, сенсибус ассуеверит дуо
|
||||
ут. Дуо алиа видит цетеро ат, еа аппареат пертинах вел. Пер
|
||||
цонституто инцидеринт ин, убияуе риденс сенсерит цум цу. Про
|
||||
ет цетерос темпорибус, те вел пурто суммо, дуо мунере вертерем
|
||||
урбанитас ад. Сит оптион елецтрам форенсибус но. Еи татион
|
||||
сапиентем ест, лаборе сцрипта сингулис но вим, усу еу елигенди
|
||||
персецути.
|
||||
|
||||
Иус ан елецтрам цонтентионес. Меи атяуи нонумес ут, вел амет
|
||||
репрехендунт ан, вис еу яуаестио патриояуе. Про синт легере
|
||||
детрацто ад. Постеа долорем евертитур при ет, вим номинави
|
||||
принципес ирацундиа ех. Доцтус интеллегебат но нам. Фацете
|
||||
оффициис нецесситатибус цу меа.
|
||||
|
||||
Промпта симилияуе вис ин. Пер бонорум перицулис аргументум
|
||||
ад. Еу дицат фацилис губергрен нам, еффициенди цомпрехенсам
|
||||
хас еу. Инани нонумы усу но, ад цонцептам репудиандае
|
||||
про. Тота нуллам делицата еа яуо, усу дуис дебет путент еи.
|
||||
|
||||
Вис апериам доценди елояуентиам еа. Ех яуот детрацто
|
||||
елояуентиам цум, ерос малис дицерет вис ин. Еа цум модус
|
||||
еяуидем, дебет нуллам ан меи. Алтерум омиттам про ет.
|
||||
|
||||
Яуи ех латине алияуам, ан меи одио нуллам. Ид хас омнис ребум
|
||||
либрис. Ет убияуе путант дебитис про, ех хис медиоцрем
|
||||
партиендо, но елит елецтрам дуо. Еу меа сонет номинави
|
||||
цотидиеяуе. Нам фалли новум минимум еу, перфецто ратионибус
|
||||
цонституто ад меа.
|
||||
|
||||
Нобис детрацто еам ид, при еу ассум пертинах, те етиам
|
||||
проприае салутанди яуо. Легимус сусципиантур ет хас, сед
|
||||
поссит дефинитионес еа. Ест не патриояуе омиттантур
|
||||
интеллегебат, еу яуо дебет цонцлудатуряуе. Еум ад мнесарчум
|
||||
дефинитионем, елитр лаборамус перципитур про не, хас феугаит
|
||||
фастидии луцилиус ид. Фастидии интеллегат ех.";
|
||||
|
||||
let mut lorem_ipsum_reader = CharReader::new(Cursor::new(lorem_ipsum));
|
||||
|
||||
for c in lorem_ipsum.chars() {
|
||||
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
|
||||
|
||||
lorem_ipsum_reader.put_back_char(c);
|
||||
|
||||
assert_eq!(lorem_ipsum_reader.peek_char().unwrap().ok(), Some(c));
|
||||
assert_eq!(lorem_ipsum_reader.read_char().unwrap().ok(), Some(c));
|
||||
}
|
||||
|
||||
assert!(lorem_ipsum_reader.read_char().is_none());
|
||||
}
|
||||
}
|
||||
1055
src/parser/lexer.rs
Normal file
1055
src/parser/lexer.rs
Normal file
File diff suppressed because it is too large
Load Diff
253
src/parser/macros.rs
Normal file
253
src/parser/macros.rs
Normal file
@@ -0,0 +1,253 @@
|
||||
#[macro_export]
|
||||
macro_rules! char_class {
|
||||
($c: expr, [$head:expr]) => ($c == $head);
|
||||
($c: expr, [$head:expr $(, $cs:expr)+]) => ($c == $head || $crate::char_class!($c, [$($cs),*]));
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! alpha_char {
|
||||
($c: expr) => {
|
||||
match $c {
|
||||
'a'..='z' => true,
|
||||
'A'..='Z' => true,
|
||||
'_' => true,
|
||||
'\u{00A0}'..='\u{00BF}' => true,
|
||||
'\u{00C0}'..='\u{00D6}' => true,
|
||||
'\u{00D8}'..='\u{00F6}' => true,
|
||||
'\u{00F8}'..='\u{00FF}' => true,
|
||||
'\u{0100}'..='\u{017F}' => true, // Latin Extended-A
|
||||
'\u{0180}'..='\u{024F}' => true, // Latin Extended-B
|
||||
'\u{0250}'..='\u{02AF}' => true, // IPA Extensions
|
||||
'\u{02B0}'..='\u{02FF}' => true, // Spacing Modifier Letters
|
||||
'\u{0300}'..='\u{036F}' => true, // Combining Diacritical Marks
|
||||
'\u{0370}'..='\u{03FF}' => true, // Greek/Coptic
|
||||
'\u{0400}'..='\u{04FF}' => true, // Cyrillic
|
||||
'\u{0500}'..='\u{052F}' => true, // Cyrillic Supplement
|
||||
'\u{0530}'..='\u{058F}' => true, // Armenian
|
||||
'\u{0590}'..='\u{05FF}' => true, // Hebrew
|
||||
'\u{0600}'..='\u{06FF}' => true, // Arabic
|
||||
'\u{0700}'..='\u{074F}' => true, // Syriac
|
||||
_ => false,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! alpha_numeric_char {
|
||||
($c: expr) => {
|
||||
$crate::alpha_char!($c) || $crate::decimal_digit_char!($c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! backslash_char {
|
||||
($c: expr) => {
|
||||
$c == '\\'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! back_quote_char {
|
||||
($c: expr) => {
|
||||
$c == '`'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! octet_char {
|
||||
($c: expr) => {
|
||||
('\u{0000}'..='\u{00FF}').contains(&$c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! capital_letter_char {
|
||||
($c: expr) => {
|
||||
('A'..='Z').contains(&$c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! comment_1_char {
|
||||
($c: expr) => {
|
||||
$c == '/'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! comment_2_char {
|
||||
($c: expr) => {
|
||||
$c == '*'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cut_char {
|
||||
($c: expr) => {
|
||||
$c == '!'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! decimal_digit_char {
|
||||
($c: expr) => {
|
||||
('0'..='9').contains(&$c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! decimal_point_char {
|
||||
($c: expr) => {
|
||||
$c == '.'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! double_quote_char {
|
||||
($c: expr) => {
|
||||
$c == '"'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! end_line_comment_char {
|
||||
($c: expr) => {
|
||||
$c == '%'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! exponent_char {
|
||||
($c: expr) => {
|
||||
$c == 'e' || $c == 'E'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! graphic_char {
|
||||
($c: expr) => ($crate::char_class!($c, ['#', '$', '&', '*', '+', '-', '.', '/', ':',
|
||||
'<', '=', '>', '?', '@', '^', '~']))
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! graphic_token_char {
|
||||
($c: expr) => {
|
||||
$crate::graphic_char!($c) || $crate::backslash_char!($c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! hexadecimal_digit_char {
|
||||
($c: expr) => {
|
||||
('0'..='9').contains(&$c) || ('A'..='F').contains(&$c) || ('a'..='f').contains(&$c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! layout_char {
|
||||
($c: expr) => {
|
||||
$crate::char_class!($c, [' ', '\n', '\t', '\u{0B}', '\u{0C}'])
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! meta_char {
|
||||
($c: expr) => {
|
||||
$crate::char_class!($c, ['\\', '\'', '"', '`'])
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! new_line_char {
|
||||
($c: expr) => {
|
||||
$c == '\n'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! octal_digit_char {
|
||||
($c: expr) => {
|
||||
('0'..='7').contains(&$c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! binary_digit_char {
|
||||
($c: expr) => {
|
||||
$c >= '0' && $c <= '1'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! prolog_char {
|
||||
($c: expr) => {
|
||||
$crate::graphic_char!($c)
|
||||
|| $crate::alpha_numeric_char!($c)
|
||||
|| $crate::solo_char!($c)
|
||||
|| $crate::layout_char!($c)
|
||||
|| $crate::meta_char!($c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! semicolon_char {
|
||||
($c: expr) => {
|
||||
$c == ';'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! sign_char {
|
||||
($c: expr) => {
|
||||
$c == '-' || $c == '+'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! single_quote_char {
|
||||
($c: expr) => {
|
||||
$c == '\''
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! small_letter_char {
|
||||
($c: expr) => {
|
||||
('a'..='z').contains(&$c)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! solo_char {
|
||||
($c: expr) => {
|
||||
$crate::char_class!($c, ['!', '(', ')', ',', ';', '[', ']', '{', '}', '|', '%'])
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! space_char {
|
||||
($c: expr) => {
|
||||
$c == ' '
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! symbolic_control_char {
|
||||
($c: expr) => {
|
||||
$crate::char_class!($c, ['a', 'b', 'f', 'n', 'r', 't', 'v', '0'])
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! symbolic_hexadecimal_char {
|
||||
($c: expr) => {
|
||||
$c == 'x'
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! variable_indicator_char {
|
||||
($c: expr) => {
|
||||
$c == '_'
|
||||
};
|
||||
}
|
||||
17
src/parser/mod.rs
Normal file
17
src/parser/mod.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
#[cfg(feature = "num-rug-adapter")]
|
||||
use num_rug_adapter as rug;
|
||||
#[cfg(feature = "rug")]
|
||||
pub use rug;
|
||||
|
||||
// #[macro_use]
|
||||
// extern crate lazy_static;
|
||||
// #[macro_use]
|
||||
// extern crate static_assertions;
|
||||
|
||||
pub mod char_reader;
|
||||
#[macro_use]
|
||||
pub mod ast;
|
||||
#[macro_use]
|
||||
pub mod macros;
|
||||
pub mod lexer;
|
||||
pub mod parser;
|
||||
1080
src/parser/parser.rs
Normal file
1080
src/parser/parser.rs
Normal file
File diff suppressed because it is too large
Load Diff
105
src/raw_block.rs
Normal file
105
src/raw_block.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use std::alloc;
|
||||
use std::ptr;
|
||||
|
||||
pub trait RawBlockTraits {
|
||||
fn init_size() -> usize;
|
||||
fn align() -> usize;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RawBlock<T: RawBlockTraits> {
|
||||
pub base: *const u8,
|
||||
pub top: *const u8,
|
||||
pub ptr: *mut u8,
|
||||
_marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: RawBlockTraits> RawBlock<T> {
|
||||
#[inline]
|
||||
fn empty_block() -> Self {
|
||||
RawBlock {
|
||||
base: ptr::null(),
|
||||
top: ptr::null(),
|
||||
ptr: ptr::null_mut(),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
let mut block = Self::empty_block();
|
||||
|
||||
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.top = (self.base as usize + cap) as *const _;
|
||||
self.ptr = self.base as *mut _;
|
||||
}
|
||||
|
||||
pub unsafe fn grow(&mut self) {
|
||||
if self.base.is_null() {
|
||||
self.init_at_size(T::init_size());
|
||||
} else {
|
||||
let size = self.size();
|
||||
let layout = alloc::Layout::from_size_align_unchecked(size, T::align());
|
||||
|
||||
self.base = alloc::realloc(self.base as *mut _, layout, size * 2) as *const _;
|
||||
self.top = (self.base as usize + size * 2) as *const _;
|
||||
self.ptr = (self.base as usize + size) as *mut _;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#[inline]
|
||||
pub fn take(&mut self) -> Self {
|
||||
mem::replace(self, Self::empty_block())
|
||||
}
|
||||
*/
|
||||
|
||||
#[inline]
|
||||
pub fn size(&self) -> usize {
|
||||
self.top as usize - self.base as usize
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn free_space(&self) -> usize {
|
||||
debug_assert!(
|
||||
self.ptr as *const _ >= self.base,
|
||||
"self.ptr = {:?} < {:?} = self.base",
|
||||
self.ptr,
|
||||
self.base
|
||||
);
|
||||
|
||||
self.top as usize - self.ptr as usize
|
||||
}
|
||||
|
||||
pub unsafe fn alloc(&mut self, size: usize) -> *mut u8 {
|
||||
if self.free_space() >= size {
|
||||
let ptr = self.ptr;
|
||||
self.ptr = (self.ptr as usize + size) as *mut _;
|
||||
ptr
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deallocate(&mut self) {
|
||||
unsafe {
|
||||
let layout = alloc::Layout::from_size_align_unchecked(self.size(), T::align());
|
||||
alloc::dealloc(self.base as *mut _, layout);
|
||||
|
||||
self.top = ptr::null();
|
||||
self.base = ptr::null();
|
||||
self.ptr = ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
511
src/read.rs
511
src/read.rs
@@ -1,263 +1,278 @@
|
||||
use prolog_parser::ast::*;
|
||||
use prolog_parser::parser::*;
|
||||
use prolog_parser::tabled_rc::TabledData;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::parser::*;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::heap::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::machine_state::MachineState;
|
||||
use crate::machine::streams::Stream;
|
||||
use crate::machine::streams::*;
|
||||
use crate::parser::char_reader::*;
|
||||
use crate::types::*;
|
||||
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::{Cmd, Config, Editor, KeyEvent};
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{Cursor, Error, ErrorKind, Read};
|
||||
|
||||
type SubtermDeque = VecDeque<(usize, usize)>;
|
||||
|
||||
pub(crate) type PrologStream = ParsingStream<Stream>;
|
||||
|
||||
pub mod readline {
|
||||
use crate::machine::streams::Stream;
|
||||
use rustyline::error::ReadlineError;
|
||||
use rustyline::{Cmd, Config, Editor, KeyEvent};
|
||||
use std::io::{Cursor, Error, ErrorKind, Read};
|
||||
|
||||
static mut PROMPT: bool = false;
|
||||
|
||||
const HISTORY_FILE: &'static str = ".scryer_history";
|
||||
|
||||
pub(crate) fn set_prompt(value: bool) {
|
||||
unsafe {
|
||||
PROMPT = value;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_prompt() -> &'static str {
|
||||
unsafe {
|
||||
if PROMPT {
|
||||
"?- "
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReadlineStream {
|
||||
rl: Editor<()>,
|
||||
pending_input: Cursor<String>,
|
||||
}
|
||||
|
||||
impl ReadlineStream {
|
||||
#[inline]
|
||||
pub(crate) fn new(pending_input: String) -> Self {
|
||||
let config = Config::builder().check_cursor_position(true).build();
|
||||
|
||||
let mut rl = Editor::<()>::with_config(config); //Editor::<()>::new();
|
||||
if let Some(mut path) = dirs_next::home_dir() {
|
||||
path.push(HISTORY_FILE);
|
||||
if path.exists() {
|
||||
if rl.load_history(&path).is_err() {
|
||||
println!("Warning: loading history failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
|
||||
ReadlineStream {
|
||||
rl,
|
||||
pending_input: Cursor::new(pending_input),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn input_stream(pending_input: String) -> Stream {
|
||||
Stream::from(Self::new(pending_input))
|
||||
}
|
||||
|
||||
fn call_readline(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
match self.rl.readline(get_prompt()) {
|
||||
Ok(text) => {
|
||||
*self.pending_input.get_mut() = text;
|
||||
self.pending_input.set_position(0);
|
||||
|
||||
unsafe {
|
||||
if PROMPT {
|
||||
self.rl.history_mut().add(self.pending_input.get_ref());
|
||||
self.save_history();
|
||||
PROMPT = false;
|
||||
}
|
||||
}
|
||||
|
||||
if self.pending_input.get_ref().chars().last() != Some('\n') {
|
||||
*self.pending_input.get_mut() += "\n";
|
||||
}
|
||||
|
||||
self.pending_input.read(buf)
|
||||
}
|
||||
Err(ReadlineError::Eof) => Ok(0),
|
||||
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn save_history(&mut self) {
|
||||
if let Some(mut path) = dirs_next::home_dir() {
|
||||
path.push(HISTORY_FILE);
|
||||
if path.exists() {
|
||||
if self.rl.append_history(&path).is_err() {
|
||||
println!("Warning: couldn't append history (existing file)");
|
||||
}
|
||||
} else {
|
||||
if self.rl.save_history(&path).is_err() {
|
||||
println!("Warning: couldn't save history (new file)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
|
||||
set_prompt(false);
|
||||
|
||||
loop {
|
||||
match self.pending_input.get_ref().bytes().next() {
|
||||
Some(b) => {
|
||||
return Ok(b);
|
||||
}
|
||||
None => match self.call_readline(&mut []) {
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
Ok(0) => {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn peek_char(&mut self) -> std::io::Result<char> {
|
||||
set_prompt(false);
|
||||
|
||||
loop {
|
||||
match self.pending_input.get_ref().chars().next() {
|
||||
Some(c) => {
|
||||
return Ok(c);
|
||||
}
|
||||
None => match self.call_readline(&mut []) {
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
Ok(0) => {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "end of file"));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for ReadlineStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
match self.pending_input.read(buf) {
|
||||
Ok(0) => self.call_readline(buf),
|
||||
result => result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn input_stream() -> Stream {
|
||||
let input_stream = ReadlineStream::input_stream(String::from(""));
|
||||
Stream::from(input_stream)
|
||||
}
|
||||
}
|
||||
// pub(crate) type PrologStream = ParsingStream<Stream>;
|
||||
|
||||
impl MachineState {
|
||||
pub(crate) fn devour_whitespace(
|
||||
&mut self,
|
||||
mut inner: Stream,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
) -> Result<bool, ParserError> {
|
||||
let mut stream = parsing_stream(inner.clone())?;
|
||||
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
|
||||
let mut parser = Parser::new(inner, self);
|
||||
|
||||
parser.devour_whitespace()?;
|
||||
inner.add_lines_read(parser.lines_read());
|
||||
|
||||
inner.add_lines_read(parser.num_lines_read());
|
||||
|
||||
let result = parser.eof();
|
||||
let buf = stream.take_buf();
|
||||
|
||||
inner.pause_stream(buf)?;
|
||||
|
||||
result
|
||||
parser.eof()
|
||||
}
|
||||
|
||||
pub(crate) fn read(
|
||||
&mut self,
|
||||
mut inner: Stream,
|
||||
atom_tbl: TabledData<Atom>,
|
||||
op_dir: &OpDir,
|
||||
) -> Result<TermWriteResult, ParserError> {
|
||||
let mut stream = parsing_stream(inner.clone())?;
|
||||
|
||||
let (term, num_lines_read) = {
|
||||
let prior_num_lines_read = inner.lines_read();
|
||||
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
|
||||
let mut parser = Parser::new(inner, self);
|
||||
|
||||
parser.add_lines_read(prior_num_lines_read);
|
||||
|
||||
let term = parser.read_term(&CompositeOpDir::new(op_dir, None))?;
|
||||
(term, parser.num_lines_read() - prior_num_lines_read)
|
||||
(term, parser.lines_read() - prior_num_lines_read)
|
||||
};
|
||||
|
||||
inner.add_lines_read(num_lines_read);
|
||||
Ok(write_term_to_heap(&term, &mut self.heap, &mut self.atom_tbl))
|
||||
}
|
||||
}
|
||||
|
||||
// 'pausing' the stream saves the pending top buffer
|
||||
// created by the parsing stream, which was created in this
|
||||
// scope and is about to be destroyed in it.
|
||||
static mut PROMPT: bool = false;
|
||||
|
||||
let buf = stream.take_buf();
|
||||
inner.pause_stream(buf)?;
|
||||
const HISTORY_FILE: &'static str = ".scryer_history";
|
||||
|
||||
Ok(write_term_to_heap(&term, self))
|
||||
pub(crate) fn set_prompt(value: bool) {
|
||||
unsafe {
|
||||
PROMPT = value;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn write_term_to_heap(term: &Term, machine_st: &mut MachineState) -> TermWriteResult {
|
||||
let term_writer = TermWriter::new(machine_st);
|
||||
fn get_prompt() -> &'static str {
|
||||
unsafe {
|
||||
if PROMPT {
|
||||
"?- "
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn input_stream(arena: &mut Arena) -> Stream {
|
||||
let input_stream = ReadlineStream::new("");
|
||||
Stream::from_readline_stream(input_stream, arena)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ReadlineStream {
|
||||
rl: Editor<()>,
|
||||
pending_input: Cursor<String>,
|
||||
}
|
||||
|
||||
impl ReadlineStream {
|
||||
#[inline]
|
||||
pub fn new(pending_input: &str) -> Self {
|
||||
let config = Config::builder().check_cursor_position(true).build();
|
||||
let mut rl = Editor::<()>::with_config(config);
|
||||
|
||||
if let Some(mut path) = dirs_next::home_dir() {
|
||||
path.push(HISTORY_FILE);
|
||||
if path.exists() && rl.load_history(&path).is_err() {
|
||||
println!("Warning: loading history failed");
|
||||
}
|
||||
}
|
||||
|
||||
rl.bind_sequence(KeyEvent::from('\t'), Cmd::Insert(1, "\t".to_string()));
|
||||
|
||||
ReadlineStream {
|
||||
rl,
|
||||
pending_input: Cursor::new(pending_input.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn reset(&mut self) {
|
||||
self.pending_input.get_mut().clear();
|
||||
self.pending_input.set_position(0);
|
||||
}
|
||||
|
||||
fn call_readline(&mut self) -> std::io::Result<usize> {
|
||||
match self.rl.readline(get_prompt()) {
|
||||
Ok(text) => {
|
||||
*self.pending_input.get_mut() = text;
|
||||
self.pending_input.set_position(0);
|
||||
|
||||
unsafe {
|
||||
if PROMPT {
|
||||
self.rl.history_mut().add(self.pending_input.get_ref());
|
||||
self.save_history();
|
||||
PROMPT = false;
|
||||
}
|
||||
}
|
||||
|
||||
if self.pending_input.get_ref().chars().last() != Some('\n') {
|
||||
*self.pending_input.get_mut() += "\n";
|
||||
}
|
||||
|
||||
Ok(self.pending_input.get_ref().len())
|
||||
}
|
||||
Err(ReadlineError::Eof) => Ok(0),
|
||||
Err(e) => Err(Error::new(ErrorKind::InvalidInput, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn save_history(&mut self) {
|
||||
if let Some(mut path) = dirs_next::home_dir() {
|
||||
path.push(HISTORY_FILE);
|
||||
if path.exists() {
|
||||
if self.rl.append_history(&path).is_err() {
|
||||
println!("Warning: couldn't append history (existing file)");
|
||||
}
|
||||
} else if self.rl.save_history(&path).is_err() {
|
||||
println!("Warning: couldn't save history (new file)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn peek_byte(&mut self) -> std::io::Result<u8> {
|
||||
loop {
|
||||
match self.pending_input.get_ref().bytes().next() {
|
||||
Some(0) => {
|
||||
return Ok(0);
|
||||
}
|
||||
Some(b) => {
|
||||
return Ok(b);
|
||||
}
|
||||
None => match self.call_readline() {
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
Ok(0) => {
|
||||
self.pending_input.get_mut().push('\u{0}');
|
||||
return Ok(0);
|
||||
}
|
||||
_ => {
|
||||
set_prompt(false);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for ReadlineStream {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
match self.pending_input.read(buf) {
|
||||
Ok(0) => {
|
||||
self.call_readline()?;
|
||||
self.pending_input.read(buf)
|
||||
}
|
||||
result => result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CharRead for ReadlineStream {
|
||||
fn peek_char(&mut self) -> Option<std::io::Result<char>> {
|
||||
loop {
|
||||
let pos = self.pending_input.position() as usize;
|
||||
|
||||
match self.pending_input.get_ref()[pos ..].chars().next() {
|
||||
Some('\u{0}') => {
|
||||
return Some(Ok('\u{0}'));
|
||||
}
|
||||
Some(c) => {
|
||||
return Some(Ok(c));
|
||||
}
|
||||
None => {
|
||||
match self.call_readline() {
|
||||
Err(e) => {
|
||||
return Some(Err(e));
|
||||
}
|
||||
Ok(0) => {
|
||||
self.pending_input.get_mut().push('\u{0}');
|
||||
return Some(Ok('\u{0}'));
|
||||
}
|
||||
_ => {
|
||||
set_prompt(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn consume(&mut self, nread: usize) {
|
||||
let offset = self.pending_input.position() as usize;
|
||||
self.pending_input.set_position((offset + nread) as u64);
|
||||
}
|
||||
|
||||
fn put_back_char(&mut self, c: char) {
|
||||
let offset = self.pending_input.position() as usize;
|
||||
self.pending_input.set_position((offset - c.len_utf8()) as u64);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn write_term_to_heap(
|
||||
term: &Term,
|
||||
heap: &mut Heap,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> TermWriteResult {
|
||||
let term_writer = TermWriter::new(heap, atom_tbl);
|
||||
term_writer.write_term_to_heap(term)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TermWriter<'a> {
|
||||
machine_st: &'a mut MachineState,
|
||||
struct TermWriter<'a, 'b> {
|
||||
heap: &'a mut Heap,
|
||||
atom_tbl: &'b mut AtomTable,
|
||||
queue: SubtermDeque,
|
||||
var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct TermWriteResult {
|
||||
pub(crate) heap_loc: usize,
|
||||
pub(crate) var_dict: HeapVarDict,
|
||||
pub struct TermWriteResult {
|
||||
pub heap_loc: usize,
|
||||
pub var_dict: HeapVarDict,
|
||||
}
|
||||
|
||||
impl<'a> TermWriter<'a> {
|
||||
impl<'a, 'b> TermWriter<'a, 'b> {
|
||||
#[inline]
|
||||
fn new(machine_st: &'a mut MachineState) -> Self {
|
||||
fn new(heap: &'a mut Heap, atom_tbl: &'b mut AtomTable) -> Self {
|
||||
TermWriter {
|
||||
machine_st,
|
||||
heap,
|
||||
atom_tbl,
|
||||
queue: SubtermDeque::new(),
|
||||
var_dict: HeapVarDict::new(),
|
||||
var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn modify_head_of_queue(&mut self, term: &TermRef<'a>, h: usize) {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
self.machine_st.heap[site_h] = HeapCellValue::Addr(self.term_as_addr(term, h));
|
||||
self.heap[site_h] = self.term_as_addr(term, h);
|
||||
|
||||
if arity > 1 {
|
||||
self.queue.push_front((arity - 1, site_h + 1));
|
||||
@@ -267,64 +282,87 @@ impl<'a> TermWriter<'a> {
|
||||
|
||||
#[inline]
|
||||
fn push_stub_addr(&mut self) {
|
||||
let h = self.machine_st.heap.h();
|
||||
self.machine_st
|
||||
.heap
|
||||
.push(HeapCellValue::Addr(Addr::HeapCell(h)));
|
||||
let h = self.heap.len();
|
||||
self.heap.push(heap_loc_as_cell!(h));
|
||||
}
|
||||
|
||||
fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> Addr {
|
||||
fn term_as_addr(&mut self, term: &TermRef<'a>, h: usize) -> HeapCellValue {
|
||||
match term {
|
||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => Addr::HeapCell(h),
|
||||
&TermRef::Cons(..) => Addr::HeapCell(h),
|
||||
&TermRef::Constant(_, _, c) => self.machine_st.heap.put_constant(c.clone()),
|
||||
&TermRef::Clause(..) => Addr::Str(h),
|
||||
&TermRef::PartialString(..) => Addr::PStrLocation(h, 0),
|
||||
&TermRef::Cons(..) => list_loc_as_cell!(h),
|
||||
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
|
||||
&TermRef::PartialString(_, _, ref src, None) =>
|
||||
if src.as_str().is_empty() {
|
||||
empty_list_as_cell!()
|
||||
} else if self.heap[h].get_tag() == HeapCellValueTag::CStr {
|
||||
heap_loc_as_cell!(h)
|
||||
} else {
|
||||
pstr_loc_as_cell!(h)
|
||||
},
|
||||
&TermRef::PartialString(..) => pstr_loc_as_cell!(h),
|
||||
&TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
|
||||
&TermRef::Clause(_,_,_,subterms) if subterms.len() == 0 => heap_loc_as_cell!(h),
|
||||
&TermRef::Clause(..) => str_loc_as_cell!(h),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_term_to_heap(mut self, term: &'a Term) -> TermWriteResult {
|
||||
let heap_loc = self.machine_st.heap.h();
|
||||
let heap_loc = self.heap.len();
|
||||
|
||||
for term in breadth_first_iter(term, true) {
|
||||
let h = self.machine_st.heap.h();
|
||||
let h = self.heap.len();
|
||||
|
||||
match &term {
|
||||
&TermRef::Cons(lvl, ..) => {
|
||||
&TermRef::Cons(Level::Root, ..) => {
|
||||
self.queue.push_back((2, h + 1));
|
||||
self.machine_st
|
||||
.heap
|
||||
.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
|
||||
self.heap.push(list_loc_as_cell!(h + 1));
|
||||
|
||||
self.push_stub_addr();
|
||||
self.push_stub_addr();
|
||||
|
||||
if let Level::Root = lvl {
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
&TermRef::Clause(lvl, _, ref ct, subterms) => {
|
||||
self.queue.push_back((subterms.len(), h + 1));
|
||||
let named = HeapCellValue::NamedStr(subterms.len(), ct.name(), ct.spec());
|
||||
&TermRef::Cons(..) => {
|
||||
self.queue.push_back((2, h));
|
||||
|
||||
self.machine_st.heap.push(named);
|
||||
self.push_stub_addr();
|
||||
self.push_stub_addr();
|
||||
}
|
||||
&TermRef::Clause(Level::Root, _, ref ct, subterms) => {
|
||||
self.heap.push(if subterms.len() == 0 {
|
||||
heap_loc_as_cell!(heap_loc + 1)
|
||||
} else {
|
||||
str_loc_as_cell!(heap_loc + 1)
|
||||
});
|
||||
|
||||
self.queue.push_back((subterms.len(), h + 2));
|
||||
let named = atom_as_cell!(ct.name(), subterms.len());
|
||||
|
||||
self.heap.push(named);
|
||||
|
||||
for _ in 0..subterms.len() {
|
||||
self.push_stub_addr();
|
||||
}
|
||||
|
||||
if let Level::Root = lvl {
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
&TermRef::Clause(_, _, ref ct, subterms) => {
|
||||
self.queue.push_back((subterms.len(), h + 1));
|
||||
let named = atom_as_cell!(ct.name(), subterms.len());
|
||||
|
||||
self.heap.push(named);
|
||||
|
||||
for _ in 0..subterms.len() {
|
||||
self.push_stub_addr();
|
||||
}
|
||||
}
|
||||
&TermRef::AnonVar(Level::Root) | &TermRef::Constant(Level::Root, ..) => {
|
||||
&TermRef::AnonVar(Level::Root) | &TermRef::Literal(Level::Root, ..) => {
|
||||
let addr = self.term_as_addr(&term, h);
|
||||
self.machine_st.heap.push(HeapCellValue::Addr(addr));
|
||||
self.heap.push(addr);
|
||||
}
|
||||
&TermRef::Var(Level::Root, _, ref var) => {
|
||||
let addr = self.term_as_addr(&term, h);
|
||||
self.var_dict.insert(var.clone(), Addr::HeapCell(h));
|
||||
self.machine_st.heap.push(HeapCellValue::Addr(addr));
|
||||
self.var_dict.insert(var.clone(), heap_loc_as_cell!(h));
|
||||
self.heap.push(addr);
|
||||
}
|
||||
&TermRef::AnonVar(_) => {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
@@ -335,25 +373,28 @@ impl<'a> TermWriter<'a> {
|
||||
|
||||
continue;
|
||||
}
|
||||
&TermRef::PartialString(lvl, _, ref pstr, tail) => {
|
||||
&TermRef::PartialString(lvl, _, ref src, tail) => {
|
||||
if tail.is_some() {
|
||||
self.machine_st.heap.allocate_pstr(&pstr);
|
||||
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
|
||||
} else {
|
||||
self.machine_st.heap.put_complete_string(&pstr);
|
||||
put_complete_string(self.heap, src.as_str(), self.atom_tbl);
|
||||
}
|
||||
|
||||
if let Level::Root = lvl {
|
||||
} else if tail.is_some() {
|
||||
let h = self.machine_st.heap.h();
|
||||
if tail.is_some() {
|
||||
let h = self.heap.len();
|
||||
self.queue.push_back((1, h - 1));
|
||||
|
||||
if let Level::Root = lvl {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
&TermRef::Var(_, _, ref var) => {
|
||||
if let Some((arity, site_h)) = self.queue.pop_front() {
|
||||
if let Some(addr) = self.var_dict.get(var).cloned() {
|
||||
self.machine_st.heap[site_h] = HeapCellValue::Addr(addr);
|
||||
self.heap[site_h] = addr;
|
||||
} else {
|
||||
self.var_dict.insert(var.clone(), Addr::HeapCell(site_h));
|
||||
self.var_dict.insert(var.clone(), heap_loc_as_cell!(site_h));
|
||||
}
|
||||
|
||||
if arity > 1 {
|
||||
|
||||
158
src/targets.rs
158
src/targets.rs
@@ -1,37 +1,41 @@
|
||||
use prolog_parser::ast::*;
|
||||
use crate::parser::ast::*;
|
||||
|
||||
use crate::clause_types::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::types::*;
|
||||
|
||||
pub(crate) struct FactInstruction;
|
||||
pub(crate) struct QueryInstruction;
|
||||
|
||||
pub(crate) trait CompilationTarget<'a> {
|
||||
type Iterator: Iterator<Item = TermRef<'a>>;
|
||||
|
||||
fn iter(_: &'a Term) -> Self::Iterator;
|
||||
fn iter(term: &'a Term) -> Self::Iterator;
|
||||
|
||||
fn to_constant(_: Level, _: Constant, _: RegType) -> Self;
|
||||
fn to_list(_: Level, _: RegType) -> Self;
|
||||
fn to_structure(_: ClauseType, _: usize, _: RegType) -> Self;
|
||||
fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
|
||||
fn to_list(lvl: Level, r: RegType) -> Instruction;
|
||||
fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction;
|
||||
|
||||
fn to_void(_: usize) -> Self;
|
||||
fn is_void_instr(&self) -> bool;
|
||||
fn to_void(num_subterms: usize) -> Instruction;
|
||||
fn is_void_instr(instr: &Instruction) -> bool;
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self;
|
||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction;
|
||||
|
||||
fn incr_void_instr(&mut self);
|
||||
fn incr_void_instr(instr: &mut Instruction);
|
||||
|
||||
fn constant_subterm(_: Constant) -> Self;
|
||||
fn constant_subterm(literal: Literal) -> Instruction;
|
||||
|
||||
fn argument_to_variable(_: RegType, _: usize) -> Self;
|
||||
fn argument_to_value(_: RegType, _: usize) -> Self;
|
||||
fn argument_to_variable(r: RegType, r: usize) -> Instruction;
|
||||
fn argument_to_value(r: RegType, val: usize) -> Instruction;
|
||||
|
||||
fn move_to_register(_: RegType, _: usize) -> Self;
|
||||
fn move_to_register(r: RegType, val: usize) -> Instruction;
|
||||
|
||||
fn subterm_to_variable(_: RegType) -> Self;
|
||||
fn subterm_to_value(_: RegType) -> Self;
|
||||
fn subterm_to_variable(r: RegType) -> Instruction;
|
||||
fn subterm_to_value(r: RegType) -> Instruction;
|
||||
|
||||
fn clause_arg_to_instr(_: RegType) -> Self;
|
||||
fn clause_arg_to_instr(r: RegType) -> Instruction;
|
||||
}
|
||||
|
||||
impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
@@ -41,66 +45,66 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
|
||||
breadth_first_iter(term, false) // do not iterate over the root clause if one exists.
|
||||
}
|
||||
|
||||
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
|
||||
FactInstruction::GetConstant(lvl, constant, reg)
|
||||
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
||||
Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
|
||||
}
|
||||
|
||||
fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self {
|
||||
FactInstruction::GetStructure(ct, arity, reg)
|
||||
fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction {
|
||||
Instruction::GetStructure(name, arity, reg)
|
||||
}
|
||||
|
||||
fn to_list(lvl: Level, reg: RegType) -> Self {
|
||||
FactInstruction::GetList(lvl, reg)
|
||||
fn to_list(lvl: Level, reg: RegType) -> Instruction {
|
||||
Instruction::GetList(lvl, reg)
|
||||
}
|
||||
|
||||
fn to_void(subterms: usize) -> Self {
|
||||
FactInstruction::UnifyVoid(subterms)
|
||||
fn to_void(num_subterms: usize) -> Instruction {
|
||||
Instruction::UnifyVoid(num_subterms)
|
||||
}
|
||||
|
||||
fn is_void_instr(&self) -> bool {
|
||||
match self {
|
||||
&FactInstruction::UnifyVoid(_) => true,
|
||||
fn is_void_instr(instr: &Instruction) -> bool {
|
||||
match instr {
|
||||
&Instruction::UnifyVoid(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
|
||||
FactInstruction::GetPartialString(lvl, string, r, has_tail)
|
||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
|
||||
Instruction::GetPartialString(lvl, string, r, has_tail)
|
||||
}
|
||||
|
||||
fn incr_void_instr(&mut self) {
|
||||
match self {
|
||||
&mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
|
||||
fn incr_void_instr(instr: &mut Instruction) {
|
||||
match instr {
|
||||
&mut Instruction::UnifyVoid(ref mut incr) => *incr += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_subterm(constant: Constant) -> Self {
|
||||
FactInstruction::UnifyConstant(constant)
|
||||
fn constant_subterm(constant: Literal) -> Instruction {
|
||||
Instruction::UnifyConstant(HeapCellValue::from(constant))
|
||||
}
|
||||
|
||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
||||
FactInstruction::GetVariable(arg, val)
|
||||
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
|
||||
Instruction::GetVariable(arg, val)
|
||||
}
|
||||
|
||||
fn move_to_register(arg: RegType, val: usize) -> Self {
|
||||
FactInstruction::GetVariable(arg, val)
|
||||
fn move_to_register(arg: RegType, val: usize) -> Instruction {
|
||||
Instruction::GetVariable(arg, val)
|
||||
}
|
||||
|
||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
||||
FactInstruction::GetValue(arg, val)
|
||||
fn argument_to_value(arg: RegType, val: usize) -> Instruction {
|
||||
Instruction::GetValue(arg, val)
|
||||
}
|
||||
|
||||
fn subterm_to_variable(val: RegType) -> Self {
|
||||
FactInstruction::UnifyVariable(val)
|
||||
fn subterm_to_variable(val: RegType) -> Instruction {
|
||||
Instruction::UnifyVariable(val)
|
||||
}
|
||||
|
||||
fn subterm_to_value(val: RegType) -> Self {
|
||||
FactInstruction::UnifyValue(val)
|
||||
fn subterm_to_value(val: RegType) -> Instruction {
|
||||
Instruction::UnifyValue(val)
|
||||
}
|
||||
|
||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
||||
FactInstruction::UnifyVariable(val)
|
||||
fn clause_arg_to_instr(val: RegType) -> Instruction {
|
||||
Instruction::UnifyVariable(val)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,65 +115,65 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
|
||||
post_order_iter(term)
|
||||
}
|
||||
|
||||
fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self {
|
||||
QueryInstruction::PutStructure(ct, arity, r)
|
||||
fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction {
|
||||
Instruction::PutStructure(name, arity, r)
|
||||
}
|
||||
|
||||
fn to_constant(lvl: Level, constant: Constant, reg: RegType) -> Self {
|
||||
QueryInstruction::PutConstant(lvl, constant, reg)
|
||||
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
|
||||
Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
|
||||
}
|
||||
|
||||
fn to_list(lvl: Level, reg: RegType) -> Self {
|
||||
QueryInstruction::PutList(lvl, reg)
|
||||
fn to_list(lvl: Level, reg: RegType) -> Instruction {
|
||||
Instruction::PutList(lvl, reg)
|
||||
}
|
||||
|
||||
fn to_pstr(lvl: Level, string: String, r: RegType, has_tail: bool) -> Self {
|
||||
QueryInstruction::PutPartialString(lvl, string, r, has_tail)
|
||||
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
|
||||
Instruction::PutPartialString(lvl, string, r, has_tail)
|
||||
}
|
||||
|
||||
fn to_void(subterms: usize) -> Self {
|
||||
QueryInstruction::SetVoid(subterms)
|
||||
fn to_void(subterms: usize) -> Instruction {
|
||||
Instruction::SetVoid(subterms)
|
||||
}
|
||||
|
||||
fn is_void_instr(&self) -> bool {
|
||||
match self {
|
||||
&QueryInstruction::SetVoid(_) => true,
|
||||
fn is_void_instr(instr: &Instruction) -> bool {
|
||||
match instr {
|
||||
&Instruction::SetVoid(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn incr_void_instr(&mut self) {
|
||||
match self {
|
||||
&mut QueryInstruction::SetVoid(ref mut incr) => *incr += 1,
|
||||
fn incr_void_instr(instr: &mut Instruction) {
|
||||
match instr {
|
||||
&mut Instruction::SetVoid(ref mut incr) => *incr += 1,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn constant_subterm(constant: Constant) -> Self {
|
||||
QueryInstruction::SetConstant(constant)
|
||||
fn constant_subterm(constant: Literal) -> Instruction {
|
||||
Instruction::SetConstant(HeapCellValue::from(constant))
|
||||
}
|
||||
|
||||
fn argument_to_variable(arg: RegType, val: usize) -> Self {
|
||||
QueryInstruction::PutVariable(arg, val)
|
||||
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
|
||||
Instruction::PutVariable(arg, val)
|
||||
}
|
||||
|
||||
fn move_to_register(arg: RegType, val: usize) -> Self {
|
||||
QueryInstruction::GetVariable(arg, val)
|
||||
fn move_to_register(arg: RegType, val: usize) -> Instruction {
|
||||
Instruction::GetVariable(arg, val)
|
||||
}
|
||||
|
||||
fn argument_to_value(arg: RegType, val: usize) -> Self {
|
||||
QueryInstruction::PutValue(arg, val)
|
||||
fn argument_to_value(arg: RegType, val: usize) -> Instruction {
|
||||
Instruction::PutValue(arg, val)
|
||||
}
|
||||
|
||||
fn subterm_to_variable(val: RegType) -> Self {
|
||||
QueryInstruction::SetVariable(val)
|
||||
fn subterm_to_variable(val: RegType) -> Instruction {
|
||||
Instruction::SetVariable(val)
|
||||
}
|
||||
|
||||
fn subterm_to_value(val: RegType) -> Self {
|
||||
QueryInstruction::SetValue(val)
|
||||
fn subterm_to_value(val: RegType) -> Instruction {
|
||||
Instruction::SetValue(val)
|
||||
}
|
||||
|
||||
fn clause_arg_to_instr(val: RegType) -> Self {
|
||||
QueryInstruction::SetValue(val)
|
||||
fn clause_arg_to_instr(val: RegType) -> Instruction {
|
||||
Instruction::SetValue(val)
|
||||
}
|
||||
}
|
||||
|
||||
37
src/tests/bom.rs
Normal file
37
src/tests/bom.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::lexer::{Lexer, Token};
|
||||
|
||||
#[test]
|
||||
fn valid_token() {
|
||||
let stream = parsing_stream("valid text".as_bytes());
|
||||
assert!(stream.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_stream() {
|
||||
let bytes: &[u8] = &[];
|
||||
assert!(parsing_stream(bytes).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_utf8_bom() {
|
||||
let mut machine_st = MachineState::new();
|
||||
let bytes: &[u8] = &[0xEF, 0xBB, 0xBF, '4' as u8, '\n' as u8];
|
||||
let stream = parsing_stream(bytes).expect("valid stream");
|
||||
let mut lexer = Lexer::new(stream, &mut machine_st);
|
||||
match lexer.next_token() {
|
||||
Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))) => (),
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_utf16_bom() {
|
||||
let bytes: &[u8] = &[0xFF, 0xFE, 'a' as u8, '\n' as u8];
|
||||
let stream = parsing_stream(bytes);
|
||||
match stream {
|
||||
Err(ParserError::Utf8Error(0, 0)) => (),
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
@@ -115,14 +115,6 @@ test_queries_on_builtins :-
|
||||
1.1 @< 1,
|
||||
1.0 @=< 1,
|
||||
\+ 1 @=< 1.0,
|
||||
\+ \+ (variant(X, Y)),
|
||||
\+ (variant(f(X), f(x))),
|
||||
\+ \+ (variant(X, X)),
|
||||
\+ \+ (variant(f(x), f(x))),
|
||||
\+ (variant([X,Y,Z], [V,W,V])),
|
||||
\+ \+ (variant([X,Y,Z], [V,W,Z])),
|
||||
\+ \+ (variant([X,Y,X], [V,W,V])),
|
||||
\+ \+ (g(B) = B, g(A) = A, variant(A, B)),
|
||||
keysort([1-1,1-1],[1-1,1-1]),
|
||||
\+ \+ findall(Sorted, keysort([2-99,1-a,3-f(_),1-z,1-a,2-44],Sorted), [[1-a,1-z,1-a,2-99,2-44,3-f(_)]]),
|
||||
\+ \+ findall(X, keysort([X-1,1-1],[2-1,1-1]), [2]).
|
||||
|
||||
@@ -16,39 +16,40 @@ test_queries_on_call_with_inference_limit :-
|
||||
\+ call_with_inference_limit(g(X), 5, R),
|
||||
maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]),
|
||||
findall([R,X],
|
||||
call_with_inference_limit(g(X), 10, R),
|
||||
call_with_inference_limit(g(X), 11, R),
|
||||
[[true, 1],
|
||||
[true, 2],
|
||||
[true, 3],
|
||||
[true, 4],
|
||||
[!, 5]]),
|
||||
findall([R,X],
|
||||
(call_with_inference_limit(g(X), 10, R), call(true)),
|
||||
(call_with_inference_limit(g(X), 11, R), call(true)),
|
||||
[[true, 1],
|
||||
[true, 2],
|
||||
[true, 3],
|
||||
[true, 4],
|
||||
[!, 5]]),
|
||||
findall([R,X],
|
||||
(call_with_inference_limit(g(X), 4, R), call(true)),
|
||||
(call_with_inference_limit(g(X), 5, R), call(true)),
|
||||
[[true, 1],
|
||||
[true, 2],
|
||||
[inference_limit_exceeded, _]]),
|
||||
findall([X,R1,R2],
|
||||
(call_with_inference_limit(g(X), 4, R1),
|
||||
call_with_inference_limit(g(X), 5, R2)),
|
||||
(call_with_inference_limit(g(X), 5, R1),
|
||||
call_with_inference_limit(g(X), 6, R2)),
|
||||
[[1,true,!],
|
||||
[2,true,!],
|
||||
[3,true,!],
|
||||
[4,true,!],
|
||||
[5,!,!]]),
|
||||
\+ \+ assertz((f(X) :- call_with_inference_limit(g(X), 8, _))),
|
||||
\+ \+ assertz((f(X) :- call_with_inference_limit(tests_on_call_with_inference_limit:g(X), 11, _))),
|
||||
findall([R,X],
|
||||
call_with_inference_limit(f(X), 12, R),
|
||||
[[true,1],
|
||||
[true,2],
|
||||
[true,3],
|
||||
[true,4],
|
||||
[!,5]]).
|
||||
call_with_inference_limit(f(X), 14, R),
|
||||
Solutions),
|
||||
Solutions == [[true,1],
|
||||
[true,2],
|
||||
[true,3],
|
||||
[true,4],
|
||||
[!,5]].
|
||||
|
||||
:- initialization(test_queries_on_call_with_inference_limit).
|
||||
|
||||
109
src/tests/parse_tokens.rs
Normal file
109
src/tests/parse_tokens.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::lexer::{Lexer, Token};
|
||||
|
||||
fn read_all_tokens(text: &str) -> Result<Vec<Token>, ParserError> {
|
||||
let mut machine_st = MachineState::new();
|
||||
let stream = parsing_stream(text.as_bytes())?;
|
||||
let mut lexer = Lexer::new(stream, &mut machine_st);
|
||||
|
||||
let mut tokens = Vec::new();
|
||||
while !lexer.eof()? {
|
||||
let token = lexer.next_token()?;
|
||||
tokens.push(token);
|
||||
}
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_multiline_comment() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("/**/ 4\n")?;
|
||||
assert_eq!(tokens, [Token::Literal(Literal::Fixnum(Fixnum::build_with(4)))]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn any_char_multiline_comment() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("/* █╗╚═══╝ © */ 4\n")?;
|
||||
assert_eq!(tokens, [Token::Literal(Literal::Fixnum(4))]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_char() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("'a'\n")?;
|
||||
assert_eq!(tokens, [Token::Literal(Literal::Char('a'))]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_meta_seq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r#"'\\' '\'' '\"' '\`' "#)?; // use literal string so \ are escaped
|
||||
assert_eq!(
|
||||
tokens,
|
||||
[
|
||||
Token::Literal(Literal::Char('\\')),
|
||||
Token::Literal(Literal::Char('\'')),
|
||||
Token::Literal(Literal::Char('"')),
|
||||
Token::Literal(Literal::Char('`'))
|
||||
]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_control_seq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r"'\a' '\b' '\r' '\f' '\t' '\n' '\v' ")?;
|
||||
assert_eq!(
|
||||
tokens,
|
||||
[
|
||||
Token::Literal(Literal::Char('\u{07}')),
|
||||
Token::Literal(Literal::Char('\u{08}')),
|
||||
Token::Literal(Literal::Char('\r')),
|
||||
Token::Literal(Literal::Char('\u{0c}')),
|
||||
Token::Literal(Literal::Char('\t')),
|
||||
Token::Literal(Literal::Char('\n')),
|
||||
Token::Literal(Literal::Char('\u{0b}')),
|
||||
]
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_octseq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r"'\60433\' ")?;
|
||||
assert_eq!(tokens, [Token::Literal(Literal::Char('愛'))]); // Japanese character
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_octseq_0() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r"'\0\' ")?;
|
||||
assert_eq!(tokens, [Token::Literal(Literal::Char('\u{0000}'))]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_hexseq() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens(r"'\x2124\' ")?;
|
||||
assert_eq!(tokens, [Token::Literal(Literal::Char('ℤ'))]); // Z math symbol
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn char_with_hexseq_invalid() {
|
||||
assert!(read_all_tokens(r"'\x\' ").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() -> Result<(), ParserError> {
|
||||
let tokens = read_all_tokens("")?;
|
||||
assert!(tokens.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comment_then_eof() -> Result<(), ParserError> {
|
||||
assert!(read_all_tokens("% only a comment").is_err());
|
||||
Ok(())
|
||||
}
|
||||
112
src/toplevel.pl
112
src/toplevel.pl
@@ -2,8 +2,10 @@
|
||||
copy_term/3]).
|
||||
|
||||
:- use_module(library(charsio)).
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(files)).
|
||||
:- use_module(library(iso_ext)).
|
||||
:- use_module(library(lambda)).
|
||||
:- use_module(library(lists)).
|
||||
:- use_module(library(si)).
|
||||
|
||||
@@ -17,7 +19,7 @@ load_scryerrc :-
|
||||
append(HomeDir, "/.scryerrc", ScryerrcFile),
|
||||
( file_exists(ScryerrcFile) ->
|
||||
atom_chars(ScryerrcFileAtom, ScryerrcFile),
|
||||
catch(consult(ScryerrcFileAtom), E, print_exception(E))
|
||||
catch(use_module(ScryerrcFileAtom), E, print_exception(E))
|
||||
; true
|
||||
)
|
||||
; true
|
||||
@@ -111,7 +113,7 @@ run_goals([g(Gs0)|Goals]) :-
|
||||
( ends_with_dot(Gs0) -> Gs1 = Gs0
|
||||
; append(Gs0, ".", Gs1)
|
||||
),
|
||||
read_term_from_chars(Gs1, Goal),
|
||||
read_from_chars(Gs1, Goal),
|
||||
( catch(
|
||||
user:Goal,
|
||||
Exception,
|
||||
@@ -152,26 +154,27 @@ instruction_match(Term, VarList) :-
|
||||
( var(Term) ->
|
||||
throw(error(instantiation_error, repl/0))
|
||||
; Term = [Item] ->
|
||||
!,
|
||||
( atom(Item) ->
|
||||
( Item == user ->
|
||||
catch(load(user_input), E, print_exception_with_check(E))
|
||||
;
|
||||
( Item == user ->
|
||||
catch(load(user_input), E, print_exception_with_check(E))
|
||||
;
|
||||
submit_query_and_print_results(consult(Item), [])
|
||||
)
|
||||
)
|
||||
; catch(type_error(atom, Item, repl/0),
|
||||
E,
|
||||
print_exception_with_check(E))
|
||||
E,
|
||||
print_exception_with_check(E))
|
||||
)
|
||||
; Term = end_of_file ->
|
||||
halt
|
||||
;
|
||||
submit_query_and_print_results(Term, VarList)
|
||||
submit_query_and_print_results(Term, VarList)
|
||||
).
|
||||
|
||||
|
||||
submit_query_and_print_results_(Term, VarList) :-
|
||||
'$get_b_value'(B),
|
||||
bb_put('$report_all', false),
|
||||
bb_put('$report_n_more', 0),
|
||||
'$call'(Term),
|
||||
write_eqs_and_read_input(B, VarList),
|
||||
!.
|
||||
@@ -184,7 +187,7 @@ submit_query_and_print_results(Term0, VarList) :-
|
||||
( functor(Term0, call, _) ->
|
||||
Term = Term0 % prevent pre-mature expansion of incomplete goal
|
||||
% in the first argument, which is done by call/N
|
||||
; expand_goal(call(Term0), user, call(Term))
|
||||
; expand_goal(Term0, user, Term)
|
||||
),
|
||||
setup_call_cleanup(bb_put('$first_answer', true),
|
||||
submit_query_and_print_results_(Term, VarList),
|
||||
@@ -193,10 +196,10 @@ submit_query_and_print_results(Term0, VarList) :-
|
||||
|
||||
needs_bracketing(Value, Op) :-
|
||||
catch((functor(Value, F, _),
|
||||
current_op(EqPrec, EqSpec, Op),
|
||||
current_op(FPrec, _, F)),
|
||||
_,
|
||||
false),
|
||||
current_op(EqPrec, EqSpec, Op),
|
||||
current_op(FPrec, _, F)),
|
||||
_,
|
||||
false),
|
||||
( EqPrec < FPrec ->
|
||||
true
|
||||
; FPrec > 0, F == Value, graphic_token_char(F) ->
|
||||
@@ -210,15 +213,15 @@ needs_bracketing(Value, Op) :-
|
||||
write_goal(G, VarList, MaxDepth) :-
|
||||
( G = (Var = Value) ->
|
||||
( var(Value) ->
|
||||
select((Var = _), VarList, NewVarList)
|
||||
select((Var = _), VarList, NewVarList)
|
||||
; VarList = NewVarList
|
||||
),
|
||||
write(Var),
|
||||
write(' = '),
|
||||
( needs_bracketing(Value, (=)) ->
|
||||
write('('),
|
||||
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
|
||||
write(')')
|
||||
write('('),
|
||||
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
|
||||
write(')')
|
||||
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)])
|
||||
)
|
||||
; G == [] ->
|
||||
@@ -229,20 +232,20 @@ write_goal(G, VarList, MaxDepth) :-
|
||||
write_last_goal(G, VarList, MaxDepth) :-
|
||||
( G = (Var = Value) ->
|
||||
( var(Value) ->
|
||||
select((Var = _), VarList, NewVarList)
|
||||
select((Var = _), VarList, NewVarList)
|
||||
; VarList = NewVarList
|
||||
),
|
||||
write(Var),
|
||||
write(' = '),
|
||||
( needs_bracketing(Value, (=)) ->
|
||||
write('('),
|
||||
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
|
||||
write(')')
|
||||
write('('),
|
||||
write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
|
||||
write(')')
|
||||
; write_term(Value, [quoted(true), variable_names(NewVarList), max_depth(MaxDepth)]),
|
||||
( trailing_period_is_ambiguous(Value) ->
|
||||
write(' ')
|
||||
; true
|
||||
)
|
||||
( trailing_period_is_ambiguous(Value) ->
|
||||
write(' ')
|
||||
; true
|
||||
)
|
||||
)
|
||||
; G == [] ->
|
||||
write('true')
|
||||
@@ -272,8 +275,13 @@ trailing_period_is_ambiguous(Value) :-
|
||||
ValueChars \== ['.'],
|
||||
graphic_token_char(Char).
|
||||
|
||||
term_variables_under_max_depth(Term, MaxDepth, Vars) :-
|
||||
'$term_variables_under_max_depth'(Term, MaxDepth, Vars).
|
||||
|
||||
write_eqs_and_read_input(B, VarList) :-
|
||||
term_variables(VarList, Vars0),
|
||||
gather_query_vars(VarList, OrigVars),
|
||||
% one layer of depth added for (=/2) functor
|
||||
'$term_variables_under_max_depth'(OrigVars, 22, Vars0),
|
||||
'$term_attributed_variables'(VarList, AttrVars),
|
||||
'$project_atts':project_attributes(Vars0, AttrVars),
|
||||
copy_term(AttrVars, AttrVars, AttrGoals),
|
||||
@@ -281,12 +289,13 @@ write_eqs_and_read_input(B, VarList) :-
|
||||
append([Vars0, AttrGoalVars, AttrVars], Vars),
|
||||
charsio:extend_var_list(Vars, VarList, NewVarList, fabricated),
|
||||
'$get_b_value'(B0),
|
||||
gather_query_vars(VarList, OrigVars),
|
||||
gather_equations(NewVarList, OrigVars, Equations),
|
||||
append(Equations, AttrGoals, Goals),
|
||||
term_variables(Equations, EquationVars),
|
||||
append([AttrGoalVars, EquationVars], Vars1),
|
||||
charsio:extend_var_list(Vars1, VarList, NewVarList0, fabricated),
|
||||
% one layer of depth added for (=/2) functor
|
||||
maplist(\Term^Vs^term_variables_under_max_depth(Term, 22, Vs), Equations, EquationVars),
|
||||
append([AttrGoalVars | EquationVars], Vars1),
|
||||
term_variables(Vars1, Vars2), % deduplicate vars of Vars1 but preserve their order.
|
||||
charsio:extend_var_list(Vars2, VarList, NewVarList0, fabricated),
|
||||
( bb_get('$first_answer', true) ->
|
||||
write(' '),
|
||||
bb_put('$first_answer', false)
|
||||
@@ -294,11 +303,11 @@ write_eqs_and_read_input(B, VarList) :-
|
||||
),
|
||||
( B0 == B ->
|
||||
( Goals == [] ->
|
||||
write('true.'), nl
|
||||
write('true.'), nl
|
||||
; loader:thread_goals(Goals, ThreadedGoals, (',')),
|
||||
write_eq(ThreadedGoals, NewVarList0, 20),
|
||||
write('.'),
|
||||
nl
|
||||
write_eq(ThreadedGoals, NewVarList0, 20),
|
||||
write('.'),
|
||||
nl
|
||||
)
|
||||
; loader:thread_goals(Goals, ThreadedGoals, (',')),
|
||||
write_eq(ThreadedGoals, NewVarList0, 20),
|
||||
@@ -306,7 +315,14 @@ write_eqs_and_read_input(B, VarList) :-
|
||||
).
|
||||
|
||||
read_input(ThreadedGoals, NewVarList) :-
|
||||
get_single_char(C),
|
||||
( bb_get('$report_all', true) ->
|
||||
C = n
|
||||
; bb_get('$report_n_more', N), N > 1 ->
|
||||
N1 is N - 1,
|
||||
bb_put('$report_n_more', N1),
|
||||
C = n
|
||||
; get_single_char(C)
|
||||
),
|
||||
( C = w ->
|
||||
nl,
|
||||
write(' '),
|
||||
@@ -323,7 +339,13 @@ read_input(ThreadedGoals, NewVarList) :-
|
||||
help_message,
|
||||
read_input(ThreadedGoals, NewVarList)
|
||||
; member(C, ['\n', .]) ->
|
||||
nl, write('; ...'), nl
|
||||
nl, write('; ... .'), nl
|
||||
; C = a ->
|
||||
bb_put('$report_all', true),
|
||||
nl, write('; '), false
|
||||
; C = f ->
|
||||
bb_put('$report_n_more', 5),
|
||||
nl, write('; '), false
|
||||
; read_input(ThreadedGoals, NewVarList)
|
||||
).
|
||||
|
||||
@@ -331,6 +353,8 @@ help_message :-
|
||||
nl, nl,
|
||||
write('SPACE, "n" or ";": next solution, if any\n'),
|
||||
write('RETURN or ".": stop enumeration\n'),
|
||||
write('"a": enumerate all solutions\n'),
|
||||
write('"f": enumerate the next 5 solutions\n'),
|
||||
write('"h": display this help message\n'),
|
||||
write('"w": write terms without depth limit\n'),
|
||||
write('"p": print terms with depth limit\n\n').
|
||||
@@ -340,7 +364,7 @@ gather_query_vars([_ = Var | Vars], QueryVars) :-
|
||||
QueryVars = [Var | QueryVars0],
|
||||
gather_query_vars(Vars, QueryVars0)
|
||||
;
|
||||
gather_query_vars(Vars, QueryVars)
|
||||
gather_query_vars(Vars, QueryVars)
|
||||
).
|
||||
gather_query_vars([], []).
|
||||
|
||||
@@ -358,8 +382,8 @@ select_all([OtherVar = OtherValue | Pairs], Var, Value, Vars, NewPairs) :-
|
||||
Vars = [OtherVar = OtherValue | Vars0],
|
||||
select_all(Pairs, Var, Value, Vars0, NewPairs)
|
||||
;
|
||||
NewPairs = [OtherVar = OtherValue | NewPairs0],
|
||||
select_all(Pairs, Var, Value, Vars, NewPairs0)
|
||||
NewPairs = [OtherVar = OtherValue | NewPairs0],
|
||||
select_all(Pairs, Var, Value, Vars, NewPairs0)
|
||||
).
|
||||
|
||||
gather_equations([], _, []).
|
||||
@@ -370,11 +394,11 @@ gather_equations([Var = Value | Pairs], OrigVarList, Goals) :-
|
||||
append([Var = Value | VarEqs], Goals0, Goals),
|
||||
gather_equations(NewPairs, OrigVarList, Goals0)
|
||||
;
|
||||
gather_equations(Pairs, OrigVarList, Goals)
|
||||
gather_equations(Pairs, OrigVarList, Goals)
|
||||
)
|
||||
;
|
||||
Goals = [Var = Value | Goals0],
|
||||
gather_equations(Pairs, OrigVarList, Goals0)
|
||||
Goals = [Var = Value | Goals0],
|
||||
gather_equations(Pairs, OrigVarList, Goals0)
|
||||
).
|
||||
|
||||
print_exception(E) :-
|
||||
|
||||
810
src/types.rs
Normal file
810
src/types.rs
Normal file
@@ -0,0 +1,810 @@
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
use crate::machine::partial_string::PartialString;
|
||||
use crate::machine::streams::*;
|
||||
use crate::parser::ast::Fixnum;
|
||||
use crate::parser::rug::{Integer, Rational};
|
||||
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::{Add, Sub, SubAssign};
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub enum HeapCellValueTag {
|
||||
// non-constants / tags with adjoining forwarding bits.
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Str = 0b000010,
|
||||
Lis = 0b000011,
|
||||
Var = 0b000110,
|
||||
StackVar = 0b000111,
|
||||
AttrVar = 0b010011,
|
||||
PStrLoc = 0b111111,
|
||||
PStrOffset = 0b001110,
|
||||
// constants.
|
||||
Fixnum = 0b010010,
|
||||
Char = 0b011011,
|
||||
Atom = 0b001010,
|
||||
PStr = 0b001011,
|
||||
CStr = 0b010110, // a complete string.
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub enum HeapCellValueView {
|
||||
// non-constants / tags with adjoining forwarding bits.
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
Str = 0b000010,
|
||||
Lis = 0b000011,
|
||||
Var = 0b000110,
|
||||
StackVar = 0b000111,
|
||||
AttrVar = 0b010011,
|
||||
PStrLoc = 0b111111,
|
||||
PStrOffset = 0b001110,
|
||||
// constants.
|
||||
Fixnum = 0b010010,
|
||||
Char = 0b011011,
|
||||
Atom = 0b001010,
|
||||
PStr = 0b001011,
|
||||
CStr = 0b010110,
|
||||
// trail elements.
|
||||
TrailedHeapVar = 0b011110,
|
||||
TrailedStackVar = 0b011111,
|
||||
TrailedAttrVarHeapLink = 0b101110,
|
||||
TrailedAttrVarListLink = 0b100010,
|
||||
TrailedAttachedValue = 0b101010,
|
||||
TrailedBlackboardEntry = 0b100110,
|
||||
TrailedBlackboardOffset = 0b100111,
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 2]
|
||||
pub enum ConsPtrMaskTag {
|
||||
Cons = 0b00,
|
||||
F64 = 0b01,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ConsPtr {
|
||||
ptr: B61,
|
||||
m: bool,
|
||||
tag: ConsPtrMaskTag,
|
||||
}
|
||||
|
||||
impl ConsPtr {
|
||||
#[inline(always)]
|
||||
pub fn build_with(ptr: *const ArenaHeader, tag: ConsPtrMaskTag) -> Self {
|
||||
ConsPtr::new()
|
||||
.with_ptr(ptr as *const u8 as u64)
|
||||
.with_m(false)
|
||||
.with_tag(tag)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_ptr(self) -> *mut u8 {
|
||||
self.ptr() as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
|
||||
#[bits = 6]
|
||||
pub(crate) enum RefTag {
|
||||
HeapCell = 0b0110,
|
||||
StackCell = 0b111,
|
||||
AttrVar = 0b10011,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||
pub struct Ref {
|
||||
val: B56,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] f: bool,
|
||||
tag: RefTag,
|
||||
}
|
||||
|
||||
impl Ord for Ref {
|
||||
fn cmp(&self, rhs: &Ref) -> Ordering {
|
||||
match self.get_tag() {
|
||||
RefTag::HeapCell | RefTag::AttrVar => {
|
||||
match rhs.get_tag() {
|
||||
RefTag::StackCell => Ordering::Less,
|
||||
_ => self.get_value().cmp(&rhs.get_value()),
|
||||
}
|
||||
}
|
||||
RefTag::StackCell => {
|
||||
match rhs.get_tag() {
|
||||
RefTag::StackCell =>
|
||||
self.get_value().cmp(&rhs.get_value()),
|
||||
_ =>
|
||||
Ordering::Greater,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Ref {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ref {
|
||||
#[inline(always)]
|
||||
pub(crate) fn build_with(tag: RefTag, value: u64) -> Self {
|
||||
Ref::new().with_tag(tag).with_val(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_tag(self) -> RefTag {
|
||||
self.tag()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_value(self) -> u64 {
|
||||
self.val()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn as_heap_cell_value(self) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(self.into_bytes())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn heap_cell(h: usize) -> Self {
|
||||
Ref::build_with(RefTag::HeapCell, h as u64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn stack_cell(h: usize) -> Self {
|
||||
Ref::build_with(RefTag::StackCell, h as u64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn attr_var(h: usize) -> Self {
|
||||
Ref::build_with(RefTag::AttrVar, h as u64)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum TrailRef {
|
||||
Ref(Ref),
|
||||
AttrVarHeapLink(usize),
|
||||
AttrVarListLink(usize, usize),
|
||||
BlackboardEntry(Atom),
|
||||
BlackboardOffset(Atom, HeapCellValue), // key atom, key value
|
||||
}
|
||||
|
||||
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[bits = 6]
|
||||
pub(crate) enum TrailEntryTag {
|
||||
TrailedHeapVar = 0b011110,
|
||||
TrailedStackVar = 0b011111,
|
||||
TrailedAttrVar = 0b101110,
|
||||
TrailedAttrVarHeapLink = 0b100010,
|
||||
TrailedAttrVarListLink = 0b100011,
|
||||
TrailedAttachedValue = 0b101010,
|
||||
TrailedBlackboardEntry = 0b100110,
|
||||
TrailedBlackboardOffset = 0b100111,
|
||||
}
|
||||
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(u64)]
|
||||
pub(crate) struct TrailEntry {
|
||||
val: B56,
|
||||
#[allow(unused)] f: bool,
|
||||
#[allow(unused)] m: bool,
|
||||
#[allow(unused)] tag: TrailEntryTag,
|
||||
}
|
||||
|
||||
impl TrailEntry {
|
||||
#[inline(always)]
|
||||
pub(crate) fn build_with(tag: TrailEntryTag, value: u64) -> Self {
|
||||
TrailEntry::new()
|
||||
.with_tag(tag)
|
||||
.with_m(false)
|
||||
.with_f(false)
|
||||
.with_val(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(crate) fn get_tag(self) -> TrailEntryTag {
|
||||
match self.tag_or_err() {
|
||||
Ok(tag) => tag,
|
||||
Err(_) => TrailEntryTag::TrailedAttachedValue,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn get_value(self) -> u64 {
|
||||
self.val()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u64)]
|
||||
#[bitfield]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct HeapCellValue {
|
||||
val: B56,
|
||||
f: bool,
|
||||
m: bool,
|
||||
tag: HeapCellValueTag,
|
||||
}
|
||||
|
||||
impl fmt::Display for HeapCellValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
read_heap_cell!(*self,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity == 0 {
|
||||
write!(f, "{}", name.as_str())
|
||||
} else {
|
||||
write!(
|
||||
f,
|
||||
"{}/{}",
|
||||
name.as_str(),
|
||||
arity
|
||||
)
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::PStr, pstr_atom) => {
|
||||
let pstr = PartialString::from(pstr_atom);
|
||||
|
||||
write!(
|
||||
f,
|
||||
"pstr ( \"{}\", )",
|
||||
pstr.as_str_from(0)
|
||||
)
|
||||
}
|
||||
(HeapCellValueTag::Cons, c) => {
|
||||
match_untyped_arena_ptr!(c,
|
||||
(ArenaHeaderTag::Integer, n) => {
|
||||
write!(f, "{}", n)
|
||||
}
|
||||
(ArenaHeaderTag::Rational, r) => {
|
||||
write!(f, "{}", r)
|
||||
}
|
||||
(ArenaHeaderTag::F64, fl) => {
|
||||
write!(f, "{}", fl)
|
||||
}
|
||||
(ArenaHeaderTag::Stream, stream) => {
|
||||
write!(f, "$stream({})", stream.as_ptr() as usize)
|
||||
}
|
||||
_ => {
|
||||
write!(f, "")
|
||||
}
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for HeapCellValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
|
||||
match self.get_tag() {
|
||||
tag @ (HeapCellValueTag::Cons | HeapCellValueTag::F64) => {
|
||||
let cons_ptr = ConsPtr::from_bytes(self.into_bytes());
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &tag)
|
||||
.field("ptr", &cons_ptr.ptr())
|
||||
.field("m", &cons_ptr.m())
|
||||
.finish()
|
||||
}
|
||||
HeapCellValueTag::Atom => {
|
||||
let (name, arity) = cell_as_atom_cell!(self)
|
||||
.get_name_and_arity();
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &HeapCellValueTag::Atom)
|
||||
.field("name", &name.as_str())
|
||||
.field("arity", &arity)
|
||||
.field("m", &self.m())
|
||||
.field("f", &self.f())
|
||||
.finish()
|
||||
}
|
||||
HeapCellValueTag::PStr => {
|
||||
let (name, _) = cell_as_atom_cell!(self)
|
||||
.get_name_and_arity();
|
||||
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &HeapCellValueTag::PStr)
|
||||
.field("contents", &name.as_str())
|
||||
.field("m", &self.m())
|
||||
.field("f", &self.f())
|
||||
.finish()
|
||||
}
|
||||
tag => {
|
||||
f.debug_struct("HeapCellValue")
|
||||
.field("tag", &tag)
|
||||
.field("value", &self.get_value())
|
||||
.field("m", &self.get_mark_bit())
|
||||
.field("f", &self.get_forwarding_bit())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<TypedArenaPtr<T>> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
|
||||
HeapCellValue::from(arena_ptr.header_ptr() as u64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<F64Ptr> for HeapCellValue {
|
||||
#[inline]
|
||||
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(
|
||||
ConsPtr::from(f64_ptr.as_ptr() as u64)
|
||||
.with_tag(ConsPtrMaskTag::F64)
|
||||
.with_m(false)
|
||||
.into_bytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConsPtr> for HeapCellValue {
|
||||
#[inline(always)]
|
||||
fn from(cons_ptr: ConsPtr) -> HeapCellValue {
|
||||
HeapCellValue::from_bytes(
|
||||
ConsPtr::from(cons_ptr.as_ptr() as u64)
|
||||
.with_tag(ConsPtrMaskTag::Cons)
|
||||
.with_m(false)
|
||||
.into_bytes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<(Number, &mut Arena)> for HeapCellValue {
|
||||
#[inline(always)]
|
||||
fn from((n, arena): (Number, &mut Arena)) -> HeapCellValue {
|
||||
match n {
|
||||
Number::Float(n) => HeapCellValue::from(arena_alloc!(n, arena)),
|
||||
Number::Integer(n) => HeapCellValue::from(n),
|
||||
Number::Rational(n) => HeapCellValue::from(n),
|
||||
Number::Fixnum(n) => fixnum_as_cell!(n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapCellValue {
|
||||
#[inline(always)]
|
||||
pub fn build_with(tag: HeapCellValueTag, value: u64) -> Self {
|
||||
HeapCellValue::new()
|
||||
.with_tag(tag)
|
||||
.with_val(value)
|
||||
.with_m(false)
|
||||
.with_f(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool {
|
||||
use crate::machine::heap::*;
|
||||
|
||||
loop {
|
||||
return read_heap_cell!(self,
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
name == atom!("[]") && arity == 0
|
||||
}
|
||||
(HeapCellValueTag::CStr) => {
|
||||
true
|
||||
}
|
||||
(HeapCellValueTag::PStrLoc, h) => {
|
||||
self = heap[h];
|
||||
continue;
|
||||
}
|
||||
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
|
||||
let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[h]));
|
||||
|
||||
if cell.is_var() {
|
||||
return false;
|
||||
}
|
||||
|
||||
self = cell;
|
||||
continue;
|
||||
}
|
||||
(HeapCellValueTag::PStrOffset, pstr_offset) => {
|
||||
heap[pstr_offset].get_tag() == HeapCellValueTag::CStr
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_forwarded(self) -> bool {
|
||||
self.get_forwarding_bit().unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_ref(self) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Str | HeapCellValueTag::Lis | HeapCellValueTag::Var |
|
||||
HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::PStrOffset => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_char(self) -> Option<char> {
|
||||
read_heap_cell!(self,
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
Some(c)
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
if arity > 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
name.as_char()
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_constant(self) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 | HeapCellValueTag::Fixnum |
|
||||
HeapCellValueTag::Char | HeapCellValueTag::CStr => {
|
||||
true
|
||||
}
|
||||
HeapCellValueTag::Atom => {
|
||||
cell_as_atom_cell!(self).get_arity() == 0
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_stack_var(self) -> bool {
|
||||
self.get_tag() == HeapCellValueTag::StackVar
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_compound(self) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Str
|
||||
| HeapCellValueTag::Lis
|
||||
| HeapCellValueTag::CStr
|
||||
| HeapCellValueTag::PStr
|
||||
| HeapCellValueTag::PStrLoc
|
||||
| HeapCellValueTag::PStrOffset => {
|
||||
true
|
||||
}
|
||||
HeapCellValueTag::Atom => {
|
||||
cell_as_atom_cell!(self).get_arity() > 0
|
||||
}
|
||||
_ => { false }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_var(self) -> bool {
|
||||
read_heap_cell!(self,
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn as_var(self) -> Option<Ref> {
|
||||
read_heap_cell!(self,
|
||||
(HeapCellValueTag::Var, h) => {
|
||||
Some(Ref::heap_cell(h))
|
||||
}
|
||||
(HeapCellValueTag::AttrVar, h) => {
|
||||
Some(Ref::attr_var(h))
|
||||
}
|
||||
(HeapCellValueTag::StackVar, s) => {
|
||||
Some(Ref::stack_cell(s))
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_value(self) -> usize {
|
||||
self.val() as usize
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_value(&mut self, val: usize) {
|
||||
self.set_val(val as u64);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tag(self) -> HeapCellValueTag {
|
||||
match self.tag_or_err() {
|
||||
Ok(tag) => tag,
|
||||
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
|
||||
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
|
||||
ConsPtrMaskTag::F64 => HeapCellValueTag::F64,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_atom(self) -> Option<Atom> {
|
||||
match self.tag() {
|
||||
HeapCellValueTag::Atom => Some(Atom::from((self.val() << 3) as usize)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_pstr(self) -> Option<PartialString> {
|
||||
match self.tag() {
|
||||
HeapCellValueTag::PStr => {
|
||||
Some(PartialString::from(Atom::from((self.val() as usize) << 3)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_fixnum(self) -> Option<Fixnum> {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Fixnum => Some(Fixnum::from_bytes(self.into_bytes())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_untyped_arena_ptr(self) -> Option<UntypedArenaPtr> {
|
||||
match self.tag() {
|
||||
HeapCellValueTag::Cons => Some(UntypedArenaPtr::from_bytes(self.into_bytes())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_forwarding_bit(self) -> Option<bool> {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
|
||||
| HeapCellValueTag::F64
|
||||
// | HeapCellValueTag::Atom
|
||||
// | HeapCellValueTag::PStr
|
||||
| HeapCellValueTag::Fixnum
|
||||
| HeapCellValueTag::Char => None,
|
||||
_ => Some(self.f()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_forwarding_bit(&mut self, f: bool) {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons // the list of non-forwardable cell tags.
|
||||
| HeapCellValueTag::F64
|
||||
// | HeapCellValueTag::Atom
|
||||
// | HeapCellValueTag::PStr
|
||||
| HeapCellValueTag::Fixnum
|
||||
| HeapCellValueTag::Char => {}
|
||||
_ => self.set_f(f),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mark_bit(self) -> bool {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
|
||||
ConsPtr::from_bytes(self.into_bytes()).m()
|
||||
}
|
||||
_ => self.m(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_mark_bit(&mut self, m: bool) {
|
||||
match self.get_tag() {
|
||||
HeapCellValueTag::Cons | HeapCellValueTag::F64 => {
|
||||
let value = ConsPtr::from_bytes(self.into_bytes()).with_m(m);
|
||||
*self = HeapCellValue::from_bytes(value.into_bytes());
|
||||
}
|
||||
_ => self.set_m(m),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn order_category(self) -> Option<TermOrderCategory> {
|
||||
match Number::try_from(self).ok() {
|
||||
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
|
||||
Some(TermOrderCategory::Integer)
|
||||
}
|
||||
Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
|
||||
None => match self.get_tag() {
|
||||
HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => {
|
||||
Some(TermOrderCategory::Variable)
|
||||
}
|
||||
HeapCellValueTag::Char => Some(TermOrderCategory::Atom),
|
||||
HeapCellValueTag::Atom => {
|
||||
Some(if cell_as_atom_cell!(self).get_arity() > 0 {
|
||||
TermOrderCategory::Compound
|
||||
} else {
|
||||
TermOrderCategory::Atom
|
||||
})
|
||||
}
|
||||
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc |
|
||||
HeapCellValueTag::CStr | HeapCellValueTag::Str => {
|
||||
Some(TermOrderCategory::Compound)
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_protected(self, e: usize) -> bool {
|
||||
read_heap_cell!(self,
|
||||
(HeapCellValueTag::StackVar, s) => {
|
||||
s < e
|
||||
}
|
||||
_ => {
|
||||
true
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<HeapCellValue>() == 8);
|
||||
|
||||
#[bitfield]
|
||||
#[repr(u64)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct UntypedArenaPtr {
|
||||
ptr: B61,
|
||||
m: bool,
|
||||
#[allow(unused)] padding: B2,
|
||||
}
|
||||
|
||||
const_assert!(mem::size_of::<UntypedArenaPtr>() == 8);
|
||||
|
||||
impl From<*const ArenaHeader> for UntypedArenaPtr {
|
||||
#[inline]
|
||||
fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr {
|
||||
unsafe { mem::transmute(ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UntypedArenaPtr> for *const ArenaHeader {
|
||||
#[inline]
|
||||
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
|
||||
unsafe { mem::transmute(ptr) }
|
||||
}
|
||||
}
|
||||
|
||||
impl UntypedArenaPtr {
|
||||
#[inline]
|
||||
pub fn set_mark_bit(&mut self, m: bool) {
|
||||
self.set_m(m);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_ptr(self) -> *const u8 {
|
||||
self.ptr() as *const u8
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_tag(self) -> ArenaHeaderTag {
|
||||
unsafe {
|
||||
let header = *(self.ptr() as *const ArenaHeader);
|
||||
header.get_tag()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn payload_offset(self) -> *const u8 {
|
||||
unsafe {
|
||||
self.get_ptr()
|
||||
.offset(mem::size_of::<ArenaHeader>() as isize)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_mark_bit(self) -> bool {
|
||||
self.m()
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for HeapCellValue {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
fn add(self, rhs: usize) -> Self::Output {
|
||||
match self.get_tag() {
|
||||
tag @ HeapCellValueTag::Str |
|
||||
tag @ HeapCellValueTag::Lis |
|
||||
tag @ HeapCellValueTag::PStrOffset |
|
||||
tag @ HeapCellValueTag::PStrLoc |
|
||||
tag @ HeapCellValueTag::Var |
|
||||
tag @ HeapCellValueTag::AttrVar => {
|
||||
HeapCellValue::build_with(tag, (self.get_value() + rhs) as u64)
|
||||
}
|
||||
_ => {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<usize> for HeapCellValue {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
fn sub(self, rhs: usize) -> Self::Output {
|
||||
match self.get_tag() {
|
||||
tag @ HeapCellValueTag::Str |
|
||||
tag @ HeapCellValueTag::Lis |
|
||||
tag @ HeapCellValueTag::PStrOffset |
|
||||
tag @ HeapCellValueTag::PStrLoc |
|
||||
tag @ HeapCellValueTag::Var |
|
||||
tag @ HeapCellValueTag::AttrVar => {
|
||||
HeapCellValue::build_with(tag, (self.get_value() - rhs) as u64)
|
||||
}
|
||||
_ => {
|
||||
self
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<usize> for HeapCellValue {
|
||||
#[inline(always)]
|
||||
fn sub_assign(&mut self, rhs: usize) {
|
||||
*self = *self - rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<i64> for HeapCellValue {
|
||||
type Output = HeapCellValue;
|
||||
|
||||
fn sub(self, rhs: i64) -> Self::Output {
|
||||
if rhs < 0 {
|
||||
match self.get_tag() {
|
||||
tag @ HeapCellValueTag::Str |
|
||||
tag @ HeapCellValueTag::Lis |
|
||||
tag @ HeapCellValueTag::PStrOffset |
|
||||
tag @ HeapCellValueTag::PStrLoc |
|
||||
tag @ HeapCellValueTag::Var |
|
||||
tag @ HeapCellValueTag::AttrVar => {
|
||||
HeapCellValue::build_with(tag, (self.get_value() + rhs.abs() as usize) as u64)
|
||||
}
|
||||
_ => {
|
||||
self
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.sub(rhs as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
674
src/write.rs
674
src/write.rs
@@ -1,674 +0,0 @@
|
||||
use crate::clause_types::*;
|
||||
use crate::forms::*;
|
||||
use crate::indexing::IndexingCodePtr;
|
||||
use crate::instructions::*;
|
||||
use crate::machine::loader::CompilationTarget;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::machine::machine_indices::*;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
impl fmt::Display for LocalCodePtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
|
||||
LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
|
||||
LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for REPLCodePtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
REPLCodePtr::AddDiscontiguousPredicate =>
|
||||
write!(f, "REPLCodePtr::AddDiscontiguousPredicate"),
|
||||
REPLCodePtr::AddDynamicPredicate =>
|
||||
write!(f, "REPLCodePtr::AddDynamicPredicate"),
|
||||
REPLCodePtr::AddMultifilePredicate =>
|
||||
write!(f, "REPLCodePtr::AddMultifilePredicate"),
|
||||
REPLCodePtr::AddGoalExpansionClause =>
|
||||
write!(f, "REPLCodePtr::AddGoalExpansionClause"),
|
||||
REPLCodePtr::AddTermExpansionClause =>
|
||||
write!(f, "REPLCodePtr::AddTermExpansionClause"),
|
||||
REPLCodePtr::AddInSituFilenameModule =>
|
||||
write!(f, "REPLCodePtr::AddInSituFilenameModule"),
|
||||
REPLCodePtr::AbolishClause =>
|
||||
write!(f, "REPLCodePtr::AbolishClause"),
|
||||
REPLCodePtr::Assertz =>
|
||||
write!(f, "REPLCodePtr::Assertz"),
|
||||
REPLCodePtr::Asserta =>
|
||||
write!(f, "REPLCodePtr::Asserta"),
|
||||
REPLCodePtr::Retract =>
|
||||
write!(f, "REPLCodePtr::Retract"),
|
||||
REPLCodePtr::ClauseToEvacuable =>
|
||||
write!(f, "REPLCodePtr::ClauseToEvacuable"),
|
||||
REPLCodePtr::ScopedClauseToEvacuable =>
|
||||
write!(f, "REPLCodePtr::ScopedClauseToEvacuable"),
|
||||
REPLCodePtr::ConcludeLoad =>
|
||||
write!(f, "REPLCodePtr::ConcludeLoad"),
|
||||
REPLCodePtr::DeclareModule =>
|
||||
write!(f, "REPLCodePtr::DeclareModule"),
|
||||
REPLCodePtr::LoadCompiledLibrary =>
|
||||
write!(f, "REPLCodePtr::LoadCompiledLibrary"),
|
||||
REPLCodePtr::LoadContextSource =>
|
||||
write!(f, "REPLCodePtr::LoadContextSource"),
|
||||
REPLCodePtr::LoadContextFile =>
|
||||
write!(f, "REPLCodePtr::LoadContextFile"),
|
||||
REPLCodePtr::LoadContextDirectory =>
|
||||
write!(f, "REPLCodePtr::LoadContextDirectory"),
|
||||
REPLCodePtr::LoadContextModule =>
|
||||
write!(f, "REPLCodePtr::LoadContextModule"),
|
||||
REPLCodePtr::LoadContextStream =>
|
||||
write!(f, "REPLCodePtr::LoadContextStream"),
|
||||
REPLCodePtr::PopLoadContext =>
|
||||
write!(f, "REPLCodePtr::PopLoadContext"),
|
||||
REPLCodePtr::PopLoadStatePayload =>
|
||||
write!(f, "REPLCodePtr::PopLoadStatePayload"),
|
||||
REPLCodePtr::PushLoadContext =>
|
||||
write!(f, "REPLCodePtr::PushLoadContext"),
|
||||
REPLCodePtr::PushLoadStatePayload =>
|
||||
write!(f, "REPLCodePtr::PushLoadStatePayload"),
|
||||
REPLCodePtr::UseModule =>
|
||||
write!(f, "REPLCodePtr::UseModule"),
|
||||
REPLCodePtr::MetaPredicateProperty =>
|
||||
write!(f, "REPLCodePtr::MetaPredicateProperty"),
|
||||
REPLCodePtr::BuiltInProperty =>
|
||||
write!(f, "REPLCodePtr::BuiltInProperty"),
|
||||
REPLCodePtr::DynamicProperty =>
|
||||
write!(f, "REPLCodePtr::DynamicProperty"),
|
||||
REPLCodePtr::MultifileProperty =>
|
||||
write!(f, "REPLCodePtr::MultifileProperty"),
|
||||
REPLCodePtr::DiscontiguousProperty =>
|
||||
write!(f, "REPLCodePtr::DiscontiguousProperty"),
|
||||
REPLCodePtr::IsConsistentWithTermQueue =>
|
||||
write!(f, "REPLCodePtr::IsConsistentWithTermQueue"),
|
||||
REPLCodePtr::FlushTermQueue =>
|
||||
write!(f, "REPLCodePtr::FlushTermQueue"),
|
||||
REPLCodePtr::RemoveModuleExports =>
|
||||
write!(f, "REPLCodePtr::RemoveModuleExports"),
|
||||
REPLCodePtr::AddNonCountedBacktracking =>
|
||||
write!(f, "REPLCodePtr::AddNonCountedBacktracking"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IndexPtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&IndexPtr::DynamicUndefined => write!(f, "undefined"),
|
||||
&IndexPtr::Undefined => write!(f, "undefined"),
|
||||
&IndexPtr::DynamicIndex(i) | &IndexPtr::Index(i) => write!(f, "{}", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompilationTarget {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
CompilationTarget::User => write!(f, "user"),
|
||||
CompilationTarget::Module(ref module_name) => write!(f, "{}", module_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for FactInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&FactInstruction::GetConstant(lvl, ref constant, ref r) => {
|
||||
write!(f, "get_constant {}, {}{}", constant, lvl, r.reg_num())
|
||||
}
|
||||
&FactInstruction::GetList(lvl, ref r) => {
|
||||
write!(f, "get_list {}{}", lvl, r.reg_num())
|
||||
}
|
||||
&FactInstruction::GetPartialString(lvl, ref s, r, has_tail) => {
|
||||
write!(f, "get_partial_string({}, {}, {}, {})",
|
||||
lvl, s, r, has_tail)
|
||||
}
|
||||
&FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
|
||||
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
|
||||
}
|
||||
&FactInstruction::GetValue(ref x, ref a) => {
|
||||
write!(f, "get_value {}, A{}", x, a)
|
||||
}
|
||||
&FactInstruction::GetVariable(ref x, ref a) => {
|
||||
write!(f, "fact:get_variable {}, A{}", x, a)
|
||||
}
|
||||
&FactInstruction::UnifyConstant(ref constant) => {
|
||||
write!(f, "unify_constant {}", constant)
|
||||
}
|
||||
&FactInstruction::UnifyVariable(ref r) => {
|
||||
write!(f, "unify_variable {}", r)
|
||||
}
|
||||
&FactInstruction::UnifyLocalValue(ref r) => {
|
||||
write!(f, "unify_local_value {}", r)
|
||||
}
|
||||
&FactInstruction::UnifyValue(ref r) => {
|
||||
write!(f, "unify_value {}", r)
|
||||
}
|
||||
&FactInstruction::UnifyVoid(n) => {
|
||||
write!(f, "unify_void {}", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for QueryInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&QueryInstruction::GetVariable(ref x, ref a) => {
|
||||
write!(f, "query:get_variable {}, A{}", x, a)
|
||||
}
|
||||
&QueryInstruction::PutConstant(lvl, ref constant, ref r) => {
|
||||
write!(f, "put_constant {}, {}{}", constant, lvl, r.reg_num())
|
||||
}
|
||||
&QueryInstruction::PutList(lvl, ref r) => {
|
||||
write!(f, "put_list {}{}", lvl, r.reg_num())
|
||||
}
|
||||
&QueryInstruction::PutPartialString(lvl, ref s, r, has_tail) => {
|
||||
write!(f, "put_partial_string({}, {}, {}, {})",
|
||||
lvl, s, r, has_tail)
|
||||
}
|
||||
&QueryInstruction::PutStructure(ref ct, ref arity, ref r) => {
|
||||
write!(f, "put_structure {}/{}, {}", ct.name(), arity, r)
|
||||
}
|
||||
&QueryInstruction::PutUnsafeValue(y, a) => write!(f, "put_unsafe_value Y{}, A{}", y, a),
|
||||
&QueryInstruction::PutValue(ref x, ref a) => write!(f, "put_value {}, A{}", x, a),
|
||||
&QueryInstruction::PutVariable(ref x, ref a) => write!(f, "put_variable {}, A{}", x, a),
|
||||
&QueryInstruction::SetConstant(ref constant) => write!(f, "set_constant {}", constant),
|
||||
&QueryInstruction::SetLocalValue(ref r) => write!(f, "set_local_value {}", r),
|
||||
&QueryInstruction::SetVariable(ref r) => write!(f, "set_variable {}", r),
|
||||
&QueryInstruction::SetValue(ref r) => write!(f, "set_value {}", r),
|
||||
&QueryInstruction::SetVoid(n) => write!(f, "set_void {}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompareNumberQT {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CompareNumberQT::GreaterThan => write!(f, ">"),
|
||||
&CompareNumberQT::GreaterThanOrEqual => write!(f, ">="),
|
||||
&CompareNumberQT::LessThan => write!(f, "<"),
|
||||
&CompareNumberQT::LessThanOrEqual => write!(f, "<="),
|
||||
&CompareNumberQT::NotEqual => write!(f, "=\\="),
|
||||
&CompareNumberQT::Equal => write!(f, "=:="),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompareTermQT {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CompareTermQT::GreaterThan => write!(f, "@>"),
|
||||
&CompareTermQT::GreaterThanOrEqual => write!(f, "@>="),
|
||||
&CompareTermQT::LessThan => write!(f, "@<"),
|
||||
&CompareTermQT::LessThanOrEqual => write!(f, "@<="),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ClauseType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
|
||||
write!(f, "$set_cp({})", r)
|
||||
}
|
||||
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
|
||||
let idx = idx.0.get();
|
||||
write!(f, "{}/{}", name, idx)
|
||||
}
|
||||
ref ct => {
|
||||
write!(f, "{}", ct.name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HeapCellValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&HeapCellValue::Addr(ref addr) => write!(f, "{}", addr),
|
||||
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
|
||||
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
|
||||
&HeapCellValue::Integer(ref n) => write!(f, "{}", n),
|
||||
&HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
|
||||
&HeapCellValue::Rational(ref n) => write!(f, "{}", n),
|
||||
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
|
||||
f,
|
||||
"{}/{} (op, priority: {}, spec: {})",
|
||||
name.as_str(),
|
||||
arity,
|
||||
cell.prec(),
|
||||
cell.assoc()
|
||||
),
|
||||
&HeapCellValue::NamedStr(arity, ref name, None) => {
|
||||
write!(f, "{}/{}", name.as_str(), arity)
|
||||
}
|
||||
&HeapCellValue::PartialString(ref pstr, has_tail) => {
|
||||
write!(
|
||||
f,
|
||||
"pstr ( buf: \"{}\", has_tail({}) )",
|
||||
pstr.as_str_from(0),
|
||||
has_tail,
|
||||
)
|
||||
}
|
||||
&HeapCellValue::Stream(ref stream) => {
|
||||
write!(f, "$stream({})", stream.as_ptr() as usize)
|
||||
}
|
||||
&HeapCellValue::TcpListener(ref tcp_listener) => {
|
||||
write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DBRef {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity),
|
||||
&DBRef::Op(priority, spec, ref name, ..) => {
|
||||
write!(f, "db_ref:op({}, {}, {})", priority, spec, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Addr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Addr::Char(c) => write!(f, "Addr::Char({})", c),
|
||||
&Addr::EmptyList => write!(f, "Addr::EmptyList"),
|
||||
&Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n),
|
||||
&Addr::Float(fl) => write!(f, "Addr::Float({})", fl),
|
||||
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
|
||||
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
|
||||
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
|
||||
&Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s),
|
||||
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
|
||||
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
|
||||
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
|
||||
&Addr::Str(s) => write!(f, "Addr::Str({})", s),
|
||||
&Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
|
||||
&Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream),
|
||||
&Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener),
|
||||
&Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ControlInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ControlInstruction::Allocate(num_cells) => write!(f, "allocate {}", num_cells),
|
||||
&ControlInstruction::CallClause(ref ct, arity, pvs, true, true) => {
|
||||
write!(f, "call_with_default_policy {}/{}, {}", ct, arity, pvs)
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, pvs, false, true) => {
|
||||
write!(f, "execute_with_default_policy {}/{}, {}", ct, arity, pvs)
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, pvs, true, false) => {
|
||||
write!(f, "execute {}/{}, {}", ct, arity, pvs)
|
||||
}
|
||||
&ControlInstruction::CallClause(ref ct, arity, pvs, false, false) => {
|
||||
write!(f, "call {}/{}, {}", ct, arity, pvs)
|
||||
}
|
||||
&ControlInstruction::Deallocate => write!(f, "deallocate"),
|
||||
&ControlInstruction::JmpBy(arity, offset, pvs, false) => {
|
||||
write!(f, "jmp_by_call {}/{}, {}", offset, arity, pvs)
|
||||
}
|
||||
&ControlInstruction::JmpBy(arity, offset, pvs, true) => {
|
||||
write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs)
|
||||
}
|
||||
&ControlInstruction::RevJmpBy(offset) => {
|
||||
write!(f, "rev_jmp_by {}", offset)
|
||||
}
|
||||
&ControlInstruction::Proceed => write!(f, "proceed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IndexedChoiceInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&IndexedChoiceInstruction::Try(offset) => write!(f, "try {}", offset),
|
||||
&IndexedChoiceInstruction::Retry(offset) => write!(f, "retry {}", offset),
|
||||
&IndexedChoiceInstruction::Trust(offset) => write!(f, "trust {}", offset),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ChoiceInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
|
||||
write!(f, "dynamic_else {}, {}, {}", offset, "inf", i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
write!(f, "dynamic_else {}, {}, fail({})", offset, "inf", i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
write!(f, "dynamic_else {}, {}, {}", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
write!(f, "dynamic_else {}, {}, fail({})", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Next(i)) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, {}", offset, "inf", i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Infinity, NextOrFail::Fail(i)) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, "inf", i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Next(i)) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, {}", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::DynamicInternalElse(offset, Death::Finite(d), NextOrFail::Fail(i)) => {
|
||||
write!(f, "dynamic_internal_else {}, {}, fail({})", offset, d, i)
|
||||
}
|
||||
&ChoiceInstruction::TryMeElse(offset) =>
|
||||
write!(f, "try_me_else {}", offset),
|
||||
&ChoiceInstruction::DefaultRetryMeElse(offset) => {
|
||||
write!(f, "retry_me_else_by_default {}", offset)
|
||||
}
|
||||
&ChoiceInstruction::RetryMeElse(offset) =>
|
||||
write!(f, "retry_me_else {}", offset),
|
||||
&ChoiceInstruction::DefaultTrustMe(_) =>
|
||||
write!(f, "trust_me_by_default"),
|
||||
&ChoiceInstruction::TrustMe(_) =>
|
||||
write!(f, "trust_me"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IndexingCodePtr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&IndexingCodePtr::DynamicExternal(o) => {
|
||||
write!(f, "IndexingCodePtr::DynamicExternal({})", o)
|
||||
}
|
||||
&IndexingCodePtr::External(o) => {
|
||||
write!(f, "IndexingCodePtr::External({})", o)
|
||||
}
|
||||
&IndexingCodePtr::Fail => {
|
||||
write!(f, "IndexingCodePtr::Fail")
|
||||
}
|
||||
&IndexingCodePtr::Internal(o) => {
|
||||
write!(f, "IndexingCodePtr::Internal({})", o)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IndexingInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
|
||||
write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
|
||||
}
|
||||
&IndexingInstruction::SwitchOnConstant(ref constants) => {
|
||||
write!(f, "switch_on_constant {}", constants.len())
|
||||
}
|
||||
&IndexingInstruction::SwitchOnStructure(ref structures) => {
|
||||
write!(f, "switch_on_structure {}", structures.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SessionError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&SessionError::ExistenceError(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
}
|
||||
// &SessionError::CannotOverwriteBuiltIn(ref msg) => {
|
||||
// write!(f, "cannot overwrite {}", msg)
|
||||
// }
|
||||
// &SessionError::CannotOverwriteImport(ref msg) => {
|
||||
// write!(f, "cannot overwrite import {}", msg)
|
||||
// }
|
||||
// &SessionError::InvalidFileName(ref filename) => {
|
||||
// write!(f, "filename {} is invalid", filename)
|
||||
// }
|
||||
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
|
||||
write!(
|
||||
f,
|
||||
"module {} does not contain claimed export {}/{}",
|
||||
module,
|
||||
key.0,
|
||||
key.1,
|
||||
)
|
||||
}
|
||||
&SessionError::OpIsInfixAndPostFix(_) => {
|
||||
write!(f, "cannot define an op to be both postfix and infix.")
|
||||
}
|
||||
&SessionError::NamelessEntry => {
|
||||
write!(f, "the predicate head is not an atom or clause.")
|
||||
}
|
||||
&SessionError::CompilationError(ref e) => {
|
||||
write!(f, "syntax_error({:?})", e)
|
||||
}
|
||||
&SessionError::QueryCannotBeDefinedAsFact => {
|
||||
write!(f, "queries cannot be defined as facts.")
|
||||
}
|
||||
&SessionError::ModuleCannotImportSelf(ref module_name) => {
|
||||
write!(f, "modules ({}, in this case) cannot import themselves.",
|
||||
module_name)
|
||||
}
|
||||
&SessionError::PredicateNotMultifileOrDiscontiguous(ref compilation_target, ref key) => {
|
||||
write!(f, "module {} does not define {}/{} as multifile or discontiguous.",
|
||||
compilation_target.module_name(), key.0, key.1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExistenceError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ExistenceError::Module(ref module_name) => {
|
||||
write!(f, "the module {} does not exist", module_name)
|
||||
}
|
||||
&ExistenceError::ModuleSource(ref module_source) => {
|
||||
write!(f, "the source/sink {} does not exist", module_source)
|
||||
}
|
||||
&ExistenceError::Procedure(ref name, arity) => {
|
||||
write!(f, "the procedure {}/{} does not exist", name, arity)
|
||||
}
|
||||
&ExistenceError::SourceSink(ref addr) => {
|
||||
write!(f, "the source/sink {} does not exist", addr)
|
||||
}
|
||||
&ExistenceError::Stream(ref addr) => {
|
||||
write!(f, "the stream at {} does not exist", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ModuleSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ModuleSource::File(ref file) => {
|
||||
write!(f, "at the file {}", file)
|
||||
}
|
||||
&ModuleSource::Library(ref library) => {
|
||||
write!(f, "at library({})", library)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IndexingLine {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&IndexingLine::Indexing(ref indexing_instr) => {
|
||||
write!(f, "{}", indexing_instr)
|
||||
}
|
||||
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
|
||||
for indexed_choice_instr in indexed_choice_instrs {
|
||||
write!(f, "{}", indexed_choice_instr)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
&IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
|
||||
for indexed_choice_instr in indexed_choice_instrs {
|
||||
write!(f, "dynamic({})", indexed_choice_instr)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Line {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Line::Arithmetic(ref arith_instr) => write!(f, "{}", arith_instr),
|
||||
&Line::Choice(ref choice_instr) => write!(f, "{}", choice_instr),
|
||||
&Line::Control(ref control_instr) => write!(f, "{}", control_instr),
|
||||
&Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr),
|
||||
&Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr),
|
||||
&Line::IndexingCode(ref indexing_instrs) => {
|
||||
for indexing_instr in indexing_instrs {
|
||||
write!(f, "{}", indexing_instr)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
&Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
|
||||
&Line::DynamicIndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
|
||||
&Line::Query(ref query_instr) => write!(f, "{}", query_instr),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Number {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Number::Fixnum(n) => write!(f, "{}", n),
|
||||
&Number::Float(fl) => write!(f, "{}", fl),
|
||||
&Number::Integer(ref bi) => write!(f, "{}", bi),
|
||||
&Number::Rational(ref r) => write!(f, "{}", r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ArithmeticTerm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ArithmeticTerm::Reg(r) => write!(f, "{}", r),
|
||||
&ArithmeticTerm::Interm(i) => write!(f, "@{}", i),
|
||||
&ArithmeticTerm::Number(ref n) => write!(f, "{}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ArithmeticInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&ArithmeticInstruction::Abs(ref a1, ref t) => write!(f, "abs {}, @{}", a1, t),
|
||||
&ArithmeticInstruction::Add(ref a1, ref a2, ref t) => {
|
||||
write!(f, "add {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Sub(ref a1, ref a2, ref t) => {
|
||||
write!(f, "sub {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Mul(ref a1, ref a2, ref t) => {
|
||||
write!(f, "mul {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Pow(ref a1, ref a2, ref t) => {
|
||||
write!(f, "** {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::IntPow(ref a1, ref a2, ref t) => {
|
||||
write!(f, "^ {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Div(ref a1, ref a2, ref t) => {
|
||||
write!(f, "div {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::IDiv(ref a1, ref a2, ref t) => {
|
||||
write!(f, "idiv {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Max(ref a1, ref a2, ref t) => {
|
||||
write!(f, "max {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Min(ref a1, ref a2, ref t) => {
|
||||
write!(f, "min {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, ref t) => {
|
||||
write!(f, "int_floor_div {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => {
|
||||
write!(f, "rdiv {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Gcd(ref a1, ref a2, ref t) => {
|
||||
write!(f, "gcd {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => {
|
||||
write!(f, "shl {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Shr(ref a1, ref a2, ref t) => {
|
||||
write!(f, "shr {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Xor(ref a1, ref a2, ref t) => {
|
||||
write!(f, "xor {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::And(ref a1, ref a2, ref t) => {
|
||||
write!(f, "and {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Or(ref a1, ref a2, ref t) => {
|
||||
write!(f, "or {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Mod(ref a1, ref a2, ref t) => {
|
||||
write!(f, "mod {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Rem(ref a1, ref a2, ref t) => {
|
||||
write!(f, "rem {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::ATan2(ref a1, ref a2, ref t) => {
|
||||
write!(f, "atan2 {}, {}, @{}", a1, a2, t)
|
||||
}
|
||||
&ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Sign(ref a, ref t) => write!(f, "sign {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Tan(ref a, ref t) => write!(f, "tan {}, @{}", a, t),
|
||||
&ArithmeticInstruction::ATan(ref a, ref t) => write!(f, "atan {}, @{}", a, t),
|
||||
&ArithmeticInstruction::ASin(ref a, ref t) => write!(f, "asin {}, @{}", a, t),
|
||||
&ArithmeticInstruction::ACos(ref a, ref t) => write!(f, "acos {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Log(ref a, ref t) => write!(f, "log {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Exp(ref a, ref t) => write!(f, "exp {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Sqrt(ref a, ref t) => write!(f, "sqrt {}, @{}", a, t),
|
||||
&ArithmeticInstruction::BitwiseComplement(ref a, ref t) => {
|
||||
write!(f, "bitwise_complement {}, @{}", a, t)
|
||||
}
|
||||
&ArithmeticInstruction::Truncate(ref a, ref t) => write!(f, "truncate {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Round(ref a, ref t) => write!(f, "round {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Ceiling(ref a, ref t) => write!(f, "ceiling {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Floor(ref a, ref t) => write!(f, "floor {}, @{}", a, t),
|
||||
&ArithmeticInstruction::Float(ref a, ref t) => write!(f, "float {}, @{}", a, t),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CutInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&CutInstruction::Cut(r) => write!(f, "cut {}", r),
|
||||
&CutInstruction::NeckCut => write!(f, "neck_cut"),
|
||||
&CutInstruction::GetLevel(r) => write!(f, "get_level {}", r),
|
||||
&CutInstruction::GetLevelAndUnify(r) => write!(f, "get_level_and_unify {}", r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Level {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Level::Root | &Level::Shallow => write!(f, "A"),
|
||||
&Level::Deep => write!(f, "X"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user