Merge pull request #3021 from mthom/rebis-dev

Merge rebis-dev to master
This commit is contained in:
Mark Thom
2025-08-02 00:01:39 -07:00
committed by GitHub
71 changed files with 10768 additions and 8165 deletions
+4 -3
View File
@@ -2,7 +2,9 @@ name: CI
on:
push:
branches: [master]
branches:
- master
- rebis-dev
tags:
- "v**"
pull_request:
@@ -47,8 +49,7 @@ jobs:
# FIXME(issue #2138): run wasm tests, failing to run since https://github.com/mthom/scryer-prolog/pull/2137 removed wasm-pack
- { os: ubuntu-22.04, rust-version: nightly, target: 'wasm32-unknown-unknown', publish: true, args: '--no-default-features' , test-args: '--no-run --no-default-features', use_swap: true }
# Cargo.toml rust-version
- { os: ubuntu-22.04, rust-version: "1.85", target: 'x86_64-unknown-linux-gnu'}
# rust versions
- { os: ubuntu-22.04, rust-version: "1.87", target: 'x86_64-unknown-linux-gnu'}
- { os: ubuntu-22.04, rust-version: beta, target: 'x86_64-unknown-linux-gnu'}
- { os: ubuntu-22.04, rust-version: nightly, target: 'x86_64-unknown-linux-gnu', miri: true, components: "miri"}
defaults:
Generated
+7 -6
View File
@@ -1673,9 +1673,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "lock_api"
version = "0.4.12"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
@@ -2011,9 +2011,9 @@ dependencies = [
[[package]]
name = "parking_lot"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -2021,9 +2021,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
version = "0.9.10"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
@@ -2712,6 +2712,7 @@ dependencies = [
"num-order",
"ordered-float",
"ouroboros",
"parking_lot",
"phf",
"pprof",
"proc-macro2",
+3 -1
View File
@@ -11,7 +11,7 @@ keywords = ["prolog", "prolog-interpreter", "prolog-system"]
categories = ["command-line-utilities"]
build = "build/main.rs"
# Remember to check CI
rust-version = "1.85"
rust-version = "1.87"
[lib]
crate-type = ["cdylib", "rlib"]
@@ -79,6 +79,7 @@ ego-tree = "0.10.0"
serde_json = "1.0.122"
serde = "1.0.204"
parking_lot = "0.12.4"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
crossterm = { version = "0.28.1", optional = true }
@@ -136,6 +137,7 @@ opt-level = 3
[profile.release]
lto = true
opt-level = 3
debug = 2
[profile.wasm-dev]
inherits = "dev"
+1 -1
View File
@@ -72,7 +72,7 @@ Extend Scryer Prolog to include the following, among other features:
(`atom`, `var`, etc) with if/else ladders. (_in progress_)
- [ ] Inlining all built-ins and system call instructions.
- [x] Greatly reducing the number of instructions used to compile disjunctives.
- [ ] Storing short atoms to heap cells without writing them to the atom table.
- [x] Storing short atoms to heap cells without writing them to the atom table.
- [ ] A compacting garbage collector satisfying the five properties of
"[Precise Garbage Collection in Prolog](https://www.complang.tuwien.ac.at/ulrich/papers/PDF/2008-ciclops.pdf)." (_in progress_)
- [ ] Mode declarations.
+185 -237
View File
@@ -19,6 +19,7 @@ use to_syn_value_derive::ToDeriveInput;
*/
use std::any::*;
use std::rc::Rc;
use std::str::FromStr;
struct ArithmeticTerm;
@@ -28,6 +29,7 @@ struct Death;
struct HeapCellValue;
struct IndexingLine;
struct Level;
// struct Literal;
struct NextOrFail;
struct RegType;
@@ -535,6 +537,16 @@ enum SystemClauseType {
UnsetEnv,
#[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))]
Shell,
#[strum_discriminants(strum(props(Arity = "8", Name = "$process_create")))]
ProcessCreate,
#[strum_discriminants(strum(props(Arity = "2", Name = "$process_id")))]
ProcessId,
#[strum_discriminants(strum(props(Arity = "3", Name = "$process_wait")))]
ProcessWait,
#[strum_discriminants(strum(props(Arity = "1", Name = "$process_kill")))]
ProcessKill,
#[strum_discriminants(strum(props(Arity = "1", Name = "$process_release")))]
ProcessRelease,
#[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))]
Pid,
#[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))]
@@ -622,7 +634,7 @@ enum InstructionTemplate {
#[strum_discriminants(strum(props(Arity = "2", Name = "get_list")))]
GetList(Level, RegType),
#[strum_discriminants(strum(props(Arity = "4", Name = "get_partial_string")))]
GetPartialString(Level, Atom, RegType, bool),
GetPartialString(Level, Rc<String>, RegType),
#[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))]
GetStructure(Level, Atom, usize, RegType),
#[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
@@ -645,7 +657,7 @@ enum InstructionTemplate {
#[strum_discriminants(strum(props(Arity = "2", Name = "put_list")))]
PutList(Level, RegType),
#[strum_discriminants(strum(props(Arity = "4", Name = "put_partial_string")))]
PutPartialString(Level, Atom, RegType, bool),
PutPartialString(Level, Rc<String>, RegType),
#[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))]
PutStructure(Atom, usize, RegType),
#[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))]
@@ -875,6 +887,7 @@ fn generate_instruction_preface() -> TokenStream {
use crate::arithmetic::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::functor_macro::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_indices::CodeIndex;
@@ -885,6 +898,7 @@ fn generate_instruction_preface() -> TokenStream {
use indexmap::IndexMap;
use std::collections::VecDeque;
use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub {
match r {
@@ -896,9 +910,9 @@ fn generate_instruction_preface() -> TokenStream {
impl Level {
fn into_functor(self) -> MachineStub {
match self {
Level::Root => functor!(atom!("level"), [atom(atom!("root"))]),
Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]),
Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]),
Level::Root => functor!(atom!("level"), [atom_as_cell((atom!("root")))]),
Level::Shallow => functor!(atom!("level"), [atom_as_cell((atom!("shallow")))]),
Level::Deep => functor!(atom!("level"), [atom_as_cell((atom!("deep")))]),
}
}
}
@@ -911,7 +925,7 @@ fn generate_instruction_preface() -> TokenStream {
functor!(atom!("intermediate"), [fixnum(i)])
}
ArithmeticTerm::Number(n) => {
vec![HeapCellValue::from((n, arena))]
functor!(atom!("number"), [number(n, arena)])
}
}
}
@@ -996,7 +1010,7 @@ fn generate_instruction_preface() -> TokenStream {
IndexingCodePtr,
IndexingCodePtr,
),
SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
SwitchOnConstant(IndexMap<HeapCellValue, IndexingCodePtr, FxBuildHasher>),
SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
}
@@ -1016,7 +1030,7 @@ fn generate_instruction_preface() -> TokenStream {
IndexingCodePtr::External(o) => functor!(atom!("external"), [fixnum(o)]),
IndexingCodePtr::Internal(o) => functor!(atom!("internal"), [fixnum(o)]),
IndexingCodePtr::Fail => {
vec![atom_as_cell!(atom!("fail"))]
functor!(atom!("fail"))
},
}
}
@@ -1030,80 +1044,43 @@ fn generate_instruction_preface() -> TokenStream {
}
impl IndexingInstruction {
pub fn to_functor(&self, mut h: usize) -> MachineStub {
pub fn to_functor(&self) -> MachineStub {
match self {
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
functor!(
atom!("switch_on_term"),
[
fixnum(arg),
indexing_code_ptr(h, vars),
indexing_code_ptr(h, constants),
indexing_code_ptr(h, lists),
indexing_code_ptr(h, structures)
indexing_code_ptr(vars),
indexing_code_ptr(constants),
indexing_code_ptr(lists),
indexing_code_ptr(structures)
]
)
}
IndexingInstruction::SwitchOnConstant(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!(
atom!(":"),
[literal(*c), indexing_code_ptr(h + 3, *ptr)]
);
key_value_list_stub.push(list_loc_as_cell!(h + 1));
key_value_list_stub.push(str_loc_as_cell!(h + 3));
key_value_list_stub.push(heap_loc_as_cell!(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(empty_list_as_cell!());
variadic_functor(
atom!("switch_on_constants"),
1,
constants.iter().map(|(c, ptr)| {
functor!(
atom!("switch_on_constant"),
[str(orig_h, 0)],
[key_value_list_stub]
atom!(":"),
[cell((*c)), indexing_code_ptr((*ptr))]
)
}),
)
}
IndexingInstruction::SwitchOnStructure(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!(
atom!("/"),
[atom(name), fixnum(*arity)]
);
let key_value_pair = functor!(
atom!(":"),
[str(h + 3, 0), indexing_code_ptr(h + 3, *ptr)],
[predicate_indicator_stub]
);
key_value_list_stub.push(list_loc_as_cell!(h + 1));
key_value_list_stub.push(str_loc_as_cell!(h + 3));
key_value_list_stub.push(heap_loc_as_cell!(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(empty_list_as_cell!());
functor!(
variadic_functor(
atom!("switch_on_structure"),
[str(orig_h, 0)],
[key_value_list_stub]
1,
structures.iter().map(|((name, arity), ptr)| {
functor!(
atom!(":"),
[functor((atom!("/")), [atom_as_cell(name), fixnum((*arity))]),
indexing_code_ptr((*ptr))]
)
}),
)
}
}
@@ -1133,18 +1110,16 @@ fn generate_instruction_preface() -> TokenStream {
}
fn arith_instr_unary_functor(
h: usize,
name: Atom,
arena: &mut Arena,
at: &ArithmeticTerm,
t: usize,
) -> MachineStub {
let at_stub = at.into_functor(arena);
functor!(name, [str(h, 0), fixnum(t)], [at_stub])
functor!(name, [functor(at_stub), fixnum(t)])
}
fn arith_instr_bin_functor(
h: usize,
name: Atom,
arena: &mut Arena,
at_1: &ArithmeticTerm,
@@ -1154,11 +1129,9 @@ fn generate_instruction_preface() -> TokenStream {
let at_1_stub = at_1.into_functor(arena);
let at_2_stub = at_2.into_functor(arena);
functor!(
name,
[str(h, 0), str(h, 1), fixnum(t)],
[at_1_stub, at_2_stub]
)
functor!(name, [functor(at_1_stub),
functor(at_2_stub),
fixnum(t)])
}
pub type Code = Vec<Instruction>;
@@ -1170,7 +1143,7 @@ fn generate_instruction_preface() -> TokenStream {
match *self {
Instruction::GetConstant(_, _, r) => vec![r],
Instruction::GetList(_, r) => vec![r],
Instruction::GetPartialString(_, _, r, _) => vec![r],
Instruction::GetPartialString(_, _, r) => vec![r],
Instruction::GetStructure(_, _, _, r) => vec![r],
Instruction::GetVariable(r, t) => vec![r, temp_v!(t)],
Instruction::GetValue(r, t) => vec![r, temp_v!(t)],
@@ -1178,7 +1151,7 @@ fn generate_instruction_preface() -> TokenStream {
Instruction::UnifyVariable(r) => vec![r],
Instruction::PutConstant(_, _, r) => vec![r],
Instruction::PutList(_, r) => vec![r],
Instruction::PutPartialString(_, _, r, _) => vec![r],
Instruction::PutPartialString(_, _, r) => vec![r],
Instruction::PutStructure(_, _, r) => vec![r],
Instruction::PutValue(r, t) => vec![r, temp_v!(t)],
Instruction::PutVariable(r, t) => vec![r, temp_v!(t)],
@@ -1242,7 +1215,6 @@ fn generate_instruction_preface() -> TokenStream {
pub fn enqueue_functors(
&self,
mut h: usize,
arena: &mut Arena,
functors: &mut Vec<MachineStub>,
) {
@@ -1251,33 +1223,30 @@ fn generate_instruction_preface() -> TokenStream {
for indexing_instr in indexing_instrs {
match indexing_instr {
IndexingLine::Indexing(indexing_instr) => {
let section = indexing_instr.to_functor(h);
h += section.len();
let section = indexing_instr.to_functor();
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!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]);
h += section.len();
let section = functor!(atom!("dynamic"),
[fixnum((*indexed_choice_instr))]);
functors.push(section);
}
}
}
}
}
instr => functors.push(instr.to_functor(h, arena)),
instr => functors.push(instr.to_functor(arena)),
}
}
fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub {
fn to_functor(&self, arena: &mut Arena) -> MachineStub {
match self {
&Instruction::InstallVerifyAttr => {
functor!(atom!("install_verify_attr"))
@@ -1290,25 +1259,23 @@ fn generate_instruction_preface() -> TokenStream {
(Death::Infinity, NextOrFail::Next(i)) => {
functor!(
atom!("dynamic_else"),
[fixnum(birth), atom(atom!("inf")), fixnum(i)]
[fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)]
)
}
(Death::Infinity, NextOrFail::Fail(i)) => {
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
functor!(
atom!("dynamic_else"),
[fixnum(birth), atom(atom!("inf")), str(h, 0)],
[next_functor]
[fixnum(birth),
atom_as_cell((atom!("inf"))),
functor((atom!("fail")), [fixnum(i)])]
)
}
(Death::Finite(d), NextOrFail::Fail(i)) => {
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
functor!(
atom!("dynamic_else"),
[fixnum(birth), fixnum(d), str(h, 0)],
[next_functor]
[fixnum(birth),
fixnum(d),
functor((atom!("fail")), [fixnum(i)])]
)
}
(Death::Finite(d), NextOrFail::Next(i)) => {
@@ -1321,25 +1288,23 @@ fn generate_instruction_preface() -> TokenStream {
(Death::Infinity, NextOrFail::Next(i)) => {
functor!(
atom!("dynamic_internal_else"),
[fixnum(birth), atom(atom!("inf")), fixnum(i)]
[fixnum(birth), atom_as_cell((atom!("inf"))), fixnum(i)]
)
}
(Death::Infinity, NextOrFail::Fail(i)) => {
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
functor!(
atom!("dynamic_internal_else"),
[fixnum(birth), atom(atom!("inf")), str(h, 0)],
[next_functor]
[fixnum(birth),
atom_as_cell((atom!("inf"))),
functor((atom!("fail")), [fixnum(i)])]
)
}
(Death::Finite(d), NextOrFail::Fail(i)) => {
let next_functor = functor!(atom!("fail"), [fixnum(i)]);
functor!(
atom!("dynamic_internal_else"),
[fixnum(birth), fixnum(d), str(h, 0)],
[next_functor]
[fixnum(birth),
fixnum(d),
functor((atom!("fail")), [fixnum(i)])]
)
}
(Death::Finite(d), NextOrFail::Next(i)) => {
@@ -1367,157 +1332,154 @@ fn generate_instruction_preface() -> TokenStream {
}
&Instruction::Cut(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("cut"), [str(h, 0)], [rt_stub])
functor!(atom!("cut"), [functor(rt_stub)])
}
&Instruction::CutPrev(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("cut_prev"), [str(h, 0)], [rt_stub])
functor!(atom!("cut_prev"), [functor(rt_stub)])
}
&Instruction::GetLevel(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
functor!(atom!("get_level"), [functor(rt_stub)])
}
&Instruction::GetPrevLevel(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_prev_level"), [str(h, 0)], [rt_stub])
functor!(atom!("get_prev_level"), [functor(rt_stub)])
}
&Instruction::GetCutPoint(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_cut_point"), [str(h, 0)], [rt_stub])
functor!(atom!("get_cut_point"), [functor(rt_stub)])
}
&Instruction::NeckCut => {
functor!(atom!("neck_cut"))
}
&Instruction::Add(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("add"), arena, at_1, at_2, t)
}
&Instruction::Sub(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("sub"), arena, at_1, at_2, t)
}
&Instruction::Mul(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("mul"), arena, at_1, at_2, t)
}
&Instruction::IntPow(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("int_pow"), arena, at_1, at_2, t)
}
&Instruction::Pow(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("pow"), arena, at_1, at_2, t)
}
&Instruction::IDiv(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("idiv"), arena, at_1, at_2, t)
}
&Instruction::Max(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("max"), arena, at_1, at_2, t)
}
&Instruction::Min(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("min"), arena, at_1, at_2, t)
}
&Instruction::IntFloorDiv(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("int_floor_div"), arena, at_1, at_2, t)
}
&Instruction::RDiv(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("rdiv"), arena, at_1, at_2, t)
}
&Instruction::Div(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("div"), arena, at_1, at_2, t)
}
&Instruction::Shl(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("shl"), arena, at_1, at_2, t)
}
&Instruction::Shr(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("shr"), arena, at_1, at_2, t)
}
&Instruction::Xor(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("xor"), arena, at_1, at_2, t)
}
&Instruction::And(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("and"), arena, at_1, at_2, t)
}
&Instruction::Or(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("or"), arena, at_1, at_2, t)
}
&Instruction::Mod(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("mod"), arena, at_1, at_2, t)
}
&Instruction::Rem(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("rem"), arena, at_1, at_2, t)
}
&Instruction::ATan2(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("rem"), arena, at_1, at_2, t)
}
&Instruction::Gcd(ref at_1, ref at_2, t) => {
arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t)
arith_instr_bin_functor(atom!("gcd"), arena, at_1, at_2, t)
}
&Instruction::Sign(ref at, t) => {
arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
arith_instr_unary_functor(atom!("sign"), arena, at, t)
}
&Instruction::Cos(ref at, t) => {
arith_instr_unary_functor(h, atom!("cos"), arena, at, t)
arith_instr_unary_functor(atom!("cos"), arena, at, t)
}
&Instruction::Sin(ref at, t) => {
arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
arith_instr_unary_functor(atom!("sin"), arena, at, t)
}
&Instruction::Tan(ref at, t) => {
arith_instr_unary_functor(h, atom!("tan"), arena, at, t)
arith_instr_unary_functor(atom!("tan"), arena, at, t)
}
&Instruction::Log(ref at, t) => {
arith_instr_unary_functor(h, atom!("log"), arena, at, t)
arith_instr_unary_functor(atom!("log"), arena, at, t)
}
&Instruction::Exp(ref at, t) => {
arith_instr_unary_functor(h, atom!("exp"), arena, at, t)
arith_instr_unary_functor(atom!("exp"), arena, at, t)
}
&Instruction::ACos(ref at, t) => {
arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
arith_instr_unary_functor(atom!("acos"), arena, at, t)
}
&Instruction::ASin(ref at, t) => {
arith_instr_unary_functor(h, atom!("asin"), arena, at, t)
arith_instr_unary_functor(atom!("asin"), arena, at, t)
}
&Instruction::ATan(ref at, t) => {
arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
arith_instr_unary_functor(atom!("atan"), arena, at, t)
}
&Instruction::Sqrt(ref at, t) => {
arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
arith_instr_unary_functor(atom!("sqrt"), arena, at, t)
}
&Instruction::Abs(ref at, t) => {
arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
arith_instr_unary_functor(atom!("abs"), arena, at, t)
}
&Instruction::Float(ref at, t) => {
arith_instr_unary_functor(h, atom!("float"), arena, at, t)
arith_instr_unary_functor(atom!("float"), arena, at, t)
}
&Instruction::Truncate(ref at, t) => {
arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
arith_instr_unary_functor(atom!("truncate"), arena, at, t)
}
&Instruction::Round(ref at, t) => {
arith_instr_unary_functor(h, atom!("round"), arena, at, t)
arith_instr_unary_functor(atom!("round"), arena, at, t)
}
&Instruction::Ceiling(ref at, t) => {
arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t)
arith_instr_unary_functor(atom!("ceiling"), arena, at, t)
}
&Instruction::Floor(ref at, t) => {
arith_instr_unary_functor(h, atom!("floor"), arena, at, t)
arith_instr_unary_functor(atom!("floor"), arena, at, t)
}
&Instruction::FloatFractionalPart(ref at, t) => {
arith_instr_unary_functor(h, atom!("float_fractional_part"), arena, at, t)
arith_instr_unary_functor(atom!("float_fractional_part"), arena, at, t)
}
&Instruction::FloatIntegerPart(ref at, t) => {
arith_instr_unary_functor(h, atom!("float_integer_part"), arena, at, t)
arith_instr_unary_functor(atom!("float_integer_part"), arena, at, t)
}
&Instruction::Neg(ref at, t) => arith_instr_unary_functor(
h,
atom!("-"),
arena,
at,
t,
),
&Instruction::Plus(ref at, t) => arith_instr_unary_functor(
h,
atom!("+"),
arena,
at,
t,
),
&Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
h,
atom!("\\"),
arena,
at,
@@ -1533,16 +1495,16 @@ fn generate_instruction_preface() -> TokenStream {
functor!(atom!("allocate"), [fixnum(num_frames)])
}
&Instruction::CallNamed(arity, name, ..) => {
functor!(atom!("call"), [atom(name), fixnum(arity)])
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
}
&Instruction::ExecuteNamed(arity, name, ..) => {
functor!(atom!("execute"), [atom(name), fixnum(arity)])
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
}
&Instruction::DefaultCallNamed(arity, name, ..) => {
functor!(atom!("call_default"), [atom(name), fixnum(arity)])
functor!(atom!("call_default"), [atom_as_cell(name), fixnum(arity)])
}
&Instruction::DefaultExecuteNamed(arity, name, ..) => {
functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)])
}
&Instruction::CallN(arity) => {
functor!(atom!("call_n"), [fixnum(arity)])
@@ -1585,7 +1547,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallSort |
&Instruction::CallGetNumber(_) => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
}
//
&Instruction::ExecuteTermGreaterThan |
@@ -1611,7 +1573,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteSort |
&Instruction::ExecuteGetNumber(_) => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
}
//
&Instruction::DefaultCallTermGreaterThan |
@@ -1637,7 +1599,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultCallSort |
&Instruction::DefaultCallGetNumber(_) => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call_default"), [atom(name), fixnum(arity)])
functor!(atom!("call_default"), [atom_as_cell(name), fixnum(arity)])
}
//
&Instruction::DefaultExecuteTermGreaterThan |
@@ -1663,7 +1625,7 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::DefaultExecuteSort |
&Instruction::DefaultExecuteGetNumber(_) => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
functor!(atom!("execute_default"), [atom_as_cell(name), fixnum(arity)])
}
&Instruction::CallIsAtom(r) |
&Instruction::CallIsAtomic(r) |
@@ -1676,7 +1638,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallIsVar(r) => {
let (name, arity) = self.to_name_and_arity();
let rt_stub = reg_type_into_functor(r);
functor!(atom!("call"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub])
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity), functor(rt_stub)])
}
&Instruction::ExecuteIsAtom(r) |
&Instruction::ExecuteIsAtomic(r) |
@@ -1689,7 +1652,8 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteIsVar(r) => {
let (name, arity) = self.to_name_and_arity();
let rt_stub = reg_type_into_functor(r);
functor!(atom!("execute"), [atom(name), fixnum(arity), str(h, 0)], [rt_stub])
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity), functor(rt_stub)])
}
//
&Instruction::CallAtomChars |
@@ -1871,6 +1835,11 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallSetEnv |
&Instruction::CallUnsetEnv |
&Instruction::CallShell |
&Instruction::CallProcessCreate |
&Instruction::CallProcessId |
&Instruction::CallProcessWait |
&Instruction::CallProcessKill |
&Instruction::CallProcessRelease |
&Instruction::CallPid |
&Instruction::CallCharsBase64 |
&Instruction::CallDevourWhitespace |
@@ -1920,14 +1889,14 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::CallEd25519VerifyRaw |
&Instruction::CallEd25519SeedToPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
}
//
#[cfg(feature = "crypto-full")]
&Instruction::CallCryptoDataEncrypt |
&Instruction::CallCryptoDataDecrypt => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
functor!(atom!("call"), [atom_as_cell(name), fixnum(arity)])
}
//
&Instruction::ExecuteAtomChars |
@@ -2109,6 +2078,11 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteSetEnv |
&Instruction::ExecuteUnsetEnv |
&Instruction::ExecuteShell |
&Instruction::ExecuteProcessCreate |
&Instruction::ExecuteProcessId |
&Instruction::ExecuteProcessWait |
&Instruction::ExecuteProcessKill |
&Instruction::ExecuteProcessRelease |
&Instruction::ExecutePid |
&Instruction::ExecuteCharsBase64 |
&Instruction::ExecuteDevourWhitespace |
@@ -2158,14 +2132,14 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::ExecuteEd25519VerifyRaw |
&Instruction::ExecuteEd25519SeedToPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
}
//
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteCryptoDataEncrypt |
&Instruction::ExecuteCryptoDataDecrypt => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
functor!(atom!("execute"), [atom_as_cell(name), fixnum(arity)])
}
//
&Instruction::Deallocate => {
@@ -2180,73 +2154,60 @@ fn generate_instruction_preface() -> TokenStream {
&Instruction::Proceed => {
functor!(atom!("proceed"))
}
&Instruction::GetConstant(lvl, c, r) => {
&Instruction::GetConstant(lvl, lit, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("get_constant"),
[str(h, 0), cell(c), str(h, 1)],
[lvl_stub, rt_stub]
)
functor!(atom!("get_constant"), [functor(lvl_stub),
cell(lit),
functor(rt_stub)])
}
&Instruction::GetList(lvl, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("get_list"),
[str(h, 0), str(h, 1)],
[lvl_stub, rt_stub]
)
functor!(atom!("get_list"), [functor(lvl_stub), functor(rt_stub)])
}
&Instruction::GetPartialString(lvl, s, r, has_tail) => {
&Instruction::GetPartialString(lvl, ref s, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("get_partial_string"),
[
str(h, 0),
string(h, s),
str(h, 1),
boolean(has_tail)
],
[lvl_stub, rt_stub]
)
functor!(atom!("get_partial_string"), [functor(lvl_stub),
string((s.to_string())),
functor(rt_stub)])
}
&Instruction::GetStructure(lvl, name, arity, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("get_structure"),
[str(h, 0), atom(name), fixnum(arity), str(h, 1)],
[lvl_stub, rt_stub]
)
functor!(atom!("get_structure"), [functor(lvl_stub),
atom_as_cell(name),
fixnum(arity),
functor(rt_stub)])
}
&Instruction::GetValue(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub])
functor!(atom!("get_value"), [functor(rt_stub),
fixnum(arg)])
}
&Instruction::GetVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
functor!(atom!("get_variable"), [functor(rt_stub), fixnum(arg)])
}
&Instruction::UnifyConstant(c) => {
functor!(atom!("unify_constant"), [cell(c)])
}
&Instruction::UnifyLocalValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub])
functor!(atom!("unify_local_value"), [functor(rt_stub)])
}
&Instruction::UnifyVariable(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
functor!(atom!("unify_variable"), [functor(rt_stub)])
}
&Instruction::UnifyValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
functor!(atom!("unify_value"), [functor(rt_stub)])
}
&Instruction::UnifyVoid(vars) => {
functor!(atom!("unify_void"), [fixnum(vars)])
@@ -2258,68 +2219,55 @@ fn generate_instruction_preface() -> TokenStream {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("put_constant"),
[str(h, 0), cell(c), str(h, 1)],
[lvl_stub, rt_stub]
)
functor!(atom!("put_constant"), [functor(rt_stub), cell(c), functor(lvl_stub)])
}
&Instruction::PutList(lvl, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("put_list"),
[str(h, 0), str(h, 1)],
[lvl_stub, rt_stub]
)
functor!(atom!("put_list"), [functor(lvl_stub), functor(rt_stub)])
}
&Instruction::PutPartialString(lvl, s, r, has_tail) => {
&Instruction::PutPartialString(lvl, ref s, r) => {
let lvl_stub = lvl.into_functor();
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("put_partial_string"),
[
str(h, 0),
string(h, s),
str(h, 1),
boolean(has_tail)
],
[lvl_stub, rt_stub]
)
functor!(atom!("put_partial_string"), [functor(lvl_stub),
string((s.to_string())),
functor(rt_stub)])
}
&Instruction::PutStructure(name, arity, r) => {
let rt_stub = reg_type_into_functor(r);
functor!(
atom!("put_structure"),
[atom(name), fixnum(arity), str(h, 0)],
[rt_stub]
)
functor!(atom!("put_structure"), [atom_as_cell(name),
fixnum(arity),
functor(rt_stub)])
}
&Instruction::PutValue(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
functor!(atom!("put_value"), [functor(rt_stub),
fixnum(arg)])
}
&Instruction::PutVariable(r, arg) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
functor!(atom!("put_variable"), [functor(rt_stub),
fixnum(arg)])
}
&Instruction::SetConstant(c) => {
functor!(atom!("set_constant"), [cell(c)])
}
&Instruction::SetLocalValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub])
functor!(atom!("set_local_value"), [functor(rt_stub)])
}
&Instruction::SetVariable(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
functor!(atom!("set_variable"), [functor(rt_stub)])
}
&Instruction::SetValue(r) => {
let rt_stub = reg_type_into_functor(r);
functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
functor!(atom!("set_value"), [functor(rt_stub)])
}
&Instruction::SetVoid(vars) => {
functor!(atom!("set_void"), [fixnum(vars)])
@@ -2770,7 +2718,7 @@ pub fn generate_instructions_rs() -> TokenStream {
if ident == "Named" {
clause_type_from_name_and_arity_arms.push(quote! {
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default(arena))
(name, arity) => ClauseType::Named(arity, name, CodeIndex::default(&mut arena.code_index_tbl))
});
clause_type_to_instr_arms.push(quote! {
@@ -3198,12 +3146,6 @@ pub fn generate_instructions_rs() -> TokenStream {
}
}
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
matches!((name, arity),
#(#is_inbuilt_arms)|*
)
}
pub fn name(&self) -> Atom {
match self {
#(
@@ -3212,6 +3154,12 @@ pub fn generate_instructions_rs() -> TokenStream {
}
}
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
matches!((name, arity),
#(#is_inbuilt_arms)|*
)
}
pub fn is_inlined(name: Atom, arity: usize) -> bool {
matches!((name, arity),
#(#is_inlined_arms)|*
@@ -3334,14 +3282,14 @@ where
let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
Ok(disc) => disc,
Err(_) => {
panic!("can't generate discriminant {}", id);
panic!("can't generate discriminant {id}");
}
};
match disc.get_str(key) {
Some(prop) => prop,
None => {
panic!("can't find property {} of discriminant {:?}", key, disc);
panic!("can't find property {key} of discriminant {disc:?}");
}
}
}
@@ -3459,7 +3407,7 @@ impl InstructionData {
(name, arity, CountableInference::HasDefault)
} else {
panic!("type ID is: {}", id);
panic!("type ID is: {id}");
};
let v_ident = variant
+39 -8
View File
@@ -84,6 +84,18 @@ impl<'ast> Visit<'ast> for StaticStrVisitor {
}
}
const INLINED_ATOM_MAX_LEN: usize = 6;
fn static_string_index(string: &str, index: usize) -> u64 {
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
let mut string_buf: [u8; 8] = [0u8; 8];
string_buf[..string.len()].copy_from_slice(string.as_bytes());
(u64::from_le_bytes(string_buf) << 1) | 1
} else {
(index << 1) as u64
}
}
pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStream {
use quote::*;
@@ -114,14 +126,14 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
match file.read_to_string(&mut src) {
Ok(_) => {}
Err(e) => {
panic!("error reading file: {:?}", e);
panic!("error reading file: {e:?}");
}
}
let syntax = match syn::parse_file(&src) {
Ok(s) => s,
Err(e) => {
panic!("parse error: {} in file {:?}", e, path);
panic!("parse error: {e} in file {path:?}");
}
};
Ok(syntax)
@@ -149,11 +161,29 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
visitor.visit_file(&syntax)
}
let indices = (0..visitor.static_strs.len()).map(|i| (i << 3) as u64);
let indices_iter = indices.clone();
let mut static_str_keys = vec![];
let mut static_strs = vec![];
let mut static_str_indices = vec![];
let static_strs_len = visitor.static_strs.len();
let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect();
let indices: Vec<u64> = visitor
.static_strs
.iter()
.map(|string| {
let index = static_string_index(string, static_strs.len());
static_str_keys.push(string);
if index & 1 == 1 {
index
} else {
static_str_indices.push(index);
static_strs.push(string);
index
}
})
.collect();
let static_strs_len = static_strs.len();
quote! {
static STRINGS: [&str; #static_strs_len] = [
@@ -163,11 +193,12 @@ pub fn index_static_strings(instruction_rs_path: &std::path::Path) -> TokenStrea
];
macro_rules! atom {
#((#static_strs) => { Atom { index: #indices_iter } };)*
#((#static_str_keys) => { Atom { index: #indices } };)*
($name:literal) => {compile_error!(concat!("unknown static atom ", $name))};
}
pub static STATIC_ATOMS_MAP: phf::Map<&'static str, Atom> = phf::phf_map! {
#(#static_strs => { Atom { index: #indices } },)*
#(#static_strs => { Atom { index: #static_str_indices } },)*
};
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ pub(crate) trait Allocator {
lvl: Level,
context: GenContext,
code: &mut CodeDeque,
);
) -> RegType;
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
+64 -406
View File
@@ -3,31 +3,27 @@
#[cfg(feature = "http")]
use crate::http::{HttpListener, HttpResponse};
use crate::machine::loader::LiveLoadState;
use crate::machine::machine_indices::*;
use crate::machine::streams::*;
use crate::raw_block::*;
use crate::offset_table::*;
use crate::read::*;
use crate::types::UntypedArenaPtr;
use crate::parser::dashu::{Integer, Rational};
use arcu::atomic::Arcu;
use arcu::epoch_counters::GlobalEpochCounterPool;
use arcu::rcu_ref::RcuRef;
use arcu::Rcu;
use ordered_float::OrderedFloat;
use std::cell::UnsafeCell;
use std::fmt;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::io::PipeReader;
use std::io::PipeWriter;
use std::mem;
use std::mem::ManuallyDrop;
use std::net::TcpListener;
use std::ops::{Deref, DerefMut};
use std::process::Child;
use std::ptr;
use std::ptr::addr_of_mut;
use std::ptr::NonNull;
use std::sync::RwLock;
macro_rules! arena_alloc {
($e:expr, $arena:expr) => {{
@@ -38,8 +34,7 @@ macro_rules! arena_alloc {
macro_rules! float_alloc {
($e:expr, $arena:expr) => {{
let result = $e;
unsafe { $arena.f64_tbl.build_with(result).as_ptr() }
$arena.f64_tbl.build_with(OrderedFloat($e))
}};
}
@@ -55,120 +50,6 @@ where
payload_offset - header_offset
}
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;
const F64_TABLE_INIT_SIZE: usize = 1 << 16;
const F64_TABLE_ALIGN: usize = 8;
#[inline(always)]
fn global_f64table() -> &'static RwLock<Weak<F64Table>> {
static GLOBAL_ATOM_TABLE: RwLock<Weak<F64Table>> = RwLock::new(Weak::new());
&GLOBAL_ATOM_TABLE
}
impl RawBlockTraits for F64Table {
#[inline]
fn init_size() -> usize {
F64_TABLE_INIT_SIZE
}
#[inline]
fn align() -> usize {
F64_TABLE_ALIGN
}
}
#[derive(Debug)]
pub struct F64Table {
block: Arcu<RawBlock<F64Table>, GlobalEpochCounterPool>,
update: Mutex<()>,
}
// TODO: Actually prove this, as it's probably unsound right now
unsafe impl Send for F64Table {}
unsafe impl Sync for F64Table {}
#[inline(always)]
pub fn lookup_float(
offset: F64Offset,
) -> RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>> {
let f64table = global_f64table()
.read()
.unwrap()
.upgrade()
.expect("We should only be looking up floats while there is a float table");
RcuRef::try_map(f64table.block.read(), |raw_block| unsafe {
raw_block
.base
.add(offset.0)
.cast_mut()
.cast::<UnsafeCell<OrderedFloat<f64>>>()
.as_ref()
})
.expect("The offset should result in a non-null pointer")
}
impl F64Table {
#[inline]
pub fn new() -> Arc<Self> {
let upgraded = global_f64table().read().unwrap().upgrade();
// don't inline upgraded, otherwise temporary will be dropped too late in case of None
if let Some(atom_table) = upgraded {
atom_table
} else {
let mut guard = global_f64table().write().unwrap();
// try to upgrade again in case we lost the race on the write lock
if let Some(atom_table) = guard.upgrade() {
atom_table
} else {
let atom_table = Arc::new(Self {
block: Arcu::new(RawBlock::new(), GlobalEpochCounterPool),
update: Mutex::new(()),
});
*guard = Arc::downgrade(&atom_table);
atom_table
}
}
}
#[allow(clippy::missing_safety_doc)]
pub unsafe fn build_with(&self, value: f64) -> F64Offset {
let update_guard = self.update.lock();
// we don't have an index table for lookups as AtomTable does so
// just get the epoch after we take the upgrade lock
let mut block_epoch = self.block.read();
let mut ptr;
loop {
ptr = block_epoch.alloc(mem::size_of::<f64>());
if ptr.is_null() {
let new_block = block_epoch.grow_new().unwrap();
self.block.replace(new_block);
block_epoch = self.block.read();
} else {
break;
}
}
ptr::write(ptr as *mut OrderedFloat<f64>, OrderedFloat(value));
let float = F64Offset(ptr as usize - block_epoch.base as usize);
// atometable would have to update the index table at this point
// expicit drop to ensure we don't accidentally drop it early
drop(update_guard);
float
}
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq)]
#[bits = 7]
pub enum ArenaHeaderTag {
@@ -193,11 +74,10 @@ pub enum ArenaHeaderTag {
TcpListener = 0b1000000,
HttpListener = 0b1000001,
HttpResponse = 0b1000010,
PipeWriter = 0b1000011,
Dropped = 0b1000100,
IndexPtrDynamicUndefined = 0b1000101,
IndexPtrDynamicIndex = 0b1000110,
IndexPtrIndex = 0b1000111,
IndexPtrUndefined = 0b1001000,
PipeReader = 0b1001001,
ChildProcess = 0b1001010,
}
#[bitfield]
@@ -436,137 +316,6 @@ pub trait ArenaAllocated {
}
}
#[derive(Debug)]
pub struct F64Ptr(RcuRef<RawBlock<F64Table>, UnsafeCell<OrderedFloat<f64>>>);
impl Clone for F64Ptr {
fn clone(&self) -> Self {
Self(RcuRef::clone(&self.0))
}
}
impl PartialEq for F64Ptr {
fn eq(&self, other: &F64Ptr) -> bool {
RcuRef::ptr_eq(&self.0, &other.0) || self.deref() == other.deref()
}
}
impl Eq for F64Ptr {}
impl PartialOrd for F64Ptr {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for F64Ptr {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl Hash for F64Ptr {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
(self as &OrderedFloat<f64>).hash(hasher)
}
}
impl fmt::Display for F64Ptr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self as &OrderedFloat<f64>)
}
}
impl Deref for F64Ptr {
type Target = OrderedFloat<f64>;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe { self.0.get().as_ref().unwrap() }
}
}
impl DerefMut for F64Ptr {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.0.get().as_mut().unwrap() }
}
}
impl F64Ptr {
#[inline(always)]
pub fn from_offset(offset: F64Offset) -> Self {
Self(lookup_float(offset))
}
#[inline(always)]
pub fn as_offset(&self) -> F64Offset {
F64Offset(self.0.get() as usize - RcuRef::get_root(&self.0).base as usize)
}
}
#[derive(Clone, Copy, Debug)]
pub struct F64Offset(usize);
impl F64Offset {
#[inline(always)]
pub fn new(offset: usize) -> Self {
Self(offset)
}
#[inline(always)]
pub fn from_ptr(ptr: F64Ptr) -> Self {
ptr.as_offset()
}
#[inline(always)]
pub fn as_ptr(self) -> F64Ptr {
F64Ptr::from_offset(self)
}
#[inline(always)]
pub fn to_u64(self) -> u64 {
self.0 as u64
}
}
impl PartialEq for F64Offset {
#[inline(always)]
fn eq(&self, other: &F64Offset) -> bool {
self.as_ptr() == other.as_ptr()
}
}
impl Eq for F64Offset {}
impl PartialOrd for F64Offset {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for F64Offset {
#[inline(always)]
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_ptr().cmp(&other.as_ptr())
}
}
impl Hash for F64Offset {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_ptr().hash(hasher)
}
}
impl fmt::Display for F64Offset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "F64Offset({})", self.0)
}
}
impl ArenaAllocated for Integer {
type Payload = Self;
#[inline]
@@ -644,43 +393,16 @@ impl ArenaAllocated for HttpResponse {
}
}
impl ArenaAllocated for IndexPtr {
type Payload = Self;
impl ArenaAllocated for Child {
type Payload = ManuallyDrop<Self>;
#[inline]
fn tag() -> ArenaHeaderTag {
ArenaHeaderTag::IndexPtrUndefined
ArenaHeaderTag::ChildProcess
}
#[inline]
fn header_offset_from_payload() -> usize {
0
}
/// # Safety
/// - the caller must guarantee that the pointee type of UntypedArenaPtr is T
/// - the pointer must be non-null
unsafe fn typed_ptr(ptr: UntypedArenaPtr) -> TypedArenaPtr<Self> {
TypedArenaPtr(NonNull::new_unchecked(
ptr.get_ptr().cast_mut().cast::<IndexPtr>(),
))
}
#[inline]
fn alloc(arena: &mut Arena, value: Self) -> TypedArenaPtr<Self> {
let slab = Box::new(IndexPtrSlab {
next: arena.base.take(),
index_ptr: value,
});
let (allocated_ptr, untyped_slab) = slab.to_untyped();
arena.base = Some(untyped_slab);
allocated_ptr
}
/// # Safety
/// - ptr points to an allocated slab of the correct kind
unsafe fn dealloc(ptr: NonNull<TypedAllocSlab<Self>>) {
drop(unsafe { Box::from_raw(ptr.as_ptr().cast::<IndexPtrSlab>()) });
}
impl AllocateInArena<Child> for Child {
fn arena_allocate(self, arena: &mut Arena) -> TypedArenaPtr<Child> {
Child::alloc(arena, ManuallyDrop::new(self))
}
}
@@ -691,13 +413,6 @@ pub struct AllocSlab {
header: ArenaHeader,
}
#[repr(C)]
#[derive(Debug)]
pub struct IndexPtrSlab {
next: Option<UntypedArenaSlab>,
index_ptr: IndexPtr,
}
const _: () = {
if std::mem::align_of::<AllocSlab>() < std::mem::align_of::<*const ()>() {
panic!("alignment of AllocSlab is too low");
@@ -706,34 +421,8 @@ const _: () = {
if std::mem::offset_of!(AllocSlab, header) % std::mem::align_of::<*const ()>() != 0 {
panic!("alignment of header not a multiple of pointers alignment");
}
if std::mem::offset_of!(AllocSlab, header) != std::mem::offset_of!(IndexPtrSlab, index_ptr) {
panic!("IndexPtrSlab.index_ptr and AllocSlab.header are at different offsets");
}
};
impl IndexPtrSlab {
#[inline]
pub fn to_untyped(self: Box<Self>) -> (TypedArenaPtr<IndexPtr>, UntypedArenaSlab) {
let raw_box = Box::into_raw(self);
// safety: the pointer from Box::into_raw fullfills addr_of_mut's saftey requirements
let index_ptr_ptr = unsafe { ptr::addr_of_mut!((*raw_box).index_ptr) };
let allocated_ptr = TypedArenaPtr(
// safety: the pointer points into a valid allocation so it is non null
unsafe { NonNull::new_unchecked(index_ptr_ptr) },
);
let untyped_arena = UntypedArenaSlab {
// safety: pointer from Box::into_raw is never null
slab: unsafe { NonNull::new_unchecked(raw_box.cast::<AllocSlab>()) },
tag: <IndexPtr as ArenaAllocated>::tag(),
};
(allocated_ptr, untyped_arena)
}
}
#[repr(C)]
#[derive(Debug)]
pub struct TypedAllocSlab<T: ?Sized + ArenaAllocated> {
@@ -786,7 +475,8 @@ impl Drop for UntypedArenaSlab {
#[derive(Debug)]
pub struct Arena {
base: Option<UntypedArenaSlab>,
pub f64_tbl: Arc<F64Table>,
pub f64_tbl: F64Table,
pub code_index_tbl: CodeIndexTable,
}
unsafe impl Send for Arena {}
@@ -799,6 +489,7 @@ impl Arena {
Arena {
base: None,
f64_tbl: F64Table::new(),
code_index_tbl: CodeIndexTable::new(),
}
}
}
@@ -874,11 +565,14 @@ unsafe fn drop_slab_in_place(value: NonNull<AllocSlab>, tag: ArenaHeaderTag) {
ArenaHeaderTag::StandardErrorStream => {
drop_typed_slab_in_place!(StandardErrorStream, value);
}
ArenaHeaderTag::IndexPtrUndefined
| ArenaHeaderTag::IndexPtrDynamicUndefined
| ArenaHeaderTag::IndexPtrDynamicIndex
| ArenaHeaderTag::IndexPtrIndex => {
drop_typed_slab_in_place!(IndexPtr, value);
ArenaHeaderTag::PipeReader => {
drop_typed_slab_in_place!(PipeReader, value);
}
ArenaHeaderTag::PipeWriter => {
drop_typed_slab_in_place!(PipeWriter, value);
}
ArenaHeaderTag::ChildProcess => {
drop_typed_slab_in_place!(Child, value);
}
ArenaHeaderTag::NullStream => {
unreachable!("NullStream is never arena allocated!");
@@ -904,35 +598,34 @@ const_assert!(mem::size_of::<OrderedFloat<f64>>() == 8);
#[cfg(test)]
mod tests {
use std::ops::Deref;
use crate::arena::*;
use crate::atom_table::*;
use crate::machine::mock_wam::*;
use crate::machine::partial_string::*;
use crate::types::*;
use crate::parser::dashu::{Integer, Rational};
use ordered_float::OrderedFloat;
#[test]
fn float_ptr_cast() {
let wam = MockWAM::new();
let mut wam = MockWAM::new();
let f = 0f64;
let fp = float_alloc!(f, wam.machine_st.arena);
let mut cell = HeapCellValue::from(fp.clone());
let mut cell = HeapCellValue::from(fp);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
assert!(!cell.get_mark_bit());
assert_eq!(fp.deref(), &OrderedFloat(f));
assert_eq!(wam.machine_st.arena.f64_tbl.get_entry(fp), OrderedFloat(f));
cell.set_mark_bit(true);
assert!(cell.get_mark_bit());
read_heap_cell!(cell,
(HeapCellValueTag::F64, ptr) => {
assert_eq!(OrderedFloat(*ptr), OrderedFloat(f))
(HeapCellValueTag::F64Offset, offset) => {
let fp = wam.machine_st.arena.f64_tbl.get_entry(offset);
assert_eq!(fp, OrderedFloat(0f64))
}
_ => { unreachable!() }
);
@@ -943,12 +636,12 @@ mod tests {
let mut wam = MockWAM::new();
#[cfg(target_pointer_width = "32")]
let const_value = HeapCellValue::from(ConsPtr::build_with(
0x0000_0431 as *const _,
std::ptr::without_provenance(0x0000_0431),
ConsPtrMaskTag::Cons,
));
#[cfg(target_pointer_width = "64")]
let const_value = HeapCellValue::from(ConsPtr::build_with(
0x0000_5555_ff00_0431 as *const _,
std::ptr::without_provenance(0x0000_5555_ff00_0431),
ConsPtrMaskTag::Cons,
));
@@ -992,7 +685,7 @@ mod tests {
assert!(!big_int_ptr.as_ptr().is_null());
let cell = HeapCellValue::from(Literal::Integer(big_int_ptr));
let cell = HeapCellValue::from(big_int_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::Cons);
let untyped_arena_ptr = match cell.to_untyped_arena_ptr() {
@@ -1098,31 +791,6 @@ mod tests {
_ => { unreachable!() }
);
// complete string
let pstr_var_cell =
put_partial_string(&mut wam.machine_st.heap, "ronan", &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 => {
unreachable!();
}
}
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));
@@ -1141,7 +809,9 @@ mod tests {
_ => { unreachable!() }
);
let fixnum_b_cell = fixnum_as_cell!(Fixnum::build_with(1 << 54));
let fixnum_b_cell = fixnum_as_cell!(
Fixnum::build_with_checked(1i64 << 54).expect("1 << 54 fits in Fixnum")
);
assert_eq!(fixnum_b_cell.get_tag(), HeapCellValueTag::Fixnum);
@@ -1150,41 +820,29 @@ mod tests {
None => unreachable!(),
}
if Fixnum::build_with_checked(1 << 56).is_ok() {
unreachable!()
}
Fixnum::build_with_checked(1i64 << 56).expect_err("1 << 56 is too large for fixnum");
if Fixnum::build_with_checked(i64::MAX).is_ok() {
unreachable!()
}
Fixnum::build_with_checked(i64::MAX).expect_err("i64::MAX is too large for Fixnum");
Fixnum::build_with_checked(i64::MIN).expect_err("i64::MIN is too small for Fixnum");
assert_eq!(
Fixnum::build_with_checked(-1i64)
.expect("-1 fits in fixnum")
.get_num(),
-1
);
if Fixnum::build_with_checked(i64::MIN).is_ok() {
unreachable!()
}
Fixnum::build_with_checked((1i64 << 55) - 1)
.expect("(1 << 55) - 1 is the largest value that fits in Fixnum");
match Fixnum::build_with_checked(-1) {
Ok(n) => assert_eq!(n.get_num(), -1),
_ => unreachable!(),
}
Fixnum::build_with_checked(-(1i64 << 55))
.expect("-(1 << 55) is the smallest value that fits in fixnum");
Fixnum::build_with_checked(-(1i64 << 55) - 1)
.expect_err("-(1<<55) - 1 is too small for Fixnum");
match Fixnum::build_with_checked((1 << 55) - 1) {
Ok(n) => assert_eq!(n.get_num(), (1 << 55) - 1),
_ => unreachable!(),
}
match Fixnum::build_with_checked(-(1 << 55)) {
Ok(n) => assert_eq!(n.get_num(), -(1 << 55)),
_ => unreachable!(),
}
if Fixnum::build_with_checked(-(1 << 55) - 1).is_ok() {
unreachable!()
}
match Fixnum::build_with_checked(-1) {
Ok(n) => assert_eq!(-n, Fixnum::build_with(1)),
_ => unreachable!(),
}
assert_eq!(
-Fixnum::build_with_checked(-1i64).expect("-1 fits in Fixnum"),
Fixnum::build_with(1)
);
// float
@@ -1192,7 +850,7 @@ mod tests {
let float_ptr = float_alloc!(float, wam.machine_st.arena);
let cell = HeapCellValue::from(float_ptr);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64);
assert_eq!(cell.get_tag(), HeapCellValueTag::F64Offset);
// char
@@ -1200,8 +858,8 @@ mod tests {
let char_cell = char_as_cell!(c);
read_heap_cell!(char_cell,
(HeapCellValueTag::Char, c) => {
assert_eq!(c, 'c');
(HeapCellValueTag::Atom, (c, _arity)) => {
assert_eq!(&*c.as_str(), "c");
}
_ => { unreachable!() }
);
@@ -1210,8 +868,8 @@ mod tests {
let cyrillic_char_cell = char_as_cell!(c);
read_heap_cell!(cyrillic_char_cell,
(HeapCellValueTag::Char, c) => {
assert_eq!(c, 'Ћ');
(HeapCellValueTag::Atom, (c, _arity)) => {
assert_eq!(&*c.as_str(), "Ћ");
}
_ => { unreachable!() }
);
+36 -19
View File
@@ -7,6 +7,7 @@ use crate::debray_allocator::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::offset_table::*;
use crate::targets::QueryInstruction;
use crate::types::*;
@@ -88,7 +89,7 @@ impl<'a> ArithInstructionIterator<'a> {
#[derive(Debug)]
pub(crate) enum ArithTermRef<'a> {
Literal(&'a Literal),
Literal(Literal),
Op(Atom, usize), // name, arity.
Var(Level, &'a Cell<VarReg>, VarPtr),
}
@@ -117,7 +118,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
self.push_subterm(lvl.child_level(), &subterms[child_num]);
}
}
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))),
TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(*c))),
TermIterState::Var(lvl, cell, var_ptr) => {
return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
}
@@ -137,6 +138,7 @@ impl<'a> Iterator for ArithInstructionIterator<'a> {
#[derive(Debug)]
pub(crate) struct ArithmeticEvaluator<'a> {
marker: &'a mut DebrayAllocator,
f64_tbl: &'a F64Table,
interm: Vec<ArithmeticTerm>,
interm_c: usize,
}
@@ -155,11 +157,18 @@ impl<'a> ArithmeticTermIter<'a> for &'a Term {
}
}
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
fn push_literal(
f64_tbl: &F64Table,
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.as_ptr()))),
&Literal::F64Offset(offset) => {
let n = f64_tbl.get_entry(offset);
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(std::f64::consts::E)),
@@ -177,9 +186,14 @@ fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), Ari
}
impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn new(marker: &'a mut DebrayAllocator, target_int: usize) -> Self {
pub(crate) fn new(
marker: &'a mut DebrayAllocator,
f64_tbl: &'a F64Table,
target_int: usize,
) -> Self {
ArithmeticEvaluator {
marker,
f64_tbl,
interm: Vec::new(),
interm_c: target_int,
}
@@ -317,7 +331,7 @@ impl<'a> ArithmeticEvaluator<'a> {
for term_ref in src.iter()? {
match term_ref? {
ArithTermRef::Literal(c) => push_literal(&mut self.interm, c)?,
ArithTermRef::Literal(c) => push_literal(self.f64_tbl, &mut self.interm, &c)?,
ArithTermRef::Var(lvl, cell, name) => {
let var_num = name.to_var_num().unwrap();
@@ -357,9 +371,8 @@ impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalError> {
match n {
&Number::Integer(i) => {
let result = (&*i).try_into();
if let Ok(value) = result {
Ok(fixnum!(Number, value, arena))
if let Ok(value) = Fixnum::build_with_checked(&*i) {
Ok(Number::Fixnum(value))
} else {
Ok(*n)
}
@@ -368,11 +381,14 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
&Number::Float(f) => {
let f = f.floor();
const I64_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MIN as f64);
const I64_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(i64::MAX as f64);
const FIXNUM_MIN_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MIN as f64);
const FIXNUM_MAX_TO_F: OrderedFloat<f64> = OrderedFloat(Fixnum::MAX as f64);
if I64_MIN_TO_F <= f && f <= I64_MAX_TO_F {
Ok(fixnum!(Number, f.into_inner() as i64, arena))
if (FIXNUM_MIN_TO_F..=FIXNUM_MAX_TO_F).contains(&f) {
Ok(Number::Fixnum(
// Safety: We checked that the value is in range
unsafe { Fixnum::build_with_unchecked(f.into_inner() as i64) },
))
} else {
Ok(Number::Integer(arena_alloc!(
Integer::try_from(classify_float(f.0)?).unwrap_or_else(|_| {
@@ -385,8 +401,8 @@ pub(crate) fn rnd_i(n: &'_ Number, arena: &mut Arena) -> Result<Number, EvalErro
Number::Rational(ref r) => {
let floor = r.floor();
if let Ok(value) = (&floor).try_into() {
Ok(fixnum!(Number, value, arena))
if let Ok(value) = Fixnum::build_with_checked(&floor) {
Ok(Number::Fixnum(value))
} else {
Ok(Number::Integer(arena_alloc!(floor, arena)))
}
@@ -649,11 +665,11 @@ impl Ord for Number {
}
}
impl TryFrom<HeapCellValue> for Number {
impl TryFrom<(HeapCellValue, &'_ F64Table)> for Number {
type Error = ();
#[inline]
fn try_from(value: HeapCellValue) -> Result<Number, Self::Error> {
fn try_from((value, f64_tbl): (HeapCellValue, &F64Table)) -> Result<Number, Self::Error> {
read_heap_cell!(value,
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
@@ -668,8 +684,9 @@ impl TryFrom<HeapCellValue> for Number {
}
)
}
(HeapCellValueTag::F64, n) => {
Ok(Number::Float(*n))
(HeapCellValueTag::F64Offset, offset) => {
let n = f64_tbl.get_entry(offset);
Ok(Number::Float(n))
}
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
Ok(Number::Fixnum(n))
+178 -97
View File
@@ -23,15 +23,124 @@ use indexmap::IndexSet;
use scryer_modular_bitfield::prelude::*;
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug)]
pub struct AtomCell {
name: B48,
arity: B8,
#[allow(unused)]
f: bool,
#[allow(unused)]
m: bool,
#[allow(unused)]
is_inlined: bool,
#[allow(unused)]
tag: B5,
}
const INLINED_ATOM_MAX_LEN: usize = 6;
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<AtomCell>());
const_assert!(mem::size_of::<AtomCell>() == 8);
const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::<Atom>());
const_assert!(mem::size_of::<Atom>() == 8);
impl AtomCell {
#[inline]
fn new_static(index: u64) -> Self {
// upper 23 bits of index must be 0
debug_assert_eq!(index & !((1 << 49) - 1), 0);
AtomCell::new()
.with_name(index)
.with_arity(0u8)
.with_m(false)
.with_f(false)
.with_is_inlined(false)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
fn new_inlined(string: &str, arity: u8) -> Self {
debug_assert!(string.len() <= INLINED_ATOM_MAX_LEN);
let mut string_buf: [u8; 8] = [0u8; 8];
string_buf[..string.len()].copy_from_slice(string.as_bytes());
let encoding = u64::from_le_bytes(string_buf);
AtomCell::new()
.with_name(encoding)
.with_arity(arity)
.with_m(false)
.with_f(false)
.with_is_inlined(true)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
pub fn new_char_inlined(c: char) -> Self {
if c == '\u{0}' {
return Self::new_static(NULL_ATOM.flat_index());
}
let mut char_buf = [0u8; 8];
c.encode_utf8(&mut char_buf);
let encoding = u64::from_le_bytes(char_buf);
AtomCell::new()
.with_name(encoding)
.with_arity(0u8)
.with_m(false)
.with_f(false)
.with_is_inlined(true)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
pub fn build_with(atom_index: u64, arity: u8) -> Self {
debug_assert!((arity as usize) <= MAX_ARITY);
AtomCell::new()
.with_name(atom_index >> 1)
.with_arity(arity)
.with_f(false)
.with_m(false)
.with_is_inlined(atom_index & 1 == 1)
.with_tag(HeapCellValueTag::Atom as u8)
}
#[inline]
pub fn get_name(self) -> Atom {
Atom {
index: (self.name() << 1) | self.is_inlined() as u64,
}
}
#[inline]
pub fn get_arity(self) -> usize {
self.arity() as usize
}
#[inline]
pub fn get_name_and_arity(self) -> (Atom, usize) {
(self.get_name(), self.get_arity())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Atom {
pub index: u64,
}
const_assert!(mem::size_of::<Atom>() == 8);
include!(concat!(env!("OUT_DIR"), "/static_atoms.rs"));
// populate these in STRINGS so they can be used from build_functor
const _: Atom = atom!(".");
const _: Atom = atom!("[]");
const NULL_ATOM: Atom = atom!("\0");
impl<'a> From<&'a Atom> for Atom {
#[inline]
fn from(atom: &'a Atom) -> Self {
@@ -39,17 +148,6 @@ impl<'a> From<&'a Atom> for Atom {
}
}
impl From<bool> for Atom {
#[inline]
fn from(value: bool) -> Self {
if value {
atom!("true")
} else {
atom!("false")
}
}
}
impl indexmap::Equivalent<Atom> for str {
fn equivalent(&self, key: &Atom) -> bool {
&*key.as_str() == self
@@ -120,25 +218,23 @@ impl Hash for Atom {
#[inline]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_str().hash(hasher)
// hasher.write_usize(self.index)
}
}
pub enum AtomString<'a> {
Static(&'a str),
Inlined([u8; 8]),
Dynamic(AtomTableRef<str>),
}
impl AtomString<'_> {
pub fn map<F>(self, f: F) -> Self
where
for<'a> F: FnOnce(&'a str) -> &'a str,
{
match self {
Self::Static(reference) => Self::Static(f(reference)),
Self::Dynamic(guard) => Self::Dynamic(AtomTableRef::map(guard, f)),
}
}
#[inline(always)]
fn inlined_to_str(bytes: &[u8; 8]) -> &str {
let slice_len = bytes
.iter()
.position(|&b| b == 0u8)
.unwrap_or(INLINED_ATOM_MAX_LEN);
unsafe { str::from_utf8_unchecked(&bytes[..slice_len]) }
}
impl std::fmt::Debug for AtomString<'_> {
@@ -158,6 +254,7 @@ impl std::ops::Deref for AtomString<'_> {
fn deref(&self) -> &Self::Target {
match self {
Self::Static(reference) => reference,
Self::Inlined(inlined) => inlined_to_str(inlined),
Self::Dynamic(guard) => guard.deref(),
}
}
@@ -175,13 +272,32 @@ impl rustyline::completion::Candidate for AtomString<'_> {
}
impl Atom {
#[inline(always)]
pub fn is_static(self) -> bool {
(self.index as usize) < STRINGS.len() << 3
#[inline]
fn new_inlined(string: &str) -> Self {
AtomCell::new_inlined(string, 0).get_name()
}
#[inline(always)]
pub fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
fn is_static(self) -> bool {
if self.is_inlined() {
true
} else {
(self.flat_index() as usize) < STRINGS.len()
}
}
#[inline]
pub(crate) fn flat_index(self) -> u64 {
self.index >> 1
}
#[inline(always)]
pub(crate) fn is_inlined(self) -> bool {
self.index & 1 == 1
}
#[inline(always)]
fn as_ptr(self) -> Option<AtomTableRef<AtomData>> {
if self.is_static() {
None
} else {
@@ -192,7 +308,7 @@ impl Atom {
let ptr = buf
.block
.base
.add((self.index as usize) - (STRINGS.len() << 3));
.add(self.flat_index() as usize - STRINGS.len());
// TODO use std::ptr::from_raw_parts instead when feature ptr_metadata is stable rust-lang/rust#81513
let atom_data = &*(std::ptr::slice_from_raw_parts(ptr, 0) as *const AtomData);
let len = atom_data.header.len();
@@ -208,8 +324,11 @@ impl Atom {
#[inline(always)]
pub fn len(self) -> usize {
if self.is_static() {
STRINGS[(self.index >> 3) as usize].len()
if let Some(s) = self.inlined_str() {
s.len()
} else if self.is_static() {
let index = self.flat_index();
STRINGS[index as usize].len()
} else {
let len: u64 = self.as_ptr().unwrap().header.len();
len as usize
@@ -220,11 +339,6 @@ impl Atom {
self.len() == 0
}
#[inline(always)]
pub fn flat_index(self) -> u64 {
self.index >> 3
}
pub fn as_char(self) -> Option<char> {
let s = self.as_str();
let mut it = s.chars();
@@ -239,14 +353,26 @@ impl Atom {
}
}
#[inline]
fn inlined_str<'a>(&self) -> Option<AtomString<'a>> {
if self.is_inlined() {
Some(AtomString::Inlined(self.flat_index().to_le_bytes()))
} else {
None
}
}
#[inline]
pub fn as_str(&self) -> AtomString<'static> {
if self.is_static() {
AtomString::Static(STRINGS[(self.index >> 3) as usize])
if let Some(s) = self.inlined_str() {
s
} else if self.is_static() {
let index = self.flat_index() as usize;
AtomString::Static(STRINGS[index])
} else if let Some(ptr) = self.as_ptr() {
AtomString::Dynamic(AtomTableRef::map(ptr, |ptr| &ptr.data))
} else {
AtomString::Static(STRINGS[(self.index >> 3) as usize])
AtomString::Static(STRINGS[(self.index >> 1) as usize])
}
}
@@ -342,6 +468,10 @@ impl AtomTable {
}
pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom {
if !string.is_empty() && string.len() <= INLINED_ATOM_MAX_LEN && !string.contains('\u{0}') {
return Atom::new_inlined(string);
}
loop {
let mut block_epoch = atom_table.inner.read();
let mut table_epoch = block_epoch.table.read();
@@ -386,13 +516,18 @@ impl AtomTable {
}
};
let ptr_base = block_epoch.block.base as usize;
let ptr_base = block_epoch.block.base.addr();
write_to_ptr(string, len_ptr);
let atom = Atom {
index: ((STRINGS.len() << 3) + len_ptr as usize - ptr_base) as u64,
};
let atom = AtomCell::new()
.with_name((STRINGS.len() + len_ptr.addr() - ptr_base) as u64)
.with_arity(0)
.with_f(false)
.with_m(false)
.with_is_inlined(false)
.with_tag(HeapCellValueTag::Atom as u8)
.get_name();
let mut table = table_epoch.clone();
table.insert(atom);
@@ -409,57 +544,3 @@ impl AtomTable {
unsafe impl Send for AtomTable {}
unsafe impl Sync for AtomTable {}
#[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() as u64) << 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() as u64) << 3), self.get_arity())
}
}
+57 -88
View File
@@ -6,6 +6,7 @@ use crate::forms::*;
use crate::indexing::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::offset_table::F64Table;
use crate::parser::ast::*;
use crate::targets::*;
use crate::types::*;
@@ -269,10 +270,10 @@ impl CodeGenSettings {
}
#[derive(Debug)]
pub(crate) struct CodeGenerator<'a> {
pub(crate) atom_tbl: &'a AtomTable,
pub(crate) struct CodeGenerator<'f64_tbl> {
marker: DebrayAllocator,
settings: CodeGenSettings,
f64_tbl: &'f64_tbl F64Table,
pub(crate) skeleton: PredicateSkeleton,
}
@@ -319,33 +320,12 @@ impl DebrayAllocator {
}
}
// if the final argument of the structure is a Literal::Index,
// decrement the arity of the PutStructure instruction by 1.
fn trim_structure_by_last_arg(instr: &mut Instruction, last_arg: &Term) {
match instr {
Instruction::PutStructure(_, ref mut arity, _)
| Instruction::GetStructure(.., ref mut arity, _) => {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
// it is acceptable if arity == 0 is the result of
// this decrement. call/N will have to read the index
// constant for '$call_inline' to succeed. to find it,
// it must know the heap location of the index.
// self.store must stop before reading the atom into a
// register.
*arity -= 1;
}
}
_ => {}
}
}
trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
fn add_term_to_free_list(&mut self, r: RegType);
fn add_subterm_to_free_list(&mut self, term: &Term);
}
impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> {
impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator<'_> {
fn add_term_to_free_list(&mut self, r: RegType) {
self.marker.add_reg_to_free_list(r);
}
@@ -353,7 +333,7 @@ impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> {
fn add_subterm_to_free_list(&mut self, _term: &Term) {}
}
impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> {
impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'_> {
#[inline(always)]
fn add_term_to_free_list(&mut self, _r: RegType) {}
@@ -375,12 +355,12 @@ fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
}
}
impl<'b> CodeGenerator<'b> {
pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self {
impl<'f64_tbl> CodeGenerator<'f64_tbl> {
pub(crate) fn new(f64_tbl: &'f64_tbl F64Table, settings: CodeGenSettings) -> Self {
CodeGenerator {
atom_tbl,
marker: DebrayAllocator::new(),
settings,
f64_tbl,
skeleton: PredicateSkeleton::new(),
}
}
@@ -446,99 +426,99 @@ impl<'b> CodeGenerator<'b> {
};
}
fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, term_loc: GenContext) -> CodeDeque
fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, context: GenContext) -> CodeDeque
where
Target: crate::targets::CompilationTarget<'a>,
Iter: Iterator<Item = TermRef<'a>>,
CodeGenerator<'b>: AddToFreeList<'a, Target>,
CodeGenerator<'f64_tbl>: AddToFreeList<'a, Target>,
{
let mut target = CodeDeque::new();
for term in iter {
match term {
TermRef::AnonVar(lvl @ Level::Shallow) => {
if let GenContext::Head = term_loc {
if let GenContext::Head = context {
self.marker.advance_arg();
} else {
self.marker
.mark_anon_var::<Target>(lvl, term_loc, &mut target);
.mark_anon_var::<Target>(lvl, context, &mut target);
}
}
TermRef::Clause(lvl, cell, name, terms) => {
self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_structure(lvl, name, terms.len(), cell.get()));
let terms_range =
if let Some(subterm @ Term::Literal(_, Literal::CodeIndexOffset(_))) =
terms.last()
{
self.subterm_to_instr::<Target>(subterm, context, &mut target);
0..terms.len() - 1
} else {
0..terms.len()
};
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
self.marker
.mark_non_var::<Target>(lvl, context, cell, &mut target);
target.push_back(Target::to_structure(lvl, name, terms_range.end, cell.get()));
<CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
self,
cell.get(),
);
if let Some(instr) = target.back_mut() {
if let Some(term) = terms.last() {
trim_structure_by_last_arg(instr, term);
}
for subterm in &terms[terms_range.clone()] {
self.subterm_to_instr::<Target>(subterm, context, &mut target);
}
for subterm in terms {
self.subterm_to_instr::<Target>(subterm, term_loc, &mut target);
}
for subterm in terms {
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
for subterm in &terms[terms_range] {
<CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
self, subterm,
);
}
}
TermRef::Cons(lvl, cell, head, tail) => {
self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
.mark_non_var::<Target>(lvl, context, cell, &mut target);
target.push_back(Target::to_list(lvl, cell.get()));
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_term_to_free_list(
<CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
self,
cell.get(),
);
self.subterm_to_instr::<Target>(head, term_loc, &mut target);
self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
self.subterm_to_instr::<Target>(head, context, &mut target);
self.subterm_to_instr::<Target>(tail, context, &mut target);
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
<CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
self, head,
);
<CodeGenerator<'b> as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
<CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
self, tail,
);
}
TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_pstr(lvl, *string, cell.get(), false));
}
TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
.mark_non_var::<Target>(lvl, context, cell, &mut target);
target.push_back(Target::to_constant(lvl, *constant, cell.get()));
}
TermRef::PartialString(lvl, cell, string, tail) => {
self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
let atom = AtomTable::build_with(self.atom_tbl, string);
.mark_non_var::<Target>(lvl, context, cell, &mut target);
target.push_back(Target::to_pstr(lvl, atom, cell.get(), true));
self.subterm_to_instr::<Target>(tail, term_loc, &mut target);
target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
self.subterm_to_instr::<Target>(tail, context, &mut target);
}
TermRef::CompleteString(lvl, cell, atom) => {
TermRef::CompleteString(lvl, cell, string) => {
self.marker
.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
target.push_back(Target::to_pstr(lvl, atom, cell.get(), false));
.mark_non_var::<Target>(lvl, context, cell, &mut target);
target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
target.push_back(Target::constant_subterm(Literal::Atom(atom!("[]"))));
}
TermRef::Var(lvl @ Level::Shallow, cell, var) => {
self.marker.mark_var::<Target>(
var.to_var_num().unwrap(),
lvl,
cell,
term_loc,
context,
&mut target,
);
}
@@ -600,9 +580,7 @@ impl<'b> CodeGenerator<'b> {
compare_number_instr!(cmp, at_1, at_2)
}
InlinedClauseType::IsAtom(..) => match &terms[0] {
Term::Literal(_, Literal::Char(_))
| Term::Literal(_, Literal::Atom(atom!("[]")))
| Term::Literal(_, Literal::Atom(..)) => {
Term::Literal(_, Literal::Atom(..)) => {
instr!("$succeed")
}
Term::Var(ref vr, ref name) => {
@@ -630,9 +608,6 @@ impl<'b> CodeGenerator<'b> {
| Term::CompleteString(..) => {
instr!("$fail")
}
Term::Literal(_, Literal::String(_)) => {
instr!("$fail")
}
Term::Literal(..) => {
instr!("$succeed")
}
@@ -654,8 +629,7 @@ impl<'b> CodeGenerator<'b> {
Term::Clause(..)
| Term::Cons(..)
| Term::PartialString(..)
| Term::CompleteString(..)
| Term::Literal(_, Literal::String(..)) => {
| Term::CompleteString(..) => {
instr!("$succeed")
}
Term::Var(ref vr, ref name) => {
@@ -695,7 +669,7 @@ impl<'b> CodeGenerator<'b> {
}
},
InlinedClauseType::IsFloat(..) => match terms[0] {
Term::Literal(_, Literal::Float(_)) => {
Term::Literal(_, Literal::F64Offset(_)) => {
instr!("$succeed")
}
Term::Var(ref vr, ref name) => {
@@ -716,7 +690,7 @@ impl<'b> CodeGenerator<'b> {
}
},
InlinedClauseType::IsNumber(..) => match terms[0] {
Term::Literal(_, Literal::Float(_))
Term::Literal(_, Literal::F64Offset(_))
| Term::Literal(_, Literal::Rational(_))
| Term::Literal(_, Literal::Integer(_))
| Term::Literal(_, Literal::Fixnum(_)) => {
@@ -810,7 +784,6 @@ impl<'b> CodeGenerator<'b> {
// inlined predicates are never counted, so this overrides nothing.
self.add_call(code, call_instr, CallPolicy::Counted);
Ok(())
}
@@ -821,7 +794,7 @@ impl<'b> CodeGenerator<'b> {
term_loc: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> {
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, self.f64_tbl, target_int);
evaluator.compile_is(term, term_loc, arg)
}
@@ -891,7 +864,7 @@ impl<'b> CodeGenerator<'b> {
Term::Literal(
_,
c @ Literal::Integer(_)
| c @ Literal::Float(_)
| c @ Literal::F64Offset(_)
| c @ Literal::Rational(_)
| c @ Literal::Fixnum(_),
) => {
@@ -909,7 +882,6 @@ impl<'b> CodeGenerator<'b> {
let at = at.unwrap_or(interm!(1));
self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
Ok(())
}
@@ -924,9 +896,9 @@ impl<'b> CodeGenerator<'b> {
while let Some(clause_item) = clause_iter.next() {
match clause_item {
ClauseItem::Chunk(chunk) => {
for (idx, term) in chunk.iter().enumerate() {
let term_loc = if idx + 1 < chunk.len() {
ClauseItem::Chunk { terms } => {
for (idx, term) in terms.iter().enumerate() {
let term_loc = if idx + 1 < terms.len() {
GenContext::Mid(chunk_num)
} else {
self.marker.in_tail_position = clause_iter.in_tail_position();
@@ -1147,9 +1119,7 @@ impl<'b> CodeGenerator<'b> {
'outer: for (right, clause) in clauses.iter().enumerate() {
if let Some(args) = clause.args() {
for (instantiated_arg_index, arg) in args.iter().enumerate() {
match arg {
Term::Var(..) | Term::AnonVar => {}
_ => {
if !matches!(arg, Term::Var(..) | Term::AnonVar) {
if optimal_index != instantiated_arg_index {
if left >= right {
optimal_index = instantiated_arg_index;
@@ -1170,7 +1140,6 @@ impl<'b> CodeGenerator<'b> {
}
}
}
}
if left < right {
subseqs.push(ClauseSpan {
@@ -1260,7 +1229,7 @@ impl<'b> CodeGenerator<'b> {
let index = code.len();
if clauses_len > 1 || self.settings.is_extensible {
code_offsets.index_term(arg, index, &mut clause_index_info, self.atom_tbl);
code_offsets.index_term(arg, index, &mut clause_index_info);
}
}
+8 -4
View File
@@ -1,6 +1,6 @@
use crate::allocator::*;
use crate::codegen::SubsumedBranchHits;
use crate::forms::Level;
use crate::forms::{GenContext, Level};
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
use crate::parser::ast::*;
@@ -251,7 +251,7 @@ impl DebrayAllocator {
}
}
if self.branch_stack.len() > 0 {
if !self.branch_stack.is_empty() {
for var_num in subsumed_hits {
self.branch_stack.add_branch_occurrence(var_num);
}
@@ -534,7 +534,9 @@ impl DebrayAllocator {
VarAlloc::Temp { safety, .. } => {
*safety = VarSafetyStatus::unneeded(branch_designator);
}
_ => unreachable!(),
_ => {
unreachable!()
}
}
}
@@ -679,7 +681,7 @@ impl Allocator for DebrayAllocator {
lvl: Level,
term_loc: GenContext,
code: &mut CodeDeque,
) {
) -> RegType {
let r = RegType::Temp(self.alloc_reg_to_non_var());
match lvl {
@@ -696,6 +698,8 @@ impl Allocator for DebrayAllocator {
code.push_back(Target::argument_to_variable(r, k));
}
};
r
}
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
+3 -3
View File
@@ -324,7 +324,7 @@ impl ForeignFunctionTable {
let mut pointer_args =
Self::build_pointer_args(&mut args, &function_impl.args, &mut self.structs)?;
return unsafe {
unsafe {
macro_rules! call_and_return {
($type:ty) => {{
let mut n: Box<u8> = Box::new(0);
@@ -410,7 +410,7 @@ impl ForeignFunctionTable {
}
_ => unreachable!(),
}
};
}
}
fn read_struct(
@@ -517,7 +517,7 @@ impl Value {
fn as_ptr(&mut self) -> Result<*mut c_void, FFIError> {
match self {
Value::CString(ref mut cstr) => Ok(&mut *cstr as *mut _ as *mut c_void),
Value::Int(n) => Ok(*n as *mut c_void),
Value::Int(n) => Ok(std::ptr::with_exposed_provenance_mut(*n as usize)),
_ => Err(FFIError::ValueCast),
}
}
+67 -32
View File
@@ -1,11 +1,12 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::functor_macro::*;
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
use crate::machine::heap::*;
use crate::machine::loader::PredicateQueue;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::offset_table::OffsetTable;
use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational};
use crate::parser::parser::CompositeOpDesc;
@@ -26,18 +27,6 @@ use std::path::PathBuf;
pub type PredicateKey = (Atom, usize); // name, arity.
/*
// vars of predicate, toplevel offset. Vec<Term> is always a vector
// of vars (we get their adjoining cells this way).
pub type JumpStub = Vec<Term>;
*/
#[derive(Debug)]
pub enum TopLevel {
Fact(Fact, VarData), // Term, line_num, col_num
Rule(Rule, VarData), // Rule, line_num, col_num
}
#[derive(Debug, Clone, Copy)]
pub enum AppendOrPrepend {
Append,
@@ -82,6 +71,28 @@ pub enum CallPolicy {
Counted,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum GenContext {
Head,
Mid(usize),
Last(usize), // Mid & Last: chunk_num
}
impl GenContext {
#[inline]
pub fn chunk_num(&self) -> usize {
match self {
GenContext::Head => 0,
&GenContext::Mid(cn) | &GenContext::Last(cn) => cn,
}
}
#[inline]
pub fn is_last(self) -> bool {
matches!(self, GenContext::Last(_))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ChunkType {
Head,
@@ -121,7 +132,7 @@ impl ChunkType {
#[derive(Debug)]
pub enum ChunkedTerms {
Branch(Vec<VecDeque<ChunkedTerms>>),
Chunk(VecDeque<QueryTerm>),
Chunk { terms: VecDeque<QueryTerm> },
}
#[derive(Debug)]
@@ -161,22 +172,30 @@ impl ChunkedTermVec {
#[inline]
pub fn add_chunk(&mut self) {
self.chunk_vec
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![])));
let chunk = ChunkedTerms::Chunk {
terms: VecDeque::from(vec![]),
};
self.chunk_vec.push_back(chunk);
}
pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() {
Some(ChunkedTerms::Branch(_)) => {
self.chunk_vec
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
let chunk = ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
};
self.chunk_vec.push_back(chunk);
}
Some(ChunkedTerms::Chunk(chunk)) => {
chunk.push_back(term);
Some(ChunkedTerms::Chunk { terms, .. }) => {
terms.push_back(term);
}
None => {
self.chunk_vec
.push_back(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
let chunk = ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
};
self.chunk_vec.push_back(chunk);
}
}
}
@@ -353,9 +372,9 @@ pub enum ModuleSource {
impl ModuleSource {
pub(crate) fn as_functor_stub(&self) -> MachineStub {
match self {
match *self {
ModuleSource::Library(name) => {
functor!(atom!("library"), [atom(name)])
functor!(atom!("library"), [atom_as_cell(name)])
}
ModuleSource::File(name) => {
functor!(name)
@@ -608,9 +627,9 @@ impl Default for Number {
impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Number::Float(fl) => write!(f, "{}", fl),
Number::Integer(n) => write!(f, "{}", n),
Number::Rational(r) => write!(f, "{}", 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()),
}
}
@@ -679,17 +698,18 @@ impl ArenaFrom<isize> for Number {
impl ArenaFrom<u32> for Number {
#[inline]
fn arena_from(value: u32, _arena: &mut Arena) -> Number {
Number::Fixnum(Fixnum::build_with(value as i64))
Number::Fixnum(Fixnum::build_with(value))
}
}
impl ArenaFrom<i32> for Number {
#[inline]
fn arena_from(value: i32, _arena: &mut Arena) -> Number {
Number::Fixnum(Fixnum::build_with(value as i64))
Number::Fixnum(Fixnum::build_with(value))
}
}
/*
impl ArenaFrom<Number> for Literal {
#[inline]
fn arena_from(value: Number, arena: &mut Arena) -> Literal {
@@ -701,6 +721,21 @@ impl ArenaFrom<Number> for Literal {
}
}
}
*/
impl ArenaFrom<u64> for HeapCellValue {
#[inline]
fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue {
HeapCellValue::from(fixnum!(Literal, value as i64, arena))
}
}
impl ArenaFrom<usize> for HeapCellValue {
#[inline]
fn arena_from(value: usize, arena: &mut Arena) -> HeapCellValue {
HeapCellValue::arena_from(value as u64, arena)
}
}
impl ArenaFrom<Number> for HeapCellValue {
#[inline]
@@ -708,7 +743,7 @@ impl ArenaFrom<Number> for HeapCellValue {
match value {
Number::Fixnum(n) => fixnum_as_cell!(n),
Number::Integer(n) => typed_arena_ptr_as_cell!(n),
Number::Float(OrderedFloat(n)) => HeapCellValue::from(float_alloc!(n, arena)),
Number::Float(n) => HeapCellValue::from(arena.f64_tbl.build_with(n)),
Number::Rational(n) => typed_arena_ptr_as_cell!(n),
}
}
@@ -771,9 +806,9 @@ impl Number {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Copy, Clone)]
pub(crate) enum OptArgIndexKey {
Literal(usize, usize, Literal, Vec<Literal>), // index, IndexingCode location, opt arg, alternatives
Literal(usize, usize, Literal, Option<Literal>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location
None,
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
+798
View File
@@ -0,0 +1,798 @@
//! A macro to construct functor terms ready to be written to the WAM
//! heap.
use crate::atom_table::*;
use crate::instructions::IndexingCodePtr;
use crate::machine::heap::Heap;
use crate::parser::ast::Fixnum;
use crate::types::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum FunctorElement {
AbsoluteCell(HeapCellValue),
Cell(HeapCellValue),
InnerFunctor(u64, Vec<FunctorElement>),
String(u64, String),
}
// helper macros
macro_rules! count {
() => (0);
( $x:tt $($xs:tt)* ) => (1 + count!($($xs)*));
}
// core macros
/*
* functor! is more declarative now, with fewer effects and more
* work done at compile time using const functions. With these
* advantages come new quirks: expressions must generally be wrapped
* in round parentheses for rustc to parse them. See the tests module
* below for examples, especially those involving atom!
* subexpressions.
*/
macro_rules! functor {
($name:expr) => ({
vec![FunctorElement::Cell(atom_as_cell!($name))]
});
($name:expr, [$($dt:ident($($value:tt),*)),+]) => ({
build_functor!([$($dt($($value),*)),*],
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
1,
[])
});
}
macro_rules! inner_functor {
($name:expr, $res_len:expr, [$($dt:ident($($value:tt),*)),+]) => ({
build_functor!([$($dt($($value),*)),*],
[FunctorElement::Cell(atom_as_cell!($name, count!($($dt) *)))],
1 + $res_len,
[])
});
}
macro_rules! build_functor {
([], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
vec![$($res,)* $($subfunctor),*]
});
([indexing_code_ptr($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
let (inner_functor, cell_size) = indexing_code_ptr($e);
let referent = if cell_size == 1 {
heap_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
} else {
str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len)
};
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(referent)],
1 + cell_size + $res_len,
[$($subfunctor, )* FunctorElement::InnerFunctor(cell_size, inner_functor)])
});
([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(fixnum_as_cell!(/*FIXME this is not safe*/ unsafe{Fixnum::build_with_unchecked($e as i64)}))],
1 + $res_len,
[$($subfunctor),*])
});
([cell($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::AbsoluteCell($e)],
1 + $res_len,
[$($subfunctor),*])
});
([literal($e:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))],
1 + $res_len,
[$($subfunctor),*])
});
([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
let number_cell = HeapCellValue::arena_from($n, $arena);
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(number_cell)],
1 + $res_len,
[$($subfunctor),*])
});
([list([]) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(empty_list_as_cell!())],
1 + $res_len,
[$($subfunctor),*])
});
([list([$id:ident($($id_value:tt),*) $(, $in_dt:ident($($in_value:tt),*))*]) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
build_functor!([functor((atom!(".")), [$id($($id_value),*), list([$($in_dt($($in_value),*)),*])])
$(, $dt($($value),*))*],
[$($res),*],
$res_len,
[$($subfunctor),*])
});
([string($s:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
#[allow(unused_parens)]
let string = $s;
let pstr_len = cell_index!(Heap::compute_pstr_size(&string)) as u64;
let result_len = 1 + count!($($dt)*) + $res_len;
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(pstr_loc_as_cell!(heap_index!(result_len as usize) as u64))],
1 + $res_len + pstr_len,
[$($subfunctor, )* FunctorElement::String(pstr_len, string)])
});
([atom_as_cell($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(atom_as_cell!($n))],
1 + $res_len,
[$($subfunctor),*])
});
([functor($stub:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
let result_len = 1u64 + count!($($dt)*) + $res_len;
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&$stub)) as u64;
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
1 + $res_len + inner_functor_size,
[$($subfunctor, )*
FunctorElement::InnerFunctor(inner_functor_size, $stub)])
});
([$id:ident($n:expr) $(, $dt:ident($($value:tt),*))*], [$($res:expr),*], $res_len:expr, [$($subfunctor:expr),*]) => ({
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell($id!($n))],
1 + $res_len,
[$($subfunctor),*])
});
([functor($name:expr, [$($in_dt:ident($($in_value:tt),*)),+]) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
[$($subfunctor:expr),*]) => ({
let result_len = 1u64 + count!($($dt)*) + $res_len;
let inner_functor = inner_functor!($name, 0, [$($in_dt($($in_value),*)),*]);
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&inner_functor)) as u64;
build_functor!([$($dt($($value),*)),*],
[$($res, )* FunctorElement::Cell(str_loc_as_cell!(result_len))],
1 + $res_len + inner_functor_size,
[$($subfunctor, )*
FunctorElement::InnerFunctor(inner_functor_size, inner_functor)])
});
}
pub(crate) fn indexing_code_ptr(code_ptr: IndexingCodePtr) -> (Vec<FunctorElement>, u64) {
match code_ptr {
IndexingCodePtr::DynamicExternal(o) => {
(functor!(atom!("dynamic_external"), [fixnum(o)]), 2)
}
IndexingCodePtr::External(o) => (functor!(atom!("external"), [fixnum(o)]), 2),
IndexingCodePtr::Internal(o) => (functor!(atom!("internal"), [fixnum(o)]), 2),
IndexingCodePtr::Fail => (vec![FunctorElement::Cell(atom_as_cell!(atom!("fail")))], 1),
}
}
pub(crate) fn variadic_functor(
name: Atom,
arity: usize,
iter: impl Iterator<Item = Vec<FunctorElement>>,
) -> Vec<FunctorElement> {
let mut arg_vec = vec![
FunctorElement::Cell(atom_as_cell!(name, arity)),
FunctorElement::Cell(list_loc_as_cell!(2)),
];
let key_value_pairs: Vec<_> = iter.collect();
let num_items = key_value_pairs.len();
let mut functor_offset = 0;
for (idx, kv_func) in key_value_pairs.iter().enumerate() {
let functor_size = cell_index!(Heap::compute_functor_byte_size(kv_func));
arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(
2 + num_items * 2 + functor_offset
)));
arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(4 + 2 * idx)));
functor_offset += functor_size;
}
arg_vec.pop();
arg_vec.push(FunctorElement::Cell(empty_list_as_cell!()));
arg_vec.extend(key_value_pairs.into_iter().map(|kv_func| {
let inner_functor_size = cell_index!(Heap::compute_functor_byte_size(&kv_func));
FunctorElement::InnerFunctor(inner_functor_size as u64, kv_func)
}));
arg_vec
}
#[cfg(test)]
#[allow(unused_parens)]
mod tests {
use super::*;
use indexmap::indexmap;
use std::string::String;
use FunctorElement::*;
#[test]
fn basic_terms() {
let functor = functor!(
atom!("first"),
[atom_as_cell((atom!("a"))), char_as_cell('c')]
);
assert_eq!(functor.len(), 3);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 2)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(char_as_cell!('c')));
let functor = functor!(
atom!("second"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
char_as_cell('c')
]
);
assert_eq!(functor.len(), 5);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("second"), 3)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(4)));
assert_eq!(functor[3], Cell(char_as_cell!('c')));
assert_eq!(
functor[4],
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
);
let functor = functor!(
atom!("third"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
functor((atom!("c")), [fixnum(1), fixnum(2)]),
char_as_cell('c')
]
);
assert_eq!(functor.len(), 7);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("third"), 4)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
assert_eq!(functor[3], Cell(str_loc_as_cell!(8)));
assert_eq!(functor[4], Cell(char_as_cell!('c')));
assert_eq!(
functor[5],
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
);
assert_eq!(
functor[6],
InnerFunctor(3, functor!(atom!("c"), [fixnum(1), fixnum(2)]))
);
let functor = functor!(
atom!("fourth"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
functor((atom!("c")), [fixnum(1)]),
functor((atom!("d")), [fixnum(453), fixnum(2)]),
char_as_cell('c')
]
);
assert_eq!(functor.len(), 9);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("fourth"), 5)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(6)));
assert_eq!(functor[3], Cell(str_loc_as_cell!(9)));
assert_eq!(functor[4], Cell(str_loc_as_cell!(11)));
assert_eq!(functor[5], Cell(char_as_cell!('c')));
assert_eq!(
functor[6],
InnerFunctor(3, functor!(atom!("b"), [fixnum(1), fixnum(2)]))
);
assert_eq!(
functor[7],
InnerFunctor(2, functor!(atom!("c"), [fixnum(1)]))
);
assert_eq!(
functor[8],
InnerFunctor(3, functor!(atom!("d"), [fixnum(453), fixnum(2)]))
);
}
#[test]
fn basic_terms_in_heap() {
let functor = functor!(
atom!("first"),
[atom_as_cell((atom!("a"))), char_as_cell('b')]
);
assert_eq!(functor.len(), 3);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(0));
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
assert_eq!(heap[2], char_as_cell!('b'));
heap.truncate(2);
let functor = functor!(
atom!("second"),
[
atom_as_cell((atom!("a"))),
functor((atom!("b")), [fixnum(1), fixnum(2)]),
functor((atom!("c")), [fixnum(1), fixnum(2)]),
char_as_cell('b')
]
);
assert_eq!(functor.len(), 7);
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(2));
assert_eq!(heap[2], atom_as_cell!(atom!("second"), 4));
assert_eq!(heap[3], atom_as_cell!(atom!("a")));
assert_eq!(heap[4], str_loc_as_cell!(7));
assert_eq!(heap[5], str_loc_as_cell!(10));
assert_eq!(heap[6], char_as_cell!('b'));
assert_eq!(heap[7], atom_as_cell!(atom!("b"), 2));
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(heap[10], atom_as_cell!(atom!("c"), 2));
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(2)));
}
#[test]
fn nested_functors() {
let functor = functor!(
atom!("first"),
[
atom_as_cell((atom!("a"))),
functor(
(atom!("d")),
[
fixnum(1),
functor(
(atom!("b")),
[atom_as_cell((atom!("c"))), char_as_cell('c')]
)
]
),
functor((atom!("e")), [fixnum(453), fixnum(2)]),
char_as_cell('b')
]
);
assert_eq!(functor.len(), 7);
assert_eq!(functor[0], Cell(atom_as_cell!(atom!("first"), 4)));
assert_eq!(functor[1], Cell(atom_as_cell!(atom!("a"))));
assert_eq!(functor[2], Cell(str_loc_as_cell!(5)));
assert_eq!(functor[3], Cell(str_loc_as_cell!(11)));
assert_eq!(functor[4], Cell(char_as_cell!('b')));
assert_eq!(
functor[5],
InnerFunctor(
6,
vec![
Cell(atom_as_cell!(atom!("d"), 2)),
Cell(fixnum_as_cell!(Fixnum::build_with(1))),
Cell(str_loc_as_cell!(3)),
InnerFunctor(
3,
functor!(atom!("b"), [atom_as_cell((atom!("c"))), char_as_cell('c')])
)
]
)
);
assert_eq!(
functor[6],
InnerFunctor(3, functor!(atom!("e"), [fixnum(453), fixnum(2)]))
);
}
#[test]
fn nested_functors_in_heap() {
let functor = functor!(
atom!("first"),
[
atom_as_cell((atom!("a"))),
functor(
(atom!("second")),
[
fixnum(1),
functor(
(atom!("third")),
[atom_as_cell((atom!("b"))), char_as_cell('c')]
)
]
),
functor((atom!("fourth")), [fixnum(453), fixnum(2)]),
char_as_cell('b')
]
);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(0));
assert_eq!(heap.cell_len(), 14);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 4));
assert_eq!(heap[1], atom_as_cell!(atom!("a")));
assert_eq!(heap[2], str_loc_as_cell!(5));
assert_eq!(heap[3], str_loc_as_cell!(11));
assert_eq!(heap[4], char_as_cell!('b'));
assert_eq!(heap[5], atom_as_cell!(atom!("second"), 2));
assert_eq!(heap[6], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[7], str_loc_as_cell!(8));
assert_eq!(heap[8], atom_as_cell!(atom!("third"), 2));
assert_eq!(heap[9], atom_as_cell!(atom!("b")));
assert_eq!(heap[10], char_as_cell!('c'));
assert_eq!(heap[11], atom_as_cell!(atom!("fourth"), 2));
assert_eq!(heap[12], fixnum_as_cell!(Fixnum::build_with(453)));
assert_eq!(heap[13], fixnum_as_cell!(Fixnum::build_with(2)));
}
#[test]
fn functors_with_strings_in_heap() {
let functor = functor!(atom!("first"), [string((String::from("a string")))]);
assert_eq!(functor.len(), 3);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, str_loc_as_cell!(0));
assert_eq!(heap.cell_len(), 5);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
assert_eq!(
heap.slice_to_str(heap_index!(2), "a string".len()),
"a string"
);
assert_eq!(heap[4], empty_list_as_cell!());
heap.truncate(0);
let functor = functor!(
atom!("second"),
[string((String::from("a stuttered\0 string")))]
);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 10);
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 1));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(2)));
assert_eq!(
heap.slice_to_str(heap_index!(2), "a stuttered".len()),
"a stuttered"
);
assert_eq!(heap[4], list_loc_as_cell!(5));
assert_eq!(heap[5], char_as_cell!('\u{0}'));
assert_eq!(heap[6], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(
heap.slice_to_str(heap_index!(7), " string".len()),
" string"
);
assert_eq!(heap[9], empty_list_as_cell!());
}
#[test]
fn functors_with_lists_in_heap() {
let functor = functor!(
atom!("first"),
[list([fixnum(1), atom_as_cell((atom!("a"))), fixnum(2)])]
);
assert_eq!(functor.len(), 3);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 11);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 1));
assert_eq!(heap[1], str_loc_as_cell!(2));
assert_eq!(heap[2], atom_as_cell!(atom!("."), 2));
assert_eq!(heap[3], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[4], str_loc_as_cell!(5));
assert_eq!(heap[5], atom_as_cell!(atom!("."), 2));
assert_eq!(heap[6], atom_as_cell!(atom!("a")));
assert_eq!(heap[7], str_loc_as_cell!(8));
assert_eq!(heap[8], atom_as_cell!(atom!("."), 2));
assert_eq!(heap[9], fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(heap[10], empty_list_as_cell!());
}
#[test]
fn inlined_atoms() {
let atom_table = AtomTable::new();
let inlined = AtomTable::build_with(&atom_table, "inline");
assert!(inlined.is_inlined());
assert_eq!(&*inlined.as_str(), "inline");
let non_inlined = AtomTable::build_with(&atom_table, "longer non-inlined atom");
assert!(!non_inlined.is_inlined());
assert_eq!(&*non_inlined.as_str(), "longer non-inlined atom");
}
#[test]
fn functors_with_indexing_code_ptr() {
let code_ptr = IndexingCodePtr::Internal(0);
let functor = functor!(
atom!("first"),
[
string((String::from("a string"))),
indexing_code_ptr(code_ptr)
]
);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 8);
assert_eq!(heap[0], atom_as_cell!(atom!("first"), 2));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(
heap.slice_to_str(heap_index!(3), "a string".len()),
"a string"
);
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!("internal"), 1));
assert_eq!(heap[7], fixnum_as_cell!(Fixnum::build_with(0)));
heap.truncate(0);
let functor = functor!(
atom!("second"),
[
string((String::from("a string"))),
functor(
(atom!("third")),
[
atom_as_cell((atom!("a"))),
string((String::from("another string"))),
indexing_code_ptr(code_ptr)
]
)
]
);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 15);
assert_eq!(heap[0], atom_as_cell!(atom!("second"), 2));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(
heap.slice_to_str(heap_index!(3), "a string".len()),
"a string"
);
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!("third"), 3));
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(10)));
assert_eq!(heap[9], str_loc_as_cell!(13));
assert_eq!(
heap.slice_to_str(heap_index!(10), "another string".len()),
"another string"
);
assert_eq!(heap[12], empty_list_as_cell!());
assert_eq!(heap[13], atom_as_cell!(atom!("internal"), 1));
assert_eq!(heap[14], fixnum_as_cell!(Fixnum::build_with(0)));
let functor = functor!(
atom!("fourth"),
[
string((String::from("a string"))),
functor(
(atom!("a")),
[
functor(
(atom!("fifth")),
[
fixnum(5),
string((String::from("another string"))),
indexing_code_ptr(code_ptr)
]
),
string((String::from("and another")))
]
)
]
);
heap.truncate(0);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 21);
assert_eq!(heap[0], atom_as_cell!(atom!("fourth"), 2));
assert_eq!(heap[1], pstr_loc_as_cell!(heap_index!(3)));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(
heap.slice_to_str(heap_index!(3), "a string".len()),
"a string"
);
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!("a"), 2));
assert_eq!(heap[7], str_loc_as_cell!(9));
assert_eq!(heap[8], pstr_loc_as_cell!(heap_index!(18))); // <-- wrong!
assert_eq!(heap[9], atom_as_cell!(atom!("fifth"), 3));
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(5)));
assert_eq!(heap[11], pstr_loc_as_cell!(heap_index!(13)));
assert_eq!(heap[12], str_loc_as_cell!(16));
assert_eq!(
heap.slice_to_str(heap_index!(13), "another string".len()),
"another string"
);
assert_eq!(heap[15], empty_list_as_cell!());
assert_eq!(heap[16], atom_as_cell!(atom!("internal"), 1));
assert_eq!(heap[17], fixnum_as_cell!(Fixnum::build_with(0)));
assert_eq!(
heap.slice_to_str(heap_index!(18), "and another".len()),
"and another"
);
assert_eq!(heap[20], empty_list_as_cell!());
let constants = indexmap![
atom_as_cell!(atom!("a")) => IndexingCodePtr::External(2),
atom_as_cell!(atom!("d")) => IndexingCodePtr::External(7),
];
let functor = variadic_functor(
atom!("switch_on_constants"),
1,
constants
.iter()
.map(|(c, ptr)| functor!(atom!(":"), [cell((*c)), indexing_code_ptr((*ptr))])),
);
heap.truncate(0);
let mut functor_writer = Heap::functor_writer(functor);
functor_writer(&mut heap).unwrap();
assert_eq!(heap[0], atom_as_cell!(atom!("switch_on_constants"), 1));
assert_eq!(heap[1], list_loc_as_cell!(2));
assert_eq!(heap[2], str_loc_as_cell!(6));
assert_eq!(heap[3], list_loc_as_cell!(4));
assert_eq!(heap[4], str_loc_as_cell!(11));
assert_eq!(heap[5], empty_list_as_cell!());
assert_eq!(heap[6], atom_as_cell!(atom!(":"), 2));
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
assert_eq!(heap[8], str_loc_as_cell!(9));
assert_eq!(heap[9], atom_as_cell!(atom!("external"), 1));
assert_eq!(heap[10], fixnum_as_cell!(Fixnum::build_with(2)));
assert_eq!(heap[11], atom_as_cell!(atom!(":"), 2));
assert_eq!(heap[12], atom_as_cell!(atom!("d")));
assert_eq!(heap[13], str_loc_as_cell!(14));
assert_eq!(heap[14], atom_as_cell!(atom!("external"), 1));
assert_eq!(heap[15], fixnum_as_cell!(Fixnum::build_with(7)));
}
#[test]
fn undefined_procedure_functor() {
// existence_error
let culprit = functor!(atom!("/"), [atom_as_cell((atom!("a"))), fixnum(1)]);
let stub = functor!(
atom!("existence_error"),
[
atom_as_cell((atom!("procedure"))),
functor((culprit.clone()))
]
);
println!("{stub:?}");
// now the error form
let lineless_error_form = functor!(atom!("error"), [functor(stub), functor(culprit)]);
println!("{lineless_error_form:?}");
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(lineless_error_form);
functor_writer(&mut heap).unwrap();
assert_eq!(heap[0], atom_as_cell!(atom!("error"), 2));
assert_eq!(heap[1], str_loc_as_cell!(3));
assert_eq!(heap[2], str_loc_as_cell!(9));
assert_eq!(heap[3], atom_as_cell!(atom!("existence_error"), 2));
assert_eq!(heap[4], atom_as_cell!(atom!("procedure")));
assert_eq!(heap[5], str_loc_as_cell!(6)); // is str_loc_as_cell!(3)
assert_eq!(heap[6], atom_as_cell!(atom!("/"), 2));
assert_eq!(heap[7], atom_as_cell!(atom!("a")));
assert_eq!(heap[8], fixnum_as_cell!(Fixnum::build_with(1)));
assert_eq!(heap[9], atom_as_cell!(atom!("/"), 2));
assert_eq!(heap[10], atom_as_cell!(atom!("a")));
assert_eq!(heap[11], fixnum_as_cell!(Fixnum::build_with(1)));
}
#[test]
fn argless_functor() {
let name = functor!(atom!("[]"));
assert_eq!(name.len(), 1);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(name);
let loc = functor_writer(&mut heap).unwrap();
assert_eq!(loc, heap_loc_as_cell!(0));
}
#[test]
fn predefined_subfunctors() {
let stub = functor!(atom!("sub"), [atom_as_cell((atom!("[]")))]);
let name = functor!(atom!("super"), [functor(stub)]);
let mut heap = Heap::new();
let mut functor_writer = Heap::functor_writer(name);
functor_writer(&mut heap).unwrap();
assert_eq!(heap.cell_len(), 4);
assert_eq!(heap[0], atom_as_cell!(atom!("super"), 1));
assert_eq!(heap[1], str_loc_as_cell!(2));
assert_eq!(heap[2], atom_as_cell!(atom!("sub"), 1));
assert_eq!(heap[3], empty_list_as_cell!());
}
}
+557 -675
View File
File diff suppressed because it is too large Load Diff
+276 -161
View File
@@ -8,11 +8,10 @@ use crate::parser::dashu::{ibig, Integer, Rational};
use crate::forms::*;
use crate::heap_iter::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::pstr_loc_and_offset;
use crate::machine::partial_string::*;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::offset_table::*;
use crate::types::*;
use dashu::base::Signed;
@@ -25,7 +24,6 @@ use std::convert::TryFrom;
use std::iter::once;
use std::net::{IpAddr, TcpListener};
use std::rc::Rc;
use std::sync::Arc;
/* contains the location, name, precision and Specifier of the parent op. */
#[derive(Debug, Copy, Clone)]
@@ -206,11 +204,12 @@ impl NumberFocus {
#[derive(Debug, Clone, Copy)]
struct CommaSeparatedCharList {
pstr: PartialString,
offset: usize,
// pstr: PartialString,
// offset: usize,
pstr_loc: usize,
max_depth: usize,
end_cell: HeapCellValue,
end_h: Option<usize>,
// end_cell: HeapCellValue,
// end_h: Option<usize>,
}
#[derive(Debug, Clone)]
@@ -389,17 +388,20 @@ fn is_numbered_var(name: Atom, arity: usize) -> bool {
#[inline]
fn negated_op_needs_bracketing(
iter: &StackfulPreOrderHeapIter<ListElider>,
f64_tbl: &F64Table,
op_dir: &OpDir,
op: &Option<DirectedOp>,
) -> bool {
if let Some(ref op) = op {
op.is_negative_sign()
&& iter.leftmost_leaf_has_property(op_dir, |addr| match Number::try_from(addr) {
&& iter.leftmost_leaf_has_property(op_dir, |addr| {
match Number::try_from((addr, f64_tbl)) {
Ok(Number::Fixnum(n)) => n.get_num() > 0,
Ok(Number::Float(OrderedFloat(f))) => f > 0f64,
Ok(Number::Integer(n)) => n.is_positive(),
Ok(Number::Rational(n)) => n.is_positive(),
_ => false,
}
})
} else {
false
@@ -473,7 +475,7 @@ pub fn fmt_float(mut fl: f64) -> String {
pub struct HCPrinter<'a, Outputter> {
outputter: Outputter,
iter: StackfulPreOrderHeapIter<'a, ListElider>,
atom_tbl: Arc<AtomTable>,
arena: &'a Arena,
op_dir: &'a OpDir,
state_stack: Vec<TokenOrRedirect>,
toplevel_spec: Option<DirectedOp>,
@@ -488,9 +490,24 @@ pub struct HCPrinter<'a, Outputter> {
pub double_quotes: bool,
}
fn ambiguity_check(
outputter: &impl HCValueOutputter,
quoted: bool,
last_item_idx: usize,
atom: &str,
) -> bool {
let tail = &outputter.as_str()[last_item_idx..];
if atom == "," || !quoted || non_quoted_token(atom.chars()) {
requires_space(tail, atom)
} else {
requires_space(tail, "'")
}
}
macro_rules! push_space_if_amb {
($self:expr, $atom:expr, $action:block) => {
if $self.ambiguity_check($atom) {
if ambiguity_check(&$self.outputter, $self.quoted, $self.last_item_idx, $atom) {
$self.outputter.push_char(' ');
$action;
} else {
@@ -516,28 +533,47 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option<String>
}
}
match Number::try_from(addr) {
Ok(Number::Fixnum(n)) if n.get_num() >= 0 => {
read_heap_cell!(addr,
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Integer, n) => {
if !n.is_negative() {
Some(numbervar(Integer::from(offset + &*n)))
} else {
None
}
}
_ => {
None
}
)
}
(HeapCellValueTag::Fixnum, n) => {
if n.get_num() >= 0 {
Some(numbervar(offset + Integer::from(n.get_num())))
} else {
None
}
Ok(Number::Integer(n)) if !n.is_negative() => Some(numbervar(Integer::from(offset + &*n))),
_ => None,
}
_ => {
None
}
)
}
impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
pub fn new(
heap: &'a mut Heap,
atom_tbl: Arc<AtomTable>,
stack: &'a mut Stack,
arena: &'a Arena,
op_dir: &'a OpDir,
output: Outputter,
cell: HeapCellValue,
term_loc: usize,
) -> Self {
HCPrinter {
outputter: output,
iter: stackful_preorder_iter(heap, stack, cell),
atom_tbl,
iter: stackful_preorder_iter(heap, stack, term_loc),
arena,
op_dir,
state_stack: vec![],
toplevel_spec: None,
@@ -553,17 +589,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
#[inline]
fn ambiguity_check(&self, atom: &str) -> bool {
let tail = &self.outputter.as_str()[self.last_item_idx..];
if atom == "," || !self.quoted || non_quoted_token(atom.chars()) {
requires_space(tail, atom)
} else {
requires_space(tail, "'")
}
}
fn set_parent_of_first_op(&mut self, parent_op: Option<DirectedOp>) {
if let Some(op) = parent_op {
if op.is_left() && op.is_prefix() {
@@ -806,13 +831,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
read_heap_cell!(cell,
(HeapCellValueTag::Lis | HeapCellValueTag::Str, h) => {
Some(format!("{}", h))
Some(format!("{h}"))
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
Some(format!("_{}", h))
Some(format!("_{h}"))
}
(HeapCellValueTag::StackVar, h) => {
Some(format!("_s_{}", h))
Some(format!("_s_{h}"))
}
_ => {
None
@@ -878,7 +903,12 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} else {
debug_assert!(cell.is_ref());
let h = cell.get_value() as usize;
let h = if cell.get_tag() == HeapCellValueTag::PStrLoc {
self.iter.focus().value()
} else {
cell.get_value()
} as usize;
self.iter.push_stack(IterStackLoc::iterable_loc(
h,
HeapOrStackTag::Heap,
@@ -908,7 +938,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
orig_cell = cell;
continue;
}
}
};
}
}
@@ -972,13 +1002,13 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
#[inline]
fn print_ip_addr(&mut self, ip: IpAddr) {
push_char!(self, '\'');
append_str!(self, &format!("{}", ip));
append_str!(self, &format!("{ip}"));
push_char!(self, '\'');
}
#[inline]
fn print_raw_ptr(&mut self, ptr: *const ArenaHeader) {
append_str!(self, &format!("0x{:x}", ptr as *const u8 as usize));
append_str!(self, &format!("0x{:x}", ptr.addr()));
}
fn print_number(&mut self, max_depth: usize, n: NumberFocus, op: &Option<DirectedOp>) {
@@ -1009,7 +1039,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.print_rational(max_depth, r, *op);
}
n => {
let output_str = format!("{}", n);
let output_str = format!("{n}");
push_space_if_amb!(self, &output_str, {
append_str!(self, &output_str);
@@ -1056,7 +1086,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
match self.op_dir.get(&(atom!("rdiv"), Fixity::In)) {
Some(op_desc) => {
if r.is_int() {
let output_str = format!("{}", r);
let output_str = format!("{r}");
push_space_if_amb!(self, &output_str, {
append_str!(self, &output_str);
@@ -1123,9 +1153,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
// returns true if max_depth limit is reached and ellipsis is printed.
fn print_string_as_functor(&mut self, focus: usize, max_depth: &mut usize) -> bool {
let iter = HeapPStrIter::new(self.iter.heap, focus);
let mut iter = HeapPStrIter::new(self.iter.heap, focus);
let mut char_count = 0;
for (char_count, c) in iter.chars().enumerate() {
while let Some(iteratee) = iter.next() {
if self.check_max_depth(max_depth) {
if char_count > 0 {
self.state_stack.push(TokenOrRedirect::Close);
@@ -1135,13 +1166,34 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
return true;
}
macro_rules! emit_char {
($c:expr) => {{
append_str!(self, "'.'");
push_char!(self, '(');
print_char!(self, self.quoted, c);
print_char!(self, self.quoted, $c);
push_char!(self, ',');
self.state_stack.push(TokenOrRedirect::Close);
char_count += 1;
}};
}
match iteratee {
PStrIteratee::Char { value, .. } => {
emit_char!(value);
}
PStrIteratee::PStrSlice {
slice_loc,
slice_len,
} => {
let s = iter.heap.slice_to_str(slice_loc, slice_len);
for c in s.chars() {
emit_char!(c);
}
}
}
}
false
@@ -1152,7 +1204,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn print_proper_string(&mut self, focus: usize, max_depth: usize) {
push_char!(self, '"');
let iter = HeapPStrIter::new(self.iter.heap, focus);
let mut iter = HeapPStrIter::new(self.iter.heap, focus);
let char_to_string = |c: char| {
// refrain from quoting characters other than '"' and '\'
// unless self.quoted is true.
@@ -1164,21 +1217,47 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
};
if max_depth == 0 {
for c in iter.chars() {
while let Some(iteratee) = iter.next() {
let iter: Box<dyn Iterator<Item = char>> = match iteratee {
PStrIteratee::Char { value: c, .. } => Box::new(std::iter::once(c)),
PStrIteratee::PStrSlice {
slice_loc,
slice_len,
} => {
let s = iter.heap.slice_to_str(slice_loc, slice_len);
Box::new(s.chars())
}
};
for c in iter {
for c in char_to_string(c).chars() {
push_char!(self, c);
}
}
}
} else {
let mut char_count = 0;
for c in iter.chars().take(max_depth) {
while let Some(iteratee) = iter.next() {
let iter: Box<dyn Iterator<Item = char>> = match iteratee {
PStrIteratee::Char { value: c, .. } => Box::new(std::iter::once(c)),
PStrIteratee::PStrSlice {
slice_loc,
slice_len,
} => {
let s = iter.heap.slice_to_str(slice_loc, slice_len);
Box::new(s.chars())
}
};
for c in iter.take(max_depth - char_count) {
char_count += 1;
for c in char_to_string(c).chars() {
push_char!(self, c);
}
}
}
if char_count == max_depth {
append_str!(self, " ...");
@@ -1194,10 +1273,9 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.iter.pop_stack();
self.iter.pop_stack();
}
HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset => {
HeapCellValueTag::PStrLoc => {
self.iter.pop_stack();
}
HeapCellValueTag::CStr => {}
_ => {
unreachable!();
}
@@ -1208,19 +1286,15 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let focus = self.iter.focus();
let mut heap_pstr_iter = HeapPStrIter::new(self.iter.heap, focus.value() as usize);
let next_h;
let next_hare;
if heap_pstr_iter.next().is_some() {
next_h = heap_pstr_iter.focus;
next_hare = heap_pstr_iter.focus();
let is_cyclic = if heap_pstr_iter.next().is_some() {
for _ in heap_pstr_iter.by_ref() {}
heap_pstr_iter.is_cyclic()
} else {
return self.push_list(max_depth);
}
};
let end_h = heap_pstr_iter.focus();
let end_cell = heap_pstr_iter.focus;
let end_cell = heap_pstr_iter.heap[end_h]; // heap_pstr_iter.focus;
if self.check_max_depth(&mut max_depth) {
self.remove_list_children(focus.value() as usize);
@@ -1230,7 +1304,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
let at_cdr = self.outputter.ends_with("|");
if self.double_quotes && !self.ignore_ops && end_cell.is_string_terminator(self.iter.heap) {
if self.double_quotes
&& !self.ignore_ops
&& !is_cyclic
&& end_cell.is_string_terminator(self.iter.heap)
{
self.remove_list_children(focus.value() as usize);
return self.print_proper_string(focus.value() as usize, max_depth);
}
@@ -1261,37 +1339,27 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
(HeapCellValueTag::Lis) => {
self.push_list(max_depth)
}
_ => {
(HeapCellValueTag::PStrLoc, h) => {
let switch = Rc::new(Cell::new((!at_cdr, 0)));
let switch = self.close_list(switch);
let (h, offset) = pstr_loc_and_offset(self.iter.heap, focus.value() as usize);
let offset = offset.get_num() as usize;
let tag = value.get_tag();
let end_h = if tag == HeapCellValueTag::PStrOffset {
// remove the fixnum offset from the iterator stack so we don't
// print an extraneous number. pstr offset value cells are never
// used by the iterator to mark cyclic terms so the removal is safe.
self.iter.pop_stack();
Some(next_hare)
// Some(end_h)
} else {
None
};
if !self.max_depth_exhausted(max_depth) {
let pstr = cell_as_string!(self.iter.heap[h]);
self.state_stack.push(TokenOrRedirect::CommaSeparatedCharList(CommaSeparatedCharList {
pstr, offset, max_depth, end_cell: next_h, end_h,
}));
self.state_stack.push(
TokenOrRedirect::CommaSeparatedCharList(
CommaSeparatedCharList {
pstr_loc: h, max_depth,
}
),
);
} else {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
}
self.open_list(switch);
}
_ => {
unreachable!()
}
);
}
}
@@ -1384,7 +1452,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|| if let Some(ref op) = op {
if self.numbervars && arity == 1 && name == atom!("$VAR") {
!self.iter.immediate_leaf_has_property(|addr| {
match Number::try_from(addr) {
match Number::try_from((addr, &self.arena.f64_tbl)) {
Ok(Number::Integer(n)) => (*n).sign() == Sign::Positive,
Ok(Number::Fixnum(n)) => n.get_num() >= 0,
Ok(Number::Float(f)) => f >= OrderedFloat(0f64),
@@ -1458,7 +1526,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
self.state_stack.push(TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port as i64))),
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(port))),
None,
));
self.state_stack.push(TokenOrRedirect::Comma);
@@ -1469,23 +1537,29 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
}
}
fn print_index_ptr(&mut self, index_ptr: IndexPtr, max_depth: usize) {
fn print_index_ptr(&mut self, idx: CodeIndexOffset, max_depth: usize) {
if self.format_struct(max_depth, 1, atom!("$index_ptr")) {
let atom = self.state_stack.pop().unwrap();
self.state_stack.pop();
self.state_stack.pop();
let offset = if index_ptr.is_undefined() || index_ptr.is_dynamic_undefined() {
let idx_ptr = self.arena.code_index_tbl.get_entry(idx);
let offset = if idx_ptr.is_undefined() || idx_ptr.is_dynamic_undefined() {
TokenOrRedirect::Atom(atom!("undefined"))
} else {
let idx = index_ptr.p() as i64;
let idx_ptr_p = idx_ptr.p() as i64;
if let Ok(n) = Fixnum::build_with_checked(idx_ptr_p) {
TokenOrRedirect::NumberFocus(
max_depth,
NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(idx))),
NumberFocus::Unfocused(Number::Fixnum(n)),
None,
)
} else {
TokenOrRedirect::Atom(atom!("out_of_bounds_idx_ptr"))
}
};
self.state_stack.push(offset);
@@ -1521,32 +1595,26 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn print_comma_separated_char_list(&mut self, char_list: CommaSeparatedCharList) {
let CommaSeparatedCharList {
pstr,
offset,
pstr_loc,
max_depth,
end_cell,
end_h,
} = char_list;
let pstr_str = pstr.as_str_from(offset);
if let Some(c) = pstr_str.chars().next() {
let offset = offset + c.len_utf8();
let c = self.iter.heap.char_at(pstr_loc);
if c != '\u{0}' {
if !self.max_depth_exhausted(max_depth) {
self.state_stack
.push(TokenOrRedirect::CommaSeparatedCharList(
CommaSeparatedCharList {
pstr,
offset,
pstr_loc: pstr_loc + c.len_utf8(),
max_depth: max_depth.saturating_sub(1),
end_cell,
end_h,
},
));
let max_depth_allows = self.max_depth == 0 || max_depth > 1;
let next_c = self.iter.heap.char_at(pstr_loc + c.len_utf8());
if max_depth_allows && pstr_str.chars().nth(1).is_some() {
if max_depth_allows && next_c != '\u{0}' {
self.state_stack.push(TokenOrRedirect::Comma);
}
@@ -1558,12 +1626,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
} else if self.max_depth_exhausted(max_depth) {
self.state_stack.push(TokenOrRedirect::Atom(atom!("...")));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
} else if end_cell != empty_list_as_cell!() {
if let Some(end_h) = end_h {
self.iter
.push_stack(IterStackLoc::iterable_loc(end_h, HeapOrStackTag::Heap));
}
} else {
self.state_stack
.push(TokenOrRedirect::FunctorRedirect(max_depth + 1));
self.state_stack.push(TokenOrRedirect::HeadTailSeparator);
@@ -1576,7 +1639,8 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
is_functor_redirect: bool,
mut max_depth: usize,
) {
let negated_operand = negated_op_needs_bracketing(&self.iter, self.op_dir, &op);
let negated_operand =
negated_op_needs_bracketing(&self.iter, &self.arena.f64_tbl, self.op_dir, &op);
let addr = match self.check_for_seen(&mut max_depth) {
Some(addr) => addr,
@@ -1658,10 +1722,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
(HeapCellValueTag::Atom, (name, arity)) => {
print_struct(self, name, arity);
}
(HeapCellValueTag::Char, c) => {
let name = AtomTable::build_with(&self.atom_tbl, &String::from(c));
print_struct(self, name, 0);
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.iter.heap[s])
.get_name_and_arity();
@@ -1682,13 +1742,17 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
});
}
}
(HeapCellValueTag::CodeIndexOffset, idx) => {
self.print_index_ptr(idx, self.max_depth);
}
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint, n) => {
self.print_number(max_depth, NumberFocus::Unfocused(Number::Fixnum(n)), &op);
}
(HeapCellValueTag::F64, f) => {
self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op);
(HeapCellValueTag::F64Offset, offset) => {
let f = self.arena.f64_tbl.get_entry(offset);
self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(f)), &op);
}
(HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
(HeapCellValueTag::PStrLoc) => {
self.print_list_like(max_depth);
}
(HeapCellValueTag::Lis) => {
@@ -1725,8 +1789,22 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
(ArenaHeaderTag::Dropped, _value) => {
self.print_impromptu_atom(atom!("$dropped_value"));
}
(ArenaHeaderTag::IndexPtr, index_ptr) => {
self.print_index_ptr(*index_ptr, max_depth);
(ArenaHeaderTag::ChildProcess, process) => {
let process_atom = atom!("$process");
if self.format_struct(max_depth, 1, process_atom) {
let atom = TokenOrRedirect::NumberFocus(max_depth, NumberFocus::Unfocused(Number::Fixnum(Fixnum::build_with(process.id()))), op);
let process_root = self.state_stack.pop().unwrap();
self.state_stack.pop();
self.state_stack.pop();
self.state_stack.push(atom);
self.state_stack.push(TokenOrRedirect::Open);
self.state_stack.push(process_root);
}
}
_ => {
}
@@ -1825,6 +1903,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
mod tests {
use super::*;
use crate::functor_macro::*;
use crate::machine::mock_wam::*;
#[test]
@@ -1832,23 +1911,30 @@ mod tests {
fn term_printing_tests() {
let mut wam = MockWAM::new();
// clear the heap of resource error data etc
wam.machine_st.heap.clear();
let f_atom = atom!("f");
let a_atom = atom!("a");
let b_atom = atom!("b");
let c_atom = atom!("c");
wam.machine_st
.heap
.extend(functor!(f_atom, [atom(a_atom), atom(b_atom)]));
let mut functor_writer = Heap::functor_writer(functor!(
f_atom,
[atom_as_cell(a_atom), atom_as_cell(b_atom)]
));
let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
wam.machine_st.heap.push_cell(cell).unwrap();
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
3,
);
let output = printer.print();
@@ -1860,24 +1946,28 @@ mod tests {
wam.machine_st.heap.clear();
wam.machine_st.heap.extend(functor!(
let mut functor_writer = Heap::functor_writer(functor!(
f_atom,
[
atom(a_atom),
atom(b_atom),
atom(a_atom),
cell(str_loc_as_cell!(0))
atom_as_cell(a_atom),
atom_as_cell(b_atom),
atom_as_cell(a_atom),
str_loc_as_cell(0)
]
));
let cell = functor_writer(&mut wam.machine_st.heap).unwrap();
wam.machine_st.heap.push_cell(cell).unwrap();
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
5,
);
let output = printer.print();
@@ -1889,19 +1979,23 @@ mod tests {
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(96).unwrap();
// print L = [L|L].
wam.machine_st.heap.push(list_loc_as_cell!(1));
wam.machine_st.heap.push(list_loc_as_cell!(1));
wam.machine_st.heap.push(list_loc_as_cell!(1));
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
section.push_cell(list_loc_as_cell!(1));
section.push_cell(list_loc_as_cell!(1));
});
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
0,
);
let output = printer.print();
@@ -1910,11 +2004,11 @@ mod tests {
let mut printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
0,
);
printer
@@ -1930,24 +2024,35 @@ mod tests {
wam.machine_st.heap.clear();
let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]);
let mut writer = wam.machine_st.heap.reserve(96).unwrap();
wam.machine_st.heap.push(list_loc_as_cell!(1));
wam.machine_st.heap.push(str_loc_as_cell!(5));
wam.machine_st.heap.push(list_loc_as_cell!(3));
wam.machine_st.heap.push(str_loc_as_cell!(5));
wam.machine_st.heap.push(empty_list_as_cell!());
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
section.push_cell(str_loc_as_cell!(5));
section.push_cell(list_loc_as_cell!(3));
section.push_cell(str_loc_as_cell!(5));
section.push_cell(empty_list_as_cell!());
});
wam.machine_st.heap.extend(functor);
let mut functor_writer = Heap::functor_writer(functor!(
f_atom,
[
atom_as_cell(a_atom),
atom_as_cell(b_atom),
atom_as_cell(b_atom)
]
));
functor_writer(&mut wam.machine_st.heap).unwrap();
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
0,
);
let output = printer.print();
@@ -1962,11 +2067,11 @@ mod tests {
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
0,
);
let output = printer.print();
@@ -1979,11 +2084,11 @@ mod tests {
{
let mut printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
0,
);
printer
@@ -1999,23 +2104,28 @@ mod tests {
// issue #382
wam.machine_st.heap.clear();
wam.machine_st.heap.push(list_loc_as_cell!(1));
let mut writer = wam.machine_st.heap.reserve(6002).unwrap();
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
for idx in 0..3000 {
wam.machine_st.heap.push(heap_loc_as_cell!(2 * idx + 1));
wam.machine_st.heap.push(list_loc_as_cell!(2 * idx + 2 + 1));
section.push_cell(heap_loc_as_cell!(2 * idx + 1));
section.push_cell(list_loc_as_cell!(2 * idx + 2 + 1));
}
wam.machine_st.heap.push(empty_list_as_cell!());
section.push_cell(empty_list_as_cell!());
});
{
let mut printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
0,
);
printer.max_depth = 5;
@@ -2029,16 +2139,19 @@ mod tests {
wam.machine_st.heap.clear();
put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl);
wam.machine_st.heap.allocate_pstr("abc").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
{
let printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
pstr_loc_as_cell!(0),
2,
);
let output = printer.print();
@@ -2048,25 +2161,27 @@ mod tests {
all_cells_unmarked(&wam.machine_st.heap);
wam.machine_st.heap.pop();
let mut writer = wam.machine_st.heap.reserve(96).unwrap();
wam.machine_st.heap.push(list_loc_as_cell!(2));
writer.write_with(|section| {
section.push_cell(atom_as_cell!(a_atom));
section.push_cell(list_loc_as_cell!(5));
section.push_cell(atom_as_cell!(b_atom));
section.push_cell(list_loc_as_cell!(7));
section.push_cell(atom_as_cell!(c_atom));
section.push_cell(empty_list_as_cell!());
});
wam.machine_st.heap.push(atom_as_cell!(a_atom));
wam.machine_st.heap.push(list_loc_as_cell!(4));
wam.machine_st.heap.push(atom_as_cell!(b_atom));
wam.machine_st.heap.push(list_loc_as_cell!(6));
wam.machine_st.heap.push(atom_as_cell!(c_atom));
wam.machine_st.heap.push(empty_list_as_cell!());
wam.machine_st.heap[1] = list_loc_as_cell!(3);
{
let mut printer = HCPrinter::new(
&mut wam.machine_st.heap,
Arc::clone(&wam.machine_st.atom_tbl),
&mut wam.machine_st.stack,
&wam.machine_st.arena,
&wam.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(0),
2,
);
printer.double_quotes = true;
+43 -73
View File
@@ -3,6 +3,7 @@ use crate::parser::ast::*;
use crate::forms::*;
use crate::instructions::*;
use crate::types::HeapCellValue;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
@@ -112,7 +113,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
match constant_key {
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
constants.insert(*constant, constant_ptr);
constants.insert(HeapCellValue::from(*constant), constant_ptr);
}
_ if constant_ptr.is_external() => {
// this must be a defunct clause, because it's been deleted
@@ -144,7 +145,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_static_indexed_choice_for_constant(
&mut self,
external: usize,
constant: Literal,
constant: HeapCellValue,
index: usize,
) {
let third_level_index = if self.append_or_prepend.is_append() {
@@ -181,7 +182,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn add_dynamic_indexed_choice_for_constant(
&mut self,
external: usize,
constant: Literal,
constant: HeapCellValue,
index: usize,
) {
let third_level_index = if self.append_or_prepend.is_append() {
@@ -235,8 +236,8 @@ impl<'a> IndexingCodeMergingPtr<'a> {
fn index_overlapping_constant(
&mut self,
orig_constant: Literal,
overlapping_constant: Literal,
orig_constant: HeapCellValue,
overlapping_constant: HeapCellValue,
index: usize,
) {
loop {
@@ -316,7 +317,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
}
}
fn index_constant(&mut self, constant: Literal, index: usize) {
fn index_constant(&mut self, constant: HeapCellValue, index: usize) {
loop {
let indexing_code_len = self.indexing_code.len();
@@ -633,12 +634,15 @@ pub(crate) fn merge_clause_index(
match &opt_arg_index_key {
OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
let offset = new_clause_loc - index_loc + 1;
merging_ptr.index_constant(*constant, offset);
merging_ptr.index_constant(HeapCellValue::from(*constant), offset);
for overlapping_constant in overlapping_constants {
if let Some(overlapping_constant) = overlapping_constants {
merging_ptr.offset = 0;
merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset);
merging_ptr.index_overlapping_constant(
HeapCellValue::from(*constant),
HeapCellValue::from(*overlapping_constant),
offset,
);
}
}
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
@@ -664,7 +668,7 @@ pub(crate) fn merge_clause_index(
pub(crate) fn remove_constant_indices(
constant: Literal,
overlapping_constants: &[Literal],
overlapping_constants: Option<Literal>,
indexing_code: &mut [IndexingLine],
offset: usize,
) {
@@ -693,7 +697,7 @@ pub(crate) fn remove_constant_indices(
let mut constants_index = 0;
for constant in iter {
for constant in iter.map(|l| HeapCellValue::from(*l)) {
loop {
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
@@ -701,8 +705,6 @@ pub(crate) fn remove_constant_indices(
)) => {
constants_index = index;
let constant = *constant;
match constants.get(&constant).cloned() {
Some(IndexingCodePtr::DynamicExternal(_))
| Some(IndexingCodePtr::External(_))
@@ -740,7 +742,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
constants.insert(*constant, ext);
constants.insert(constant, ext);
}
_ => {
unreachable!()
@@ -773,7 +775,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
constants.insert(*constant, ext);
constants.insert(constant, ext);
}
_ => {
unreachable!()
@@ -1033,7 +1035,7 @@ pub(crate) fn remove_index(
) {
match opt_arg_index_key {
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
remove_constant_indices(*constant, *overlapping_constants, indexing_code, clause_loc);
}
OptArgIndexKey::Structure(_, _, name, arity) => {
remove_structure_index(*name, *arity, indexing_code, clause_loc);
@@ -1095,56 +1097,26 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
}
}
pub(crate) fn constant_key_alternatives(
constant: Literal,
atom_tbl: &AtomTable,
// arena: &mut Arena,
) -> Vec<Literal> {
let mut constants = vec![];
pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
let n = match &constant {
Literal::Rational(n) if n.denominator().is_one() => n.numerator(),
Literal::Integer(n) => n,
_ => return None,
};
match constant {
Literal::Atom(ref name) => {
if let Some(c) = name.as_char() {
constants.push(Literal::Char(c));
}
}
Literal::Char(c) => {
let atom = AtomTable::build_with(atom_tbl, &c.to_string());
constants.push(Literal::Atom(atom));
}
/*
// constant_to_literal takes care of the downward conversion from Integer to Fixnum
// if possible.
Literal::Fixnum(ref n) => {
constants.push(Literal::Integer(arena_alloc!(n, arena)));
}
*/
Literal::Integer(ref n) => {
let result = (&**n).try_into();
if let Ok(value) = result {
Fixnum::build_with_checked(value)
.map(|n| {
constants.push(Literal::Fixnum(n));
})
.unwrap();
}
}
_ => {}
}
constants
Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
}
#[derive(Debug)]
pub(crate) struct StaticCodeIndices {
constants: IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
constants: IndexMap<HeapCellValue, VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
lists: VecDeque<IndexedChoiceInstruction>,
structures: IndexMap<(Atom, usize), VecDeque<IndexedChoiceInstruction>, FxBuildHasher>,
}
#[derive(Debug)]
pub(crate) struct DynamicCodeIndices {
constants: IndexMap<Literal, VecDeque<usize>, FxBuildHasher>,
constants: IndexMap<HeapCellValue, VecDeque<usize>, FxBuildHasher>,
lists: VecDeque<usize>,
structures: IndexMap<(Atom, usize), VecDeque<usize>, FxBuildHasher>,
}
@@ -1156,7 +1128,7 @@ pub(crate) trait Indexer {
fn constants(
&mut self,
) -> &mut IndexMap<Literal, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
) -> &mut IndexMap<HeapCellValue, VecDeque<Self::ThirdLevelIndex>, FxBuildHasher>;
fn lists(&mut self) -> &mut VecDeque<Self::ThirdLevelIndex>;
fn structures(
&mut self,
@@ -1204,7 +1176,7 @@ impl Indexer for StaticCodeIndices {
#[inline]
fn constants(
&mut self,
) -> &mut IndexMap<Literal, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
) -> &mut IndexMap<HeapCellValue, VecDeque<IndexedChoiceInstruction>, FxBuildHasher> {
&mut self.constants
}
@@ -1328,7 +1300,7 @@ impl Indexer for DynamicCodeIndices {
}
#[inline]
fn constants(&mut self) -> &mut IndexMap<Literal, VecDeque<usize>, FxBuildHasher> {
fn constants(&mut self) -> &mut IndexMap<HeapCellValue, VecDeque<usize>, FxBuildHasher> {
&mut self.constants
}
@@ -1447,14 +1419,13 @@ impl<I: Indexer> CodeOffsets<I> {
self.indices.lists().push_back(index);
}
fn index_constant(
&mut self,
atom_tbl: &AtomTable,
constant: Literal,
index: usize,
) -> Vec<Literal> {
let overlapping_constants = constant_key_alternatives(constant, atom_tbl);
let code = self.indices.constants().entry(constant).or_default();
fn index_constant(&mut self, constant: Literal, index: usize) -> Option<Literal> {
let overlapping_constant_opt = constant_key_alternatives(constant);
let code = self
.indices
.constants()
.entry(HeapCellValue::from(constant))
.or_default();
let is_initial_index = code.is_empty();
code.push_back(I::compute_index(
@@ -1463,8 +1434,8 @@ impl<I: Indexer> CodeOffsets<I> {
self.non_counted_bt,
));
for constant in &overlapping_constants {
let code = self.indices.constants().entry(*constant).or_default();
if let Some(constant) = overlapping_constant_opt.map(HeapCellValue::from) {
let code = self.indices.constants().entry(constant).or_default();
let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
@@ -1472,7 +1443,7 @@ impl<I: Indexer> CodeOffsets<I> {
code.push_back(index);
}
overlapping_constants
overlapping_constant_opt
}
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
@@ -1494,14 +1465,13 @@ impl<I: Indexer> CodeOffsets<I> {
optimal_arg: &Term,
index: usize,
clause_index_info: &mut ClauseIndexInfo,
atom_tbl: &AtomTable,
) {
match optimal_arg {
&Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Cons(..) | &Term::Literal(_, Literal::String(_)) | &Term::PartialString(..) => {
&Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
@@ -1512,7 +1482,7 @@ impl<I: Indexer> CodeOffsets<I> {
self.index_structure(name, terms.len(), index);
}
&Term::Literal(_, constant) => {
let overlapping_constants = self.index_constant(atom_tbl, constant, index);
let overlapping_constants = self.index_constant(constant, index);
clause_index_info.opt_arg_index_key =
OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
+25 -34
View File
@@ -6,6 +6,7 @@ use crate::parser::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::iter::*;
use std::rc::Rc;
use std::vec::Vec;
#[allow(clippy::borrowed_box)]
@@ -15,27 +16,11 @@ pub(crate) enum TermRef<'a> {
Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
Literal(Level, &'a Cell<RegType>, &'a Literal),
Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
PartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Atom),
PartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
Var(Level, &'a Cell<VarReg>, VarPtr),
}
/*
impl<'a> TermRef<'a> {
pub(crate) fn level(&self) -> Level {
match self {
TermRef::AnonVar(lvl) |
TermRef::Cons(lvl, ..) |
TermRef::Literal(lvl, ..) |
TermRef::Var(lvl, ..) |
TermRef::Clause(lvl, ..) |
TermRef::CompleteString(lvl, ..) |
TermRef::PartialString(lvl, ..) => *lvl,
}
}
}
*/
#[allow(clippy::borrowed_box)]
#[derive(Debug)]
pub(crate) enum TermIterState<'a> {
@@ -44,9 +29,9 @@ pub(crate) enum TermIterState<'a> {
Literal(Level, &'a Cell<RegType>, &'a Literal),
InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
InitialPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
FinalPartialString(Level, &'a Cell<RegType>, &'a String, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Atom),
InitialPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
FinalPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
CompleteString(Level, &'a Cell<RegType>, Rc<String>),
Var(Level, &'a Cell<VarReg>, VarPtr),
}
@@ -62,9 +47,11 @@ impl<'a> TermIterState<'a> {
}
Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
Term::PartialString(cell, string_buf, tail) => {
TermIterState::InitialPartialString(lvl, cell, string_buf, tail)
TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail)
}
Term::CompleteString(cell, string) => {
TermIterState::CompleteString(lvl, cell, string.clone())
}
Term::CompleteString(cell, atom) => TermIterState::CompleteString(lvl, cell, *atom),
Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
}
}
@@ -182,11 +169,11 @@ impl<'a> Iterator for QueryIterator<'a> {
.push(TermIterState::FinalPartialString(lvl, cell, string, tail));
self.push_subterm(lvl.child_level(), tail);
}
TermIterState::FinalPartialString(lvl, cell, atom, tail) => {
return Some(TermRef::PartialString(lvl, cell, atom, tail));
TermIterState::FinalPartialString(lvl, cell, string, tail) => {
return Some(TermRef::PartialString(lvl, cell, string, tail));
}
TermIterState::CompleteString(lvl, cell, atom) => {
return Some(TermRef::CompleteString(lvl, cell, atom));
TermIterState::CompleteString(lvl, cell, string) => {
return Some(TermRef::CompleteString(lvl, cell, string));
}
TermIterState::FinalCons(lvl, cell, head, tail) => {
return Some(TermRef::Cons(lvl, cell, head, tail));
@@ -242,16 +229,20 @@ impl<'a> FactIterator<'a> {
head.as_ref(),
tail.as_ref(),
)],
Term::PartialString(cell, string_buf, tail) => {
Term::PartialString(cell, string, tail) => {
vec![TermIterState::InitialPartialString(
Level::Root,
cell,
string_buf,
string.clone(),
tail,
)]
}
Term::CompleteString(cell, atom) => {
vec![TermIterState::CompleteString(Level::Root, cell, *atom)]
Term::CompleteString(cell, string) => {
vec![TermIterState::CompleteString(
Level::Root,
cell,
string.clone(),
)]
}
Term::Literal(cell, constant) => {
vec![TermIterState::Literal(Level::Root, cell, constant)]
@@ -336,7 +327,7 @@ pub(crate) enum ClauseItem<'a> {
FirstBranch(usize),
NextBranch,
BranchEnd(usize),
Chunk(&'a VecDeque<QueryTerm>),
Chunk { terms: &'a VecDeque<QueryTerm> },
}
#[derive(Debug)]
@@ -412,8 +403,8 @@ impl<'a> Iterator for ClauseIterator<'a> {
self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, 0));
}
ChunkedTerms::Chunk(chunk) => {
return Some(ClauseItem::Chunk(chunk));
ChunkedTerms::Chunk { ref terms } => {
return Some(ClauseItem::Chunk { terms });
}
}
}
+3
View File
@@ -11,8 +11,11 @@ pub(crate) mod macros;
pub(crate) mod atom_table;
#[macro_use]
pub(crate) mod arena;
pub(crate) mod offset_table;
#[macro_use]
pub(crate) mod parser;
#[macro_use]
pub(crate) mod functor_macro;
mod allocator;
mod arithmetic;
pub(crate) mod codegen;
+14 -7
View File
@@ -125,7 +125,7 @@ call(_, _, _, _, _, _, _, _, _).
%
% The flags that Scryer Prolog support are:
%
% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 1023. Read only.
% * `max_arity`: The max arity a predicate can have in Prolog. On Scryer is set to 255. Read only.
% * `bounded`: `true` if integer arithmethic is bounded between some min/max values. On Scryer is always set
% to `false` since it supports unbounded integer arithmethic. Read only.
% * `integer_rounding_function`: Describes the rounding donde by `//` and `rem` functions. On Scryer is
@@ -145,8 +145,8 @@ call(_, _, _, _, _, _, _, _, _).
% `fail` (the call silently fails) and `warn` (the call fails and a warning about the undefined predicate is printed).
% * `answer_write_options`: Additional write options used by the top level for writing answers.
%
current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 1023.
current_prolog_flag(max_arity, 1023).
current_prolog_flag(Flag, Value) :- Flag == max_arity, !, Value = 255.
current_prolog_flag(max_arity, 255).
current_prolog_flag(Flag, Value) :- Flag == bounded, !, Value = false.
current_prolog_flag(bounded, false).
current_prolog_flag(Flag, Value) :- Flag == integer_rounding_function, !, Value == toward_zero.
@@ -1719,20 +1719,27 @@ must_be_number(N, PI) :-
).
chars_or_vars(Cs, _) :-
chars_or_vars(Cs, PI) :-
( '$is_partial_string'(Cs) ->
% use a fast test for the expected case
true
; chars_or_vars_(Cs, PI)
).
chars_or_vars_(Cs, _) :-
( var(Cs) ->
!
; Cs == [] ->
!
).
chars_or_vars([C|Cs], PI) :-
chars_or_vars_([C|Cs], PI) :-
( nonvar(C) ->
( atom(C),
atom_length(C, 1) ->
chars_or_vars(Cs, PI)
chars_or_vars_(Cs, PI)
; throw(error(type_error(character, C), PI))
)
; chars_or_vars(Cs, PI)
; chars_or_vars_(Cs, PI)
).
+6 -7
View File
@@ -22,6 +22,7 @@ but they're not part of the ISO Prolog standard at the moment.
copy_term/3]).
:- use_module(library(error), [can_be/2,
must_be/2,
domain_error/3,
instantiation_error/1,
type_error/3]).
@@ -275,17 +276,15 @@ call_with_inference_limit(_, _, R, Bb, B) :-
; nonvar(R)
).
%% partial_string(String, L, L0)
%% partial_string(String, Ls0, Ls)
%
% Explicitly construct a partial string "manually". It can be used as an optimized append/3.
% It's not recommended to use this predicate in application code.
partial_string(String, L, L0) :-
partial_string(String, Ls0, Ls) :-
must_be(chars, String),
( String == [] ->
L = L0
; catch(atom_chars(Atom, String),
error(E, _),
throw(error(E, partial_string/3))),
'$create_partial_string'(Atom, L, L0)
Ls0 = Ls
; '$create_partial_string'(String, Ls0, Ls)
).
%% partial_string(+String)
+22 -14
View File
@@ -39,7 +39,8 @@
% represented as a list of characters.
phrase_from_stream(GRBody, Stream) :-
stream_to_lazy_list(Stream, Ls),
stream_property(Stream, reposition(Reposition)),
stream_to_lazy_list(Reposition, Stream, Ls),
phrase(GRBody, Ls).
%% phrase_from_file(+GRBody, +File)
@@ -64,7 +65,7 @@ phrase_from_file(NT, File, Options) :-
; Type = text
),
setup_call_cleanup(
open(File, read, Stream, Options),
open(File, read, Stream, [reposition(true)|Options]),
phrase_from_stream(NT, Stream),
close(Stream)
)
@@ -73,34 +74,41 @@ phrase_from_file(NT, File, Options) :-
% How many chars to read from stream and buffer in each step
chars_to_read(4096).
stream_to_lazy_list(Stream, Ls) :-
get_stream_buffer_position(Stream, Pos),
freeze(Ls, render_step(Stream, Pos, Ls)).
stream_to_lazy_list(Reposition, Stream, Ls) :-
get_stream_buffer_position(Reposition, Stream, Pos),
freeze(Ls, render_step(Reposition, Stream, Pos, Ls)).
render_step(Stream, Pos, Ls) :-
set_stream_buffer_position(Stream, Pos),
( buffer_at_end_of_stream(Stream) ->
render_step(Reposition, Stream, Pos, Ls) :-
set_stream_buffer_position(Reposition, Stream, Pos),
( buffer_at_end_of_stream(Reposition, Stream) ->
Ls = []
; chars_to_read(CharsToRead),
buffer_get_n_chars(Stream, CharsToRead, Chars),
buffer_get_n_chars(Reposition, Stream, CharsToRead, Chars),
partial_string(Chars, Ls, Ls0),
stream_to_lazy_list(Stream, Ls0)
stream_to_lazy_list(Reposition, Stream, Ls0)
).
buffer_at_end_of_stream(Stream) :-
buffer_at_end_of_stream(true, Stream) :- at_end_of_stream(Stream).
buffer_at_end_of_stream(false, Stream) :-
stream_bufferids(Stream, _, BufferPosId, _),
bb_get(BufferPosId, Pos),
Pos = eof.
get_stream_buffer_position(Stream, Pos) :-
get_stream_buffer_position(true, Stream, Pos) :-
stream_property(Stream, position(Pos)).
get_stream_buffer_position(false, Stream, Pos) :-
stream_bufferids(Stream, _, BufferPosId, _),
bb_get(BufferPosId, Pos).
set_stream_buffer_position(Stream, Pos) :-
set_stream_buffer_position(true, Stream, Pos) :-
set_stream_position(Stream, Pos).
set_stream_buffer_position(false, Stream, Pos) :-
stream_bufferids(Stream, _, BufferPosId, _),
bb_put(BufferPosId, Pos).
buffer_get_n_chars(Stream, N, Chars) :-
buffer_get_n_chars(true, Stream, N, Chars) :-
get_n_chars(Stream, N, Chars).
buffer_get_n_chars(false, Stream, N, Chars) :-
stream_bufferids(Stream, BufferId, BufferPosId, BufferLenId),
buffer_prepare_for_n(Stream, BufferId, BufferPosId, BufferLenId, N),
bb_get(BufferId, Buffer),
+224
View File
@@ -0,0 +1,224 @@
:- module(process, [
process_create/3,
process_id/2,
process_release/1,
process_wait/2,
process_wait/3,
process_kill/1
]).
:- use_module(library(error)).
:- use_module(library(iso_ext)).
:- use_module(library(lists), [member/2, maplist/2, maplist/3, append/2]).
:- use_module(library(reif), [tfilter/3, memberd_t/3]).
%% process_create(+Exe, +Args:list, +Options).
%
% Create a new process by executing the executable Exe and passing it the Arguments Args.
%
% Note: On windows please take note of [windows argument splitting](https://doc.rust-lang.org/std/process/index.html#windows-argument-splitting).
%
% Options is a list consisting of the following options:
%
% * `cwd(+Path)` Set the processes working directory to `Path`
% * `process(-Process)` `Process` will be assigned a process handle for the spawned process
% * `env(+List)` Don't inherit environment variables and set the variables defined in `List`
% * `environment(+List)` Inherit environment variables and set/override the variables defined in `List`
% * `stdin(Spec)`, `stdout(Spec)` or `stderr(Spec)` defines how to redirect the spawned processes io streams
%
% The elements of `List` in `env(List)`/`environment(List)` List must be string pairs using `=/2`.
% `env/1` and `environment/1` may not be both specified.
%
% The following stdio `Spec` are available:
%
% * `std` inherit the current processes original stdio streams (does currently not account for stdio being changed by `set_input` or `set_output`)
% * `file(+Path)` attach the strea to the file at `Path`
% * `null` discards writes and behaves as eof for read. Equivalent to using `file(/dev/null)`
% * `pipe(-Steam)` create a new pipe and assigne one end to the created process and the other end to `Stream`
%
% Specifying an option multiple times is an error, when an option is not specified the following defaults apply:
%
% - `cwd(".")`
% - `environment([])`
% - `stdin(std)`, `stdout(std)`, `stderr(std)`
%
process_create(Exe, Args, Options) :- call_with_error_context(process_create_(Exe, Args, Options), predicate-process_create/3).
process_create_(Exe, Args, Options) :-
must_be(chars, Exe),
must_be(list, Args),
maplist(must_be(chars), Args),
must_be(list, Options),
check_options(
[
option([stdin], valid_stdio, stdin(std), stdin(Stdin)),
option([stdout], valid_stdio, stdout(std), stdout(Stdout)),
option([stderr], valid_stdio, stderr(std), stderr(Stderr)),
option([env, environment], valid_env, environment([]), Env),
option([process], valid_uninit_process, process(_), process(Process)),
option([cwd], valid_cwd, cwd("."), cwd(Cwd))
],
Options,
process_create_option
),
Stdin =.. Stdin1,
Stdout =.. Stdout1,
Stderr =.. Stderr1,
simplify_env(Env, Env1),
'$process_create'(Exe, Args, Stdin1, Stdout1, Stderr1, Env1, Cwd, Process).
%% process_id(+Process, -Pid).
%
process_id(Process, Pid) :- call_with_error_context(process_id_(Process, Pid), predicate-process_id/2).
process_id_(Process, Pid) :-
valid_process(Process),
must_be(var, Pid),
'$process_id'(Process, Pid).
%% process_wait(+Process, Status).
%
% See `process_create/3` with `Options = []`
%
process_wait(Process, Status) :- call_with_error_context(process_wait(Process, Status, []), predicate-process_wait/2).
%% process_wait(+Process, Status, Options).
%
% Wait for the process behind the process handle `Process` to exit.
%
% When the process exits regulary `Status` will be unified with `exit(Exit)` where `Exit` is the processes exit code.
% When the process exits was killed `Status` will be unified with `killed(Signal)` where `Signal` is the signal number that killed the process.
% When the process doesn't exit before the timeout `Status` will be unified with `timeout`.
%
% `Options` is a a list of the following options
%
% * timeout(Timeout) supported values for `Timeout` are 0 or `infinite`
%
% Each options may be specified at most once, when an option is not specified the following defaults apply:
%
% - timeout(infinite)
%
process_wait(Process, Status, Options) :- call_with_error_context(process_wait_(Process, Status, Options), predicate-process_wait/3).
process_wait_(Process, Status, Options) :-
valid_process(Process),
check_options(
[
option([timeout], valid_timeout, timeout(infinite), timeout(Timeout))
],
Options,
process_wait_option
),
'$process_wait'(Process, Exit, Timeout),
Exit = Status.
valid_timeout(timeout(infinite)).
valid_timeout(timeout(0)).
%% process_kill(+Process).
%
% Kill the process using the process handle `Process`.
% On Unix this sends SIGKILL.
%
% Only works for processes spawned with `process_create/3` that have not yet been release with `process_release/1`
%
process_kill(Process) :- call_with_error_context(process_kill_(Process), predicate-process_kill/1).
process_kill_(Process) :-
valid_process(Process),
'$process_kill'(Process).
%% process_release(+Process)
%
% wait for the process to exit (if not already) and release process handle `Process`
%
% It's an error if `Process` is not a valid process handle
%
process_release(Process) :- call_with_error_context(process_release_(Process), predicate-process_release/1).
process_release_(Process) :-
valid_process(Process),
process_wait(Process, _),
'$process_release'(Process).
must_be_known_options(Valid, Options, Domain) :- call_with_error_context(must_be_known_options_(Valid, [], Options, Domain),predicate-must_be_known_options/3).
must_be_known_options_(_, _, [], _).
must_be_known_options_(Valid, Found, [X|XS], Domain) :-
( functor(X, Option, 1) -> true
; domain_error(Domain, X, [])
) ,
( member(Option, Found) -> domain_error(non_duplicate_options, Option , [])
; member(Option, Valid) -> true
; domain_error(Domain, Option, [])
),
must_be_known_options_(Valid, [Option | Found], XS, Domain).
check_options(KnownOptions, Options, Domain) :- call_with_error_context(check_options_(KnownOptions, Options, Domain), predicate-check_options/3).
check_options_(KnownOptions, Options, Domain) :-
maplist(option_names, KnownOptions, Namess),
append(Namess, Names),
must_be_known_options(Names, Options, Domain),
extract_options(KnownOptions, Options).
option_names(option(Names,_,_,_), Names).
extract_options(KnownOptions, Options) :- call_with_error_context(extract_options_(KnownOptions, Options), predicate-extract_options/2).
extract_options_([], _).
extract_options_([X | XS], Options) :-
option(Kinds, Pred, Default, Choice) = X,
tfilter(find_option(Kinds), Options, Solutions),
( Solutions = [] -> Choice = Default
; Solutions = [Provided] -> functor(Pred, Name, Arity), ArityP1 is Arity+1, call_with_error_context(call(Pred, Provided),predicate-Name/ArityP1), Choice = Provided
; domain_error(non_conflicting_options, Solutions, [])
),
extract_options_(XS, Options).
find_option(Names, Found, T) :-
functor(Found, Name, 1),
memberd_t(Name, Names, T).
valid_stdio(IO) :- arg(1, IO, Arg),
( var(Arg) -> instantiation_error([])
; valid_stdio_(Arg) -> true
; domain_error(stdio_spec, Arg, [])
).
valid_stdio_(std).
valid_stdio_(null).
valid_stdio_(pipe(Stream)) :- must_be(var, Stream).
valid_stdio_(file(Path)) :- must_be(chars, Path).
valid_env(env(E)) :-
must_be(list, E),
( valid_env_(E) -> true
; domain_error(process_create_option, env(E), [])
).
valid_env(environment(E)) :-
must_be(list, E),
( valid_env_(E) -> true
; domain_error(process_create_option, environment(E), [])
).
valid_env_([]).
valid_env_([N=V|ES]) :-
must_be(chars, N),
must_be(chars, V),
valid_env_(ES).
valid_uninit_process(process(Process)) :- must_be(var, Process).
valid_process(Process) :- var(Process) -> instantiation_error([]) ; true.
valid_cwd(cwd(Cwd)) :- must_be(chars, Cwd).
simplify_env(E, [Kind, Envs1]) :- E =.. [Kind, Envs], simplify_env_(Envs, Envs1).
simplify_env_([],[]).
simplify_env_([N=V|E],[[N, V]|E1]) :- simplify_env_(E, E1).
+6 -6
View File
@@ -96,14 +96,14 @@ is_sgml_source([]).
is_sgml_source([C|Cs]) :- must_be(chars, [C|Cs]).
load_structure_([], [], _, _).
load_structure_([C|Cs], [E], Options, What) :-
load_(What, [C|Cs], E, Options).
load_structure_(file(Fs), [E], Options, What) :-
load_structure_([C|Cs], [E|Es], Options, What) :-
load_(What, [C|Cs], [E|Es], Options).
load_structure_(file(Fs), [E|Es], Options, What) :-
once(phrase_from_file(seq(Cs), Fs)),
load_(What, Cs, E, Options).
load_structure_(stream(Stream), [E], Options, What) :-
load_(What, Cs, [E|Es], Options).
load_structure_(stream(Stream), [E|Es], Options, What) :-
get_n_chars(Stream, _, Cs),
load_(What, Cs, E, Options).
load_(What, Cs, [E|Es], Options).
load_(html, Cs, E, Options) :- '$load_html'(Cs, E, Options).
load_(xml, Cs, E, Options) :- '$load_xml'(Cs, E, Options).
+2 -2
View File
@@ -299,7 +299,7 @@ expand_term_goals(Terms0, Terms) :-
( atom(Module) ->
prolog_load_context(module, Target),
module_expanded_head_variables(Head2, HeadVars),
catch(expand_goal(Body0, Target, Body1, HeadVars, []),
catch('$call'(loader:expand_goal(Body0, Target, Body1, HeadVars, [])),
error(type_error(callable, Pred), _),
( loader:print_goal_expansion_warning(Pred),
builtins:(Body1 = Body0)
@@ -309,7 +309,7 @@ expand_term_goals(Terms0, Terms) :-
)
; module_expanded_head_variables(Head1, HeadVars),
prolog_load_context(module, Target),
catch(expand_goal(Body0, Target, Body1, HeadVars, []),
catch('$call'(loader:expand_goal(Body0, Target, Body1, HeadVars, [])),
error(type_error(callable, Pred), _),
( loader:print_goal_expansion_warning(Pred),
builtins:(Body1 = Body0)
+24 -20
View File
@@ -11,6 +11,7 @@ use crate::forms::*;
use crate::heap_iter::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_state::*;
use crate::offset_table::*;
use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational};
use crate::types::*;
@@ -48,7 +49,7 @@ macro_rules! drop_iter_on_err {
};
}
fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen {
fn zero_divisor_eval_error(stub_gen: impl Fn() -> MachineStub + 'static) -> MachineStubGen {
Box::new(move |machine_st| {
let eval_error = machine_st.evaluation_error(EvalError::ZeroDivisor);
let stub = stub_gen();
@@ -57,7 +58,7 @@ fn zero_divisor_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Mach
})
}
fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> MachineStubGen {
fn undefined_eval_error(stub_gen: impl Fn() -> MachineStub + 'static) -> MachineStubGen {
Box::new(move |machine_st| {
let eval_error = machine_st.evaluation_error(EvalError::Undefined);
let stub = stub_gen();
@@ -69,7 +70,7 @@ fn undefined_eval_error(stub_gen: impl Fn() -> FunctorStub + 'static) -> Machine
fn numerical_type_error(
valid_type: ValidType,
n: Number,
stub_gen: impl Fn() -> FunctorStub + 'static,
stub_gen: impl Fn() -> MachineStub + 'static,
) -> MachineStubGen {
Box::new(move |machine_st| {
let type_error = machine_st.type_error(valid_type, n);
@@ -197,11 +198,10 @@ pub(crate) fn neg(n: Number, arena: &mut Arena) -> Number {
pub(crate) fn abs(n: Number, arena: &mut Arena) -> Number {
match n {
Number::Fixnum(n) => {
if let Some(n) = n.get_num().checked_abs() {
fixnum!(Number, n, arena)
if let Some(n) = n.checked_abs() {
Number::Fixnum(n)
} else {
let arena_int = Integer::from(n.get_num());
Number::arena_from(arena_int.abs(), arena)
Number::arena_from(Integer::from(Fixnum::MAX + 1), arena)
}
}
Number::Integer(n) => {
@@ -528,7 +528,7 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result<Number, MachineStubGen> {
pub fn rational_from_number(
n: Number,
stub_gen: impl Fn() -> FunctorStub + 'static,
stub_gen: impl Fn() -> MachineStub + 'static,
arena: &mut Arena,
) -> Result<TypedArenaPtr<Rational>, MachineStubGen> {
match n {
@@ -1104,7 +1104,7 @@ pub(crate) fn round(num: Number, arena: &mut Arena) -> Result<Number, MachineStu
pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
match n1 {
Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))),
Number::Fixnum(n) => Ok(Number::Fixnum(!n)),
Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
_ => {
let stub_gen = || {
@@ -1124,9 +1124,12 @@ impl MachineState {
&ArithmeticTerm::Reg(r) => {
let value = self.store(self.deref(self[r]));
match Number::try_from(value) {
match Number::try_from((value, &self.arena.f64_tbl)) {
Ok(n) => Ok(n),
Err(_) => self.arith_eval_by_metacall(value),
Err(_) => {
self.heap[0] = value;
self.arith_eval_by_metacall(0)
}
}
}
&ArithmeticTerm::Interm(i) => Ok(mem::replace(
@@ -1140,7 +1143,7 @@ impl MachineState {
pub fn get_rational(
&mut self,
at: &ArithmeticTerm,
caller: impl Fn() -> FunctorStub + 'static,
caller: impl Fn() -> MachineStub + 'static,
) -> Result<TypedArenaPtr<Rational>, MachineStub> {
let n = self.get_number(at)?;
@@ -1152,11 +1155,11 @@ impl MachineState {
pub(crate) fn arith_eval_by_metacall(
&mut self,
value: HeapCellValue,
term_loc: usize,
) -> Result<Number, MachineStub> {
let stub_gen = || functor_stub(atom!("is"), 2);
let mut iter =
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, value);
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_loc);
while let Some(value) = iter.next() {
if value.get_forwarding_bit() {
@@ -1169,7 +1172,7 @@ impl MachineState {
(HeapCellValueTag::Str, s) => {
cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
(HeapCellValueTag::Lis | // HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
HeapCellValueTag::PStrLoc) => {
(atom!("."), 2)
}
@@ -1385,8 +1388,9 @@ impl MachineState {
(HeapCellValueTag::Fixnum, n) => {
self.interms.push(Number::Fixnum(n));
}
(HeapCellValueTag::F64, fl) => {
self.interms.push(Number::Float(*fl));
(HeapCellValueTag::F64Offset, offset) => {
let fl = self.arena.f64_tbl.get_entry(offset);
self.interms.push(Number::Float(fl));
}
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
@@ -1449,7 +1453,7 @@ mod tests {
parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
assert_eq!(
wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
wam.arith_eval_by_metacall(term_write_result.heap_loc),
Ok(Number::Fixnum(Fixnum::build_with(8))),
);
@@ -1459,7 +1463,7 @@ mod tests {
parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
assert_eq!(
wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
wam.arith_eval_by_metacall(term_write_result.heap_loc),
Ok(Number::Fixnum(Fixnum::build_with(19))),
);
@@ -1469,7 +1473,7 @@ mod tests {
parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
assert_eq!(
wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
wam.arith_eval_by_metacall(term_write_result.heap_loc),
Ok(Number::Fixnum(Fixnum::build_with(-1)))
);
}
+36 -16
View File
@@ -6,7 +6,6 @@ use crate::types::*;
use indexmap::IndexSet;
use std::cmp::Ordering;
use std::vec::IntoIter;
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
@@ -55,32 +54,36 @@ impl MachineState {
self.attr_var_init.bindings.push((h, addr));
}
fn populate_var_and_value_lists(&mut self) -> (HeapCellValue, HeapCellValue) {
fn populate_var_and_value_lists(&mut self) -> Result<(HeapCellValue, HeapCellValue), usize> {
let size = self.attr_var_init.bindings.len();
let iter = self
.attr_var_init
.bindings
.iter()
.map(|(ref h, _)| attr_var_as_cell!(*h));
let var_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
let var_list_addr = sized_iter_to_heap_list(&mut self.heap, size, iter)?;
let iter = self.attr_var_init.bindings.drain(0..).map(|(_, ref v)| *v);
let value_list_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, iter));
let value_list_addr = sized_iter_to_heap_list(&mut self.heap, size, iter)?;
(var_list_addr, value_list_addr)
Ok((var_list_addr, value_list_addr))
}
fn verify_attributes(&mut self) {
fn verify_attributes(&mut self) -> Result<(), usize> {
for (h, _) in &self.attr_var_init.bindings {
self.heap[*h] = attr_var_as_cell!(*h);
}
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists();
let (var_list_addr, value_list_addr) = self.populate_var_and_value_lists()?;
self[temp_v!(1)] = var_list_addr;
self[temp_v!(2)] = value_list_addr;
Ok(())
}
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> IntoIter<HeapCellValue> {
pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> Vec<HeapCellValue> {
let mut attr_vars: Vec<_> = if b >= self.attr_var_init.attr_var_queue.len() {
vec![]
} else {
@@ -104,10 +107,10 @@ impl MachineState {
});
attr_vars.dedup();
attr_vars.into_iter()
attr_vars
}
pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) {
pub(super) fn verify_attr_interrupt(&mut self, p: usize, arity: usize) -> Result<(), usize> {
self.allocate(arity + 3);
let e = self.e;
@@ -117,23 +120,40 @@ impl MachineState {
and_frame[i] = self.registers[i];
}
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));
and_frame[arity + 1] =
fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.b0 as i64) }
);
and_frame[arity + 2] =
fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.num_of_args as i64) }
);
and_frame[arity + 3] =
fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(self.attr_var_init.cp as i64) }
);
self.verify_attributes();
self.verify_attributes()?;
self.num_of_args = 3;
self.b0 = self.b;
self.p = p;
Ok(())
}
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
debug_assert!(cell.is_ref());
let mut seen_set = IndexSet::new();
let mut seen_vars = vec![];
let mut iter =
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, cell);
self.heap[0] = cell;
let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
while let Some(value) = iter.next() {
read_heap_cell!(value,
+55 -52
View File
@@ -133,7 +133,7 @@ fn merge_indices(
);
retraction_info.push_record(RetractionRecord::AddedIndex(
skeleton[clause_index].opt_arg_index_key.clone(),
skeleton[clause_index].opt_arg_index_key,
clause_loc,
));
} else {
@@ -246,7 +246,7 @@ fn remove_index_from_subsequence(
// appear anywhere inside an Internal record.
retraction_info.push_record(RetractionRecord::RemovedIndex(
index_loc,
opt_arg_index_key.clone(),
*opt_arg_index_key,
offset,
));
}
@@ -700,31 +700,25 @@ fn remove_non_leading_clause(
}
}
fn finalize_retract(
fn finalize_retract<'a, LS: LoadState<'a>>(
payload: &mut <LS as LoadState<'a>>::LoaderFieldType,
key: PredicateKey,
compilation_target: CompilationTarget,
skeleton: &mut PredicateSkeleton,
code_index: CodeIndex,
target_pos: usize,
index_ptr_opt: Option<IndexPtr>,
retraction_info: &mut RetractionInfo,
) -> usize {
let clause_clause_loc = delete_from_skeleton(
compilation_target,
key,
skeleton,
target_pos,
retraction_info,
&mut payload.retraction_info,
);
if let Some(index_ptr) = index_ptr_opt {
set_code_index(
retraction_info,
&compilation_target,
key,
code_index,
index_ptr,
);
set_code_index::<LS>(payload, &compilation_target, key, code_index, index_ptr);
}
clause_clause_loc
@@ -814,7 +808,7 @@ fn prepend_compiled_clause(
skeleton.clauses[0].clause_start = clause_loc + 2;
retraction_info.push_record(RetractionRecord::AddedIndex(
skeleton.clauses[0].opt_arg_index_key.clone(),
skeleton.clauses[0].opt_arg_index_key,
skeleton.clauses[0].clause_start,
));
@@ -1076,7 +1070,7 @@ fn append_compiled_clause(
skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1;
retraction_info.push_record(RetractionRecord::AddedIndex(
skeleton.clauses[target_pos].opt_arg_index_key.clone(),
skeleton.clauses[target_pos].opt_arg_index_key,
skeleton.clauses[target_pos].clause_start,
));
@@ -1237,12 +1231,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
settings: CodeGenSettings,
) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(settings);
let clause = preprocessor.try_term_to_tl(self, term)?;
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
// let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
let f64_tbl = &LS::machine_st(&mut self.payload).arena.f64_tbl;
let mut cg = CodeGenerator::new(f64_tbl, settings);
let clause_code = cg.compile_predicate(vec![clause])?;
Ok(StandaloneCompileResult {
@@ -1257,7 +1250,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
mut predicates: PredicateQueue,
settings: CodeGenSettings,
) -> Result<CodeIndex, SessionError> {
let code_index = self.get_or_insert_code_index(key, predicates.compilation_target);
let code_idx = self.get_or_insert_code_index(key, predicates.compilation_target);
LS::err_on_builtin_overwrite(self, key)?;
@@ -1268,11 +1261,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut preprocessor = Preprocessor::new(settings);
for term in predicates.predicates.drain(0..) {
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
clauses.push(preprocessor.try_term_to_tl(self, term)?);
}
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
let f64_tbl = &LS::machine_st(&mut self.payload).arena.f64_tbl;
let mut cg = CodeGenerator::new(f64_tbl, settings);
let mut code = cg.compile_predicate(clauses)?;
if settings.is_extensible {
@@ -1331,9 +1325,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
);
}
let index_ptr = LS::machine_st(&mut self.payload)
.arena
.code_index_tbl
.get_entry(code_idx.into());
print_overwrite_warning(
&predicates.compilation_target,
code_index.get(),
index_ptr,
key,
settings.is_dynamic(),
);
@@ -1344,16 +1343,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
IndexPtr::index(code_ptr)
};
set_code_index(
&mut self.payload.retraction_info,
set_code_index::<LS>(
&mut self.payload,
&predicates.compilation_target,
key,
code_index,
code_idx,
index_ptr,
);
self.wam_prelude.code.extend(code);
Ok(code_index)
Ok(code_idx)
}
fn extend_local_predicate_skeleton(
@@ -1555,19 +1554,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.push_back_to_local_predicate_skeleton(&compilation_target, &key, code_len);
let code_index = self.get_or_insert_code_index(key, compilation_target);
let code_idx = self.get_or_insert_code_index(key, compilation_target);
if let Some(new_code_ptr) = result {
set_code_index(
&mut self.payload.retraction_info,
set_code_index::<LS>(
&mut self.payload,
&compilation_target,
key,
code_index,
code_idx,
new_code_ptr,
);
}
Ok(code_index)
Ok(code_idx)
}
AppendOrPrepend::Prepend => {
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
@@ -1597,17 +1596,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.push_front_to_local_predicate_skeleton(&compilation_target, &key, code_len);
let code_index = self.get_or_insert_code_index(key, compilation_target);
let code_idx = self.get_or_insert_code_index(key, compilation_target);
set_code_index(
&mut self.payload.retraction_info,
set_code_index::<LS>(
&mut self.payload,
&compilation_target,
key,
code_index,
code_idx,
new_code_ptr,
);
Ok(code_index)
Ok(code_idx)
}
}
}
@@ -1655,7 +1654,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize {
let payload_compilation_target = self.payload.compilation_target;
let code_index = self.get_or_insert_code_index(key, payload_compilation_target);
let code_idx_offset = self.get_or_insert_code_index(key, payload_compilation_target);
let skeleton = self
.wam_prelude
@@ -1733,14 +1732,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
None
};
return finalize_retract(
return finalize_retract::<LS>(
&mut self.payload,
key,
payload_compilation_target,
skeleton,
code_index,
code_idx_offset,
target_pos,
index_ptr_opt,
&mut self.payload.retraction_info,
);
}
None => {
@@ -1762,14 +1761,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
)
};
return finalize_retract(
return finalize_retract::<LS>(
&mut self.payload,
key,
payload_compilation_target,
skeleton,
code_index,
code_idx_offset,
target_pos,
index_ptr_opt,
&mut self.payload.retraction_info,
);
}
}
@@ -1992,14 +1991,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
}
};
finalize_retract(
finalize_retract::<LS>(
&mut self.payload,
key,
payload_compilation_target,
skeleton,
code_index,
code_idx_offset,
target_pos,
index_ptr_opt,
&mut self.payload.retraction_info,
)
}
}
@@ -2226,18 +2225,22 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
};
let predicates = self.payload.predicates.take();
let code_index = self.compile(key, predicates, settings)?;
let offset = self.compile(key, predicates, settings)?;
if let Some(filename) = self.listing_src_file_name() {
if let Some(ref mut module) = self.wam_prelude.indices.modules.get_mut(&filename) {
let index_ptr = code_index.get();
let code_index = *module.code_dir.entry(key).or_insert(code_index);
let index_ptr = LS::machine_st(&mut self.payload)
.arena
.code_index_tbl
.get_entry(offset.into());
set_code_index(
&mut self.payload.retraction_info,
let offset = *module.code_dir.entry(key).or_insert(offset);
set_code_index::<LS>(
&mut self.payload,
&CompilationTarget::Module(filename),
key,
code_index,
offset,
index_ptr,
);
}
+527 -176
View File
@@ -1,12 +1,71 @@
use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use crate::atom_table::*;
use crate::machine::get_structure_index;
use crate::machine::heap::*;
use crate::machine::stack::*;
use crate::types::*;
use std::mem;
use std::ops::IndexMut;
use scryer_modular_bitfield::specifiers::*;
use scryer_modular_bitfield::*;
type Trail = Vec<(Ref, HeapCellValue)>;
use std::collections::BTreeMap;
use std::mem;
use std::ops::{IndexMut, Range};
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
#[bits = 6]
enum TrailRefTag {
HeapCell = 0b001011,
StackCell = 0b001101,
AttrVar = 0b010001,
PStrLoc = 0b001111,
}
#[bitfield]
#[repr(u64)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct TrailRef {
val: B56,
#[allow(unused)]
m: bool,
#[allow(unused)]
f: bool,
tag: TrailRefTag,
}
impl TrailRef {
#[inline(always)]
fn heap_cell(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::HeapCell)
.with_val(h as u64)
}
#[inline(always)]
fn stack_cell(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::StackCell)
.with_val(h as u64)
}
#[inline(always)]
fn attr_var(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::AttrVar)
.with_val(h as u64)
}
#[inline(always)]
fn pstr_loc(h: usize) -> Self {
TrailRef::new()
.with_tag(TrailRefTag::PStrLoc)
.with_val(h as u64)
}
}
type Trail = Vec<(TrailRef, HeapCellValue)>;
#[derive(Debug, Clone, Copy)]
pub enum AttrVarPolicy {
@@ -17,22 +76,39 @@ pub enum AttrVarPolicy {
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 push_attr_var_queue(&mut self, attr_var_loc: usize);
fn stack(&mut self) -> &mut Stack;
fn threshold(&self) -> usize;
// returns the tail location of the pstr on success
fn as_slice_from<'a>(&'a self, from: usize) -> Box<dyn Iterator<Item = u8> + 'a>;
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize>;
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize>;
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize>;
}
pub(crate) fn copy_term<T: CopierTarget>(
target: T,
addr: HeapCellValue,
attr_var_policy: AttrVarPolicy,
) {
) -> Result<usize, usize> {
let mut copy_term_state = CopyTermState::new(target, attr_var_policy);
let old_threshold = copy_term_state.target.threshold();
copy_term_state.copy_term_impl(addr);
copy_term_state.copy_attr_var_lists();
copy_term_state.copy_term_impl(addr)?;
copy_term_state.copy_attr_var_lists()?;
copy_term_state.unwind_trail();
let new_threshold = copy_term_state.target.threshold();
copy_term_state.copy_pstrs()?;
Ok(new_threshold - old_threshold)
}
#[derive(Debug)]
pub struct PStrData {
pre_old_h_tail_loc: usize,
post_old_h_tail_loc: usize,
post_old_h_pstr_loc_locs: IndexSet<usize, FxBuildHasher>,
}
#[derive(Debug)]
@@ -43,6 +119,9 @@ struct CopyTermState<T: CopierTarget> {
target: T,
attr_var_policy: AttrVarPolicy,
attr_var_list_locs: Vec<(usize, HeapCellValue)>,
// keys of pstr_loc_locs are byte indices rounded down to the
// nearest cell boundary
pstr_loc_locs: BTreeMap<usize, PStrData>,
}
impl<T: CopierTarget> CopyTermState<T> {
@@ -54,6 +133,7 @@ impl<T: CopierTarget> CopyTermState<T> {
target,
attr_var_policy,
attr_var_list_locs: vec![],
pstr_loc_locs: BTreeMap::new(),
}
}
@@ -64,17 +144,17 @@ impl<T: CopierTarget> CopyTermState<T> {
fn trail_list_cell(&mut self, addr: usize, threshold: usize) {
let trail_item = mem::replace(&mut self.target[addr], list_loc_as_cell!(threshold));
self.trail.push((Ref::heap_cell(addr), trail_item));
self.trail.push((TrailRef::heap_cell(addr), trail_item));
}
fn copy_list(&mut self, addr: usize) {
fn copy_list(&mut self, addr: usize) -> Result<(), usize> {
for offset in 0..2 {
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 Ok(());
}
}
_ => {
@@ -83,14 +163,10 @@ impl<T: CopierTarget> CopyTermState<T> {
}
let threshold = self.target.threshold();
self.target.copy_slice_to_end(addr..addr + 2)?;
*self.value_at_scan() = list_loc_as_cell!(threshold);
for i in 0..2 {
let hcv = self.target[addr + i];
self.target.push(hcv);
}
let cdr = self
.target
.store(self.target.deref(heap_loc_as_cell!(addr + 1)));
@@ -113,80 +189,108 @@ impl<T: CopierTarget> CopyTermState<T> {
}
self.scan += 1;
Ok(())
}
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)
}
};
fn copy_partial_string(&mut self, pstr_loc: usize) -> Result<(), usize> {
match self.pstr_loc_locs.range_mut(..=pstr_loc).next_back() {
Some((
_prev_pstr_loc,
&mut PStrData {
pre_old_h_tail_loc,
ref mut post_old_h_pstr_loc_locs,
..
},
)) if pre_old_h_tail_loc >= cell_index!(pstr_loc) => {
post_old_h_pstr_loc_locs.insert(self.scan);
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;
return Ok(());
}
_ => {}
);
let threshold = self.target.threshold();
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)
let offset = self
.target
.as_slice_from(pstr_loc)
.take_while(|b| *b != 0u8)
.count();
let left_pstr_boundary = cell_index!(pstr_loc + offset);
let flag = u64::from_be_bytes(self.target[left_pstr_boundary].into_bytes());
let pstr_loc_idx = cell_index!(pstr_loc);
if flag == 1 {
if left_pstr_boundary != pstr_loc_idx {
let mut pstr_data = self
.pstr_loc_locs
.remove(&heap_index!(left_pstr_boundary))
.unwrap();
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
self.pstr_loc_locs
.insert(heap_index!(cell_index!(pstr_loc)), pstr_data);
let old_cell = self.target[pstr_loc_idx];
self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1));
self.trail
.push((TrailRef::pstr_loc(pstr_loc_idx), old_cell));
} else {
debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset);
pstr_offset_as_cell!(threshold)
let pstr_data = self
.pstr_loc_locs
.get_mut(&heap_index!(left_pstr_boundary))
.unwrap();
pstr_data.post_old_h_pstr_loc_locs.insert(self.scan);
}
} else {
let old_cell = self.target[pstr_loc_idx];
self.target[pstr_loc_idx] = HeapCellValue::from_bytes(u64::to_be_bytes(1));
self.trail
.push((TrailRef::pstr_loc(pstr_loc_idx), old_cell));
let old_tail_idx = if (pstr_loc + offset + 1) % Heap::heap_cell_alignment() == 0 {
cell_index!(pstr_loc + offset) + 2
} else {
cell_index!(pstr_loc + offset) + 1
};
self.target.push(self.target[pstr_loc]);
self.target.push(self.target[pstr_loc + 1]);
let tail_cell = self.target[old_tail_idx];
pstr_loc_as_cell!(threshold)
let new_tail_idx = self.target.threshold();
let mut writer = self.target.reserve(1)?;
writer.write_with(|section| {
section.push_cell(tail_cell);
});
let mut post_old_h_pstr_loc_locs = IndexSet::with_hasher(FxBuildHasher::default());
post_old_h_pstr_loc_locs.insert(self.scan);
let pstr_data = PStrData {
pre_old_h_tail_loc: old_tail_idx,
post_old_h_tail_loc: new_tail_idx,
post_old_h_pstr_loc_locs,
};
self.pstr_loc_locs
.insert(heap_index!(pstr_loc_idx), pstr_data);
}
);
self.scan += 1;
let trail_item = mem::replace(&mut self.target[pstr_loc], replacement);
self.trail.push((Ref::heap_cell(pstr_loc), trail_item));
Ok(())
}
fn copy_attr_var_lists(&mut self) {
fn copy_attr_var_lists(&mut self) -> Result<(), usize> {
while !self.attr_var_list_locs.is_empty() {
let iter = std::mem::take(&mut self.attr_var_list_locs);
let mut list_loc_vec = std::mem::take(&mut self.attr_var_list_locs);
for (threshold, list_loc) in iter {
while let Some((threshold, list_loc)) = list_loc_vec.pop() {
self.target[threshold] = list_loc_as_cell!(self.target.threshold());
self.target.push_attr_var_queue(threshold - 1);
self.copy_attr_var_list(list_loc);
self.copy_attr_var_list(list_loc)?;
}
}
Ok(())
}
/*
@@ -194,48 +298,49 @@ impl<T: CopierTarget> CopyTermState<T> {
* structure which is ensured by this function and not at all by
* the vanilla copier.
*/
fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) {
fn copy_attr_var_list(&mut self, mut list_addr: HeapCellValue) -> Result<(), usize> {
while let HeapCellValueTag::Lis = list_addr.get_tag() {
let threshold = self.target.threshold();
let heap_loc = list_addr.get_value() as usize;
let str_loc = self.target[heap_loc].get_value() as usize;
let str_cell = self.target[str_loc];
let mut writer = self.target.reserve(3).unwrap();
self.target.push(heap_loc_as_cell!(threshold + 2));
self.target.push(heap_loc_as_cell!(threshold + 1));
writer.write_with(|section| {
section.push_cell(heap_loc_as_cell!(threshold + 2));
section.push_cell(heap_loc_as_cell!(threshold + 1));
read_heap_cell!(self.target[str_loc],
(HeapCellValueTag::Atom) => {
self.target.push(self.target[str_loc]);
if str_cell.to_atom().is_some() {
section.push_cell(str_cell);
}
(HeapCellValueTag::Str) => {
self.copy_term_impl(self.target[str_loc]);
}
_ => {
unreachable!();
}
);
});
debug_assert_eq!(str_cell.get_tag(), HeapCellValueTag::Str);
self.copy_term_impl(str_cell)?;
list_addr = self.target[heap_loc + 1];
if HeapCellValueTag::Lis == list_addr.get_tag() {
self.target[threshold + 1] = list_loc_as_cell!(self.target.threshold());
}
}
Ok(())
}
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) {
fn reinstantiate_var(&mut self, addr: HeapCellValue, frontier: usize) -> Result<(), 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::heap_cell(h), heap_loc_as_cell!(h)));
self.trail.push((TrailRef::heap_cell(h), heap_loc_as_cell!(h)));
}
(HeapCellValueTag::StackVar, s) => {
self.target[frontier] = heap_loc_as_cell!(frontier);
self.target.stack()[s] = heap_loc_as_cell!(frontier);
self.trail.push((Ref::stack_cell(s), stack_loc_as_cell!(s)));
self.trail.push((TrailRef::stack_cell(s), stack_loc_as_cell!(s)));
}
(HeapCellValueTag::AttrVar, h) => {
let threshold = if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
@@ -247,14 +352,18 @@ impl<T: CopierTarget> CopyTermState<T> {
self.target[frontier] = heap_loc_as_cell!(threshold);
self.target[h] = heap_loc_as_cell!(threshold);
self.trail.push((Ref::attr_var(h), attr_var_as_cell!(h)));
self.trail.push((TrailRef::attr_var(h), attr_var_as_cell!(h)));
if let AttrVarPolicy::DeepCopy = self.attr_var_policy {
self.target.push(attr_var_as_cell!(threshold));
self.target.push(heap_loc_as_cell!(threshold + 1));
let mut writer = self.target.reserve(2)?;
writer.write_with(|section| {
section.push_cell(attr_var_as_cell!(threshold));
section.push_cell(heap_loc_as_cell!(threshold + 1));
});
let old_list_link = self.target[h + 1];
self.trail.push((Ref::heap_cell(h + 1), old_list_link));
self.trail.push((TrailRef::heap_cell(h + 1), old_list_link));
self.target[h + 1] = heap_loc_as_cell!(threshold + 1);
if old_list_link.get_tag() == HeapCellValueTag::Lis {
@@ -266,9 +375,11 @@ impl<T: CopierTarget> CopyTermState<T> {
unreachable!()
}
);
Ok(())
}
fn copy_var(&mut self, addr: HeapCellValue) {
fn copy_var(&mut self, addr: HeapCellValue) -> Result<(), usize> {
let index = addr.get_value() as usize;
let rd = self.target.deref(addr);
let ra = self.target.store(rd);
@@ -278,7 +389,7 @@ impl<T: CopierTarget> CopyTermState<T> {
if h >= self.old_h {
*self.value_at_scan() = ra;
self.scan += 1;
return;
return Ok(());
}
}
(HeapCellValueTag::Lis, h) => {
@@ -292,47 +403,52 @@ impl<T: CopierTarget> CopyTermState<T> {
);
self.scan += 1;
return;
return Ok(());
}
}
_ => {}
);
if rd == ra {
self.reinstantiate_var(ra, self.scan);
self.reinstantiate_var(ra, self.scan)?;
self.scan += 1;
} else {
*self.value_at_scan() = ra;
}
Ok(())
}
fn copy_structure(&mut self, addr: usize) {
fn copy_structure(&mut self, addr: usize) -> Result<(), usize> {
read_heap_cell!(self.target[addr],
(HeapCellValueTag::Atom, (name, arity)) => {
(HeapCellValueTag::Atom, (_name, arity)) => {
let threshold = self.target.threshold();
*self.value_at_scan() = str_loc_as_cell!(threshold);
let index_cell = self.target[addr.saturating_sub(1)];
let str_cell = if get_structure_index(index_cell).is_some() {
// copy the index pointer trailing this
// inlined or expanded goal.
let mut writer = self.target.reserve(1).unwrap();
writer.write_with(|section| {
section.push_cell(index_cell);
});
str_loc_as_cell!(threshold + 1)
} else {
str_loc_as_cell!(threshold)
};
*self.value_at_scan() = str_cell;
self.target.copy_slice_to_end(addr .. addr + 1 + arity)?;
let trail_item = mem::replace(
&mut self.target[addr],
str_loc_as_cell!(threshold),
str_cell,
);
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];
self.target.push(hcv);
}
let index_cell = self.target[addr + 1 + arity];
if get_structure_index(index_cell).is_some() {
// copy the index pointer trailing this
// inlined or expanded goal.
self.target.push(index_cell);
}
self.trail.push((TrailRef::heap_cell(addr), trail_item));
}
(HeapCellValueTag::Str, h) => {
*self.value_at_scan() = str_loc_as_cell!(h);
@@ -343,11 +459,16 @@ impl<T: CopierTarget> CopyTermState<T> {
);
self.scan += 1;
Ok(())
}
fn copy_term_impl(&mut self, addr: HeapCellValue) {
fn copy_term_impl(&mut self, addr: HeapCellValue) -> Result<(), usize> {
self.scan = self.target.threshold();
self.target.push(addr);
let mut writer = self.target.reserve(1)?;
writer.write_with(|section| {
section.push_cell(addr);
});
while self.scan < self.target.threshold() {
let addr = *self.value_at_scan();
@@ -356,37 +477,64 @@ impl<T: CopierTarget> CopyTermState<T> {
(HeapCellValueTag::Lis, h) => {
if h >= self.old_h {
self.scan += 1;
continue;
} else {
self.copy_list(h);
self.copy_list(h)
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => {
self.copy_var(addr);
self.copy_var(addr)
}
(HeapCellValueTag::Str, h) => {
self.copy_structure(h);
self.copy_structure(h)
}
(HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, pstr_loc) => {
self.copy_partial_string(addr.get_tag(), pstr_loc);
(HeapCellValueTag::PStrLoc, pstr_loc) => {
self.copy_partial_string(pstr_loc)
}
_ => {
self.scan += 1;
continue;
}
);
}
)?;
}
fn unwind_trail(mut self) {
for (r, value) in self.trail {
let index = r.get_value() as usize;
Ok(())
}
match r.get_tag() {
RefTag::AttrVar | RefTag::HeapCell => {
fn copy_pstrs(&mut self) -> Result<(), usize> {
while let Some((least_pstr_loc, pstr_data)) = self.pstr_loc_locs.pop_first() {
let threshold = heap_index!(self.target.threshold());
for pstr_loc_loc in pstr_data.post_old_h_pstr_loc_locs {
let pstr_loc = self.target[pstr_loc_loc].get_value() as usize;
self.target[pstr_loc_loc] =
pstr_loc_as_cell!(threshold + pstr_loc - least_pstr_loc);
}
self.target.copy_pstr_to_threshold(least_pstr_loc)?;
let mut writer = self.target.reserve(1)?;
writer.write_with(|section| {
section.push_cell(heap_loc_as_cell!(pstr_data.post_old_h_tail_loc));
});
}
Ok(())
}
fn unwind_trail(&mut self) {
for (r, value) in self.trail.drain(..) {
let index = r.val() as usize;
match r.tag() {
TrailRefTag::AttrVar | TrailRefTag::HeapCell => {
self.target[index] = value;
self.target[index].set_mark_bit(false);
self.target[index].set_forwarding_bit(false);
}
RefTag::StackCell => self.target.stack()[index] = value,
TrailRefTag::StackCell => self.target.stack()[index] = value,
TrailRefTag::PStrLoc => self.target[index] = value,
}
}
}
@@ -395,19 +543,26 @@ impl<T: CopierTarget> CopyTermState<T> {
#[cfg(test)]
mod tests {
use super::*;
use crate::functor_macro::*;
use crate::machine::mock_wam::*;
#[test]
fn copier_tests() {
let mut wam = MockWAM::new();
// clear the heap of resource error data etc
wam.machine_st.heap.clear();
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)]));
let mut functor_writer = Heap::functor_writer(functor!(
f_atom,
[atom_as_cell(a_atom), atom_as_cell(b_atom)]
));
functor_writer(&mut wam.machine_st.heap).unwrap();
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));
@@ -415,7 +570,7 @@ mod tests {
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
// check that the original heap state is still intact.
@@ -430,69 +585,266 @@ mod tests {
wam.machine_st.heap.clear();
let pstr_var_cell =
put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl);
let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize];
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
wam.machine_st.heap.pop();
wam.machine_st.heap.push(pstr_loc_as_cell!(2));
writer.write_with(|section| {
section.push_pstr("abc ");
section.push_cell(pstr_loc_as_cell!(heap_index!(2)));
let pstr_second_var_cell =
put_partial_string(&mut wam.machine_st.heap, "def", &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)));
section.push_pstr("def");
section.push_cell(pstr_loc_as_cell!(0));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
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.slice_to_str(0, "abc ".len()), "abc ");
assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(heap_index!(2)));
assert_eq!(
wam.machine_st.heap[5],
fixnum_as_cell!(Fixnum::build_with(0i64))
wam.machine_st
.heap
.slice_to_str(heap_index!(2), "def".len()),
"def"
);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(7)));
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(9)));
assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7)));
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
.slice_to_str(heap_index!(7), "abc ".len()),
"abc "
);
assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(9), "def".len()),
"def"
);
assert_eq!(wam.machine_st.heap[10], heap_loc_as_cell!(6));
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 mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("abc ");
section.push_cell(pstr_loc_as_cell!(heap_index!(2) + 9));
section.push_pstr("defdefdefdef");
section.push_cell(pstr_loc_as_cell!(0));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy);
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(wam.machine_st.heap.slice_to_str(0, "abc ".len()), "abc ");
assert_eq!(
wam.machine_st.heap[1],
pstr_loc_as_cell!(heap_index!(2) + 9)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(2), "defdefdefdef".len()),
"defdefdefdef"
);
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(0));
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(8)));
assert_eq!(
wam.machine_st.heap[6],
pstr_loc_as_cell!(heap_index!(10) + 1)
);
assert_eq!(wam.machine_st.heap[7], pstr_loc_as_cell!(heap_index!(8)));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(8), "abc ".len()),
"abc "
);
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(6));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(10), "fdef".len()),
"fdef"
);
assert_eq!(wam.machine_st.heap[11], heap_loc_as_cell!(7));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0)));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(heap_index!(0)));
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6)));
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[5], pstr_loc_as_cell!(heap_index!(6)));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 9));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(
wam.machine_st.heap[3],
pstr_loc_as_cell!(heap_index!(0) + 9)
);
assert_eq!(wam.machine_st.heap[4], pstr_loc_as_cell!(heap_index!(6)));
assert_eq!(
wam.machine_st.heap[5],
pstr_loc_as_cell!(heap_index!(6) + 9)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 7));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(
wam.machine_st.heap[3],
pstr_loc_as_cell!(heap_index!(0) + 7)
);
assert_eq!(
wam.machine_st.heap[4],
pstr_loc_as_cell!(heap_index!(6) + 11)
);
assert_eq!(
wam.machine_st.heap[5],
pstr_loc_as_cell!(heap_index!(6) + 7)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "012345678912345".len()),
"012345678912345"
);
assert_eq!(wam.machine_st.heap[9], heap_loc_as_cell!(5));
wam.machine_st.heap.clear();
let mut writer = wam.machine_st.heap.reserve(4).unwrap();
writer.write_with(|section| {
section.push_pstr("012345678912345");
section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 12));
});
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, pstr_loc_as_cell!(11), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(
wam.machine_st.heap.slice_to_str(0, "012345678912345".len()),
"012345678912345"
);
assert_eq!(
wam.machine_st.heap[3],
pstr_loc_as_cell!(heap_index!(0) + 12)
);
assert_eq!(
wam.machine_st.heap[4],
pstr_loc_as_cell!(heap_index!(6) + 3)
);
assert_eq!(
wam.machine_st.heap[5],
pstr_loc_as_cell!(heap_index!(6) + 4)
);
assert_eq!(
wam.machine_st
.heap
.slice_to_str(heap_index!(6), "8912345".len()),
"8912345"
);
assert_eq!(wam.machine_st.heap[8], heap_loc_as_cell!(5));
wam.machine_st.heap.clear();
let mut functor_writer = Heap::functor_writer(functor!(
f_atom,
[
atom_as_cell(a_atom),
atom_as_cell(b_atom),
atom_as_cell(a_atom),
str_loc_as_cell(0)
]
));
functor_writer(&mut wam.machine_st.heap).unwrap();
{
let wam = TermCopyingMockWAM { wam: &mut wam };
copy_term(wam, str_loc_as_cell!(0), AttrVarPolicy::DeepCopy).unwrap();
}
assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4));
@@ -500,7 +852,6 @@ mod tests {
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));
+14 -57
View File
@@ -1,4 +1,5 @@
use crate::atom_table::*;
use crate::machine::heap::*;
use crate::types::*;
/* Use the pointer reversal technique of the Deutsch-Schorr-Waite
@@ -11,7 +12,7 @@ use crate::types::*;
* - Cells are only marked during the backward phase
* - Visiting subterms of a visited compound does not immediately shift to the backward phase
* - The heads of LIS structures are both marked and forwarded rather
* than just forwarded to distinguish them from tails;
* than just forwarded to distinguish them from tails
* continue_forwarding() checks for this before entering the forward
* phase
*
@@ -22,7 +23,7 @@ use crate::types::*;
#[derive(Debug)]
pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
pub(crate) heap: &'a mut [HeapCellValue],
pub(crate) heap: &'a mut Heap,
start: usize,
current: usize,
next: u64,
@@ -31,7 +32,7 @@ pub(crate) struct CycleDetectingIter<'a, const STOP_AT_CYCLES: bool> {
}
impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self {
pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self {
heap[start].set_forwarding_bit(true);
let next = heap[start].get_value();
@@ -127,7 +128,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
self.current = next;
self.next = temp;
if self.next < self.heap.len() as u64 {
if self.next < self.heap.cell_len() as u64 {
return Some(HeapCellValue::build_with(tag, next as u64));
}
}
@@ -136,10 +137,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
let cell = self.heap[h];
let arity = cell_as_atom_cell!(self.heap[h]).get_arity();
let last_cell_loc = match self.traverse_subterm(h + 1, arity) {
Some(last_cell_loc) => last_cell_loc,
None => return None,
};
let last_cell_loc = self.traverse_subterm(h + 1, arity)?;
if last_cell_loc == h {
if self.backward() {
@@ -170,10 +168,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
let mut cell = self.heap[self.current];
cell.set_value(self.next);
let last_cell_loc = match self.traverse_subterm(self.next as usize, 2) {
Some(last_cell_loc) => last_cell_loc,
None => return None,
};
let last_cell_loc = self.traverse_subterm(self.next as usize, 2)?;
if self.cycle_detection_active() {
for idx in (self.next as usize..last_cell_loc).rev() {
@@ -205,10 +200,9 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
}
HeapCellValueTag::PStrLoc => {
let h = self.next as usize;
let cell = self.heap[h];
let last_cell_loc = h + 1;
let tail_idx = self.heap.scan_slice_to_str(h).tail_idx;
if self.heap[last_cell_loc].get_forwarding_bit() {
if self.heap[tail_idx].get_forwarding_bit() {
if self.cycle_detection_active() {
self.cycle_found = true;
return None;
@@ -219,45 +213,13 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
continue;
}
self.heap[last_cell_loc].set_forwarding_bit(true);
self.heap[tail_idx].set_forwarding_bit(true);
self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current as u64);
self.current = last_cell_loc;
self.next = self.heap[tail_idx].get_value();
self.heap[tail_idx].set_value(self.current as u64);
self.current = tail_idx;
return Some(cell);
}
HeapCellValueTag::PStrOffset => {
let h = self.next as usize;
let cell = self.heap[h];
let last_cell_loc = h + 1;
if self.heap[h].get_tag() == HeapCellValueTag::PStr {
if self.heap[last_cell_loc].get_forwarding_bit() {
if self.cycle_detection_active() {
self.cycle_found = true;
return None;
} else if self.backward() {
return None;
}
continue;
}
self.heap[last_cell_loc].set_forwarding_bit(true);
self.next = self.heap[last_cell_loc].get_value();
self.heap[last_cell_loc].set_value(self.current as u64);
self.current = last_cell_loc;
} else {
debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::CStr);
self.next = self.heap[h].get_value();
self.heap[h].set_value(self.current as u64);
self.current = h;
}
return Some(cell);
return Some(pstr_loc_as_cell!(h));
}
tag @ HeapCellValueTag::Atom => {
let cell = HeapCellValue::build_with(tag, self.next);
@@ -269,11 +231,6 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> {
return None;
}
}
HeapCellValueTag::PStr => {
if self.backward() {
return None;
}
}
_ => {
return Some(self.backward_and_return());
}
+9 -8
View File
@@ -200,10 +200,12 @@ impl VarData {
match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => {
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
build_stack.push_front(ChunkedTerms::Chunk {
terms: VecDeque::from(vec![term]),
});
}
Some(ChunkedTerms::Chunk(chunk)) => {
chunk.push_front(term);
Some(ChunkedTerms::Chunk { terms, .. }) => {
terms.push_front(term);
}
None => {
unreachable!()
@@ -423,7 +425,6 @@ impl VariableClassifier {
// "probe_head_var". note the difference between it
// and "probe_body_var".
let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
let needs_new_branch = branch_info_v.is_empty();
if needs_new_branch {
@@ -578,7 +579,7 @@ impl VariableClassifier {
mut terms,
) if terms.len() == 3 => {
if let Some(last_arg) = terms.last() {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
if let Term::Literal(_, Literal::CodeIndexOffset(_)) = last_arg {
terms.pop();
state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
@@ -801,7 +802,7 @@ impl VariableClassifier {
self.call_policy,
));
}
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
Term::Literal(_, Literal::Atom(atom!("!"))) => {
let (var_num, is_global) =
if let Some(var_num) = self.global_cut_var_num_override {
(var_num, false)
@@ -879,10 +880,10 @@ impl BranchMap {
for var_info in chunk.vars.iter_mut() {
if var_info.lvl == Level::Shallow {
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
let context = var_info.chunk_type.to_gen_context(chunk.chunk_num);
temp_var_data
.use_set
.insert((term_loc, var_info.classify_info.arg_c));
.insert((context, var_info.classify_info.arg_c));
}
}
+434 -244
View File
File diff suppressed because it is too large Load Diff
+760 -812
View File
File diff suppressed because it is too large Load Diff
+1091 -170
View File
File diff suppressed because it is too large Load Diff
+51 -78
View File
@@ -1,14 +1,15 @@
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::rc::Rc;
use crate::atom_table;
use crate::heap_iter::{stackful_post_order_iter, NonListElider};
use crate::machine::machine_indices::VarKey;
use crate::machine::mock_wam::CompositeOpDir;
use crate::machine::{
ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC,
LIB_QUERY_SUCCESS,
ArenaHeaderTag, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, LIB_QUERY_SUCCESS,
};
use crate::offset_table::*;
use crate::parser::ast::{Var, VarPtr};
use crate::parser::parser::{Parser, Tokens};
use crate::read::{write_term_to_heap, TermWriteResult};
@@ -175,10 +176,13 @@ impl Term {
) -> Self {
// Adapted from MachineState::read_term_from_heap
let mut term_stack = vec![];
let iter = stackful_post_order_iter::<NonListElider>(
machine.machine_st.heap[0] = heap_cell;
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut machine.machine_st.heap,
&mut machine.machine_st.stack,
heap_cell,
0,
);
let mut anon_count: usize = 0;
@@ -193,7 +197,7 @@ impl Term {
},
};
for addr in iter {
while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr);
read_heap_cell!(addr,
@@ -244,11 +248,11 @@ impl Term {
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
let var = var_names.get(&addr).map(|x| x.borrow().clone());
match var {
Some(Var::Named(name)) => term_stack.push(Term::Var(name)),
Some(Var::Named(name)) => term_stack.push(Term::Var(name.as_ref().to_owned())),
_ => {
let anon_name = loop {
// Generate a name for the anonymous variable
let anon_name = count_to_letter_code(anon_count);
let anon_name = Rc::new(count_to_letter_code(anon_count));
// Find if this name is already being used
var_names.sort_by(|_, a, _, b| {
@@ -269,21 +273,19 @@ impl Term {
},
}
};
term_stack.push(Term::Var(anon_name));
term_stack.push(Term::Var(anon_name.as_ref().to_owned()));
},
}
}
(HeapCellValueTag::F64, f) => {
term_stack.push(Term::Float((*f).into()));
}
(HeapCellValueTag::Char, c) => {
term_stack.push(Term::Atom(c.into()));
(HeapCellValueTag::F64Offset, offset) => {
let f = machine.machine_st.arena.f64_tbl.get_entry(offset);
term_stack.push(Term::Float(f.into()));
}
(HeapCellValueTag::Fixnum, n) => {
term_stack.push(Term::Integer(n.into()));
}
(HeapCellValueTag::Cons, ptr) => {
if let Ok(n) = Number::try_from(addr) {
if let Ok(n) = Number::try_from((addr, &machine.machine_st.arena.f64_tbl)) {
match n {
Number::Integer(i) => term_stack.push(Term::Integer((*i).clone())),
Number::Rational(r) => term_stack.push(Term::Rational((*r).clone())),
@@ -296,7 +298,7 @@ impl Term {
Term::atom(alias.as_str().to_string())
} else {
Term::compound("$stream", [
Term::integer(stream.as_ptr() as usize)
Term::integer(stream.as_ptr().addr())
])
};
term_stack.push(stream_term);
@@ -310,35 +312,7 @@ impl Term {
);
}
}
(HeapCellValueTag::CStr, s) => {
term_stack.push(Term::String(s.as_str().to_string()));
}
(HeapCellValueTag::Atom, (name, arity)) => {
//let h = iter.focus().value() as usize;
//let mut arity = arity;
// Not sure why/if this is needed.
// Might find out with better testing later.
/*
if iter.heap.len() > h + arity + 1 {
let value = iter.heap[h + arity + 1];
if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0,
// meaning idx cannot pertain to this atom
// if it is the direct subterm of a larger
// structure.
if arity > 0 || !iter.direct_subterm_of_str(h) {
term_stack.push(
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
);
arity += 1;
}
}
}
*/
if arity == 0 {
let atom_name = name.as_str().to_string();
if atom_name == "[]" {
@@ -354,8 +328,9 @@ impl Term {
term_stack.push(Term::Compound(name.as_str().to_string(), subterms));
}
}
(HeapCellValueTag::PStr, atom) => {
(HeapCellValueTag::PStrLoc, pstr_loc) => {
let tail = term_stack.pop().unwrap();
let char_iter = iter.base_iter.heap.char_iter(pstr_loc);
match tail {
Term::Atom(atom) => {
@@ -363,21 +338,18 @@ impl Term {
term_stack.push(Term::String(atom.as_str().to_string()));
}
},
Term::List(l) if l.is_empty() => {
term_stack.push(Term::String(char_iter.collect()));
}
Term::List(l) => {
let mut list: Vec<Term> = atom
.as_str()
.to_string()
.chars()
let mut list: Vec<Term> = char_iter
.map(|x| Term::Atom(x.to_string()))
.collect();
list.extend(l.into_iter());
term_stack.push(Term::List(list));
},
_ => {
let mut list: Vec<Term> = atom
.as_str()
.to_string()
.chars()
let mut list: Vec<Term> = char_iter
.map(|x| Term::Atom(x.to_string()))
.collect();
@@ -403,19 +375,6 @@ impl Term {
}
}
}
// I dont know if this is needed here.
/*
(HeapCellValueTag::PStrLoc, h) => {
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
let tail = term_stack.pop().unwrap();
term_stack.push(Term::PartialString(
Cell::default(),
atom.as_str().to_owned(),
Box::new(tail),
));
}
*/
_ => {
unreachable!();
}
@@ -467,11 +426,20 @@ impl Iterator for QueryState<'_> {
// this should halt the search for solutions as it
// does in the Scryer top-level. the exception term is
// contained in self.machine_st.ball.
let h = machine.machine_st.heap.len();
machine
let h = machine.machine_st.heap.cell_len();
if let Err(resource_err_loc) = machine
.machine_st
.heap
.extend(machine.machine_st.ball.stub.clone());
.append(&machine.machine_st.ball.stub)
{
return Some(Err(Term::from_heapcell(
machine,
machine.machine_st.heap[resource_err_loc],
&mut IndexMap::new(),
)));
}
let exception_term =
Term::from_heapcell(machine, machine.machine_st.heap[h], &mut var_names.clone());
@@ -503,7 +471,7 @@ impl Iterator for QueryState<'_> {
let mut var_name = var_key.to_string();
if var_name.starts_with('_') {
let should_print = var_names.values().any(|x| match x.borrow().clone() {
Var::Named(v) => v == var_name,
Var::Named(v) => *v == *var_name,
_ => false,
});
if !should_print {
@@ -522,10 +490,10 @@ impl Iterator for QueryState<'_> {
// Var dict is in the order things appear in the query. If var_name appears
// after term in the query, switch their places.
let var_name_idx = var_dict
.get_index_of(&VarKey::VarPtr(Var::Named(var_name.clone()).into()))
.get_index_of(&VarKey::VarPtr(Var::from(var_name.clone()).into()))
.unwrap();
let term_idx =
var_dict.get_index_of(&VarKey::VarPtr(Var::Named(term_str.clone()).into()));
var_dict.get_index_of(&VarKey::VarPtr(Var::from(term_str.clone()).into()));
if let Some(idx) = term_idx {
if idx < var_name_idx {
let new_term = Term::Var(var_name);
@@ -559,7 +527,7 @@ impl Machine {
/// Consults a module into the [`Machine`] from a string.
pub fn consult_module_string(&mut self, module_name: &str, program: impl Into<String>) {
let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
self.machine_st.registers[1] = stream.into();
self.machine_st.registers[1] = stream_as_cell!(stream);
self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(
&self.machine_st.atom_tbl,
module_name
@@ -588,7 +556,7 @@ impl Machine {
or_frame.prelude.attr_var_queue_len = 0;
self.machine_st.b = stub_b;
self.machine_st.hb = self.machine_st.heap.len();
self.machine_st.hb = self.machine_st.heap.cell_len();
self.machine_st.block = stub_b;
}
@@ -606,8 +574,7 @@ impl Machine {
self.allocate_stub_choice_point();
// Write parsed term to heap
let term_write_result =
write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap)
.expect("couldn't write term to heap");
let var_names: IndexMap<_, _> = term_write_result
@@ -630,9 +597,15 @@ impl Machine {
.indices
.code_dir
.get(&(atom!("call"), 1))
.expect("couldn't get code index")
.local()
.unwrap();
.cloned()
.map(|offset| {
self.machine_st
.arena
.code_index_tbl
.get_entry(offset.into())
.p() as usize
})
.expect("couldn't get code index");
self.machine_st.execute_at_index(1, call_index_p);
+90 -79
View File
@@ -2,7 +2,6 @@ use crate::forms::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::preprocessor::*;
use crate::machine::term_stream::*;
use crate::machine::*;
use crate::parser::ast::*;
@@ -16,35 +15,38 @@ use std::mem;
pub(super) type ModuleOpExports = Vec<(OpDecl, Option<OpDesc>)>;
pub(super) fn set_code_index(
retraction_info: &mut RetractionInfo,
pub(super) fn set_code_index<'a, LS: LoadState<'a>>(
payload: &mut <LS as LoadState<'a>>::LoaderFieldType,
compilation_target: &CompilationTarget,
key: PredicateKey,
mut code_index: CodeIndex,
code_idx: CodeIndex,
code_ptr: IndexPtr,
) {
let record = match compilation_target {
let record = LS::machine_st(payload).arena.code_index_tbl.with_entry_mut(
code_idx.into(),
|code_idx_ptr| match compilation_target {
CompilationTarget::User => {
if IndexPtrTag::Undefined == code_index.get().tag() {
code_index.set(code_ptr);
if IndexPtrTag::Undefined == code_idx_ptr.tag() {
*code_idx_ptr = code_ptr;
RetractionRecord::AddedUserPredicate(key)
} else {
let replaced = code_index.replace(code_ptr);
let replaced = mem::replace(code_idx_ptr, code_ptr);
RetractionRecord::ReplacedUserPredicate(key, replaced)
}
}
CompilationTarget::Module(ref module_name) => {
if IndexPtrTag::Undefined == code_index.get().tag() {
code_index.set(code_ptr);
if IndexPtrTag::Undefined == code_idx_ptr.tag() {
*code_idx_ptr = code_ptr;
RetractionRecord::AddedModulePredicate(*module_name, key)
} else {
let replaced = code_index.replace(code_ptr);
let replaced = mem::replace(code_idx_ptr, code_ptr);
RetractionRecord::ReplacedModulePredicate(*module_name, key, replaced)
}
}
};
},
);
retraction_info.push_record(record);
payload.retraction_info.push_record(record);
}
fn add_op_decl_as_module_export<'a, LS: LoadState<'a>>(
@@ -134,21 +136,28 @@ pub(super) fn import_module_exports<'a, LS: LoadState<'a>>(
}
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let arena = &mut LS::machine_st(payload).arena;
let code_idx_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
let target_code_index = *code_dir
.entry(key)
.or_insert_with(|| CodeIndex::default(arena));
.or_insert_with(|| CodeIndex::default(code_idx_tbl));
set_code_index(
&mut payload.retraction_info,
let src_code_index_ptr = code_idx_tbl.get_entry(src_code_index.into());
set_code_index::<LS>(
payload,
compilation_target,
key,
target_code_index,
src_code_index.get(),
src_code_index_ptr,
);
if src_code_index.is_dynamic_undefined() {
if LS::machine_st(payload)
.arena
.code_index_tbl
.get_entry(src_code_index.into())
.is_dynamic_undefined()
{
code_dir.insert(key, src_code_index);
}
} else {
@@ -190,19 +199,20 @@ fn import_module_exports_into_module<'a, LS: LoadState<'a>>(
meta_predicates.insert(key, meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena;
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
let target_code_index = *code_dir
.entry(key)
.or_insert_with(|| CodeIndex::default(arena));
.or_insert_with(|| CodeIndex::default(code_index_tbl));
set_code_index(
&mut payload.retraction_info,
set_code_index::<LS>(
payload,
compilation_target,
key,
target_code_index,
src_code_index.get(),
src_code_ptr,
);
} else {
return Err(SessionError::ModuleDoesNotContainExport(
@@ -243,21 +253,21 @@ fn import_qualified_module_exports<'a, LS: LoadState<'a>>(
.insert(key, meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena;
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
let target_code_index = *wam_prelude
.indices
.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
let target_code_index =
*wam_prelude.indices.code_dir.entry(key).or_insert_with(|| {
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
});
set_code_index(
&mut payload.retraction_info,
set_code_index::<LS>(
payload,
compilation_target,
key,
target_code_index,
src_code_index.get(),
src_code_ptr,
);
} else {
return Err(SessionError::ModuleDoesNotContainExport(
@@ -304,19 +314,20 @@ fn import_qualified_module_exports_into_module<'a, LS: LoadState<'a>>(
meta_predicates.insert(key, meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let arena = &mut LS::machine_st(payload).arena;
if let Some(src_code_index) = imported_module.code_dir.get(&key).cloned() {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
let target_code_index = *code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl));
set_code_index(
&mut payload.retraction_info,
set_code_index::<LS>(
payload,
&payload_compilation_target,
key,
target_code_index,
src_code_index.get(),
src_code_ptr,
);
} else {
return Err(SessionError::ModuleDoesNotContainExport(
@@ -434,19 +445,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.retract_local_clauses_impl(clause_clause_compilation_target, key, clause_locs);
}
pub(super) fn try_term_to_tl(
&mut self,
term: Term,
preprocessor: &mut Preprocessor,
) -> Result<PredicateClause, SessionError> {
let tl = preprocessor.try_term_to_tl(self, term)?;
Ok(match tl {
TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data),
TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data),
})
}
#[inline]
pub(super) fn remove_module_op_exports(&mut self) {
for (mut op_decl, record) in self.payload.module_op_exports.drain(0..) {
@@ -482,11 +480,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.indices
.get_predicate_skeleton(local_compilation_target, key)
{
let old_index_ptr = code_index.replace(if global_skeleton.core.is_dynamic {
let old_index_ptr = code_index.replace(
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
if global_skeleton.core.is_dynamic {
IndexPtr::dynamic_undefined()
} else {
IndexPtr::undefined()
});
},
);
self.payload.retraction_info.push_record(
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
@@ -500,8 +501,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
continue;
}
if !code_index.is_undefined() && !code_index.is_dynamic_undefined() {
let old_index_ptr = code_index.replace(IndexPtr::undefined());
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
let code_ptr = code_index_tbl.get_entry((*code_index).into());
if !code_ptr.is_undefined() && !code_ptr.is_dynamic_undefined() {
let old_index_ptr = code_index.replace(code_index_tbl, IndexPtr::undefined());
self.payload.retraction_info.push_record(
RetractionRecord::ReplacedModulePredicate(module_name, *key, old_index_ptr),
@@ -531,27 +535,32 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
None => return,
};
fn remove_module_exports(
fn remove_module_exports<'b, LS: LoadState<'b>>(
payload: &mut <LS as LoadState<'b>>::LoaderFieldType,
removed_module: &Module,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
retraction_info: &mut RetractionInfo,
predicate_retractor: impl Fn(PredicateKey, IndexPtr) -> RetractionRecord,
op_retractor: impl Fn(OpDecl, OpDesc) -> RetractionRecord,
) {
for export in removed_module.module_decl.exports.iter() {
match export {
ModuleExport::PredicateKey(ref key) => {
match (removed_module.code_dir.get(key), code_dir.get_mut(key)) {
(Some(module_code_index), Some(target_code_index))
if module_code_index.get() == target_code_index.get() =>
{
if let (Some(module_code_idx), Some(target_code_idx)) = (
removed_module.code_dir.get(key).cloned(),
code_dir.get_mut(key).cloned(),
) {
let code_index_tbl = &mut LS::machine_st(payload).arena.code_index_tbl;
let module_code_ptr = code_index_tbl.get_entry(module_code_idx.into());
let target_code_ptr = code_index_tbl.get_entry(target_code_idx.into());
if module_code_ptr == target_code_ptr {
let old_index_ptr =
target_code_index.replace(IndexPtr::undefined());
retraction_info
target_code_idx.replace(code_index_tbl, IndexPtr::undefined());
payload
.retraction_info
.push_record(predicate_retractor(*key, old_index_ptr));
}
_ => {}
}
}
ModuleExport::OpDecl(op_decl) => {
@@ -559,7 +568,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.swap_remove(&(op_decl.name, op_decl.op_desc.get_spec().fixity()));
if let Some(op_desc) = op_dir_value_opt {
retraction_info.push_record(op_retractor(*op_decl, op_desc));
payload
.retraction_info
.push_record(op_retractor(*op_decl, op_desc));
}
}
}
@@ -568,11 +579,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
match self.payload.compilation_target {
CompilationTarget::User => {
remove_module_exports(
remove_module_exports::<LS>(
&mut self.payload,
&removed_module,
&mut self.wam_prelude.indices.code_dir,
&mut self.wam_prelude.indices.op_dir,
&mut self.payload.retraction_info,
RetractionRecord::ReplacedUserPredicate,
RetractionRecord::ReplacedUserOp,
);
@@ -592,11 +603,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.modules
.get_mut(&target_module_name)
{
remove_module_exports(
remove_module_exports::<LS>(
&mut self.payload,
&removed_module,
&mut module.code_dir,
&mut module.op_dir,
&mut self.payload.retraction_info,
predicate_retractor,
op_retractor,
);
@@ -622,7 +633,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
CodeIndex::new(
IndexPtr::undefined(),
&mut LS::machine_st(&mut self.payload).arena,
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
)
}),
None => {
@@ -632,7 +643,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
Some(ref mut module) => *module.code_dir.entry(key).or_insert_with(|| {
CodeIndex::new(
IndexPtr::undefined(),
&mut LS::machine_st(&mut self.payload).arena,
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl,
)
}),
None => {
@@ -648,7 +659,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
key: PredicateKey,
compilation_target: CompilationTarget,
) -> CodeIndex {
let arena = &mut LS::machine_st(&mut self.payload).arena;
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
match compilation_target {
CompilationTarget::User => *self
@@ -656,7 +667,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.indices
.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena)),
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl)),
CompilationTarget::Module(module_name) => {
self.get_or_insert_local_code_index(module_name, key)
}
@@ -668,15 +679,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
module_name: Atom,
key: PredicateKey,
) -> CodeIndex {
let arena = &mut LS::machine_st(&mut self.payload).arena;
let code_index_tbl = &mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
if module_name == atom!("user") {
return *self
*self
.wam_prelude
.indices
.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), code_index_tbl))
} else {
self.get_or_insert_local_code_index(module_name, key)
}
+96 -81
View File
@@ -20,6 +20,7 @@ use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
/*
* The loader compiles Prolog terms read from a TermStream instance,
@@ -382,7 +383,6 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
let repo_len = loader.wam_prelude.code.len();
loader.payload.retraction_info.reset(repo_len);
loader.remove_module_op_exports();
Ok(loader.payload.compilation_target)
@@ -720,7 +720,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.wam_prelude.indices.modules.get_mut(&module_name)
{
if let Some(code_idx) = module.code_dir.get_mut(&key) {
code_idx.set(old_code_idx)
let code_index_tbl =
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
code_idx.set(code_index_tbl, old_code_idx);
}
}
}
@@ -741,7 +743,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
}
RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => {
if let Some(code_idx) = self.wam_prelude.indices.code_dir.get_mut(&key) {
code_idx.set(old_code_idx)
let code_index_tbl =
&mut LS::machine_st(&mut self.payload).arena.code_index_tbl;
code_idx.set(code_index_tbl, old_code_idx)
}
}
RetractionRecord::AddedIndex(index_key, clause_loc) => {
@@ -762,7 +766,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
) => {
remove_constant_indices(
constant,
&overlapping_constants,
overlapping_constants,
indexing_code,
clause_loc - index_loc, // WAS: &inner_index_locs,
);
@@ -1046,8 +1050,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let cell = machine_st[r];
let export_list = machine_st.read_term_from_heap(cell);
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
let export_list = setup_module_export_list(export_list, atom_tbl)?;
let export_list = setup_module_export_list(export_list)?;
Ok(export_list.into_iter().collect())
}
@@ -1060,7 +1063,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
self.payload.clause_clauses.push((head, body));
}
head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => {
head @ (Term::Clause(..) | Term::Literal(_, Literal::Atom(_))) => {
let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
self.payload.clause_clauses.push((head, body));
}
@@ -1218,14 +1221,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
* but to multifile and discontiguous predicates as well.
*/
let code_index = self.get_or_insert_code_index(key, compilation_target);
let offset = self.get_or_insert_code_index(key, compilation_target);
let code_idx_ptr = LS::machine_st(&mut self.payload)
.arena
.code_index_tbl
.get_entry(offset.into());
if code_index.is_undefined() {
set_code_index(
&mut self.payload.retraction_info,
if code_idx_ptr.is_undefined() {
set_code_index::<LS>(
&mut self.payload,
&compilation_target,
key,
code_index,
offset,
IndexPtr::dynamic_undefined(),
);
}
@@ -1289,13 +1296,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
if let Some(predicate_name) = ClauseInfo::name(term) {
let arity = ClauseInfo::arity(term);
let predicate_arity = ClauseInfo::arity(term);
let predicates_compilation_target = self.payload.predicates.compilation_target;
let is_dynamic = self
.wam_prelude
.indices
.get_predicate_skeleton(&predicates_compilation_target, &(predicate_name, arity))
.get_predicate_skeleton(
&predicates_compilation_target,
&(predicate_name, predicate_arity),
)
.map(|skeleton| skeleton.core.is_dynamic)
.unwrap_or(false);
@@ -1369,8 +1379,9 @@ impl<'a> MachinePreludeView<'a> {
impl MachineState {
pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
let mut term_stack = vec![];
self.heap[0] = term_addr;
let mut iter =
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_addr);
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr);
@@ -1384,46 +1395,32 @@ impl MachineState {
match as_partial_string(head, tail) {
Ok((string, Some(tail))) => {
term_stack.push(Term::PartialString(Cell::default(), string, tail));
term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail));
}
Ok((string, None)) => {
let atom = AtomTable::build_with(&self.atom_tbl, &string);
term_stack.push(Term::CompleteString(Cell::default(), atom));
term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
}
Err(cons_term) => term_stack.push(cons_term),
}
}
(HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64Offset) => {
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
}
(HeapCellValueTag::StackVar, h) => {
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{h}"))));
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
}
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{h}"))));
}
(HeapCellValueTag::Atom, (name, arity)) => {
let h = iter.focus().value() as usize;
let mut arity = arity;
if iter.heap.len() > h + arity + 1 {
let value = iter.heap[h + arity + 1];
let value = iter.heap[h.saturating_sub(1)];
if let Some(idx) = get_structure_index(value) {
// in the second condition, arity == 0,
// meaning idx cannot pertain to this atom
// if it is the direct subterm of a larger
// structure.
if arity > 0 || !iter.direct_subterm_of_str(h) {
term_stack.push(
Term::Literal(Cell::default(), Literal::CodeIndex(idx))
);
term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndexOffset(idx.into())));
arity += 1;
}
}
}
if arity == 0 {
term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
@@ -1435,28 +1432,22 @@ impl MachineState {
term_stack.push(Term::Clause(Cell::default(), name, subterms));
}
}
(HeapCellValueTag::PStr, atom) => {
let tail = term_stack.pop().unwrap();
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
term_stack.push(Term::CompleteString(Cell::default(), atom));
} else {
term_stack.push(Term::PartialString(
Cell::default(),
atom.as_str().to_owned(),
Box::new(tail),
));
}
}
(HeapCellValueTag::PStrLoc, h) => {
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h);
let tail = term_stack.pop().unwrap();
term_stack.push(Term::PartialString(
term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) {
Term::CompleteString(
Cell::default(),
atom.as_str().to_owned(),
Rc::new(string.to_owned()),
)
} else {
Term::PartialString(
Cell::default(),
Rc::new(string.to_owned()),
Box::new(tail),
));
)
});
}
_ => {
}
@@ -1605,7 +1596,7 @@ impl Machine {
let predicate_name = cell_as_atom!(self.deref_register(2));
let arity = self.deref_register(3);
let arity = match Number::try_from(arity) {
let arity = match Number::try_from((arity, &self.machine_st.arena.f64_tbl)) {
Ok(Number::Integer(n)) if *n >= Integer::ZERO && *n <= Integer::from(MAX_ARITY) => {
let value: usize = (&*n).try_into().unwrap();
Ok(value)
@@ -1981,7 +1972,6 @@ impl Machine {
};
let stub_gen = || functor_stub(key.0, key.1);
let head = self.deref_register(2);
if head.is_var() {
@@ -2017,7 +2007,14 @@ impl Machine {
.wam_prelude
.indices
.get_predicate_code_index(name, arity, module_name)
.map(|code_idx| code_idx.get_tag())
.map(|offset| {
loader
.payload
.machine_st
.arena
.code_index_tbl
.with_entry(offset.into(), |idx| idx.tag())
})
.unwrap_or(IndexPtrTag::DynamicUndefined);
if idx_tag == IndexPtrTag::Index {
@@ -2123,14 +2120,16 @@ impl Machine {
.indices
.remove_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| {
let mut clause_clause_skeleton = loader
.wam_prelude
.indices
.remove_predicate_skeleton(
let mut clause_clause_skeleton =
match loader.wam_prelude.indices.remove_predicate_skeleton(
&clause_clause_compilation_target,
&(atom!("$clause"), 2),
)
.unwrap();
) {
Some(skeleton) => skeleton,
None => {
return vec![];
}
};
let result = skeleton
.core
@@ -2160,9 +2159,16 @@ impl Machine {
.indices
.remove_predicate_skeleton(&compilation_target, &key);
let mut code_index = loader.get_or_insert_code_index(key, compilation_target);
let offset = loader.get_or_insert_code_index(key, compilation_target);
code_index.set(IndexPtr::undefined());
loader
.payload
.machine_st
.arena
.code_index_tbl
.with_entry_mut(offset.into(), |code_idx| {
*code_idx = IndexPtr::undefined();
});
loader.payload.compilation_target = clause_clause_compilation_target;
@@ -2192,7 +2198,7 @@ impl Machine {
.machine_st
.store(self.machine_st.deref(self.machine_st[temp_v!(3)]));
let target_pos = match Number::try_from(target_pos) {
let target_pos = match Number::try_from((target_pos, &self.machine_st.arena.f64_tbl)) {
Ok(Number::Integer(n)) => {
let value: usize = (&*n).try_into().unwrap();
value
@@ -2342,29 +2348,38 @@ impl Machine {
.get_meta_predicate_spec(predicate_name, arity, &compilation_target)
{
Some(meta_specs) => {
let term_loc = self.machine_st.heap.len();
let term_loc = self.machine_st.heap.cell_len();
self.machine_st
.heap
.push(atom_as_cell!(predicate_name, arity));
self.machine_st
.heap
.extend(meta_specs.iter().map(|meta_spec| match meta_spec {
let mut writer = match self.machine_st.heap.reserve(3 + meta_specs.len()) {
Ok(writer) => writer,
Err(err_loc) => {
self.machine_st.throw_resource_error(err_loc);
return;
}
};
writer.write_with(|section| {
section.push_cell(atom_as_cell!(predicate_name, arity));
for meta_spec in meta_specs.iter() {
section.push_cell(match meta_spec {
MetaSpec::Minus => atom_as_cell!(atom!("+")),
MetaSpec::Plus => atom_as_cell!(atom!("-")),
MetaSpec::Either => atom_as_cell!(atom!("?")),
MetaSpec::Colon => atom_as_cell!(atom!(":")),
MetaSpec::RequiresExpansionWithArgument(ref arg_num) => {
fixnum_as_cell!(Fixnum::build_with(*arg_num as i64))
fixnum_as_cell!(/* FIXME this is not safe */ unsafe {
Fixnum::build_with_unchecked(*arg_num as i64)
})
}
});
}
}));
let heap_loc = self.machine_st.heap.len();
section.push_cell(atom_as_cell!(atom!("meta_predicate"), 1));
section.push_cell(str_loc_as_cell!(term_loc));
});
self.machine_st
.heap
.push(atom_as_cell!(atom!("meta_predicate"), 1));
self.machine_st.heap.push(str_loc_as_cell!(term_loc));
let heap_loc = self.machine_st.heap.cell_len() - 2;
unify!(
self.machine_st,
+201 -203
View File
@@ -5,6 +5,7 @@ use crate::parser::ast::*;
#[cfg(feature = "ffi")]
use crate::ffi::FFIError;
use crate::forms::*;
use crate::functor_macro::*;
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_state::*;
@@ -12,20 +13,13 @@ use crate::machine::streams::*;
use crate::machine::system_calls::BrentAlgState;
use crate::types::*;
pub type MachineStub = Vec<HeapCellValue>;
pub type MachineStub = Vec<FunctorElement>;
pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
#[derive(Debug, Clone, Copy)]
enum ErrorProvenance {
Constructed, // if constructed, offset the addresses.
Received, // otherwise, preserve the addresses.
}
#[derive(Debug)]
pub(crate) struct MachineError {
stub: MachineStub,
location: Option<(usize, usize)>, // line_num, col_num
from: ErrorProvenance,
}
// from 7.12.2 b) of 13211-1:1995
@@ -50,6 +44,7 @@ pub(crate) enum ValidType {
// PredicateIndicator,
// Variable
TcpListener,
Process,
}
impl ValidType {
@@ -73,6 +68,7 @@ impl ValidType {
// ValidType::PredicateIndicator => atom!("predicate_indicator"),
// ValidType::Variable => atom!("variable")
ValidType::TcpListener => atom!("tcp_listener"),
ValidType::Process => atom!("process"),
}
}
}
@@ -91,45 +87,26 @@ impl TypeError for HeapCellValue {
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
let stub = functor!(
atom!("type_error"),
[atom(valid_type.as_atom()), cell(self)]
[atom_as_cell((valid_type.as_atom())), cell(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
impl TypeError for MachineStub {
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
fn type_error(self, _machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
let stub = functor!(
atom!("type_error"),
[atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
[self]
[atom_as_cell((valid_type.as_atom())), functor(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
}
impl TypeError for FunctorStub {
fn type_error(self, machine_st: &mut MachineState, valid_type: ValidType) -> MachineError {
let stub = functor!(
atom!("type_error"),
[atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
[self]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
}
@@ -139,15 +116,14 @@ impl TypeError for Number {
let stub = functor!(
atom!("type_error"),
[
atom(valid_type.as_atom()),
number(&mut machine_st.arena, self)
atom_as_cell((valid_type.as_atom())),
number(self, (&mut machine_st.arena))
]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
@@ -171,16 +147,15 @@ impl PermissionError for Atom {
let stub = functor!(
atom!("permission_error"),
[
atom(perm.as_atom()),
atom(index_atom),
cell(atom_as_cell!(self))
atom_as_cell((perm.as_atom())),
atom_as_cell(index_atom),
atom_as_cell(self)
]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
@@ -214,13 +189,16 @@ impl PermissionError for HeapCellValue {
let stub = functor!(
atom!("permission_error"),
[atom(perm.as_atom()), atom(index_atom), cell(cell)]
[
atom_as_cell((perm.as_atom())),
atom_as_cell(index_atom),
cell(cell)
]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
@@ -228,24 +206,22 @@ impl PermissionError for HeapCellValue {
impl PermissionError for MachineStub {
fn permission_error(
self,
machine_st: &mut MachineState,
_machine_st: &mut MachineState,
index_atom: Atom,
perm: Permission,
) -> MachineError {
let stub = functor!(
atom!("permission_error"),
[
atom(perm.as_atom()),
atom(index_atom),
str(machine_st.heap.len(), 0)
],
[self]
atom_as_cell((perm.as_atom())),
atom_as_cell(index_atom),
functor(self)
]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
}
@@ -256,32 +232,14 @@ pub(super) trait DomainError {
impl DomainError for HeapCellValue {
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
let stub = functor!(atom!("domain_error"), [atom(error.as_atom()), cell(self)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
impl DomainError for FunctorStub {
fn domain_error(
self,
machine_st: &mut MachineState,
valid_type: DomainErrorType,
) -> MachineError {
let stub = functor!(
atom!("domain_error"),
[atom(valid_type.as_atom()), str(machine_st.heap.len(), 0)],
[self]
[atom_as_cell((error.as_atom())), cell(self)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
}
@@ -290,26 +248,36 @@ impl DomainError for Number {
fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
let stub = functor!(
atom!("domain_error"),
[atom(error.as_atom()), number(&mut machine_st.arena, self)]
[
atom_as_cell((error.as_atom())),
number(self, (&mut machine_st.arena))
]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
}
pub(super) type FunctorStub = [HeapCellValue; 3];
impl DomainError for MachineStub {
fn domain_error(self, _machine_st: &mut MachineState, error: DomainErrorType) -> MachineError {
let stub = functor!(
atom!("domain_error"),
[atom_as_cell((error.as_atom())), functor(self)]
);
MachineError {
stub,
location: None,
}
}
}
#[inline(always)]
pub(super) fn functor_stub(name: Atom, arity: usize) -> FunctorStub {
[
atom_as_cell!(atom!("/"), 2),
atom_as_cell!(name),
fixnum_as_cell!(Fixnum::build_with(arity as i64)),
]
pub(super) fn functor_stub(name: Atom, arity: usize) -> MachineStub {
functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)])
}
impl MachineState {
@@ -320,37 +288,40 @@ impl MachineState {
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super) fn evaluation_error(&mut self, eval_error: EvalError) -> MachineError {
let stub = functor!(atom!("evaluation_error"), [atom(eval_error.as_atom())]);
let stub = functor!(
atom!("evaluation_error"),
[atom_as_cell((eval_error.as_atom()))]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError {
pub(super) fn resource_error(err: ResourceError) -> MachineError {
let stub = match err {
ResourceError::FiniteMemory(size_requested) => {
functor!(
atom!("resource_error"),
[atom(atom!("finite_memory")), cell(size_requested)]
[atom_as_cell((atom!("finite_memory"))), cell(size_requested)]
)
}
ResourceError::OutOfFiles => {
functor!(atom!("resource_error"), [atom(atom!("file_descriptors"))])
functor!(
atom!("resource_error"),
[atom_as_cell((atom!("file_descriptors")))]
)
}
};
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
@@ -367,13 +338,12 @@ impl MachineState {
ExistenceError::Module(name) => {
let stub = functor!(
atom!("existence_error"),
[atom(atom!("source_sink")), atom(name)]
[atom_as_cell((atom!("source_sink"))), atom_as_cell(name)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
ExistenceError::QualifiedProcedure {
@@ -381,36 +351,30 @@ impl MachineState {
name,
arity,
} => {
let h = self.heap.len();
let ind_stub = functor!(atom!("/"), [atom(name), fixnum(arity)]);
let res_stub = functor!(atom!(":"), [atom(module_name), str(h + 3, 0)], [ind_stub]);
let ind_stub = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
let res_stub = functor!(atom!(":"), [atom_as_cell(module_name), functor(ind_stub)]);
let stub = functor!(
atom!("existence_error"),
[atom(atom!("procedure")), str(h, 0)],
[res_stub]
[atom_as_cell((atom!("procedure"))), functor(res_stub)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
ExistenceError::Procedure(name, arity) => {
let culprit = functor!(atom!("/"), [atom(name), fixnum(arity)]);
let culprit = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]);
let stub = functor!(
atom!("existence_error"),
[atom(atom!("procedure")), str(self.heap.len(), 0)],
[culprit]
[atom_as_cell((atom!("procedure"))), functor(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
ExistenceError::ModuleSource(source) => {
@@ -418,40 +382,83 @@ impl MachineState {
let stub = functor!(
atom!("existence_error"),
[atom(atom!("source_sink")), str(self.heap.len(), 0)],
[source_stub]
[atom_as_cell((atom!("source_sink"))), functor(source_stub)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
ExistenceError::SourceSink(culprit) => {
let stub = functor!(
atom!("existence_error"),
[atom(atom!("source_sink")), cell(culprit)]
[atom_as_cell((atom!("source_sink"))), cell(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
ExistenceError::Stream(culprit) => {
let stub = functor!(
atom!("existence_error"),
[atom(atom!("stream")), cell(culprit)]
[atom_as_cell((atom!("stream"))), cell(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
ExistenceError::Process(culprit) => {
let stub = functor!(
atom!("existence_error"),
[atom_as_cell((atom!("process"))), cell(culprit)]
);
MachineError {
stub,
location: None,
}
}
}
}
pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError {
match err {
DirectiveError::ExpectedDirective(_term) => self.domain_error(
DomainErrorType::Directive,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidDirective(name, arity) => {
self.domain_error(DomainErrorType::Directive, functor_stub(name, arity))
}
DirectiveError::InvalidOpDeclNameType(_term) => self.type_error(
ValidType::List,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error(
DomainErrorType::OperatorSpecifier,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidOpDeclSpecValue(atom) => {
self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom))
}
DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error(
ValidType::Integer,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidOpDeclPrecDomain(num) => {
self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num))
}
DirectiveError::ShallNotCreate(atom) => {
self.permission_error(Permission::Create, atom!("operator"), atom)
}
DirectiveError::ShallNotModify(atom) => {
self.permission_error(Permission::Modify, atom!("operator"), atom)
}
}
}
@@ -471,12 +478,11 @@ impl MachineState {
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
match err {
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
ArithmeticError::NonEvaluableFunctor(literal, arity) => {
let culprit = functor!(atom!("/"), [literal(literal), fixnum(arity)]);
ArithmeticError::NonEvaluableFunctor(cell, arity) => {
let culprit = functor!(atom!("/"), [literal(cell), fixnum(arity)]);
self.type_error(ValidType::Evaluable, culprit)
}
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
}
}
@@ -495,7 +501,6 @@ impl MachineState {
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
@@ -504,16 +509,12 @@ impl MachineState {
SessionError::CannotOverwriteBuiltIn(key) => self.permission_error(
Permission::Modify,
atom!("static_procedure"),
functor_stub(key.0, key.1)
.into_iter()
.collect::<MachineStub>(),
functor_stub(key.0, key.1),
),
SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error(
Permission::Modify,
atom!("static_procedure"),
functor_stub(key.0, key.1)
.into_iter()
.collect::<MachineStub>(),
functor_stub(key.0, key.1),
),
SessionError::CannotOverwriteBuiltInModule(module) => {
self.permission_error(Permission::Modify, atom!("static_module"), module)
@@ -524,8 +525,7 @@ impl MachineState {
let stub = functor!(
atom!("module_does_not_contain_claimed_export"),
[atom(module_name), str(self.heap.len() + 4, 0)],
[functor_stub]
[atom_as_cell(module_name), functor(functor_stub)]
);
self.permission_error(Permission::Access, atom!("private_procedure"), stub)
@@ -536,7 +536,7 @@ impl MachineState {
self.permission_error(
Permission::Modify,
atom!("module"),
functor!(error_atom, [atom(module_name)]),
functor!(error_atom, [atom_as_cell(module_name)]),
)
}
SessionError::NamelessEntry => {
@@ -555,15 +555,12 @@ impl MachineState {
}
SessionError::CompilationError(err) => self.syntax_error(err),
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
let functor_stub = functor_stub(key.0, key.1);
let stub = functor!(
atom!(":"),
[
atom(compilation_target.module_name()),
str(self.heap.len() + 4, 0)
],
[functor_stub]
atom_as_cell((compilation_target.module_name())),
functor((key.0), [fixnum((key.1))])
]
);
self.permission_error(
@@ -587,30 +584,36 @@ impl MachineState {
}
let location = err.line_and_col_num();
let len = self.heap.len();
let stub = err.as_functor();
let stub = functor!(atom!("syntax_error"), [str(len, 0)], [stub]);
let stub = functor!(atom!("syntax_error"), [functor(stub)]);
MachineError {
stub,
location,
from: ErrorProvenance::Constructed,
}
MachineError { stub, location }
}
pub(super) fn representation_error(&mut self, flag: RepFlag) -> MachineError {
let stub = functor!(atom!("representation_error"), [atom(flag.as_atom())]);
pub(super) fn representation_error(&self, flag: RepFlag) -> MachineError {
let stub = functor!(
atom!("representation_error"),
[atom_as_cell((flag.as_atom()))]
);
MachineError {
stub,
location: None,
}
}
pub(super) fn unreachable_error(&self) -> MachineError {
let stub = functor!(atom!("system_error"));
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
#[cfg(feature = "ffi")]
pub(super) fn ffi_error(&mut self, err: FFIError) -> MachineError {
pub(super) fn ffi_error(&self, err: FFIError) -> MachineError {
let error_atom = match err {
FFIError::ValueCast => atom!("value_cast"),
FFIError::ValueDontFit => atom!("value_dont_fit"),
@@ -619,62 +622,50 @@ impl MachineState {
FFIError::FunctionNotFound => atom!("function_not_found"),
FFIError::StructNotFound => atom!("struct_not_found"),
};
let stub = functor!(atom!("ffi_error"), [atom(error_atom)]);
let stub = functor!(atom!("ffi_error"), [atom_as_cell(error_atom)]);
MachineError {
stub,
location: None,
from: ErrorProvenance::Constructed,
}
}
pub(super) fn error_form(&mut self, err: MachineError, src: FunctorStub) -> MachineStub {
let h = self.heap.len();
let location = err.location;
let stub_addition_len = if err.len() == 1 {
0 // if err contains 1 cell, it can be inlined at stub[1].
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
if let Some((line_num, _col_num)) = err.location {
functor!(
atom!("error"),
[
functor((err.stub)),
functor(
(atom!(":")),
[functor(src), number(line_num, (&mut self.arena))]
)
]
)
} else {
err.len()
};
let mut stub = vec![
atom_as_cell!(atom!("error"), 2),
str_loc_as_cell!(h + 3),
str_loc_as_cell!(h + 3 + stub_addition_len),
];
if stub_addition_len > 0 {
stub.extend(err.into_iter(3));
} else {
stub[1] = err.stub[0];
functor!(atom!("error"), [functor((err.stub)), functor(src)])
}
}
if let Some((line_num, _)) = location {
stub.push(atom_as_cell!(atom!(":"), 2));
stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
stub.push(integer_as_cell!(Number::arena_from(
line_num,
&mut self.arena
)));
}
stub.extend(src.iter());
stub
// throw an error pre-allocated in the heap
pub(super) fn throw_resource_error(&mut self, err_loc: usize) {
self.registers[1] = str_loc_as_cell!(err_loc);
self.set_ball();
self.unwind_stack();
}
pub(super) fn throw_exception(&mut self, err: MachineStub) {
let h = self.heap.len();
let err_len = err.len();
self.ball.boundary = 0;
self.ball.stub.truncate(0);
self.heap.extend(err);
let mut writer = Heap::functor_writer(err);
self.registers[1] = if err_len == 1 {
heap_loc_as_cell!(h)
} else {
str_loc_as_cell!(h)
self.registers[1] = match writer(&mut self.heap) {
Ok(loc) => loc,
Err(resource_err_loc) => {
self.throw_resource_error(resource_err_loc);
return;
}
};
self.set_ball();
@@ -682,21 +673,6 @@ impl MachineState {
}
}
impl MachineError {
fn into_iter(self, offset: usize) -> Box<dyn Iterator<Item = HeapCellValue>> {
match self.from {
ErrorProvenance::Constructed => {
Box::new(self.stub.into_iter().map(move |hcv| hcv + offset))
}
ErrorProvenance::Received => Box::new(self.stub.into_iter()),
}
}
fn len(&self) -> usize {
self.stub.len()
}
}
#[derive(Debug)]
pub enum CompilationError {
Arithmetic(ArithmeticError),
@@ -711,6 +687,7 @@ pub enum CompilationError {
InvalidRuleHead,
InvalidUseModuleDecl,
InvalidModuleResolution(Atom),
FiniteMemoryInHeap(usize),
}
#[derive(Debug)]
@@ -757,11 +734,9 @@ impl CompilationError {
functor!(atom!("exceeded_max_arity"))
}
CompilationError::InadmissibleFact => {
// TODO: type_error(callable, _).
functor!(atom!("inadmissible_fact"))
}
CompilationError::InadmissibleQueryTerm => {
// TODO: type_error(callable, _).
functor!(atom!("inadmissible_query_term"))
}
CompilationError::InvalidDirective(_) => {
@@ -776,8 +751,8 @@ impl CompilationError {
CompilationError::InvalidModuleExport => {
functor!(atom!("invalid_module_export"))
}
CompilationError::InvalidModuleResolution(ref module_name) => {
functor!(atom!("no_such_module"), [atom(module_name)])
&CompilationError::InvalidModuleResolution(module_name) => {
functor!(atom!("no_such_module"), [atom_as_cell(module_name)])
}
CompilationError::InvalidRuleHead => {
functor!(atom!("invalid_head_of_rule")) // TODO: type_error(callable, _).
@@ -788,6 +763,9 @@ impl CompilationError {
CompilationError::ParserError(ref err) => {
functor!(err.as_atom())
}
CompilationError::FiniteMemoryInHeap(h) => {
vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))]
}
}
}
}
@@ -896,14 +874,29 @@ impl EvalError {
// used by '$skip_max_list'.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CycleSearchResult {
Cyclic(usize),
Cyclic {
lambda: usize,
}, // number of steps
EmptyList,
NotList(usize, HeapCellValue), // the list length until the second argument in the heap
PartialList(usize, Ref), // the list length (up to max), and an offset into the heap.
ProperList(usize), // the list length.
PStrLocation(usize, usize, usize), // list length (up to max), the heap address of the PStr, the offset
UntouchedList(usize, usize), // list length (up to max), the address of an uniterated Addr::Lis(address).
UntouchedCStr(Atom, usize),
NotList {
num_steps: usize,
heap_loc: HeapCellValue,
},
PartialList {
num_steps: usize,
heap_loc: HeapCellValue,
},
ProperList {
num_steps: usize,
},
PStrLocation {
num_steps: usize,
pstr_loc: HeapCellValue,
},
UntouchedList {
num_steps: usize,
list_loc: usize,
},
}
impl MachineState {
@@ -915,11 +908,11 @@ impl MachineState {
let sorted = self.store(self.deref(self.registers[2]));
match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::PartialList(..) => {
CycleSearchResult::PartialList { .. } => {
let err = self.instantiation_error();
return Err(self.error_form(err, stub_gen()));
}
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
let err = self.type_error(ValidType::List, list);
return Err(self.error_form(err, stub_gen()));
}
@@ -927,7 +920,9 @@ impl MachineState {
};
match BrentAlgState::detect_cycles(&self.heap, sorted) {
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !sorted.is_var() => {
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. }
if !sorted.is_var() =>
{
let err = self.type_error(ValidType::List, sorted);
Err(self.error_form(err, stub_gen()))
}
@@ -939,7 +934,9 @@ impl MachineState {
let stub_gen = || functor_stub(atom!("keysort"), 2);
match BrentAlgState::detect_cycles(&self.heap, list) {
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) if !list.is_var() => {
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. }
if !list.is_var() =>
{
let err = self.type_error(ValidType::List, list);
Err(self.error_form(err, stub_gen()))
}
@@ -1001,11 +998,11 @@ impl MachineState {
let sorted = self.store(self.deref(self[temp_v!(2)]));
match BrentAlgState::detect_cycles(&self.heap, pairs) {
CycleSearchResult::PartialList(..) => {
CycleSearchResult::PartialList { .. } => {
let err = self.instantiation_error();
Err(self.error_form(err, stub_gen()))
}
CycleSearchResult::NotList(..) | CycleSearchResult::Cyclic(_) => {
CycleSearchResult::NotList { .. } | CycleSearchResult::Cyclic { .. } => {
let err = self.type_error(ValidType::List, pairs);
Err(self.error_form(err, stub_gen()))
}
@@ -1028,6 +1025,7 @@ pub enum ExistenceError {
},
SourceSink(HeapCellValue),
Stream(HeapCellValue),
Process(HeapCellValue),
}
#[derive(Debug)]
+34 -51
View File
@@ -2,7 +2,6 @@
use crate::parser::ast::*;
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::loader::*;
@@ -10,6 +9,7 @@ use crate::machine::machine_state::*;
use crate::machine::streams::{Stream, StreamOptions};
use crate::machine::ClauseType;
use crate::machine::MachineStubGen;
use crate::offset_table::*;
use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet};
@@ -18,7 +18,6 @@ use scryer_modular_bitfield::{bitfield, BitfieldSpecifier};
use std::cmp::Ordering;
use std::collections::BTreeSet;
use std::ops::{Deref, DerefMut};
use crate::types::*;
@@ -126,10 +125,19 @@ impl IndexPtr {
pub(crate) fn is_dynamic_undefined(&self) -> bool {
matches!(self.tag(), IndexPtrTag::DynamicUndefined)
}
#[inline]
pub(crate) fn local(&self) -> Option<usize> {
match self.tag() {
IndexPtrTag::Index => Some(self.p() as usize),
IndexPtrTag::DynamicIndex => Some(self.p() as usize),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(TypedArenaPtr<IndexPtr>);
#[derive(Debug, Clone, Copy)] // , Ord, Hash, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(CodeIndexOffset);
#[cfg(target_pointer_width = "32")]
const_assert!(std::mem::align_of::<CodeIndex>() == 4);
@@ -137,78 +145,53 @@ const_assert!(std::mem::align_of::<CodeIndex>() == 4);
#[cfg(target_pointer_width = "64")]
const_assert!(std::mem::align_of::<CodeIndex>() == 8);
impl Deref for CodeIndex {
type Target = TypedArenaPtr<IndexPtr>;
impl From<CodeIndex> for HeapCellValue {
#[inline(always)]
fn deref(&self) -> &TypedArenaPtr<IndexPtr> {
&self.0
fn from(idx: CodeIndex) -> HeapCellValue {
HeapCellValue::from(idx.0)
}
}
impl DerefMut for CodeIndex {
impl From<CodeIndexOffset> for CodeIndex {
#[inline(always)]
fn deref_mut(&mut self) -> &mut TypedArenaPtr<IndexPtr> {
&mut self.0
fn from(offset: CodeIndexOffset) -> CodeIndex {
CodeIndex(offset)
}
}
impl From<CodeIndex> for UntypedArenaPtr {
impl From<CodeIndex> for CodeIndexOffset {
#[inline(always)]
fn from(ptr: CodeIndex) -> UntypedArenaPtr {
UntypedArenaPtr::build_with(ptr.0.as_ptr() as usize)
fn from(value: CodeIndex) -> CodeIndexOffset {
value.0
}
}
impl From<TypedArenaPtr<IndexPtr>> for CodeIndex {
impl From<&'_ CodeIndex> for CodeIndexOffset {
#[inline(always)]
fn from(ptr: TypedArenaPtr<IndexPtr>) -> CodeIndex {
CodeIndex(ptr)
fn from(value: &'_ CodeIndex) -> CodeIndexOffset {
value.0
}
}
impl CodeIndex {
#[inline]
pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self {
CodeIndex(arena_alloc!(ptr, arena))
pub(crate) fn new(ptr: IndexPtr, code_index_tbl: &mut CodeIndexTable) -> Self {
CodeIndex(code_index_tbl.build_with(ptr))
}
#[inline(always)]
pub(crate) fn default(arena: &mut Arena) -> Self {
CodeIndex::new(IndexPtr::undefined(), arena)
}
pub(crate) fn local(&self) -> Option<usize> {
match self.0.tag() {
IndexPtrTag::Index => Some(self.0.p() as usize),
IndexPtrTag::DynamicIndex => Some(self.0.p() as usize),
_ => None,
}
pub(crate) fn default(code_index_tbl: &mut CodeIndexTable) -> Self {
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
}
#[inline(always)]
pub(crate) fn get(&self) -> IndexPtr {
*self.0.deref()
pub(crate) fn set(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) {
code_index_tbl.with_entry_mut(self.0, |idx| *idx = value);
}
#[inline(always)]
pub(crate) fn set(&mut self, value: IndexPtr) {
*self.0.deref_mut() = value;
}
#[inline(always)]
pub(crate) fn get_tag(self) -> IndexPtrTag {
self.0.tag()
}
#[inline(always)]
pub(crate) fn replace(&mut self, value: IndexPtr) -> IndexPtr {
std::mem::replace(self.0.deref_mut(), value)
}
#[inline(always)]
pub(crate) fn as_ptr(&self) -> *const IndexPtr {
self.0.as_ptr()
pub(crate) fn replace(&self, code_index_tbl: &mut CodeIndexTable, value: IndexPtr) -> IndexPtr {
code_index_tbl.with_entry_mut(self.0, |idx| std::mem::replace(idx, value))
}
}
@@ -223,7 +206,7 @@ impl VarKey {
#[inline]
pub(crate) fn to_string(&self) -> String {
match self {
VarKey::AnonVar(h) => format!("_{}", h),
VarKey::AnonVar(h) => format!("_{h}"),
VarKey::VarPtr(var) => var.borrow().to_string(),
}
}
@@ -543,7 +526,7 @@ impl IndexStore {
&'a self,
range: R,
) -> impl Iterator<Item = Stream> + 'a {
self.streams.range(range).into_iter().copied()
self.streams.range(range).copied()
}
/// Forcibly sets `alias` to `stream`.
+192 -158
View File
@@ -1,6 +1,7 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::functor_macro::*;
use crate::heap_iter::*;
use crate::heap_print::*;
use crate::machine::attributed_variables::*;
@@ -21,7 +22,7 @@ use indexmap::IndexMap;
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Index, IndexMut};
use std::ops::{Index, IndexMut, Range};
use std::sync::Arc;
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
@@ -35,8 +36,8 @@ pub(super) enum MachineMode {
#[derive(Debug, Clone)]
pub(super) enum HeapPtr {
HeapCell(usize),
PStrChar(usize, usize),
PStrLocation(usize, usize),
PStr(usize), // Char(usize),
// PStrLocation(usize),
}
impl Default for HeapPtr {
@@ -183,47 +184,62 @@ impl IndexMut<RegType> for MachineState {
}
}
pub type CallResult = Result<(), Vec<HeapCellValue>>;
#[inline(always)]
pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) {
read_heap_cell!(heap[index],
(HeapCellValueTag::PStr | HeapCellValueTag::CStr) => {
(index, Fixnum::build_with(0))
}
(HeapCellValueTag::PStrOffset, h) => {
(h, cell_as_fixnum!(heap[index+1]))
}
_ => {
unreachable!()
}
)
}
pub type CallResult = Result<(), Vec<FunctorElement>>;
// size may be an upper bound.
// true_size is calculated to compute the exact offset.
fn push_var_eq_functors<'a>(
heap: &mut Heap,
size: usize,
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
atom_tbl: &AtomTable,
) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![];
) -> Result<HeapCellValue, usize> {
let src_h = heap.cell_len();
let true_size = if size > 0 {
let mut writer = heap.reserve(2 + 5 * size)?;
writer
.write_with(|section| {
let mut size = 0;
for (var, binding) in iter {
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
let h = heap.len();
heap.push(atom_as_cell!(atom!("="), 2));
heap.push(atom_as_cell!(var_atom));
heap.push(*binding);
section.push_cell(atom_as_cell!(atom!("="), 2));
section.push_cell(atom_as_cell!(var_atom));
section.push_cell(*binding);
list_of_var_eqs.push(str_loc_as_cell!(h));
size += 1;
}
list_of_var_eqs
for idx in 0..size {
section.push_cell(list_loc_as_cell!(section.cell_len() + 1));
section.push_cell(str_loc_as_cell!(src_h + 3 * idx));
}
if size > 0 {
section.push_cell(empty_list_as_cell!());
}
size
})
.result
} else {
size
};
Ok(if true_size > 0 {
heap_loc_as_cell!(src_h + 3 * true_size)
} else {
empty_list_as_cell!()
})
}
#[derive(Debug)]
pub struct Ball {
pub(super) boundary: usize,
pub(super) pstr_boundary: usize,
pub(super) stub: Heap,
}
@@ -231,23 +247,44 @@ impl Ball {
pub(super) fn new() -> Self {
Ball {
boundary: 0,
pstr_boundary: 0,
stub: Heap::new(),
}
}
pub(super) fn reset(&mut self) {
self.boundary = 0;
self.pstr_boundary = 0;
self.stub.clear();
}
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
pub(super) fn copy_and_align_to(&self, dest: &mut Heap) -> Result<usize, usize> {
let h = dest.cell_len();
let diff = self.boundary as i64 - h as i64;
self.stub
.iter()
.cloned()
.map(|heap_value| heap_value - diff)
.collect()
let mut dest_writer = dest.reserve(self.stub.cell_len())?;
dest_writer.write_with(|section| {
for idx in 0..self.pstr_boundary {
section.push_cell(self.stub[idx] - diff);
}
});
let mut pstr_threshold = heap_index!(self.pstr_boundary);
while pstr_threshold < heap_index!(self.stub.cell_len()) {
let HeapStringScan { string, tail_idx } = self.stub.scan_slice_to_str(pstr_threshold);
pstr_threshold += dest_writer
.write_with(|section| {
if section.push_pstr(string).is_some() {
section.push_cell(self.stub[tail_idx] - diff);
}
})
.bytes_written;
}
Ok(h)
}
}
@@ -279,21 +316,6 @@ impl<'a> IndexMut<usize> for CopyTerm<'a> {
}
impl<'a> CopierTarget for CopyTerm<'a> {
#[inline(always)]
fn threshold(&self) -> usize {
self.state.heap.len()
}
#[inline(always)]
fn push(&mut self, hcv: HeapCellValue) {
self.state.heap.push(hcv);
}
#[inline(always)]
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
self.state.attr_var_init.attr_var_queue.push(attr_var_loc);
}
#[inline(always)]
fn store(&self, value: HeapCellValue) -> HeapCellValue {
self.state.store(value)
@@ -304,10 +326,40 @@ impl<'a> CopierTarget for CopyTerm<'a> {
self.state.deref(value)
}
#[inline(always)]
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
self.state.attr_var_init.attr_var_queue.push(attr_var_loc);
}
#[inline(always)]
fn stack(&mut self) -> &mut Stack {
&mut self.state.stack
}
#[inline(always)]
fn threshold(&self) -> usize {
self.state.heap.cell_len()
}
#[inline(always)]
fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
Box::new(self.state.heap.as_slice()[from..].iter().cloned())
}
#[inline(always)]
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
self.state.heap.copy_pstr_within(pstr_loc)
}
#[inline(always)]
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
self.state.heap.reserve(num_cells)
}
#[inline(always)]
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
self.state.heap.copy_slice_to_end(bounds)
}
}
#[derive(Debug)]
@@ -315,7 +367,6 @@ pub(super) struct CopyBallTerm<'a> {
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
heap_boundary: usize,
stub: &'a mut Heap,
}
@@ -326,13 +377,10 @@ impl<'a> CopyBallTerm<'a> {
heap: &'a mut Heap,
stub: &'a mut Heap,
) -> Self {
let hb = heap.len();
CopyBallTerm {
attr_var_queue,
stack,
heap,
heap_boundary: hb,
stub,
}
}
@@ -342,10 +390,10 @@ impl<'a> Index<usize> for CopyBallTerm<'a> {
type Output = HeapCellValue;
fn index(&self, index: usize) -> &Self::Output {
if index < self.heap_boundary {
if index < self.heap.cell_len() {
&self.heap[index]
} else {
let index = index - self.heap_boundary;
let index = index - self.heap.cell_len();
&self.stub[index]
}
}
@@ -353,10 +401,10 @@ impl<'a> Index<usize> for CopyBallTerm<'a> {
impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index < self.heap_boundary {
if index < self.heap.cell_len() {
&mut self.heap[index]
} else {
let index = index - self.heap_boundary;
let index = index - self.heap.cell_len();
&mut self.stub[index]
}
}
@@ -364,11 +412,7 @@ impl<'a> IndexMut<usize> for CopyBallTerm<'a> {
impl<'a> CopierTarget for CopyBallTerm<'a> {
fn threshold(&self) -> usize {
self.heap_boundary + self.stub.len()
}
fn push(&mut self, value: HeapCellValue) {
self.stub.push(value);
self.heap.cell_len() + self.stub.cell_len()
}
#[inline(always)]
@@ -379,10 +423,10 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
fn store(&self, value: HeapCellValue) -> HeapCellValue {
read_heap_cell!(value,
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
if h < self.heap_boundary {
if h < self.heap.cell_len() {
self.heap[h]
} else {
let index = h - self.heap_boundary;
let index = h - self.heap.cell_len();
self.stub[index]
}
}
@@ -411,6 +455,45 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
fn stack(&mut self) -> &mut Stack {
self.stack
}
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
debug_assert!(pstr_loc < self.heap.byte_len());
let HeapStringScan { string, tail_idx } = self.heap.scan_slice_to_str(pstr_loc);
self.stub.allocate_pstr(string)?;
Ok(tail_idx)
}
fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
if from < self.heap.byte_len() {
Box::new(
self.heap.as_slice()[from..]
.iter()
.cloned()
.chain(self.stub.as_slice().iter().cloned()),
)
} else {
Box::new(self.stub.as_slice()[from..].iter().cloned())
}
}
#[inline]
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
self.stub.reserve(num_cells)
}
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
let len = bounds.end - bounds.start;
let mut stub_writer = self.stub.reserve(len)?;
stub_writer.write_with(|section| {
for idx in bounds {
section.push_cell(self.heap[idx]);
}
});
Ok(())
}
}
impl MachineState {
@@ -461,10 +544,6 @@ impl MachineState {
let addr = self.store(self.deref(addr));
read_heap_cell!(addr,
(HeapCellValueTag::Char, c) => {
chars.push(c);
continue;
}
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
if let Some(c) = name.as_char() {
@@ -537,39 +616,26 @@ impl MachineState {
pub fn write_read_term_options(
&mut self,
mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
singleton_var_list: Vec<HeapCellValue>,
singleton_heap_list: HeapCellValue,
) -> CallResult {
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
let list_of_var_eqs = push_var_eq_functors(
&mut self.heap,
var_list.iter().filter_map(|(var_name, var, _)| {
if var_name.is_anon() {
None
} else {
Some((var_name, var))
}
}),
&self.atom_tbl,
);
let singleton_addr = self.registers[3];
let singletons_offset = heap_loc_as_cell!(iter_to_heap_list(
&mut self.heap,
singleton_var_list.into_iter()
));
unify_fn!(*self, singletons_offset, singleton_addr);
unify_fn!(*self, singleton_heap_list, singleton_addr);
if self.fail {
return Ok(());
}
let vars_addr = self.registers[4];
let vars_offset = heap_loc_as_cell!(iter_to_heap_list(
let vars_offset = resource_error_call_result!(
self,
sized_iter_to_heap_list(
&mut self.heap,
var_list.into_iter().map(|(_, cell, _)| cell)
));
var_list.len(),
var_list.iter().map(|(_, cell, _)| *cell),
)
);
unify_fn!(*self, vars_offset, vars_addr);
@@ -578,24 +644,27 @@ impl MachineState {
}
let var_names_addr = self.registers[5];
let var_names_offset = heap_loc_as_cell!(iter_to_heap_list(
let var_names_offset = resource_error_call_result!(
self,
push_var_eq_functors(
&mut self.heap,
list_of_var_eqs.into_iter()
));
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
var_list.len(),
var_list.iter().filter_map(|(var_name, var, _)| {
if var_name.is_anon() {
None
} else {
Some((var_name, var))
}
}),
&self.atom_tbl,
)
);
unify_fn!(*self, var_names_offset, var_names_addr);
Ok(())
}
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
pstr_loc_as_cell!(term_write_result.heap_loc)
}
_ => {
heap_loc_as_cell!(term_write_result.heap_loc)
}
);
let heap_loc = heap_loc_as_cell!(term_write_result.heap_loc);
unify_fn!(*self, heap_loc, self.registers[2]);
if self.fail {
@@ -607,10 +676,9 @@ impl MachineState {
}
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
self.heap[0] = heap_loc;
for cell in
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, heap_loc)
{
for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0) {
let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.as_var() {
@@ -622,8 +690,11 @@ impl MachineState {
}
}
let singleton_var_list = push_var_eq_functors(
let singleton_var_list = resource_error_call_result!(
self,
push_var_eq_functors(
&mut self.heap,
term_write_result.var_dict.len(),
term_write_result
.var_dict
.iter()
@@ -639,12 +710,9 @@ impl MachineState {
}
}),
&self.atom_tbl,
)
);
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
let mut var_list = Vec::with_capacity(singleton_var_set.len());
for (var_name, addr) in term_write_result.var_dict {
@@ -741,7 +809,8 @@ impl MachineState {
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
match eof_handler(self, stream)? {
OnEOF::Return => {
return self.write_read_term_options(vec![], vec![])
return self
.write_read_term_options(vec![], empty_list_as_cell!());
}
OnEOF::Continue => continue,
}
@@ -790,19 +859,16 @@ impl MachineState {
}
read_heap_cell!(atom,
(HeapCellValueTag::Char, c) => {
var_names.insert(var, VarPtr::from(c.to_string()));
}
(HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0);
var_names.insert(var, VarPtr::from(&*name.as_str()));
var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
var_names.insert(var, VarPtr::from(&*name.as_str()));
var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
}
_ => {
unreachable!();
@@ -881,13 +947,15 @@ impl MachineState {
}
);
self.heap[0] = term_to_be_printed;
let mut printer = HCPrinter::new(
&mut self.heap,
Arc::clone(&self.atom_tbl),
&mut self.stack,
&self.arena,
op_dir,
PrinterOutputter::new(),
term_to_be_printed,
0,
);
printer.ignore_ops = ignore_ops;
@@ -895,7 +963,7 @@ impl MachineState {
printer.quoted = quoted;
printer.double_quotes = double_quotes;
match Number::try_from(max_depth) {
match Number::try_from((max_depth, &self.arena.f64_tbl)) {
Ok(Number::Fixnum(n)) => {
if let Ok(n) = usize::try_from(n.get_num()) {
printer.max_depth = n;
@@ -920,7 +988,6 @@ impl MachineState {
}
printer.var_names = var_names;
printer
}
Err(err) => {
@@ -937,7 +1004,10 @@ impl MachineState {
arity: HeapCellValue,
) -> (Atom, usize) {
let name = cell_as_atom!(self.store(self.deref(name)));
let arity = cell_as_fixnum!(self.store(self.deref(arity)));
let arity = unsafe {
self.store(self.deref(arity))
.to_fixnum_or_cut_point_unchecked()
};
(name, usize::try_from(arity.get_num()).unwrap())
}
@@ -978,42 +1048,6 @@ impl MachineState {
}
);
}
pub(crate) fn directive_error(&mut self, err: DirectiveError) -> MachineError {
match err {
DirectiveError::ExpectedDirective(_term) => self.domain_error(
DomainErrorType::Directive,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidDirective(name, arity) => {
self.domain_error(DomainErrorType::Directive, functor_stub(name, arity))
}
DirectiveError::InvalidOpDeclNameType(_term) => self.type_error(
ValidType::List,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidOpDeclSpecDomain(_term) => self.domain_error(
DomainErrorType::OperatorSpecifier,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidOpDeclSpecValue(atom) => {
self.domain_error(DomainErrorType::OperatorSpecifier, atom_as_cell!(atom))
}
DirectiveError::InvalidOpDeclPrecType(_term) => self.type_error(
ValidType::Integer,
atom_as_cell!(atom!("todo_insert_invalid_term_here")),
),
DirectiveError::InvalidOpDeclPrecDomain(num) => {
self.domain_error(DomainErrorType::OperatorPriority, fixnum_as_cell!(num))
}
DirectiveError::ShallNotCreate(atom) => {
self.permission_error(Permission::Create, atom!("operator"), atom)
}
DirectiveError::ShallNotModify(atom) => {
self.permission_error(Permission::Modify, atom!("operator"), atom)
}
}
}
}
#[allow(clippy::upper_case_acronyms)]
File diff suppressed because it is too large Load Diff
+200 -121
View File
@@ -4,16 +4,13 @@ pub use crate::machine::machine_state::*;
pub use crate::machine::streams::*;
pub use crate::machine::*;
pub use crate::parser::ast::*;
use crate::read::*;
pub use crate::types::*;
use std::sync::Arc;
#[cfg(test)]
use crate::machine::copier::CopierTarget;
use crate::read::TermWriteResult;
#[cfg(test)]
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
// a mini-WAM for test purposes.
@@ -31,7 +28,6 @@ impl MockWAM {
Self {
machine_st: MachineState::new(),
op_dir,
//flags: MachineFlags::default(),
}
}
@@ -55,16 +51,15 @@ impl MockWAM {
term_string: &'static str,
) -> Result<String, CompilationError> {
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);
print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc);
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
Arc::clone(&self.machine_st.atom_tbl),
&mut self.machine_st.stack,
&self.machine_st.arena,
&self.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc),
term_write_result.heap_loc,
);
printer.var_names = term_write_result
@@ -95,6 +90,7 @@ pub struct TermCopyingMockWAM<'a> {
impl<'a> Index<usize> for TermCopyingMockWAM<'a> {
type Output = HeapCellValue;
#[inline]
fn index(&self, index: usize) -> &HeapCellValue {
&self.wam.machine_st.heap[index]
}
@@ -112,6 +108,7 @@ impl<'a> IndexMut<usize> for TermCopyingMockWAM<'a> {
impl<'a> Deref for TermCopyingMockWAM<'a> {
type Target = MockWAM;
#[inline]
fn deref(&self) -> &Self::Target {
self.wam
}
@@ -119,6 +116,7 @@ impl<'a> Deref for TermCopyingMockWAM<'a> {
#[cfg(test)]
impl<'a> DerefMut for TermCopyingMockWAM<'a> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.wam
}
@@ -153,10 +151,6 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
}
}
fn push(&mut self, val: HeapCellValue) {
self.wam.machine_st.heap.push(val);
}
fn push_attr_var_queue(&mut self, attr_var_loc: usize) {
self.wam
.machine_st
@@ -170,43 +164,66 @@ impl<'a> CopierTarget for TermCopyingMockWAM<'a> {
}
fn threshold(&self) -> usize {
self.wam.machine_st.heap.len()
self.wam.machine_st.heap.cell_len()
}
#[inline(always)]
fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result<usize, usize> {
self.wam.machine_st.heap.copy_pstr_within(pstr_loc)
}
#[inline(always)]
fn as_slice_from<'b>(&'b self, from: usize) -> Box<dyn Iterator<Item = u8> + 'b> {
Box::new(self.wam.machine_st.heap.as_slice()[from..].iter().cloned())
}
#[inline(always)]
fn reserve(&mut self, num_cells: usize) -> Result<HeapWriter, usize> {
self.wam.machine_st.heap.reserve(num_cells)
}
#[inline(always)]
fn copy_slice_to_end(&mut self, bounds: Range<usize>) -> Result<(), usize> {
self.wam.machine_st.heap.copy_slice_to_end(bounds)
}
}
#[cfg(test)]
pub fn all_cells_marked_and_unforwarded(heap: &[HeapCellValue]) {
for (idx, cell) in heap.iter().enumerate() {
pub fn all_cells_marked_and_unforwarded(heap: &Heap, offset: usize) {
for curr_idx in offset..heap.cell_len() {
let cell = heap[curr_idx];
assert!(
cell.get_mark_bit(),
"cell {:?} at index {} is not marked",
cell,
idx
"cell {cell:?} at index {curr_idx} is not marked"
);
assert!(
!cell.get_forwarding_bit(),
"cell {:?} at index {} is forwarded",
cell,
idx
"cell {cell:?} at index {curr_idx} is forwarded"
);
}
}
#[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
);
pub fn unmark_all_cells(heap: &mut Heap, offset: usize) {
for idx in offset..heap.cell_len() {
heap[idx].set_mark_bit(false);
}
}
#[cfg(test)]
pub fn all_cells_unmarked(iter: &impl SizedHeap) {
let mut idx = 0;
let cell_len = iter.cell_len();
while idx < cell_len {
let curr_idx = idx;
idx += 1;
let cell = iter[curr_idx];
assert!(
!cell.get_forwarding_bit(),
"cell {:?} at index {} is still forwarded",
cell,
idx
!cell.get_mark_bit(),
"cell {cell:?} at index {curr_idx} is still marked"
);
}
}
@@ -232,6 +249,7 @@ pub(crate) fn parse_and_write_parsed_term_to_heap(
impl Machine {
/// For use in tests.
#[allow(clippy::unbuffered_bytes)]
pub fn test_load_file(&mut self, file: &str) -> Vec<u8> {
let stream = Stream::from_owned_string(
std::fs::read_to_string(AsRef::<std::path::Path>::as_ref(file)).unwrap(),
@@ -243,6 +261,7 @@ impl Machine {
}
/// For use in tests.
#[allow(clippy::unbuffered_bytes)]
pub fn test_load_string(&mut self, code: &str) -> Vec<u8> {
let stream = Stream::from_owned_string(code.to_owned(), &mut self.machine_st.arena);
@@ -255,6 +274,8 @@ impl Machine {
mod tests {
use super::*;
use crate::functor_macro::FunctorElement;
#[test]
fn unify_tests() {
let mut wam = MachineState::new();
@@ -387,36 +408,66 @@ mod tests {
wam.heap.clear();
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
wam.heap.push(heap_loc_as_cell!(1));
let mut writer = wam.heap.reserve(96).unwrap();
wam.heap.push(pstr_as_cell!(atom!("this is a string")));
wam.heap.push(pstr_loc_as_cell!(4));
writer.write_with(|section| {
section.push_pstr("this is a string"); // 0
wam.heap.push(pstr_offset_as_cell!(0));
wam.heap.push(fixnum_as_cell!(Fixnum::build_with(6)));
let h = section.cell_len();
assert_eq!(h, 3);
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2));
section.push_cell(heap_loc_as_cell!(h)); // 3
section.push_pstr("this is a string"); // 4
let h = section.cell_len();
assert_eq!(h + 1, 8);
section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1))); // 7
section.push_pstr("this is a string"); // 8
section.push_cell(pstr_loc_as_cell!(heap_index!(h + 1)));
});
unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(heap_index!(4)));
assert!(!wam.fail);
assert_eq!(wam.heap[1], pstr_loc_as_cell!(4));
all_cells_unmarked(&wam.heap);
assert_eq!(
wam.heap
.slice_to_str(heap_index!(0), "this is a string".len()),
"this is a string"
);
assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8)));
assert_eq!(
wam.heap
.slice_to_str(heap_index!(4), "this is a string".len()),
"this is a string"
);
assert_eq!(wam.heap[7], pstr_loc_as_cell!(heap_index!(8)));
assert_eq!(
wam.heap
.slice_to_str(heap_index!(8), "this is a string".len()),
"this is a string"
);
assert_eq!(wam.heap[11], pstr_loc_as_cell!(heap_index!(8)));
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));
let mut writer = wam.heap.reserve(96).unwrap();
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));
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
section.push_cell(atom_as_cell!(atom!("a")));
section.push_cell(list_loc_as_cell!(3));
section.push_cell(atom_as_cell!(atom!("b")));
section.push_cell(heap_loc_as_cell!(0));
section.push_cell(list_loc_as_cell!(6));
section.push_cell(atom_as_cell!(atom!("a")));
section.push_cell(list_loc_as_cell!(8));
section.push_cell(atom_as_cell!(atom!("b")));
section.push_cell(heap_loc_as_cell!(5));
});
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
@@ -426,17 +477,21 @@ mod tests {
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));
let mut writer = wam.heap.reserve(96).unwrap();
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));
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
section.push_cell(atom_as_cell!(atom!("a")));
section.push_cell(list_loc_as_cell!(3));
section.push_cell(atom_as_cell!(atom!("b")));
section.push_cell(heap_loc_as_cell!(0));
section.push_cell(list_loc_as_cell!(6));
section.push_cell(atom_as_cell!(atom!("a")));
section.push_cell(list_loc_as_cell!(8));
section.push_cell(atom_as_cell!(atom!("c")));
section.push_cell(heap_loc_as_cell!(5));
});
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
@@ -444,19 +499,24 @@ mod tests {
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));
let mut writer = wam.heap.reserve(96).unwrap();
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));
writer.write_with(|section| {
section.push_cell(list_loc_as_cell!(1));
section.push_cell(atom_as_cell!(atom!("a")));
section.push_cell(list_loc_as_cell!(3));
section.push_cell(atom_as_cell!(atom!("b")));
section.push_cell(heap_loc_as_cell!(5));
section.push_cell(list_loc_as_cell!(6));
section.push_cell(atom_as_cell!(atom!("a")));
section.push_cell(list_loc_as_cell!(8));
section.push_cell(atom_as_cell!(atom!("b")));
section.push_cell(heap_loc_as_cell!(0));
});
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
@@ -468,7 +528,7 @@ mod tests {
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);
print_heap_terms(&wam.heap, term_write_result_1.heap_loc);
unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
@@ -510,8 +570,15 @@ mod tests {
let mut wam = MachineState::new();
wam.heap.push(heap_loc_as_cell!(0));
wam.heap.push(heap_loc_as_cell!(1));
// clear the heap of resource error data etc
wam.heap.clear();
let mut writer = wam.heap.reserve(96).unwrap();
writer.write_with(|section| {
section.push_cell(heap_loc_as_cell!(0));
section.push_cell(heap_loc_as_cell!(1));
});
assert_eq!(
compare_term_test!(wam, wam.heap[0], wam.heap[1]),
@@ -533,12 +600,10 @@ mod tests {
Some(Ordering::Equal)
);
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!(
compare_term_test!(
wam,
atom_as_cell!(atom!("atom")),
atom_as_cstr_cell!(atom!("string"))
),
compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
Some(Ordering::Less)
);
@@ -571,8 +636,12 @@ mod tests {
wam.heap.clear();
wam.heap.push(atom_as_cell!(atom!("f"), 1));
wam.heap.push(heap_loc_as_cell!(1));
let mut writer = wam.heap.reserve(96).unwrap();
writer.write_with(|section| {
section.push_cell(atom_as_cell!(atom!("f"), 1));
section.push_cell(heap_loc_as_cell!(1));
});
assert_eq!(
compare_term_test!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(0)),
@@ -586,21 +655,25 @@ mod tests {
wam.heap.clear();
let mut writer = wam.heap.reserve(96).unwrap();
writer.write_with(|section| {
// [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!());
section.push_cell(list_loc_as_cell!(1));
section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
section.push_cell(list_loc_as_cell!(3));
section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
section.push_cell(list_loc_as_cell!(5));
section.push_cell(fixnum_as_cell!(Fixnum::build_with(3)));
section.push_cell(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!());
section.push_cell(list_loc_as_cell!(8));
section.push_cell(fixnum_as_cell!(Fixnum::build_with(1)));
section.push_cell(list_loc_as_cell!(10));
section.push_cell(fixnum_as_cell!(Fixnum::build_with(2)));
section.push_cell(empty_list_as_cell!());
});
assert_eq!(
compare_term_test!(wam, heap_loc_as_cell!(7), heap_loc_as_cell!(7)),
@@ -626,12 +699,10 @@ mod tests {
Some(Ordering::Greater)
);
let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!(
compare_term_test!(
wam,
empty_list_as_cell!(),
atom_as_cstr_cell!(atom!("string"))
),
compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
Some(Ordering::Less)
);
@@ -662,55 +733,63 @@ mod tests {
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))));
let mut writer = wam.heap.reserve(96).unwrap();
wam.heap.push(heap_loc_as_cell!(0));
writer.write_with(|section| {
section.push_cell(atom_as_cell!(atom!("f")));
section.push_cell(fixnum_as_cell!(Fixnum::build_with(555)));
section.push_cell(heap_loc_as_cell!(0));
});
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(0)));
assert!(!wam.is_cyclic_term(0));
assert!(!wam.is_cyclic_term(1));
assert!(!wam.is_cyclic_term(2));
all_cells_unmarked(&wam.heap);
wam.heap.clear();
wam.heap
.extend(functor!(atom!("f"), [atom(atom!("a")), atom(atom!("b"))]));
let mut functor_writer = Heap::functor_writer(functor!(
atom!("f"),
[atom_as_cell((atom!("a"))), atom_as_cell((atom!("b")))]
));
assert!(!wam.is_cyclic_term(str_loc_as_cell!(0)));
functor_writer(&mut wam.heap).unwrap();
let h = wam.heap.cell_len();
wam.heap.push_cell(str_loc_as_cell!(0)).unwrap();
assert!(!wam.is_cyclic_term(h));
all_cells_unmarked(&wam.heap);
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1)));
assert!(!wam.is_cyclic_term(1));
all_cells_unmarked(&wam.heap);
assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2)));
assert!(!wam.is_cyclic_term(2));
all_cells_unmarked(&wam.heap);
wam.heap[2] = str_loc_as_cell!(0);
print_heap_terms(wam.heap.iter(), 0);
print_heap_terms(&wam.heap, 0);
assert!(wam.is_cyclic_term(str_loc_as_cell!(0)));
assert!(wam.is_cyclic_term(2));
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)));
assert!(wam.is_cyclic_term(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!());
let h = wam.heap.cell_len();
wam.heap.allocate_cstr("a string").unwrap();
assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0)));
assert!(!wam.is_cyclic_term(h));
}
}
+86 -76
View File
@@ -45,6 +45,7 @@ use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::offset_table::*;
use crate::parser::ast::*;
use crate::parser::dashu::{Integer, Rational};
use crate::types::*;
@@ -207,13 +208,8 @@ pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
#[inline]
pub(crate) fn get_structure_index(value: HeapCellValue) -> Option<CodeIndex> {
read_heap_cell!(value,
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::IndexPtr, ip) => {
return Some(CodeIndex::from(ip));
}
_ => {}
);
(HeapCellValueTag::CodeIndexOffset, offset) => {
return Some(CodeIndex::from(offset));
}
_ => {
}
@@ -246,7 +242,7 @@ impl Machine {
}
/// Runs the predicate `key` in `module_name` until completion.
/// Siltently ignores failure, thrown errors and choice points.
/// Silently ignores failure, thrown errors and choice points.
///
/// Consider using [`Machine::run_query`] if you wish to handle
/// predicates that may fail, leave a choice point or throw.
@@ -256,8 +252,14 @@ impl Machine {
key: PredicateKey,
) -> std::process::ExitCode {
if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(code_index) = module.code_dir.get(&key) {
let p = code_index.local().unwrap();
if let Some(code_idx) = module.code_dir.get(&key) {
let index_ptr = self
.machine_st
.arena
.code_index_tbl
.get_entry(code_idx.into());
let p = index_ptr.local().unwrap();
// Leave a halting choice point to backtrack to in case the predicate fails or throws.
self.allocate_stub_choice_point();
@@ -328,8 +330,13 @@ impl Machine {
self.load_file(path_buf.to_str().unwrap(), stream);
if let Some(module) = self.indices.modules.get(&atom!("$atts")) {
if let Some(code_index) = module.code_dir.get(&(atom!("driver"), 2)) {
self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap();
if let Some(code_idx) = module.code_dir.get(&(atom!("driver"), 2)) {
let index_ptr = self
.machine_st
.arena
.code_index_tbl
.get_entry(code_idx.into());
self.machine_st.attr_var_init.verify_attrs_loc = index_ptr.local().unwrap();
}
}
}
@@ -343,13 +350,16 @@ impl Machine {
for arity in 1..66 {
let key = (atom!("call"), arity);
match loader.code_dir.get(&key) {
match loader.code_dir.get(&key).cloned() {
Some(src_code_index) => {
let target_code_index = target_code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::undefined(), arena));
let code_index_tbl = &mut arena.code_index_tbl;
target_code_index.set(src_code_index.get());
let target_code_index = target_code_dir.entry(key).or_insert_with(|| {
CodeIndex::new(IndexPtr::undefined(), code_index_tbl)
});
let src_code_ptr = code_index_tbl.get_entry(src_code_index.into());
target_code_index.set(code_index_tbl, src_code_ptr);
}
None => {
unreachable!();
@@ -458,7 +468,7 @@ impl Machine {
key,
CodeIndex::new(
IndexPtr::index(p + impls_offset),
&mut self.machine_st.arena,
&mut self.machine_st.arena.code_index_tbl,
),
);
}
@@ -485,7 +495,10 @@ impl Machine {
#[inline(always)]
pub(crate) fn run_verify_attr_interrupt(&mut self, arity: usize) {
let p = self.machine_st.attr_var_init.verify_attrs_loc;
self.machine_st.verify_attr_interrupt(p, arity);
step_or_resource_error!(
self.machine_st,
self.machine_st.verify_attr_interrupt(p, arity)
);
}
fn next_clause_applicable(&mut self, mut offset: usize) -> bool {
@@ -509,8 +522,8 @@ impl Machine {
.select_switch_on_term_index(cell, v, c, l, s)
}
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
let lit = self.machine_st.constant_to_literal(cell);
hm.get(&lit).cloned().unwrap_or(IndexingCodePtr::Fail)
// let lit = self.machine_st.constant_to_literal(cell);
hm.get(&cell).cloned().unwrap_or(IndexingCodePtr::Fail)
}
IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
self.machine_st.select_switch_on_structure_index(cell, hm)
@@ -536,34 +549,8 @@ impl Machine {
if cell.is_var() {
offset += 1;
} else if lit.get_tag() == HeapCellValueTag::CStr {
read_heap_cell!(cell,
(HeapCellValueTag::CStr) => {
if cell == lit {
offset += 1;
} else {
return false;
}
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
offset += 1;
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
offset += 1;
} else {
return false;
}
}
_ => {
return false;
}
);
} else {
self.machine_st.write_literal_to_var(cell, lit);
unify!(self.machine_st, cell, lit);
if self.machine_st.fail {
self.machine_st.fail = false;
@@ -577,7 +564,7 @@ impl Machine {
let cell = self.deref_register(t);
read_heap_cell!(cell,
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {// | HeapCellValueTag::CStr) => {
offset += 1;
}
(HeapCellValueTag::Str, s) => {
@@ -616,27 +603,24 @@ impl Machine {
}
);
}
&Instruction::GetPartialString(
Level::Shallow,
string,
RegType::Temp(t),
has_tail,
) => {
&Instruction::GetPartialString(Level::Shallow, ref string, RegType::Temp(t)) => {
let cell = self.deref_register(t);
read_heap_cell!(cell,
(HeapCellValueTag::CStr, cstr) => {
if !has_tail && string != cstr {
return false;
}
(HeapCellValueTag::PStrLoc, pstr_loc) => {
let heap_slice = &self.machine_st.heap.as_slice()[pstr_loc ..];
offset += 1;
match compare_pstr_slices(heap_slice, string.as_bytes()) {
PStrSegmentCmpResult::Continue(..) => offset += 1,
_ => return false,
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
}
(HeapCellValueTag::Lis) => {
offset += 1;
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity();
let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
offset += 1;
@@ -759,7 +743,7 @@ impl Machine {
or_frame.prelude.boip = 0;
or_frame.prelude.biip = 0;
or_frame.prelude.tr = self.machine_st.tr;
or_frame.prelude.h = self.machine_st.heap.len();
or_frame.prelude.h = self.machine_st.heap.cell_len();
or_frame.prelude.b0 = self.machine_st.b0;
or_frame.prelude.attr_var_queue_len =
self.machine_st.attr_var_init.attr_var_queue.len();
@@ -770,7 +754,7 @@ impl Machine {
or_frame[i] = self.machine_st.registers[i + 1];
}
self.machine_st.hb = self.machine_st.heap.len();
self.machine_st.hb = self.machine_st.heap.cell_len();
}
self.machine_st.p += 1;
@@ -791,7 +775,7 @@ impl Machine {
or_frame.prelude.boip = self.machine_st.oip;
or_frame.prelude.biip = self.machine_st.iip + iip_offset; // 1
or_frame.prelude.tr = self.machine_st.tr;
or_frame.prelude.h = self.machine_st.heap.len();
or_frame.prelude.h = self.machine_st.heap.cell_len();
or_frame.prelude.b0 = self.machine_st.b0;
or_frame.prelude.attr_var_queue_len =
self.machine_st.attr_var_init.attr_var_queue.len();
@@ -802,7 +786,7 @@ impl Machine {
or_frame[i] = self.machine_st.registers[i + 1];
}
self.machine_st.hb = self.machine_st.heap.len();
self.machine_st.hb = self.machine_st.heap.cell_len();
// self.machine_st.oip = 0;
// self.machine_st.iip = 0;
@@ -1069,13 +1053,15 @@ impl Machine {
if module_name == atom!("user") {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
self.try_call(name, arity, idx.get())
let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
self.try_call(name, arity, index_ptr)
} else {
Err(self.machine_st.throw_undefined_error(name, arity))
}
} else if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
self.try_call(name, arity, idx.get())
let index_ptr = self.machine_st.arena.code_index_tbl.get_entry(idx.into());
self.try_call(name, arity, index_ptr)
} else {
self.undefined_procedure(name, arity)
}
@@ -1098,14 +1084,24 @@ impl Machine {
let (name, arity) = key;
if module_name == atom!("user") {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
self.try_execute(name, arity, idx.get())
if let Some(offset) = self.indices.code_dir.get(&(name, arity)).cloned() {
let index_ptr = self
.machine_st
.arena
.code_index_tbl
.get_entry(offset.into());
self.try_execute(name, arity, index_ptr)
} else {
self.undefined_procedure(name, arity)
}
} else if let Some(module) = self.indices.modules.get(&module_name) {
if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
self.try_execute(name, arity, idx.get())
if let Some(offset) = module.code_dir.get(&(name, arity)).cloned() {
let index_ptr = self
.machine_st
.arena
.code_index_tbl
.get_entry(offset.into());
self.try_execute(name, arity, index_ptr)
} else {
self.undefined_procedure(name, arity)
}
@@ -1147,12 +1143,24 @@ impl Machine {
let r_c_w_h = self
.indices
.get_predicate_code_index(r_c_w_h_atom, 0, iso_ext)
.and_then(|item| item.local())
.and_then(|code_idx| {
self.machine_st
.arena
.code_index_tbl
.get_entry(code_idx.into())
.local()
})
.unwrap();
let r_c_wo_h = self
.indices
.get_predicate_code_index(r_c_wo_h_atom, 1, iso_ext)
.and_then(|item| item.local())
.and_then(|code_idx| {
self.machine_st
.arena
.code_index_tbl
.get_entry(code_idx.into())
.local()
})
.unwrap();
(r_c_w_h, r_c_wo_h)
});
@@ -1162,8 +1170,10 @@ impl Machine {
let (idx, arity) = if self.machine_st.effective_block() > prev_block {
(r_c_w_h, 0)
} else {
self.machine_st.registers[1] =
fixnum_as_cell!(Fixnum::build_with(b_cutoff as i64));
self.machine_st.registers[1] = fixnum_as_cell!(
/* FIXME this is not safe */
unsafe { Fixnum::build_with_unchecked(b_cutoff as i64) }
);
(r_c_wo_h, 1)
};
File diff suppressed because it is too large Load Diff
+27 -41
View File
@@ -21,11 +21,10 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result<OpDeclSpec, CompilationError
})
}
fn setup_op_decl(mut terms: Vec<Term>, atom_tbl: &AtomTable) -> Result<OpDecl, CompilationError> {
fn setup_op_decl(mut terms: Vec<Term>) -> Result<OpDecl, CompilationError> {
// should allow non-partial lists?
let name = match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => name,
Term::Literal(_, Literal::Char(c)) => AtomTable::build_with(atom_tbl, &c.to_string()),
other => {
return Err(CompilationError::InvalidDirective(
DirectiveError::InvalidOpDeclNameType(other),
@@ -112,16 +111,13 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, Compilatio
}
}
fn setup_module_export(
mut term: Term,
atom_tbl: &AtomTable,
) -> Result<ModuleExport, CompilationError> {
fn setup_module_export(mut term: Term) -> 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 == atom!("op") {
Ok(ModuleExport::OpDecl(setup_op_decl(terms, atom_tbl)?))
Ok(ModuleExport::OpDecl(setup_op_decl(terms)?))
} else {
Err(CompilationError::InvalidModuleDecl)
}
@@ -140,12 +136,11 @@ pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
pub(super) fn setup_module_export_list(
mut export_list: Term,
atom_tbl: &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)?;
let module_export = setup_module_export(*t1)?;
exports.push(module_export);
export_list = *t2;
@@ -158,10 +153,7 @@ pub(super) fn setup_module_export_list(
}
}
fn setup_module_decl(
mut terms: Vec<Term>,
atom_tbl: &AtomTable,
) -> Result<ModuleDecl, CompilationError> {
fn setup_module_decl(mut terms: Vec<Term>) -> Result<ModuleDecl, CompilationError> {
let export_list = terms.pop().unwrap();
let name = terms.pop().unwrap();
@@ -171,8 +163,7 @@ fn setup_module_decl(
}
.ok_or(CompilationError::InvalidModuleDecl)?;
let exports = setup_module_export_list(export_list, atom_tbl)?;
let exports = setup_module_export_list(export_list)?;
Ok(ModuleDecl { name, exports })
}
@@ -191,10 +182,7 @@ fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, Compilati
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import(
mut terms: Vec<Term>,
atom_tbl: &AtomTable,
) -> Result<UseModuleExport, CompilationError> {
fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, CompilationError> {
let mut export_list = terms.pop().unwrap();
let module_src = match terms.pop().unwrap() {
Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
@@ -210,7 +198,7 @@ fn setup_qualified_import(
let mut exports = IndexSet::new();
while let Term::Cons(_, t1, t2) = export_list {
exports.insert(setup_module_export(*t1, atom_tbl)?);
exports.insert(setup_module_export(*t1)?);
export_list = *t2;
}
@@ -252,7 +240,7 @@ fn setup_qualified_import(
* contained in src/lib/ops_and_meta_predicates.pl, which is loaded before
* src/lib/builtins.pl.
*
* Meta-specs have three forms:
* Meta-specs have four forms:
*
* (:) (the argument should be expanded with (:)/2 as described above)
* + (mode declarations under the mode syntax, which currently have no effect)
@@ -340,23 +328,15 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity))
}
(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!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)),
(atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)),
(atom!("non_counted_backtracking"), 1) => {
let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity))
}
(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)?;
let (name, exports) = setup_qualified_import(terms)?;
Ok(Declaration::UseQualifiedModule(name, exports))
}
(atom!("meta_predicate"), 1) => {
@@ -444,7 +424,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
let term = match term {
Term::Clause(cell, name, mut terms) => {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() {
arg_terms
.push(process_term(module_name, Term::Clause(cell, name, terms)));
@@ -453,7 +433,10 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
let idx = loader.get_or_insert_qualified_code_index(module_name, key);
terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
terms.push(Term::Literal(
Cell::default(),
Literal::CodeIndexOffset(idx.into()),
));
process_term(module_name, Term::Clause(cell, name, terms))
}
Term::Literal(cell, Literal::Atom(name)) => {
@@ -464,7 +447,10 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
Term::Clause(
cell,
name,
vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
vec![Term::Literal(
Cell::default(),
Literal::CodeIndexOffset(idx.into()),
)],
),
)
}
@@ -489,7 +475,7 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>,
call_policy: CallPolicy,
) -> QueryTerm {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() {
// supplementary code vector indices are unnecessary for
// root-level clauses.
terms.pop();
@@ -524,7 +510,7 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
mut terms: Vec<Term>,
call_policy: CallPolicy,
) -> QueryTerm {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = terms.last() {
// supplementary code vector indices are unnecessary for
// root-level clauses.
terms.pop();
@@ -605,7 +591,7 @@ impl Preprocessor {
&mut self,
loader: &mut Loader<'a, LS>,
term: Term,
) -> Result<TopLevel, CompilationError> {
) -> Result<PredicateClause, CompilationError> {
match term {
Term::Clause(r, name, mut terms) => {
let is_rule = name == atom!(":-") && terms.len() == 2;
@@ -615,16 +601,16 @@ impl Preprocessor {
let head = terms.pop().unwrap();
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
Ok(TopLevel::Rule(rule, var_data))
Ok(PredicateClause::Rule(rule, var_data))
} else {
let term = Term::Clause(r, name, terms);
let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
Ok(PredicateClause::Fact(fact, var_data))
}
}
term => {
let (fact, var_data) = self.setup_fact(term)?;
Ok(TopLevel::Fact(fact, var_data))
Ok(PredicateClause::Fact(fact, var_data))
}
}
}
+41 -44
View File
@@ -59,9 +59,10 @@ impl Index<usize> for AndFrame {
unsafe {
let ptr = self as *const crate::machine::stack::AndFrame as *const u8;
let ptr = ptr as usize + prelude_offset + index_offset;
&*(ptr as *const HeapCellValue)
// This address falls outside the provenance for self, therefore we have to get it
// from exposed provenance.
&*std::ptr::with_exposed_provenance(ptr.addr() + prelude_offset + index_offset)
}
}
}
@@ -72,10 +73,11 @@ impl IndexMut<usize> for AndFrame {
let index_offset = (index - 1) * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = self as *mut crate::machine::stack::AndFrame as *const u8;
let ptr = ptr as usize + prelude_offset + index_offset;
let ptr = self as *mut crate::machine::stack::AndFrame as *mut u8;
&mut *(ptr as *mut HeapCellValue)
// This address falls outside the provenance for self, therefore we have to get it
// from exposed provenance.
&mut *std::ptr::with_exposed_provenance_mut(ptr.addr() + prelude_offset + index_offset)
}
}
}
@@ -85,20 +87,14 @@ impl Index<usize> for Stack {
#[inline]
fn index(&self, index: usize) -> &Self::Output {
unsafe {
let ptr = self.buf.base as usize + index;
&*(ptr as *const HeapCellValue)
}
unsafe { &*self.buf.base.add(index).cast() }
}
}
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)
}
unsafe { &mut *self.buf.base.add(index).cast_mut().cast() }
}
}
@@ -132,9 +128,10 @@ impl Index<usize> for OrFrame {
unsafe {
let ptr = self as *const crate::machine::stack::OrFrame as *const u8;
let ptr = ptr as usize + prelude_offset + index_offset;
&*(ptr as *const HeapCellValue)
// This address falls outside the provenance for self, therefore we have to get it
// from exposed provenance.
&*std::ptr::with_exposed_provenance(ptr.addr() + prelude_offset + index_offset)
}
}
}
@@ -146,10 +143,11 @@ impl IndexMut<usize> for OrFrame {
let index_offset = index * mem::size_of::<HeapCellValue>();
unsafe {
let ptr = self as *mut crate::machine::stack::OrFrame as *const u8;
let ptr = ptr as usize + prelude_offset + index_offset;
let ptr = self as *mut crate::machine::stack::OrFrame as *mut u8;
&mut *(ptr as *mut HeapCellValue)
// This address falls outside the provenance for self, therefore we have to get it
// from exposed provenance.
&mut *std::ptr::with_exposed_provenance_mut(ptr.addr() + prelude_offset + index_offset)
}
}
}
@@ -187,15 +185,19 @@ impl Stack {
let frame_size = AndFrame::size_of(num_cells);
unsafe {
let e = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
let e = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr();
let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<AndFramePrelude>();
for idx in 0..num_cells {
ptr::write(
new_ptr.add(offset) as *mut HeapCellValue,
stack_loc_as_cell!(AndFrame, e, idx + 1),
);
let cell_ptr = new_ptr.add(offset) as *mut HeapCellValue;
ptr::write(cell_ptr, stack_loc_as_cell!(AndFrame, e, idx + 1));
// Because in the Index and IndexMut inplementations we need to get this from
// exposed provenance, we need to expose the provenance here, even though we don't
// actually use the value for anything. This is a reminder that `expose_provenance`
// isn't just a cast from a pointer to an integer but has actual side effects.
cell_ptr.expose_provenance();
offset += mem::size_of::<HeapCellValue>();
}
@@ -208,22 +210,26 @@ impl Stack {
}
pub(crate) fn top(&self) -> usize {
unsafe { (*self.buf.ptr.get()) as usize - self.buf.base as usize }
unsafe { (*self.buf.ptr.get()).addr() - self.buf.base.addr() }
}
pub(crate) fn allocate_or_frame(&mut self, num_cells: usize) -> usize {
let frame_size = OrFrame::size_of(num_cells);
unsafe {
let b = (*self.buf.ptr.get_mut()) as usize - self.buf.base as usize;
let b = (*self.buf.ptr.get_mut()).addr() - self.buf.base.addr();
let new_ptr = self.alloc(frame_size);
let mut offset = prelude_size::<OrFramePrelude>();
for idx in 0..num_cells {
ptr::write(
(new_ptr as usize + offset) as *mut HeapCellValue,
stack_loc_as_cell!(OrFrame, b, idx),
);
let cell_ptr = new_ptr.byte_add(offset) as *mut HeapCellValue;
ptr::write(cell_ptr, stack_loc_as_cell!(OrFrame, b, idx));
// Because in the Index and IndexMut inplementations we need to get this from
// exposed provenance, we need to expose the provenance here, even though we don't
// actually use the value for anything. This is a reminder that `expose_provenance`
// isn't just a cast from a pointer to an integer but has actual side effects.
cell_ptr.expose_provenance();
offset += mem::size_of::<HeapCellValue>();
}
@@ -237,10 +243,7 @@ impl Stack {
#[inline(always)]
pub(crate) fn index_and_frame(&self, e: usize) -> &AndFrame {
unsafe {
let ptr = self.buf.base as usize + e;
&*(ptr as *const AndFrame)
}
unsafe { &*self.buf.base.add(e).cast() }
}
#[inline(always)]
@@ -254,26 +257,20 @@ impl Stack {
#[inline(always)]
pub(crate) fn index_or_frame(&self, b: usize) -> &OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
&*(ptr as *const OrFrame)
}
unsafe { &*self.buf.base.add(b).cast() }
}
#[inline(always)]
pub(crate) fn index_or_frame_mut(&mut self, b: usize) -> &mut OrFrame {
unsafe {
let ptr = self.buf.base as usize + b;
&mut *(ptr as *mut OrFrame)
}
unsafe { &mut *self.buf.base.add(b).cast_mut().cast() }
}
#[inline(always)]
pub(crate) fn truncate(&mut self, b: usize) {
let base = self.buf.base as usize + b;
let base = unsafe { self.buf.base.add(b) };
if base < (*self.buf.ptr.get_mut()) as usize {
*self.buf.ptr.get_mut() = base as *mut _;
if base < (*self.buf.ptr.get_mut()) {
*self.buf.ptr.get_mut() = base.cast_mut();
}
}
}
+89 -20
View File
@@ -1,12 +1,12 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::functor_macro::*;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::read::*;
#[cfg(feature = "http")]
use crate::http::HttpResponse;
use crate::machine::heap::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
@@ -23,6 +23,8 @@ use std::fmt::Debug;
use std::fs::{File, OpenOptions};
use std::hash::Hash;
use std::io;
use std::io::PipeReader;
use std::io::PipeWriter;
use std::io::{Cursor, ErrorKind, Read, Seek, SeekFrom, Write};
use std::mem::ManuallyDrop;
use std::net::{Shutdown, TcpStream};
@@ -476,7 +478,7 @@ impl StreamOptions {
#[inline]
pub fn get_alias(self) -> Option<Atom> {
if self.has_alias() {
Some(Atom::from(self.alias() << 3))
Some(Atom::from(self.alias()))
} else {
None
}
@@ -487,7 +489,7 @@ impl StreamOptions {
self.set_has_alias(alias.is_some());
if let Some(alias) = alias {
self.set_alias(alias.flat_index());
self.set_alias(alias.index);
}
}
}
@@ -588,6 +590,8 @@ arena_allocated_impl_for_stream!(StandardOutputStream, StandardOutputStream);
arena_allocated_impl_for_stream!(StandardErrorStream, StandardErrorStream);
arena_allocated_impl_for_stream!(CharReader<CallbackStream>, CallbackStream);
arena_allocated_impl_for_stream!(CharReader<InputChannelStream>, InputChannelStream);
arena_allocated_impl_for_stream!(CharReader<PipeReader>, PipeReader);
arena_allocated_impl_for_stream!(CharReader<PipeWriter>, PipeWriter);
#[derive(Debug, Copy, Clone)]
pub enum Stream {
@@ -608,6 +612,8 @@ pub enum Stream {
StandardError(TypedArenaPtr<StandardErrorStream>),
Callback(TypedArenaPtr<CallbackStream>),
InputChannel(TypedArenaPtr<InputChannelStream>),
PipeReader(TypedArenaPtr<PipeReader>),
PipeWriter(TypedArenaPtr<PipeWriter>),
}
impl From<TypedArenaPtr<ReadlineStream>> for Stream {
@@ -688,6 +694,8 @@ impl Stream {
ArenaHeaderTag::InputChannelStream => {
Stream::InputChannel(unsafe { ptr.as_typed_ptr() })
}
ArenaHeaderTag::PipeReader => Stream::PipeReader(unsafe { ptr.as_typed_ptr() }),
ArenaHeaderTag::PipeWriter => Stream::PipeWriter(unsafe { ptr.as_typed_ptr() }),
_ => unreachable!(),
}
}
@@ -726,6 +734,8 @@ impl Stream {
Stream::StandardError(ptr) => ptr.header_ptr(),
Stream::Callback(ptr) => ptr.header_ptr(),
Stream::InputChannel(ptr) => ptr.header_ptr(),
Stream::PipeReader(ptr) => ptr.header_ptr(),
Stream::PipeWriter(ptr) => ptr.header_ptr(),
}
}
@@ -748,6 +758,8 @@ impl Stream {
Stream::StandardError(ref ptr) => &ptr.options,
Stream::Callback(ref ptr) => &ptr.options,
Stream::InputChannel(ref ptr) => &ptr.options,
Stream::PipeReader(ref ptr) => &ptr.options,
Stream::PipeWriter(ref ptr) => &ptr.options,
}
}
@@ -770,6 +782,8 @@ impl Stream {
Stream::StandardError(ref mut ptr) => &mut ptr.options,
Stream::Callback(ref mut ptr) => &mut ptr.options,
Stream::InputChannel(ref mut ptr) => &mut ptr.options,
Stream::PipeReader(ref mut ptr) => &mut ptr.options,
Stream::PipeWriter(ref mut ptr) => &mut ptr.options,
}
}
@@ -793,6 +807,8 @@ impl Stream {
Stream::StandardError(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::Callback(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::InputChannel(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::PipeReader(ptr) => ptr.lines_read += incr_num_lines_read,
Stream::PipeWriter(_) => {}
}
}
@@ -816,6 +832,8 @@ impl Stream {
Stream::StandardError(ptr) => ptr.lines_read = value,
Stream::Callback(ptr) => ptr.lines_read = value,
Stream::InputChannel(ptr) => ptr.lines_read = value,
Stream::PipeReader(ptr) => ptr.lines_read = value,
Stream::PipeWriter(_) => {}
}
}
@@ -839,6 +857,8 @@ impl Stream {
Stream::StandardError(ptr) => ptr.lines_read,
Stream::Callback(ptr) => ptr.lines_read,
Stream::InputChannel(ptr) => ptr.lines_read,
Stream::PipeReader(ptr) => ptr.lines_read,
Stream::PipeWriter(_) => 0,
}
}
}
@@ -856,6 +876,8 @@ impl CharRead for Stream {
Stream::StaticString(src) => (*src).peek_char(),
Stream::Byte(cursor) => (*cursor).peek_char(),
Stream::InputChannel(cursor) => (*cursor).peek_char(),
Stream::PipeReader(cursor) => (*cursor).peek_char(),
#[cfg(feature = "http")]
Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied,
@@ -865,7 +887,8 @@ impl CharRead for Stream {
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::Null(_)
| Stream::Callback(_) => Some(Err(std::io::Error::new(
| Stream::Callback(_)
| Stream::PipeWriter(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
))),
@@ -884,6 +907,7 @@ impl CharRead for Stream {
Stream::StaticString(src) => (*src).read_char(),
Stream::Byte(cursor) => (*cursor).read_char(),
Stream::InputChannel(cursor) => (*cursor).read_char(),
Stream::PipeReader(cursor) => (*cursor).read_char(),
#[cfg(feature = "http")]
Stream::HttpWrite(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied,
@@ -893,7 +917,8 @@ impl CharRead for Stream {
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::Null(_)
| Stream::Callback(_) => Some(Err(std::io::Error::new(
| Stream::Callback(_)
| Stream::PipeWriter(_) => Some(Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
))),
@@ -911,13 +936,15 @@ impl CharRead for Stream {
Stream::Readline(rl_stream) => rl_stream.put_back_char(c),
Stream::StaticString(src) => src.put_back_char(c),
Stream::Byte(cursor) => cursor.put_back_char(c),
Stream::PipeReader(cursor) => cursor.put_back_char(c),
#[cfg(feature = "http")]
Stream::HttpWrite(_) => {}
Stream::OutputFile(_)
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::Null(_)
| Stream::Callback(_) => {}
| Stream::Callback(_)
| Stream::PipeWriter(_) => {}
Stream::InputChannel(_) => {}
}
}
@@ -934,13 +961,15 @@ impl CharRead for Stream {
Stream::StaticString(ref mut src) => src.consume(nread),
Stream::Byte(ref mut cursor) => cursor.consume(nread),
Stream::InputChannel(ref mut cursor) => cursor.consume(nread),
Stream::PipeReader(ref mut cursor) => cursor.consume(nread),
#[cfg(feature = "http")]
Stream::HttpWrite(_) => {}
Stream::OutputFile(_)
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::Null(_)
| Stream::Callback(_) => {}
| Stream::Callback(_)
| Stream::PipeWriter(_) => {}
}
}
}
@@ -959,6 +988,7 @@ impl Read for Stream {
Stream::StaticString(src) => (*src).read(buf),
Stream::Byte(cursor) => (*cursor).read(buf),
Stream::InputChannel(cursor) => (*cursor).read(buf),
Stream::PipeReader(cursor) => (*cursor).read(buf),
#[cfg(feature = "http")]
Stream::HttpWrite(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
@@ -967,7 +997,8 @@ impl Read for Stream {
Stream::OutputFile(_)
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::Callback(_) => Err(std::io::Error::new(
| Stream::Callback(_)
| Stream::PipeWriter(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::ReadFromOutputStream,
)),
@@ -989,6 +1020,7 @@ impl Write for Stream {
Stream::StandardError(stream) => stream.write(buf),
#[cfg(feature = "http")]
Stream::HttpWrite(ref mut stream) => stream.get_mut().write(buf),
Stream::PipeWriter(ref mut stream) => stream.get_mut().write(buf),
#[cfg(feature = "http")]
Stream::HttpRead(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
@@ -998,7 +1030,8 @@ impl Write for Stream {
Stream::StaticString(_)
| Stream::InputChannel(_)
| Stream::Readline(_)
| Stream::InputFile(..) => Err(std::io::Error::new(
| Stream::InputFile(..)
| Stream::PipeReader(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::WriteToInputStream,
)),
@@ -1015,6 +1048,7 @@ impl Write for Stream {
Stream::Callback(ref mut callback_stream) => callback_stream.stream.get_mut().flush(),
Stream::StandardError(stream) => stream.stream.flush(),
Stream::StandardOutput(stream) => stream.stream.flush(),
Stream::PipeWriter(ref mut stream) => stream.stream.get_mut().flush(),
#[cfg(feature = "http")]
Stream::HttpWrite(ref mut stream) => stream.stream.get_mut().flush(),
#[cfg(feature = "http")]
@@ -1026,7 +1060,8 @@ impl Write for Stream {
Stream::StaticString(_)
| Stream::InputChannel(_)
| Stream::Readline(_)
| Stream::InputFile(_) => Err(std::io::Error::new(
| Stream::InputFile(_)
| Stream::PipeReader(_) => Err(std::io::Error::new(
ErrorKind::PermissionDenied,
StreamError::FlushToInputStream,
)),
@@ -1192,6 +1227,8 @@ impl Stream {
Stream::StandardError(stream) => stream.past_end_of_stream,
Stream::Callback(stream) => stream.past_end_of_stream,
Stream::InputChannel(stream) => stream.past_end_of_stream,
Stream::PipeReader(stream) => stream.past_end_of_stream,
Stream::PipeWriter(stream) => stream.past_end_of_stream,
}
}
@@ -1220,6 +1257,8 @@ impl Stream {
Stream::StandardError(stream) => stream.past_end_of_stream = value,
Stream::Callback(stream) => stream.past_end_of_stream = value,
Stream::InputChannel(stream) => stream.past_end_of_stream = value,
Stream::PipeReader(stream) => stream.past_end_of_stream = value,
Stream::PipeWriter(stream) => stream.past_end_of_stream = value,
}
}
@@ -1330,7 +1369,8 @@ impl Stream {
| Stream::InputChannel(_)
| Stream::Readline(_)
| Stream::StaticString(_)
| Stream::InputFile(..) => atom!("read"),
| Stream::InputFile(..)
| Stream::PipeReader(_) => atom!("read"),
Stream::NamedTcp(..) => atom!("read_append"),
Stream::OutputFile(file) if file.is_append => atom!("append"),
#[cfg(feature = "http")]
@@ -1338,7 +1378,8 @@ impl Stream {
Stream::OutputFile(_)
| Stream::StandardError(_)
| Stream::StandardOutput(_)
| Stream::Callback(_) => {
| Stream::Callback(_)
| Stream::PipeWriter(_) => {
atom!("write")
}
Stream::Null(_) => atom!(""),
@@ -1372,6 +1413,20 @@ impl Stream {
))
}
pub(crate) fn from_pipe_writer(writer: io::PipeWriter, arena: &mut Arena) -> Stream {
Stream::PipeWriter(arena_alloc!(
ManuallyDrop::new(StreamLayout::new(CharReader::new(writer))),
arena
))
}
pub(crate) fn from_pipe_reader(reader: io::PipeReader, arena: &mut Arena) -> Stream {
Stream::PipeReader(arena_alloc!(
ManuallyDrop::new(StreamLayout::new(CharReader::new(reader))),
arena
))
}
#[inline]
pub(crate) fn from_tcp_stream(address: Atom, tcp_stream: TcpStream, arena: &mut Arena) -> Self {
tcp_stream.set_read_timeout(None).unwrap();
@@ -1512,6 +1567,16 @@ impl Stream {
Ok(())
}
Stream::PipeReader(mut stream) => {
stream.drop_payload();
Ok(())
}
Stream::PipeWriter(mut stream) => {
stream.drop_payload();
Ok(())
}
Stream::Null(_) => Ok(()),
Stream::Readline(_) | Stream::StandardOutput(_) | Stream::StandardError(_) => {
@@ -1538,6 +1603,7 @@ impl Stream {
| Stream::Readline(_)
| Stream::StaticString(_)
| Stream::InputFile(..)
| Stream::PipeReader(_)
| Stream::Null(_) => true,
_ => false,
}
@@ -1556,6 +1622,7 @@ impl Stream {
| Stream::Byte(_)
| Stream::OutputFile(..)
| Stream::Callback(_)
| Stream::PipeWriter(_)
| Stream::Null(_) => true,
_ => false,
}
@@ -1653,7 +1720,8 @@ impl MachineState {
};
stream.set_past_end_of_stream(true);
Ok(unify!(self, result, end_of_stream))
unify!(self, result, end_of_stream);
Ok(())
}
EOFAction::Reset => {
if !stream.reset() {
@@ -1844,10 +1912,11 @@ impl MachineState {
(HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => {
if stream.is_null_stream() {
unreachable!("Null streams have no Cons representation");
}
return Ok(stream);
return if stream.is_null_stream() {
Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
} else {
Ok(stream)
};
}
(ArenaHeaderTag::Dropped, _value) => {
let stub = functor_stub(caller, arity);
@@ -1953,7 +2022,7 @@ impl MachineState {
let err = self.permission_error(
Permission::Open,
atom!("source_sink"),
functor!(atom!("alias"), [atom(alias)]),
functor!(atom!("alias"), [atom_as_cell(alias)]),
);
self.error_form(err, stub)
@@ -1961,7 +2030,7 @@ impl MachineState {
pub(crate) fn reposition_error(&mut self, stub_name: Atom, stub_arity: usize) -> MachineStub {
let stub = functor_stub(stub_name, stub_arity);
let rep_stub = functor!(atom!("reposition"), [atom(atom!("true"))]);
let rep_stub = functor!(atom!("reposition"), [atom_as_cell((atom!("true")))]);
let err = self.permission_error(Permission::Open, atom!("source_sink"), rep_stub);
self.error_form(err, stub)
@@ -2086,7 +2155,7 @@ impl MachineState {
_ => {
// assume the OS is out of file descriptors.
let stub = functor_stub(atom!("open"), 4);
let err = self.resource_error(ResourceError::OutOfFiles);
let err = Self::resource_error(ResourceError::OutOfFiles);
return Err(self.error_form(err, stub));
}
+1909 -1029
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -4,6 +4,7 @@ use crate::machine::loader::*;
use crate::machine::machine_errors::*;
use crate::machine::*;
use crate::parser::ast::*;
use crate::parser::lexer::*;
use crate::parser::parser::*;
use crate::read::devour_whitespace;
@@ -61,7 +62,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
devour_whitespace(&mut self.parser) // eliminate dangling comments before checking for EOF.
devour_whitespace(&mut self.parser.lexer) // eliminate dangling comments before checking for EOF.
.map_err(CompilationError::from)
}
+57 -303
View File
@@ -2,11 +2,10 @@ use crate::arena::*;
use crate::forms::*;
use crate::heap_iter::{stackful_preorder_iter, NonListElider};
use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::*;
use crate::offset_table::*;
use crate::types::*;
use std::cmp::Ordering;
use std::ops::{Deref, DerefMut};
use derive_more::*;
@@ -14,6 +13,18 @@ use fxhash::FxBuildHasher;
use indexmap::IndexSet;
use num_order::NumOrd;
impl MachineState {
pub(crate) fn partial_string_to_pdl(&mut self, pstr_loc: usize, l: usize) {
let (c, succ_cell) = self.heap.last_str_char_and_tail(pstr_loc);
self.pdl.push(heap_loc_as_cell!(l + 1));
self.pdl.push(succ_cell);
self.pdl.push(heap_loc_as_cell!(l));
self.pdl.push(char_as_cell!(c));
}
}
pub(crate) trait Unifier: DerefMut<Target = MachineState> {
fn unify_structure(&mut self, s1: usize, value: HeapCellValue) {
// s1 is the value of a STR cell.
@@ -82,8 +93,8 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
self.fail = true;
}
}
(HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr | HeapCellValueTag::PStr) => {
Self::unify_partial_string(self, list_loc_as_cell!(l1), value)
(HeapCellValueTag::PStrLoc, l) => {
Self::unify_partial_string(self, l, list_loc_as_cell!(l1))
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), list_loc_as_cell!(l1));
@@ -100,261 +111,43 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
);
}
fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) {
fn unify_partial_string(&mut self, pstr_loc: usize, value: HeapCellValue) {
if let Some(r) = value.as_var() {
if atom == atom!("") {
Self::bind(self, r, atom_as_cell!(atom!("[]")));
} else {
Self::bind(self, r, atom_as_cstr_cell!(atom));
}
return;
}
read_heap_cell!(value,
(HeapCellValueTag::Atom, (cstr_atom, arity)) if atom == atom!("") => {
debug_assert_eq!(arity, 0);
self.fail = cstr_atom != atom!("[]");
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
if arity == 0 {
self.fail = atom == atom!("") && name != atom!("[]");
} else {
// this is intentionally the same policy for
// value.tag() == Lis and PStrLoc. they're not
// grouped together to allow for arity == 0.
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() {
Self::unify_internal(self);
}
}
}
(HeapCellValueTag::CStr, cstr_atom) => {
self.fail = atom != cstr_atom;
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value);
if !self.pdl.is_empty() {
Self::unify_internal(self);
}
}
_ => {
self.fail = true;
}
);
}
// the return value of unify_partial_string is interpreted as
// follows:
//
// Some(None) -- the strings are equal, nothing to unify
// Some(Some(f2,f1)) -- prefixes equal, try to unify focus values f2, f1
// None -- prefixes not equal, unification fails
//
// d1's tag is assumed to be one of LIS, STR or PSTRLOC.
fn unify_partial_string(&mut self, value_1: HeapCellValue, value_2: HeapCellValue) {
if let Some(r) = value_2.as_var() {
Self::bind(self, r, value_1);
Self::bind(self, r, pstr_loc_as_cell!(pstr_loc));
return;
}
let machine_st = self.deref_mut();
let s1 = machine_st.heap.len();
machine_st.heap.push(value_1);
machine_st.heap.push(value_2);
let mut pstr_iter1 = HeapPStrIter::new(&machine_st.heap, s1);
let mut pstr_iter2 = HeapPStrIter::new(&machine_st.heap, s1 + 1);
fn unify_sequence(
machine_st: &mut MachineState,
iter: PStrIteratee,
source_cell: HeapCellValue,
) -> bool {
match iter {
PStrIteratee::Char(focus, _) => {
machine_st.pdl.push(machine_st.heap[focus]);
machine_st.pdl.push(source_cell);
}
PStrIteratee::PStrSegment(focus, _, n) => {
read_heap_cell!(machine_st.heap[focus],
(HeapCellValueTag::CStr | HeapCellValueTag::PStr, pstr_atom) => {
if focus < machine_st.heap.len() - 2 {
machine_st.heap.pop();
machine_st.heap.pop();
}
if n == 0 {
let target_cell = match machine_st.heap[focus].get_tag() {
HeapCellValueTag::CStr => {
atom_as_cstr_cell!(pstr_atom)
}
HeapCellValueTag::PStr => {
pstr_loc_as_cell!(focus)
}
_ => {
unreachable!()
}
};
machine_st.pdl.push(target_cell);
machine_st.pdl.push(source_cell);
} else {
let h_len = machine_st.heap.len();
machine_st.heap.push(pstr_offset_as_cell!(focus));
machine_st.heap.push(fixnum_as_cell!(
Fixnum::build_with(n as i64)
));
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
machine_st.pdl.push(source_cell);
}
return true;
}
(HeapCellValueTag::PStrOffset, pstr_loc) => {
let n0 = cell_as_fixnum!(machine_st.heap[focus+1])
.get_num() as usize;
if pstr_loc < machine_st.heap.len() - 2 {
machine_st.heap.pop();
machine_st.heap.pop();
}
if n == n0 {
machine_st.pdl.push(pstr_loc_as_cell!(focus));
machine_st.pdl.push(source_cell);
} else {
let h_len = machine_st.heap.len();
machine_st.heap.push(pstr_offset_as_cell!(pstr_loc));
machine_st.heap.push(fixnum_as_cell!(
Fixnum::build_with(n as i64)
));
machine_st.pdl.push(pstr_loc_as_cell!(h_len));
machine_st.pdl.push(source_cell);
}
return true;
}
_ => {
}
);
if focus < machine_st.heap.len() - 2 {
machine_st.heap.pop();
machine_st.heap.pop();
}
machine_st.pdl.push(machine_st.heap[focus]);
machine_st.pdl.push(source_cell);
return true;
}
}
false
}
match compare_pstr_prefixes(&mut pstr_iter1, &mut pstr_iter2) {
PStrCmpResult::Ordered(Ordering::Equal) => {}
PStrCmpResult::Ordered(Ordering::Less) => {
if pstr_iter2.focus.as_var().is_none() {
machine_st.fail = true;
} else {
machine_st.pdl.push(empty_list_as_cell!());
machine_st.pdl.push(pstr_iter2.focus);
}
}
PStrCmpResult::Ordered(Ordering::Greater) => {
if pstr_iter1.focus.as_var().is_none() {
machine_st.fail = true;
} else {
machine_st.pdl.push(empty_list_as_cell!());
machine_st.pdl.push(pstr_iter1.focus);
}
}
continuable @ PStrCmpResult::FirstIterContinuable(iteratee)
| continuable @ PStrCmpResult::SecondIterContinuable(iteratee) => {
if continuable.is_second_iter() {
std::mem::swap(&mut pstr_iter1, &mut pstr_iter2);
}
let mut chars_iter = PStrCharsIter {
iter: pstr_iter1,
item: Some(iteratee),
};
let mut focus = pstr_iter2.focus;
'outer: {
while let Some(c) = chars_iter.peek() {
read_heap_cell!(focus,
(HeapCellValueTag::Lis, l) => {
let val = pstr_iter2.heap[l];
machine_st.pdl.push(val);
machine_st.pdl.push(char_as_cell!(c));
focus = pstr_iter2.heap[l+1];
}
read_heap_cell!(value,
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(pstr_iter2.heap[s])
let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
.get_name_and_arity();
if name == atom!(".") && arity == 2 {
machine_st.pdl.push(pstr_iter2.heap[s+1]);
machine_st.pdl.push(char_as_cell!(c));
focus = pstr_iter2.heap[s+2];
machine_st.partial_string_to_pdl(pstr_loc, s+1);
} else {
machine_st.fail = true;
break 'outer;
}
}
(HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => {
unify_sequence(machine_st, chars_iter.item.unwrap(), focus);
return;
(HeapCellValueTag::Lis, l) => {
machine_st.partial_string_to_pdl(pstr_loc, l);
}
(HeapCellValueTag::PStrLoc, other_pstr_loc) => {
match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) {
PStrSegmentCmpResult::Continue(v1, v2) => {
machine_st.pdl.push(v1.offset_by(pstr_loc));
machine_st.pdl.push(v2.offset_by(other_pstr_loc));
}
_ => {
machine_st.fail = true;
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if unify_sequence(machine_st, chars_iter.item.unwrap(), heap_loc_as_cell!(h)) {
return;
}
break 'outer;
}
_ => {
machine_st.fail = true;
break 'outer;
}
);
chars_iter.next();
}
chars_iter.iter.next();
machine_st.pdl.push(focus);
machine_st.pdl.push(chars_iter.iter.focus);
}
}
PStrCmpResult::Unordered => {
machine_st.pdl.push(pstr_iter1.focus);
machine_st.pdl.push(pstr_iter2.focus);
}
}
machine_st.heap.pop();
machine_st.heap.pop();
}
fn unify_atom(&mut self, atom: Atom, value: HeapCellValue) {
@@ -368,16 +161,6 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
self.fail = !(arity == 0 && name == atom);
}
(HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => {
self.fail = cstr_atom != atom!("");
}
(HeapCellValueTag::Char, c1) => {
if let Some(c2) = atom.as_char() {
self.fail = c1 != c2;
} else {
self.fail = true;
}
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom));
}
@@ -412,11 +195,6 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
self.fail = true;
}
}
(HeapCellValueTag::Char, c2) => {
if c != c2 {
self.fail = true;
}
}
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), char_as_cell!(c));
}
@@ -438,7 +216,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
return;
}
match Number::try_from(value) {
let machine_st = self.deref();
match Number::try_from((value, &machine_st.arena.f64_tbl)) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if n1.get_num() == n2.get_num() => {}
Number::Integer(n2) if (*n2).num_eq(&n1.get_num()) => {}
@@ -459,7 +239,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
return;
}
match Number::try_from(value) {
let machine_st = self.deref();
match Number::try_from((value, &machine_st.arena.f64_tbl)) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if (*n1).num_eq(&n2.get_num()) => {}
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
@@ -480,7 +262,9 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
return;
}
match Number::try_from(value) {
let machine_st = self.deref_mut();
match Number::try_from((value, &machine_st.arena.f64_tbl)) {
Ok(n2) => match n2 {
Number::Fixnum(n2) if (*n1).num_eq(&Integer::from(n2.get_num())) => {}
Number::Integer(n2) if (*n1).num_eq(&*n2) => {}
@@ -495,15 +279,20 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
}
}
fn unify_f64(&mut self, f1: F64Ptr, value: HeapCellValue) {
fn unify_f64(&mut self, f1: F64Offset, value: HeapCellValue) {
if let Some(r) = value.as_var() {
Self::bind(self, r, HeapCellValue::from(f1));
return;
}
read_heap_cell!(value,
(HeapCellValueTag::F64, f2) => {
self.fail = **f1 != **f2;
(HeapCellValueTag::F64Offset, f2) => {
let machine_st = self.deref_mut();
let f1 = machine_st.arena.f64_tbl.get_entry(f1);
let f2 = machine_st.arena.f64_tbl.get_entry(f2);
self.fail = f1 != f2;
}
_ => {
self.fail = true;
@@ -610,7 +399,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
tabu_list.insert((d1, d2));
}
}
(HeapCellValueTag::PStrLoc) => {
(HeapCellValueTag::PStrLoc, l) => {
read_heap_cell!(d2,
(HeapCellValueTag::PStrLoc |
HeapCellValueTag::Lis |
@@ -619,8 +408,7 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
continue;
}
}
(HeapCellValueTag::CStr |
HeapCellValueTag::AttrVar |
(HeapCellValueTag::AttrVar |
HeapCellValueTag::Var |
HeapCellValueTag::StackVar) => {
}
@@ -630,52 +418,19 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
}
);
Self::unify_partial_string(self, d1, d2);
Self::unify_partial_string(self, l, d2);
if !self.fail && !d2.is_constant() {
let d2 = self.store(d2);
tabu_list.insert((d1, d2));
}
}
(HeapCellValueTag::CStr) => {
read_heap_cell!(d2,
(HeapCellValueTag::AttrVar, h) => {
Self::bind(self, Ref::attr_var(h), d1);
continue;
}
(HeapCellValueTag::Var, h) => {
Self::bind(self, Ref::heap_cell(h), d1);
continue;
}
(HeapCellValueTag::StackVar, s) => {
Self::bind(self, Ref::stack_cell(s), d1);
continue;
}
(HeapCellValueTag::Str |
HeapCellValueTag::Lis |
HeapCellValueTag::PStrLoc) => {
}
(HeapCellValueTag::CStr) => {
self.fail = d1 != d2;
continue;
}
_ => {
self.fail = true;
return;
}
);
Self::unify_partial_string(self, d2, d1);
}
(HeapCellValueTag::F64, f1) => {
(HeapCellValueTag::F64Offset, f1) => {
Self::unify_f64(self, f1, d2);
}
(HeapCellValueTag::Fixnum, n1) => {
Self::unify_fixnum(self, n1, d2);
}
(HeapCellValueTag::Char, c1) => {
Self::unify_char(self, c1, d2);
}
(HeapCellValueTag::Cons, ptr_1) => {
Self::unify_constant(self, ptr_1, d2);
}
@@ -707,12 +462,11 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
if !value.is_constant() {
let machine_st: &mut MachineState = unifier.deref_mut();
machine_st.heap[0] = value;
for cell in stackful_preorder_iter::<NonListElider>(
&mut machine_st.heap,
&mut machine_st.stack,
value,
) {
for cell in
stackful_preorder_iter::<NonListElider>(&mut machine_st.heap, &mut machine_st.stack, 0)
{
let cell = unmark_cell_bits!(cell);
if let Some(inner_r) = cell.as_var() {
+88 -230
View File
@@ -1,15 +1,10 @@
/* A simple macro to count the arguments in a variadic list
* of token trees.
*/
macro_rules! count_tt {
() => { 0 };
($odd:tt $($a:tt $b:tt)*) => { (count_tt!($($a)*) << 1) | 1 };
($($a:tt $even:tt)*) => { count_tt!($($a)*) << 1 };
}
macro_rules! char_as_cell {
($c: expr) => {
HeapCellValue::build_with(HeapCellValueTag::Char, $c as u64)
HeapCellValue::from_bytes(AtomCell::new_char_inlined($c).into_bytes())
};
}
@@ -19,12 +14,6 @@ macro_rules! fixnum_as_cell {
};
}
macro_rules! cell_as_fixnum {
($cell:expr) => {
Fixnum::from_bytes($cell.into_bytes())
};
}
macro_rules! integer_as_cell {
($n: expr) => {{
match $n {
@@ -45,31 +34,17 @@ macro_rules! empty_list_as_cell {
macro_rules! atom_as_cell {
($atom:expr) => {
HeapCellValue::from_bytes(
AtomCell::build_with($atom.flat_index(), 0, HeapCellValueTag::Atom).into_bytes(),
)
HeapCellValue::from_bytes(AtomCell::build_with($atom.index, 0).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_string {
($cell:expr) => {
PartialString::from(cell_as_atom!($cell))
HeapCellValue::from_bytes(AtomCell::build_with($atom.index, $arity as u8).into_bytes())
};
}
macro_rules! cell_as_atom {
($cell:expr) => {{
let cell = AtomCell::from_bytes($cell.into_bytes());
let name = (cell.get_index() as u64) << 3;
Atom::from(name)
}};
($cell:expr) => {
AtomCell::from_bytes($cell.into_bytes()).get_name()
};
}
macro_rules! cell_as_atom_cell {
@@ -78,10 +53,17 @@ macro_rules! cell_as_atom_cell {
};
}
macro_rules! cell_as_f64_ptr {
macro_rules! cell_as_f64_offset {
($cell:expr) => {{
let offset = $cell.get_value() as usize;
F64Ptr::from_offset(F64Offset::new(offset))
F64Offset::from(offset)
}};
}
macro_rules! cell_as_code_index_offset {
($cell:expr) => {{
let offset = $cell.get_value() as usize;
CodeIndexOffset::from(offset)
}};
}
@@ -91,26 +73,12 @@ macro_rules! cell_as_untyped_arena_ptr {
};
}
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)
@@ -172,11 +140,11 @@ macro_rules! typed_arena_ptr_as_cell {
macro_rules! raw_ptr_as_cell {
($ptr:expr) => {{
// Cell is 64-bit, but raw ptr is 32-bit in 32-bit systems
// TODO use <*{const,mut} _>::addr instead of as when the strict_provenance feature is stable rust-lang/rust#95228
// we might need <*{const,mut} _>::expose_provenance for strict provenance, dependening on how we recreate a pointer later
let ptr : *const _ = $ptr;
debug_assert!(!$ptr.is_null());
HeapCellValue::from_ptr_addr(ptr as usize)
let ptr: *const _ = $ptr;
// This needs to expose provenance because it needs to be turned back into a pointer
// in contexts where there is no available provenance locally. For example, in
// `ConsPtr::as_ptr`.
HeapCellValue::from_ptr_addr(ptr.expose_provenance())
}};
}
@@ -186,36 +154,10 @@ macro_rules! untyped_arena_ptr_as_cell {
};
}
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) => {
raw_ptr_as_cell!($ptr.as_ptr())
};
}
macro_rules! cell_as_stream {
@@ -276,9 +218,21 @@ macro_rules! match_untyped_arena_ptr_pat_body {
#[allow(unused_braces)]
$code
}};
($ptr:ident, IndexPtr, $ip:ident, $code:expr) => {{
($ptr:ident, PipeReader, $listener:ident, $code:expr) => {{
#[allow(unused_mut)]
let mut $ip = unsafe { $ptr.as_typed_ptr::<IndexPtr>() };
let mut $listener = unsafe { $ptr.as_typed_ptr::<PipeReader>() };
#[allow(unused_braces)]
$code
}};
($ptr:ident, PipeWriter, $listener:ident, $code:expr) => {{
#[allow(unused_mut)]
let mut $listener = unsafe { $ptr.as_typed_ptr::<PipeWriter>() };
#[allow(unused_braces)]
$code
}};
($ptr:ident, ChildProcess, $listener:ident, $code:expr) => {{
#[allow(unused_mut)]
let mut $listener = unsafe { $ptr.as_typed_ptr::<std::process::Child>() };
#[allow(unused_braces)]
$code
}};
@@ -304,12 +258,8 @@ macro_rules! match_untyped_arena_ptr_pat {
| ArenaHeaderTag::InputChannelStream
| ArenaHeaderTag::StandardOutputStream
| ArenaHeaderTag::StandardErrorStream
};
(IndexPtr) => {
ArenaHeaderTag::IndexPtrUndefined
| ArenaHeaderTag::IndexPtrDynamicUndefined
| ArenaHeaderTag::IndexPtrDynamicIndex
| ArenaHeaderTag::IndexPtrIndex
| ArenaHeaderTag::PipeReader
| ArenaHeaderTag::PipeWriter
};
($tag:ident) => {
ArenaHeaderTag::$tag
@@ -336,8 +286,13 @@ macro_rules! read_heap_cell_pat_body {
#[allow(unused_braces)]
$code
}};
($cell:ident, F64, $n:ident, $code:expr) => {{
let $n = cell_as_f64_ptr!($cell);
($cell:ident, F64Offset, $n:ident, $code:expr) => {{
let $n = cell_as_f64_offset!($cell);
#[allow(unused_braces)]
$code
}};
($cell:ident, CodeIndexOffset, $n:ident, $code:expr) => {{
let $n = cell_as_code_index_offset!($cell);
#[allow(unused_braces)]
$code
}};
@@ -346,26 +301,6 @@ macro_rules! read_heap_cell_pat_body {
#[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)]
@@ -386,11 +321,6 @@ macro_rules! read_heap_cell_pat_body {
#[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)]
@@ -432,119 +362,6 @@ macro_rules! read_heap_cell {
});
}
macro_rules! functor {
($name:expr, [$($dt:ident($($value:expr),*)),+], [$($aux:ident),*]) => ({
{
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let arity: usize = count_tt!($($dt) +);
#[allow(unused_variables)]
let aux_lens: [usize; count_tt!($($aux) *)] = [$($aux.len()),*];
let mut result =
vec![ atom_as_cell!($name, arity as u16),
$(functor_term!( $dt($($value),*), arity, aux_lens, addendum ),)+ ];
$(
result.extend($aux.iter());
)*
result.extend(addendum.into_iter());
result
}
});
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{
let arity: usize = count_tt!($($dt) +);
#[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let mut result =
vec![ atom_as_cell!($name, arity as u16),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
}
});
($name:expr) => ({
vec![ atom_as_cell!($name) ]
});
}
macro_rules! functor_term {
(str(0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
str_loc_as_cell!($arity + 1)
});
(str($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let len: usize = $aux_lens[0 .. $e].iter().sum();
str_loc_as_cell!($arity + 1 + len)
});
(str($h:expr, 0), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
str_loc_as_cell!($arity + $h + 1)
});
(str($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let len: usize = $aux_lens[0 .. $e].iter().sum();
str_loc_as_cell!($arity + $h + 1 + len)
});
(literal($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::from($e)
);
(integer($e:expr, $arena:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::arena_from(Number::arena_from($e, $arena), $arena)
);
(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!(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.len() + $h;
$addendum.extend(stub.into_iter());
str_loc_as_cell!(h)
});
(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) => (
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.len() + $h;
let cell = string_as_pstr_cell!($e);
$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(atom!("true")), $arity, $aux_lens, $addendum)
} else {
functor_term!(atom(atom!("false")), $arity, $aux_lens, $addendum)
}
});
(cell($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e
);
}
macro_rules! compare_number_instr {
($cmp: expr, $at_1: expr, $at_2: expr) => {{
$cmp.set_terms($at_1, $at_2);
@@ -629,3 +446,44 @@ macro_rules! compare_term_test {
$machine_st.compare_term_test($var_comparison)
}};
}
macro_rules! step_or_resource_error {
($machine_st:expr, $val:expr) => {{
match $val {
Ok(r) => r,
Err(err_loc) => {
$machine_st.throw_resource_error(err_loc);
return;
}
}
}};
($machine_st:expr, $val:expr, $fail:block) => {{
match $val {
Ok(r) => r,
Err(err_loc) => {
$machine_st.throw_resource_error(err_loc);
$fail
}
}
}};
}
macro_rules! resource_error_call_result {
($machine_st:expr, $val:expr) => {
step_or_resource_error!($machine_st, $val, {
return Err(vec![]);
})
};
}
macro_rules! heap_index {
($idx:expr) => {
($idx) * std::mem::size_of::<HeapCellValue>()
};
}
macro_rules! cell_index {
($idx:expr) => {
(($idx) / std::mem::size_of::<HeapCellValue>())
};
}
+422
View File
@@ -0,0 +1,422 @@
use std::cell::UnsafeCell;
use std::sync::Arc;
use std::{fmt, mem, ptr};
use arcu::atomic::Arcu;
use arcu::epoch_counters::GlobalEpochCounterPool;
use arcu::rcu_ref::RcuRef;
use arcu::Rcu;
use parking_lot::RwLock;
use crate::machine::machine_indices::IndexPtr;
use crate::raw_block::RawBlock;
use crate::raw_block::RawBlockTraits;
use ordered_float::OrderedFloat;
const F64_TABLE_INIT_SIZE: usize = 1 << 16;
const F64_TABLE_ALIGN: usize = 8;
const CODE_INDEX_TABLE_INIT_SIZE: usize = 1 << 16;
const CODE_INDEX_TABLE_ALIGN: usize = 8;
impl RawBlockTraits for OrderedFloat<f64> {
#[inline]
fn init_size() -> usize {
F64_TABLE_INIT_SIZE
}
#[inline]
fn align() -> usize {
F64_TABLE_ALIGN
}
}
impl RawBlockTraits for IndexPtr {
#[inline]
fn init_size() -> usize {
CODE_INDEX_TABLE_INIT_SIZE
}
#[inline]
fn align() -> usize {
CODE_INDEX_TABLE_ALIGN
}
}
#[derive(Debug)]
pub struct OffsetTableImpl<T: RawBlockTraits>(InnerOffsetTableImpl<T>);
impl<T: RawBlockTraits> From<Arc<ConcurrentOffsetTable<T>>> for OffsetTableImpl<T> {
#[inline]
fn from(value: Arc<ConcurrentOffsetTable<T>>) -> Self {
OffsetTableImpl(InnerOffsetTableImpl::Concurrent(value))
}
}
impl<T: fmt::Debug + RawBlockTraits> OffsetTableImpl<T> {
#[inline(always)]
pub fn new() -> Self {
Self(InnerOffsetTableImpl::Serial(SerialOffsetTable::new()))
}
#[must_use = "the returned concurrent table must be absorbed into the owned OffsetTable"]
pub fn single_to_concurrent(&mut self) -> Arc<ConcurrentOffsetTable<T>> {
match &mut self.0 {
InnerOffsetTableImpl::Serial(serial_tbl) => {
let empty_serial_tbl = SerialOffsetTable {
block: RawBlock::empty_block(),
};
let serial_tbl = mem::replace(serial_tbl, empty_serial_tbl);
let num_tbl_entries = serial_tbl.block.size() / size_of::<T>();
let block = Arcu::new(serial_tbl.block, GlobalEpochCounterPool);
let offset_locks: Vec<RwLock<()>> =
(0..num_tbl_entries).map(|_| RwLock::new(())).collect();
let concurrent_tbl = Arc::new(ConcurrentOffsetTable {
block,
growth_lock: RwLock::new(()),
offset_locks: RwLock::new(offset_locks),
});
self.0 = InnerOffsetTableImpl::Concurrent(concurrent_tbl.clone());
concurrent_tbl
}
InnerOffsetTableImpl::Concurrent(concurrent_tbl) => concurrent_tbl.clone(),
}
}
#[must_use = "the transition to a single-threaded offset table may fail if the concurrent table is held from multiple places"]
pub fn concurrent_to_single(&mut self) -> Result<(), ()> {
match &mut self.0 {
InnerOffsetTableImpl::Serial(_serial_tbl) => Ok(()),
InnerOffsetTableImpl::Concurrent(concurrent_tbl) => {
let table_arc = std::mem::replace(
concurrent_tbl,
Arc::new(ConcurrentOffsetTable {
block: Arcu::new(RawBlock::empty_block(), GlobalEpochCounterPool),
growth_lock: RwLock::new(()),
offset_locks: RwLock::new(vec![]),
}),
);
match Arc::try_unwrap(table_arc) {
Ok(table) => {
// this was the only instance of the concurrent table, as such
// at this point no build_with/with_entry{_mut} call can be in-progress/made
// this shouldn't be able to fail
let raw_block =
Arc::try_unwrap(table.block.replace(RawBlock::empty_block())).unwrap();
self.0 =
InnerOffsetTableImpl::Serial(SerialOffsetTable { block: raw_block });
Ok(())
}
Err(table_arc) => {
// restore the concurrent_tbl
*concurrent_tbl = table_arc;
Err(())
}
}
}
}
}
#[inline]
pub fn get_entry(&self, offset: <Self as OffsetTable<T>>::Offset) -> T
where
Self: OffsetTable<T>,
T: Copy,
{
self.with_entry(offset, |value| *value)
}
}
impl<T: fmt::Debug + RawBlockTraits> Default for OffsetTableImpl<T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
struct SerialOffsetTable<T: RawBlockTraits> {
block: RawBlock<T>,
}
#[derive(Debug)]
pub struct ConcurrentOffsetTable<T: RawBlockTraits> {
block: Arcu<RawBlock<T>, GlobalEpochCounterPool>,
growth_lock: RwLock<()>,
offset_locks: RwLock<Vec<RwLock<()>>>,
}
#[derive(Debug)]
enum InnerOffsetTableImpl<T: RawBlockTraits> {
Serial(SerialOffsetTable<T>),
#[allow(dead_code)]
Concurrent(Arc<ConcurrentOffsetTable<T>>),
}
impl<T: RawBlockTraits> InnerOffsetTableImpl<T> {
#[inline(always)]
fn build_with(&mut self, value: T) -> usize {
match self {
Self::Concurrent(concurrent_tbl) => concurrent_tbl.build_with(value),
Self::Serial(serial_tbl) => unsafe { serial_tbl.build_with(value) },
}
}
#[inline(always)]
fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: usize, f: F) -> R {
match self {
Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry(offset, f),
Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup(offset) }),
}
}
#[inline(always)]
fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&mut self, offset: usize, f: F) -> R {
match self {
Self::Concurrent(concurrent_tbl) => concurrent_tbl.with_entry_mut(offset, f),
Self::Serial(serial_tbl) => f(unsafe { serial_tbl.lookup_mut(offset) }),
}
}
}
pub trait OffsetTable<T: RawBlockTraits> {
type Offset: Copy + Into<usize>;
fn build_with(&mut self, value: T) -> Self::Offset;
fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: Self::Offset, f: F) -> R;
fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&mut self, offset: Self::Offset, f: F) -> R;
}
impl OffsetTable<OrderedFloat<f64>> for OffsetTableImpl<OrderedFloat<f64>> {
type Offset = F64Offset;
fn build_with(&mut self, value: OrderedFloat<f64>) -> F64Offset {
F64Offset(self.0.build_with(value))
}
#[inline]
fn with_entry<R, F: FnOnce(&OrderedFloat<f64>) -> R>(&self, offset: F64Offset, f: F) -> R {
self.0.with_entry(offset.into(), f)
}
#[inline]
fn with_entry_mut<R, F: FnOnce(&mut OrderedFloat<f64>) -> R>(
&mut self,
offset: F64Offset,
f: F,
) -> R {
self.0.with_entry_mut(offset.into(), f)
}
}
impl OffsetTable<IndexPtr> for OffsetTableImpl<IndexPtr> {
type Offset = CodeIndexOffset;
fn build_with(&mut self, value: IndexPtr) -> CodeIndexOffset {
CodeIndexOffset(self.0.build_with(value))
}
#[inline]
fn with_entry<R, F: FnOnce(&IndexPtr) -> R>(&self, offset: CodeIndexOffset, f: F) -> R {
self.0.with_entry(offset.into(), f)
}
#[inline]
fn with_entry_mut<R, F: FnOnce(&mut IndexPtr) -> R>(
&mut self,
offset: CodeIndexOffset,
f: F,
) -> R {
self.0.with_entry_mut(offset.into(), f)
}
}
impl<T: RawBlockTraits> SerialOffsetTable<T> {
#[inline]
fn new() -> Self {
Self {
block: RawBlock::new(),
}
}
unsafe fn build_with(&mut self, value: T) -> usize {
let mut ptr;
loop {
ptr = self.block.alloc(size_of::<T>());
if ptr.is_null() {
let new_block = self.block.grow_new().unwrap();
self.block = new_block;
} else {
break;
}
}
ptr::write(ptr as *mut T, value);
ptr.addr() - self.block.base.addr()
}
#[inline]
unsafe fn lookup(&self, offset: usize) -> &T {
&*self.block.base.add(offset).cast::<T>()
}
#[inline]
unsafe fn lookup_mut(&mut self, offset: usize) -> &mut T {
&mut *self.block.base.add(offset).cast::<T>().cast_mut()
}
}
impl<T: RawBlockTraits> ConcurrentOffsetTable<T> {
#[allow(clippy::missing_safety_doc)]
fn build_with(&self, value: T) -> usize {
let growth_lock = self.growth_lock.write();
// we don't have an index table for lookups as AtomTable does so
// just get the epoch after we take the upgrade lock
let mut block_epoch = self.block.read();
let mut ptr;
loop {
ptr = unsafe { block_epoch.alloc(mem::size_of::<T>()) };
if ptr.is_null() {
let new_block = unsafe { block_epoch.grow_new().unwrap() };
self.block.replace(new_block);
block_epoch = self.block.read();
} else {
break;
}
}
let new_tbl_sz = block_epoch.size() / size_of::<T>();
let mut offset_locks = self.offset_locks.write();
offset_locks.resize_with(new_tbl_sz, || RwLock::new(()));
unsafe {
ptr::write(ptr as *mut T, value);
}
let value = ptr.addr() - block_epoch.base.addr();
// AtomTable would have to update the index table at this point
// explicit drop to ensure we don't accidentally drop it early
drop(offset_locks);
drop(growth_lock);
value
}
fn with_entry<R, F: FnOnce(&T) -> R>(&self, offset: usize, f: F) -> R {
let outer_offset_lock = self.offset_locks.read();
let inner_offset_lock = outer_offset_lock[offset / size_of::<T>()].read();
let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe {
raw_block.base.add(offset).cast::<T>().as_ref()
})
.expect("offset valid");
let result = f(&*rcu_ref);
drop(inner_offset_lock);
drop(outer_offset_lock);
result
}
fn with_entry_mut<R, F: FnOnce(&mut T) -> R>(&self, offset: usize, f: F) -> R {
let growth_lock = self.growth_lock.read();
let outer_offset_lock = self.offset_locks.read();
let inner_offset_lock = outer_offset_lock[offset / size_of::<T>()].write();
let rcu_ref = RcuRef::try_map(self.block.read(), |raw_block| unsafe {
raw_block
.base
.add(offset)
.cast_mut()
.cast::<UnsafeCell<T>>()
.as_ref()
})
.expect("offset valid");
let result = f(unsafe { &mut *rcu_ref.get().as_mut().unwrap() });
drop(inner_offset_lock);
drop(outer_offset_lock);
drop(growth_lock);
result
}
}
pub type F64Table = OffsetTableImpl<OrderedFloat<f64>>;
pub type CodeIndexTable = OffsetTableImpl<IndexPtr>;
#[derive(Clone, Copy, Debug)]
pub struct F64Offset(usize);
impl From<usize> for F64Offset {
#[inline(always)]
fn from(offset: usize) -> Self {
Self(offset)
}
}
impl From<F64Offset> for usize {
fn from(val: F64Offset) -> Self {
val.0
}
}
#[derive(Debug, Clone, Copy)]
pub struct CodeIndexOffset(usize);
impl From<usize> for CodeIndexOffset {
#[inline(always)]
fn from(offset: usize) -> Self {
Self(offset)
}
}
impl From<CodeIndexOffset> for usize {
#[inline(always)]
fn from(val: CodeIndexOffset) -> Self {
val.0
}
}
impl CodeIndexOffset {
#[inline(always)]
pub fn to_u64(self) -> u64 {
self.0 as u64
}
}
impl fmt::Display for CodeIndexOffset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "CodeIndexOffset({})", self.0)
}
}
impl F64Offset {
#[inline(always)]
pub fn to_u64(self) -> u64 {
self.0 as u64
}
}
impl fmt::Display for F64Offset {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "F64Offset({})", self.0)
}
}
+141 -77
View File
@@ -2,21 +2,24 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::machine::machine_indices::*;
use crate::offset_table::*;
use crate::parser::char_reader::*;
use crate::types::HeapCellValueTag;
use std::cell::{Cell, Ref, RefCell, RefMut};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use std::hash::Hasher;
use std::io::{Error as IOError, ErrorKind};
use std::ops::Not;
use std::ops::RangeInclusive;
use std::ops::{Deref, Neg};
use std::rc::Rc;
use std::sync::Arc;
use std::vec::Vec;
use crate::parser::dashu::{Integer, Rational};
use dashu::Integer;
use dashu::Rational;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use scryer_modular_bitfield::error::OutOfBounds;
@@ -24,7 +27,7 @@ use scryer_modular_bitfield::prelude::*;
pub type Specifier = u32;
pub const MAX_ARITY: usize = 1023;
pub const MAX_ARITY: usize = 255;
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -264,8 +267,8 @@ impl RegType {
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),
RegType::Perm(val) => write!(f, "Y{val}"),
RegType::Temp(val) => write!(f, "X{val}"),
}
}
}
@@ -287,10 +290,10 @@ impl VarReg {
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),
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{reg} A{arg}"),
VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{reg} A{arg}"),
}
}
}
@@ -307,28 +310,6 @@ macro_rules! temp_v {
};
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum GenContext {
Head,
Mid(usize),
Last(usize), // Mid & Last: chunk_num
}
impl GenContext {
#[inline]
pub fn chunk_num(self) -> usize {
match self {
GenContext::Head => 0,
GenContext::Mid(cn) | GenContext::Last(cn) => cn,
}
}
#[inline]
pub fn is_last(self) -> bool {
matches!(self, GenContext::Last(_))
}
}
#[bitfield]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
pub struct OpDesc {
@@ -420,7 +401,7 @@ pub fn default_op_dir() -> OpDir {
op_dir
}
#[derive(Debug, Clone)]
#[derive(Debug, Copy, Clone)]
pub enum ArithmeticError {
NonEvaluableFunctor(Literal, usize),
UninstantiatedVar,
@@ -570,9 +551,90 @@ pub struct Fixnum {
tag: B6,
}
mod private {
use dashu::Integer;
pub(crate) trait FitsInFixnumSeal {}
pub(crate) trait MightNotFitInFixnumSeal {}
macro_rules! impl_fits_in_fixnum {
($t:ty) => {
impl $crate::parser::ast::private::FitsInFixnumSeal for $t {}
impl $crate::parser::ast::FitsInFixnum for $t {
fn into_i56(self) -> i64 {
self.into()
}
}
};
}
impl_fits_in_fixnum!(u8);
impl_fits_in_fixnum!(i8);
impl_fits_in_fixnum!(u16);
impl_fits_in_fixnum!(i16);
impl_fits_in_fixnum!(u32);
impl_fits_in_fixnum!(i32);
impl FitsInFixnumSeal for char {}
impl super::FitsInFixnum for char {
fn into_i56(self) -> i64 {
u32::from(self) as i64
}
}
impl MightNotFitInFixnumSeal for i64 {}
impl MightNotFitInFixnumSeal for &Integer {}
impl MightNotFitInFixnumSeal for Integer {}
impl MightNotFitInFixnumSeal for usize {}
}
#[allow(private_bounds)]
pub trait FitsInFixnum: private::FitsInFixnumSeal {
fn into_i56(self) -> i64;
}
#[allow(private_bounds)]
pub trait MightNotFitInFixnum: private::MightNotFitInFixnumSeal {
fn try_into_i56(self) -> Option<i64>;
}
impl<T> MightNotFitInFixnum for T
where
T: private::MightNotFitInFixnumSeal + TryInto<i64>,
{
fn try_into_i56(self) -> Option<i64> {
let val = self.try_into().ok()?;
if Fixnum::RANGE.contains(&val) {
Some(val)
} else {
None
}
}
}
impl Fixnum {
pub(crate) const MIN: i64 = -(1 << 55);
pub(crate) const MAX: i64 = (1 << 55) - 1;
const RANGE: RangeInclusive<i64> = Self::MIN..=Self::MAX;
// if you have a type that is not guaranteed to fit use `Fixnum::build_with_checked` or `Fixnum::build_with_unchecked` instead
#[inline]
pub fn build_with(num: i64) -> Self {
pub fn build_with(num: impl FitsInFixnum) -> Self {
// Safety: FitsInFixnum is only implemented by types that only have valid values
// and FitsInFixnumSeal ensures no one outside this crate can violate that
unsafe { Self::build_with_unchecked(num.into_i56()) }
}
#[inline]
pub unsafe fn build_with_unchecked(num: i64) -> Self {
debug_assert!(
Self::RANGE.contains(&num),
"{num} should be in the range {}..={}",
Self::MIN,
Self::MAX
);
Fixnum::new()
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
.with_tag(HeapCellValueTag::Fixnum as u8)
@@ -581,12 +643,8 @@ impl Fixnum {
}
#[inline]
pub fn as_cutpoint(num: i64) -> Self {
Fixnum::new()
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1))
.with_tag(HeapCellValueTag::CutPoint as u8)
.with_m(false)
.with_f(false)
pub fn as_cutpoint(self) -> Self {
self.with_tag(HeapCellValueTag::CutPoint as u8)
}
#[inline]
@@ -595,20 +653,14 @@ impl Fixnum {
HeapCellValueTag::from_bytes(self.tag()).unwrap()
}
// if you have a type that is guaranteed to fit use `Fixnum::build_with` instead
#[inline]
pub fn build_with_checked(num: i64) -> Result<Self, OutOfBounds> {
const UPPER_BOUND: i64 = (1 << 55) - 1;
const LOWER_BOUND: i64 = -(1 << 55);
if (LOWER_BOUND..=UPPER_BOUND).contains(&num) {
Ok(Fixnum::new()
.with_m(false)
.with_f(false)
.with_tag(HeapCellValueTag::Fixnum as u8)
.with_num(u64::from_ne_bytes(num.to_ne_bytes()) & ((1 << 56) - 1)))
} else {
Err(OutOfBounds {})
}
pub fn build_with_checked(num: impl MightNotFitInFixnum) -> Result<Self, OutOfBounds> {
Ok(unsafe {
// Safety: all MightNotFitInFixnum impls return None when the value is out-of-bounds
// and MightNotFitInFixnumSeal ensures no one outside this crate can violate that
Self::build_with_unchecked(num.try_into_i56().ok_or(OutOfBounds {})?)
})
}
#[inline]
@@ -618,6 +670,10 @@ impl Fixnum {
debug_assert!(!overflowed);
n
}
pub fn checked_abs(self) -> Option<Self> {
Self::build_with_checked(self.get_num().abs()).ok()
}
}
impl Neg for Fixnum {
@@ -625,23 +681,33 @@ impl Neg for Fixnum {
#[inline]
fn neg(self) -> Self::Output {
Fixnum::build_with(-self.get_num())
// Safety: the truncating behaviour is correct
unsafe { Self::build_with_unchecked(-self.get_num()) }
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
impl Not for Fixnum {
type Output = Self;
#[inline]
fn not(self) -> Self::Output {
// Safety: the truncating behaviour is correct
unsafe { Self::build_with_unchecked(!self.get_num()) }
}
}
#[derive(Debug, Copy, Clone)]
pub enum Literal {
Atom(Atom),
Char(char),
CodeIndex(CodeIndex),
CodeIndexOffset(CodeIndexOffset),
Fixnum(Fixnum),
Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>),
Float(F64Offset),
String(Atom),
F64Offset(F64Offset),
}
impl From<F64Ptr> for Literal {
/*
impl From<F64Ptr<'_>> for Literal {
#[inline(always)]
fn from(ptr: F64Ptr) -> Literal {
Literal::Float(ptr.as_offset())
@@ -654,16 +720,15 @@ impl fmt::Display for Literal {
Literal::Atom(ref atom) => {
write!(f, "{}", atom.flat_index())
}
Literal::Char(c) => write!(f, "'{}'", *c as u32),
Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64),
Literal::CodeIndexOffset(i) => write!(f, "{}", *i),
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::FloatOffset(ref n) => write!(f, "{}", *n),
}
}
}
*/
impl Literal {
pub fn as_atom(&self, atom_tbl: &Arc<AtomTable>) -> Option<Atom> {
@@ -742,20 +807,20 @@ impl From<&str> for VarPtr {
pub enum Var {
Generated(usize),
InSitu(usize),
Named(String),
Named(Rc<String>),
}
impl From<String> for Var {
#[inline(always)]
fn from(value: String) -> Var {
Var::Named(value)
Var::Named(Rc::new(value))
}
}
impl From<&str> for Var {
#[inline(always)]
fn from(value: &str) -> Var {
Var::Named(value.to_owned())
Var::Named(Rc::new(value.to_owned()))
}
}
@@ -764,8 +829,8 @@ impl Var {
#[inline(always)]
pub fn to_string(&self) -> String {
match self {
Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
Var::Named(value) => value.to_owned(),
Var::InSitu(n) | Var::Generated(n) => format!("_{n}"),
Var::Named(value) => value.as_ref().clone(),
}
}
}
@@ -778,8 +843,8 @@ pub enum Term {
Literal(Cell<RegType>, Literal),
// PartialString wraps a String in anticipation of it absorbing
// other PartialString variants in as_partial_string.
PartialString(Cell<RegType>, String, Box<Term>),
CompleteString(Cell<RegType>, Atom),
PartialString(Cell<RegType>, Rc<String>, Box<Term>),
CompleteString(Cell<RegType>, Rc<String>),
Var(Cell<VarReg>, VarPtr),
}
@@ -792,10 +857,9 @@ impl Term {
}
pub fn name(&self) -> Option<Atom> {
match self {
&Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => {
Some(*atom)
}
match *self {
Term::Literal(_, Literal::Atom(atom)) => Some(atom),
Term::Clause(_, atom, ..) => Some(atom),
_ => None,
}
}
@@ -810,7 +874,7 @@ impl Term {
pub(crate) fn unfold_by_str_once(term: &mut Term, s: Atom) -> Option<(Term, Term)> {
if let Term::Clause(_, ref name, ref mut subterms) = term {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = subterms.last() {
if let Some(Term::Literal(_, Literal::CodeIndexOffset(_))) = subterms.last() {
subterms.pop();
}
+50 -27
View File
@@ -1,11 +1,13 @@
use crate::arena::F64Ptr;
use crate::arena::TypedArenaPtr;
use crate::arena::*;
use crate::atom_table::*;
pub use crate::machine::machine_state::*;
use crate::offset_table::*;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::dashu::Integer;
use ordered_float::OrderedFloat;
use std::convert::TryFrom;
use std::fmt;
@@ -28,10 +30,11 @@ struct LayoutInfo {
more: bool,
}
#[derive(Debug, PartialEq)]
#[derive(Debug)]
pub enum Token {
Literal(Literal),
Var(String),
String(String),
Open, // '('
OpenCT, // '('
Close, // ')'
@@ -55,16 +58,17 @@ impl Token {
enum Number {
BigInt(TypedArenaPtr<Integer>),
Fixnum(Fixnum),
Float(F64Ptr),
Float(F64Offset),
}
impl Number {
#[inline]
#[allow(clippy::wrong_self_convention)]
fn to_literal(self) -> Literal {
match self {
Number::BigInt(ibig) => Literal::Integer(ibig),
Number::Fixnum(fixnum) => Literal::Fixnum(fixnum),
Number::Float(f) => Literal::Float(f.as_offset()),
Number::Float(f) => Literal::F64Offset(f),
}
}
}
@@ -77,6 +81,7 @@ enum NumberToken {
impl NumberToken {
#[inline]
#[allow(clippy::wrong_self_convention)]
fn to_token(self) -> Option<Token> {
match self {
NumberToken::Number(number) => Some(Token::Literal(number.to_literal())),
@@ -100,7 +105,7 @@ macro_rules! try_nt {
}};
}
pub struct Lexer<'a, R> {
pub(crate) struct Lexer<'a, R> {
pub(crate) reader: R,
pub(crate) machine_st: &'a mut MachineState,
pub(crate) line_num: usize,
@@ -109,7 +114,7 @@ pub struct Lexer<'a, R> {
impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Lexer")
f.debug_struct("LexerParser")
.field("reader", &"&'a mut R") // Hacky solution.
.field("line_num", &self.line_num)
.field("col_num", &self.col_num)
@@ -119,7 +124,7 @@ impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
impl<'a, R: CharRead> Lexer<'a, R> {
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
Lexer {
Self {
reader: src,
machine_st,
line_num: 0,
@@ -505,7 +510,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if hexadecimal_digit_char!(c) {
self.skip_char(c);
token.push(c);
c = try_nt!(token, self.lookahead_char());
c = match self.lookahead_char() {
Ok(c) => c,
Err(e) if e.is_unexpected_eof() => {
break;
}
Err(e) => return Err(e),
};
} else {
break;
}
@@ -530,7 +541,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if octal_digit_char!(c) {
self.skip_char(c);
token.push(c);
c = try_nt!(token, self.lookahead_char());
c = match self.lookahead_char() {
Ok(c) => c,
Err(e) if e.is_unexpected_eof() => {
break;
}
Err(e) => return Err(e),
};
} else {
break;
}
@@ -555,7 +572,13 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if binary_digit_char!(c) {
self.skip_char(c);
token.push(c);
c = try_nt!(token, self.lookahead_char());
c = match self.lookahead_char() {
Ok(c) => c,
Err(e) if e.is_unexpected_eof() => {
break;
}
Err(e) => return Err(e),
};
} else {
break;
}
@@ -632,7 +655,9 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if !token.is_empty() && token.chars().nth(1).is_none() {
if let Some(c) = token.chars().next() {
return Ok(Token::Literal(Literal::Char(c)));
return Ok(Token::Literal(Literal::Atom(
AtomCell::new_char_inlined(c).get_name(),
)));
}
}
} else {
@@ -679,12 +704,8 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
}
fn parse_integer_by_radix(
&mut self,
token: &String,
radix: u32,
) -> Result<Number, ParserError> {
i64::from_str_radix(&token, radix)
fn parse_integer_by_radix(&mut self, token: &str, radix: u32) -> Result<Number, ParserError> {
i64::from_str_radix(token, radix)
.map(|n| {
Fixnum::build_with_checked(n)
.map(Number::Fixnum)
@@ -701,7 +722,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
#[inline]
fn parse_integer(&mut self, token: &String) -> Result<Number, ParserError> {
fn parse_integer(&mut self, token: &str) -> Result<Number, ParserError> {
self.parse_integer_by_radix(token, 10)
}
@@ -785,6 +806,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
let n = parse_float_lossy(&token)?;
Ok(NumberToken::Number(Number::Float(float_alloc!(
n,
self.machine_st.arena
@@ -847,7 +869,7 @@ impl<'a, R: CharRead> Lexer<'a, R> {
}
self.get_single_quoted_char()
.map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c as i64))))
.map(|c| NumberToken::Number(Number::Fixnum(Fixnum::build_with(c))))
.or_else(|err| {
match err {
ParserError::UnexpectedChar('\'', ..) => {}
@@ -933,13 +955,14 @@ impl<'a, R: CharRead> Lexer<'a, R> {
Ok(n) => Ok(Token::Literal(n.to_literal())),
Err(_) => {
let n = parse_float_lossy(&token_string)?;
Ok(Token::Literal(Literal::Float(
float_alloc!(n, self.machine_st.arena).as_offset(),
)))
Ok(Token::Literal(Literal::F64Offset(float_alloc!(
n,
self.machine_st.arena
))))
}
},
Ok(NumberToken::Number(n)) => return Ok(Token::Literal(n.to_literal())),
Err(e) => return Err(e),
Ok(NumberToken::Number(n)) => Ok(Token::Literal(n.to_literal())),
Err(e) => Err(e),
}
}
@@ -1028,12 +1051,12 @@ impl<'a, R: CharRead> Lexer<'a, R> {
if c == '"' {
let s = self.char_code_list_token(c)?;
let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
Ok(Token::Literal(Literal::Atom(atom)))
} else {
Ok(Token::Literal(Literal::String(atom)))
Ok(Token::String(s))
};
}
+63 -64
View File
@@ -3,6 +3,7 @@ use dashu::Rational;
use crate::arena::*;
use crate::atom_table::*;
use crate::offset_table::OffsetTable;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::lexer::*;
@@ -10,6 +11,7 @@ use crate::parser::lexer::*;
use std::cell::Cell;
use std::mem;
use std::ops::Neg;
use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq)]
enum TokenType {
@@ -73,7 +75,6 @@ pub(crate) fn as_partial_string(
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
}
}
Term::Literal(_, Literal::Char(c)) => c.to_string(),
_ => {
return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
}
@@ -93,9 +94,6 @@ pub(crate) fn as_partial_string(
return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
}
}
Term::Literal(_, Literal::Char(c)) => {
string.push(*c);
}
_ => {
tail = Term::Cons(
Cell::default(),
@@ -113,7 +111,7 @@ pub(crate) fn as_partial_string(
tail_ref = tail;
}
Term::CompleteString(_, cstr) => {
string += &*cstr.as_str();
string += cstr.as_str();
tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
break;
}
@@ -124,13 +122,17 @@ pub(crate) fn as_partial_string(
}
}
match &tail {
match tail {
Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
Term::Literal(_, Literal::String(tail)) => {
string += &*tail.as_str();
Term::CompleteString(_, tail) => {
string += &tail;
Ok((string, None))
}
Term::PartialString(_, tail_string, tail) => {
string += &tail_string;
Ok((string, Some(tail)))
}
_ => Ok((string, Some(Box::new(tail)))),
}
}
@@ -237,7 +239,7 @@ pub struct Parser<'a, R> {
terms: Vec<Term>,
}
fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserError> {
pub fn read_tokens<R: CharRead>(lexer: &mut Lexer<'_, R>) -> Result<Vec<Token>, ParserError> {
let mut tokens = vec![];
loop {
@@ -263,23 +265,31 @@ fn read_tokens<R: CharRead>(lexer: &mut Lexer<R>) -> Result<Vec<Token>, ParserEr
}
tokens.reverse();
Ok(tokens)
}
fn atomize_term(atom_tbl: &AtomTable, term: &Term) -> Option<Atom> {
fn atomize_term(term: &Term) -> Option<Atom> {
match term {
Term::Literal(_, ref c) => atomize_constant(atom_tbl, *c),
&Term::Literal(_, Literal::Atom(c)) => Some(c),
_ => None,
}
}
fn atomize_constant(atom_tbl: &AtomTable, c: Literal) -> Option<Atom> {
match c {
Literal::Atom(ref name) => Some(*name),
Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())),
impl TokenType {
fn sep_to_atom(&mut self) -> Option<Atom> {
match self {
TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
TokenType::Close => Some(atom!(")")),
TokenType::OpenList => Some(atom!("[")),
TokenType::CloseList => Some(atom!("]")),
TokenType::OpenCurly => Some(atom!("{")),
TokenType::CloseCurly => Some(atom!("}")),
TokenType::HeadTailSeparator => Some(atom!("|")),
TokenType::Comma => Some(atom!(",")),
TokenType::End => Some(atom!(".")),
_ => None,
}
}
}
impl<'a, R: CharRead> Parser<'a, R> {
@@ -301,21 +311,6 @@ impl<'a, R: CharRead> Parser<'a, R> {
}
}
fn sep_to_atom(&mut self, tt: TokenType) -> Option<Atom> {
match tt {
TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
TokenType::Close => Some(atom!(")")),
TokenType::OpenList => Some(atom!("[")),
TokenType::CloseList => Some(atom!("]")),
TokenType::OpenCurly => Some(atom!("{")),
TokenType::CloseCurly => Some(atom!("}")),
TokenType::HeadTailSeparator => Some(atom!("|")),
TokenType::Comma => Some(atom!(",")),
TokenType::End => Some(atom!(".")),
_ => None,
}
}
fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
match td.tt {
TokenType::HeadTailSeparator => Some(atom!("|")),
@@ -385,9 +380,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
let tt = match token {
Token::Literal(Literal::String(s))
if self.lexer.machine_st.flags.double_quotes.is_codes() =>
{
Token::String(s) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
for c in s.as_str().chars().rev() {
@@ -395,7 +388,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
Cell::default(),
Box::new(Term::Literal(
Cell::default(),
Literal::Fixnum(Fixnum::build_with(c as i64)),
Literal::Fixnum(Fixnum::build_with(c)),
)),
Box::new(list),
);
@@ -404,10 +397,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.terms.push(list);
TokenType::Term
}
Token::Literal(Literal::String(s))
if self.lexer.machine_st.flags.double_quotes.is_chars() =>
{
self.terms.push(Term::CompleteString(Cell::default(), s));
Token::String(s) => {
debug_assert!(self.lexer.machine_st.flags.double_quotes.is_chars());
self.terms
.push(Term::CompleteString(Cell::default(), Rc::new(s)));
TokenType::Term
}
Token::Literal(c) => {
@@ -549,17 +542,13 @@ impl<'a, R: CharRead> Parser<'a, R> {
let idx = self.terms.len() - arity;
if TokenType::Term == self.stack[stack_len].tt
&& atomize_term(&self.lexer.machine_st.atom_tbl, &self.terms[idx - 1]).is_some()
&& atomize_term(&self.terms[idx - 1]).is_some()
{
self.stack.truncate(stack_len + 1);
let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
if let Some(name) = self
.terms
.pop()
.and_then(|t| atomize_term(&self.lexer.machine_st.atom_tbl, &t))
{
if let Some(name) = self.terms.pop().and_then(|t| atomize_term(&t)) {
// reduce the '.' functor to a cons cell if it applies.
if name == atom!(".") && subterms.len() == 2 {
let tail = subterms.pop().unwrap();
@@ -567,12 +556,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.terms.push(match as_partial_string(head, tail) {
Ok((string_buf, Some(tail))) => {
Term::PartialString(Cell::default(), string_buf, tail)
Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
}
Ok((string_buf, None)) => {
let atom =
AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
Term::CompleteString(Cell::default(), atom)
Term::CompleteString(Cell::default(), Rc::new(string_buf))
}
Err(term) => term,
});
@@ -754,11 +741,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.terms.push(match list {
Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
Ok((string_buf, Some(tail))) => {
Term::PartialString(Cell::default(), string_buf, tail)
Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
}
Ok((string_buf, None)) => {
let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf);
Term::CompleteString(Cell::default(), atom)
Term::CompleteString(Cell::default(), Rc::new(string_buf))
}
Err(term) => term,
},
@@ -846,7 +832,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
return false;
}
if let Some(atom) = self.sep_to_atom(self.stack[idx].tt) {
if let Some(atom) = self.stack[idx].tt.sep_to_atom() {
self.terms
.push(Term::Literal(Cell::default(), Literal::Atom(atom)));
}
@@ -967,8 +953,8 @@ impl<'a, R: CharRead> Parser<'a, R> {
}
match token {
Token::Literal(Literal::Fixnum(n)) => {
self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
Token::String(string) => {
self.shift(Token::String(string), 0, TERM);
}
Token::Literal(Literal::Integer(n)) => {
self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n))
@@ -976,21 +962,34 @@ impl<'a, R: CharRead> Parser<'a, R> {
Token::Literal(Literal::Rational(n)) => {
self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
}
Token::Literal(Literal::Float(n)) if F64Ptr::from_offset(n).is_infinite() => {
Token::Literal(Literal::F64Offset(n))
if self
.lexer
.machine_st
.arena
.f64_tbl
.get_entry(n)
.is_infinite() =>
{
return Err(ParserError::InfiniteFloat(
self.lexer.line_num,
self.lexer.col_num,
));
}
Token::Literal(Literal::Float(n)) => self.negate_number(
**n.as_ptr(),
|n, _| -n,
|n, arena| Literal::from(float_alloc!(n, arena)),
),
Token::Literal(c) => {
let atomized = atomize_constant(&self.lexer.machine_st.atom_tbl, c);
Token::Literal(Literal::F64Offset(n)) => {
let n = self.lexer.machine_st.arena.f64_tbl.get_entry(n);
if let Some(name) = atomized {
self.negate_number(
n,
|n, _| -n,
|n, arena| Literal::F64Offset(arena.f64_tbl.build_with(n)),
)
}
Token::Literal(Literal::Fixnum(n)) => {
self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
}
Token::Literal(c) => {
if let Literal::Atom(name) = c {
if !self.shift_op(name, op_dir)? {
self.shift(Token::Literal(c), 0, TERM);
}
+6 -6
View File
@@ -19,7 +19,7 @@ pub struct RawBlock<T: RawBlockTraits> {
impl<T: RawBlockTraits> RawBlock<T> {
#[inline]
fn empty_block() -> Self {
pub fn empty_block() -> Self {
RawBlock {
base: ptr::null(),
top: ptr::null(),
@@ -66,8 +66,8 @@ impl<T: RawBlockTraits> RawBlock<T> {
false
} else {
self.base = new_base;
self.top = (self.base as usize + size * 2) as *const _;
*self.ptr.get_mut() = (self.base as usize + size) as *mut _;
self.top = self.base.add(size * 2);
*self.ptr.get_mut() = self.base.add(size).cast_mut();
true
}
}
@@ -83,7 +83,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
// allocation failed
None
} else {
let allocated = (*self.ptr.get()) as usize - self.base as usize;
let allocated = (*self.ptr.get()).addr() - self.base.addr();
self.base.copy_to(new_block.base.cast_mut(), allocated);
*new_block.ptr.get_mut() = new_block.base.add(allocated).cast_mut();
Some(new_block)
@@ -93,7 +93,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
#[inline]
pub fn size(&self) -> usize {
self.top as usize - self.base as usize
self.top.addr() - self.base.addr()
}
#[inline(always)]
@@ -105,7 +105,7 @@ impl<T: RawBlockTraits> RawBlock<T> {
self.base
);
self.top as usize - (*self.ptr.get()) as usize
self.top.addr() - (*self.ptr.get()).addr()
}
pub unsafe fn alloc(&self, size: usize) -> *mut u8 {
+74 -50
View File
@@ -1,4 +1,5 @@
use crate::parser::ast::*;
use crate::parser::lexer::Lexer;
use crate::parser::parser::*;
use crate::atom_table::*;
@@ -32,9 +33,9 @@ use std::sync::Arc;
type SubtermDeque = VecDeque<(usize, usize)>;
pub(crate) fn devour_whitespace<R: CharRead>(
parser: &mut Parser<'_, R>,
lexer: &mut Lexer<'_, R>,
) -> Result<bool, ParserError> {
match parser.lexer.scan_for_layout() {
match lexer.scan_for_layout() {
Err(e) if e.is_unexpected_eof() => Ok(true),
Err(e) => Err(e),
Ok(_) => Ok(false),
@@ -80,7 +81,7 @@ impl MachineState {
};
inner.add_lines_read(num_lines_read);
write_term_to_heap(&term, &mut self.heap, &self.atom_tbl)
write_term_to_heap(&term, &mut self.heap)
}
}
@@ -295,16 +296,14 @@ impl CharRead for ReadlineStream {
pub(crate) fn write_term_to_heap(
term: &Term,
heap: &mut Heap,
atom_tbl: &AtomTable,
) -> Result<TermWriteResult, CompilationError> {
let term_writer = TermWriter::new(heap, atom_tbl);
let term_writer = TermWriter::new(heap);
term_writer.write_term_to_heap(term)
}
#[derive(Debug)]
struct TermWriter<'a, 'b> {
struct TermWriter<'a> {
heap: &'a mut Heap,
atom_tbl: &'b AtomTable,
queue: SubtermDeque,
var_dict: HeapVarDict,
}
@@ -315,12 +314,11 @@ pub struct TermWriteResult {
pub var_dict: HeapVarDict,
}
impl<'a, 'b> TermWriter<'a, 'b> {
impl<'a> TermWriter<'a> {
#[inline]
fn new(heap: &'a mut Heap, atom_tbl: &'b AtomTable) -> Self {
fn new(heap: &'a mut Heap) -> Self {
TermWriter {
heap,
atom_tbl,
queue: SubtermDeque::new(),
var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
}
@@ -338,25 +336,23 @@ impl<'a, 'b> TermWriter<'a, 'b> {
}
#[inline]
fn push_stub_addr(&mut self) {
let h = self.heap.len();
self.heap.push(heap_loc_as_cell!(h));
fn push_stub_addr(&mut self) -> Result<(), CompilationError> {
let h = self.heap.cell_len();
self.push_cell(heap_loc_as_cell!(h))
}
#[inline]
fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> {
self.heap
.push_cell(cell)
.map_err(CompilationError::FiniteMemoryInHeap)
}
fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
match term {
&TermRef::Cons(..) => list_loc_as_cell!(h),
&TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
TermRef::CompleteString(_, _, src) => {
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::PartialString(..) | TermRef::CompleteString(..) => heap_loc_as_cell!(h),
&TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
&TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
&TermRef::Clause(..) => str_loc_as_cell!(h),
@@ -364,45 +360,45 @@ impl<'a, 'b> TermWriter<'a, 'b> {
}
fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
let heap_loc = self.heap.len();
let heap_loc = self.heap.cell_len();
for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
let h = self.heap.len();
let h = self.heap.cell_len();
match &term {
&TermRef::Cons(Level::Root, ..) => {
self.queue.push_back((2, h + 1));
self.heap.push(list_loc_as_cell!(h + 1));
self.push_cell(list_loc_as_cell!(h + 1))?;
self.push_stub_addr();
self.push_stub_addr();
self.push_stub_addr()?;
self.push_stub_addr()?;
continue;
}
&TermRef::Cons(..) => {
self.queue.push_back((2, h));
self.push_stub_addr();
self.push_stub_addr();
self.push_stub_addr()?;
self.push_stub_addr()?;
}
&TermRef::Clause(Level::Root, _, name, subterms) => {
if subterms.len() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
}
self.heap.push(if subterms.is_empty() {
self.push_cell(if subterms.is_empty() {
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!(name, subterms.len());
self.heap.push(named);
self.push_cell(named)?;
for _ in 0..subterms.len() {
self.push_stub_addr();
self.push_stub_addr()?;
}
continue;
@@ -411,20 +407,20 @@ impl<'a, 'b> TermWriter<'a, 'b> {
self.queue.push_back((subterms.len(), h + 1));
let named = atom_as_cell!(name, subterms.len());
self.heap.push(named);
self.push_cell(named)?;
for _ in 0..subterms.len() {
self.push_stub_addr();
self.push_stub_addr()?;
}
}
&TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
let addr = self.term_as_addr(&term, h);
self.heap.push(addr);
self.push_cell(addr)?;
}
&TermRef::Var(Level::Root, _, ref var_ptr) => {
let addr = self.term_as_addr(&term, h);
self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
self.heap.push(addr);
self.push_cell(addr)?;
}
&TermRef::AnonVar(_) => {
if let Some((arity, site_h)) = self.queue.pop_front() {
@@ -438,25 +434,53 @@ impl<'a, 'b> TermWriter<'a, 'b> {
continue;
}
TermRef::CompleteString(_, _, src) => {
let src = src.as_str().to_owned();
put_complete_string(self.heap, &src, self.atom_tbl);
}
&TermRef::PartialString(lvl, _, src, _) => {
TermRef::CompleteString(lvl, _, src) => {
if let Level::Root = lvl {
// Var tags can't refer directly to partial strings,
// so a PStrLoc cell must be pushed.
self.heap.push(pstr_loc_as_cell!(heap_loc + 1));
self.push_stub_addr()?;
}
allocate_pstr(self.heap, src.as_str(), self.atom_tbl);
let cell = self
.heap
.allocate_cstr(src)
.map_err(CompilationError::FiniteMemoryInHeap)?;
let h = self.heap.len();
self.queue.push_back((1, h - 1));
let new_h = self.heap.cell_len();
self.push_cell(cell)?;
if !matches!(lvl, Level::Root) {
self.modify_head_of_queue(&term, new_h);
} else {
self.heap[h] = cell;
}
if let Level::Root = lvl {
continue;
}
TermRef::PartialString(lvl, _, src, _) => {
if let Level::Root = lvl {
self.push_stub_addr()?;
}
let cell = self
.heap
.allocate_pstr(src)
.map_err(CompilationError::FiniteMemoryInHeap)?;
let tail_h = self.heap.cell_len();
self.push_stub_addr()?;
if matches!(lvl, Level::Root) {
self.heap[h] = cell;
} else {
self.push_cell(cell)?;
};
self.queue.push_back((1, tail_h));
if !matches!(lvl, Level::Root) {
self.modify_head_of_queue(&term, tail_h + 1);
}
continue;
}
TermRef::Var(.., var) => {
if let Some((arity, site_h)) = self.queue.pop_front() {
+12 -10
View File
@@ -6,6 +6,8 @@ use crate::instructions::*;
use crate::iterators::*;
use crate::types::*;
use std::rc::Rc;
pub(crate) struct FactInstruction;
pub(crate) struct QueryInstruction;
@@ -14,14 +16,14 @@ pub(crate) trait CompilationTarget<'a> {
fn iter(term: &'a Term) -> Self::Iterator;
fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
fn to_constant(lvl: Level, constant: Literal, r: RegType) -> Instruction;
fn to_list(lvl: Level, r: RegType) -> Instruction;
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
fn to_void(num_subterms: usize) -> Instruction;
fn is_void_instr(instr: &Instruction) -> bool;
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction;
fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction;
fn incr_void_instr(instr: &mut Instruction);
@@ -67,8 +69,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
matches!(instr, &Instruction::UnifyVoid(_))
}
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
Instruction::GetPartialString(lvl, string, r, has_tail)
fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction {
Instruction::GetPartialString(lvl, string, r)
}
fn incr_void_instr(instr: &mut Instruction) {
@@ -125,16 +127,12 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
Instruction::PutStructure(name, arity, r)
}
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
}
fn to_list(lvl: Level, reg: RegType) -> Instruction {
Instruction::PutList(lvl, reg)
}
fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
Instruction::PutPartialString(lvl, string, r, has_tail)
fn to_pstr(lvl: Level, string: Rc<String>, r: RegType) -> Instruction {
Instruction::PutPartialString(lvl, string, r)
}
fn to_void(subterms: usize) -> Instruction {
@@ -155,6 +153,10 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
Instruction::SetConstant(HeapCellValue::from(constant))
}
fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
}
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
Instruction::PutVariable(arg, val)
}
+195 -118
View File
@@ -3,10 +3,12 @@
use crate::arena::*;
use crate::atom_table::*;
use crate::forms::*;
use crate::machine::heap::*;
use crate::machine::machine_indices::*;
use crate::machine::partial_string::PartialString;
use crate::machine::streams::*;
use crate::offset_table::*;
use crate::parser::ast::Fixnum;
use crate::parser::ast::Literal;
use std::cmp::Ordering;
use std::convert::TryFrom;
@@ -14,60 +16,67 @@ use std::fmt;
use std::mem;
use std::ops::{Add, Sub, SubAssign};
use dashu::{Integer, Rational};
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
#[bits = 6]
pub enum HeapCellValueTag {
Str = 0b000011,
Str = 0b000001,
Lis = 0b000101,
Var = 0b000111,
StackVar = 0b001001,
AttrVar = 0b001011,
PStrLoc = 0b001101,
PStrOffset = 0b001111,
Var = 0b001011,
StackVar = 0b001101,
AttrVar = 0b010001,
PStrLoc = 0b010011,
// constants.
Cons = 0b0,
F64 = 0b010001,
Fixnum = 0b010011,
Char = 0b010101,
Atom = 0b010111,
PStr = 0b011001,
CStr = 0b011011,
CutPoint = 0b011111,
F64Offset = 0b010101,
Fixnum = 0b011001,
CodeIndexOffset = 0b011011,
Atom = 0b011111,
CutPoint = 0b011101,
// trail elements.
TrailedHeapVar = 0b100001,
TrailedStackVar = 0b100011,
TrailedAttrVar = 0b100101,
TrailedAttrVarListLink = 0b101001,
TrailedAttachedValue = 0b101011,
TrailedBlackboardEntry = 0b101101,
TrailedBlackboardOffset = 0b110001,
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
#[bits = 6]
pub enum HeapCellValueView {
Str = 0b000011,
Str = 0b000001,
Lis = 0b000101,
Var = 0b000111,
StackVar = 0b001001,
AttrVar = 0b001011,
PStrLoc = 0b001101,
PStrOffset = 0b001111,
Var = 0b001011,
StackVar = 0b001101,
AttrVar = 0b010001,
PStrLoc = 0b010011,
// constants.
Cons = 0b0,
F64 = 0b010001,
Fixnum = 0b010011,
Char = 0b010101,
Atom = 0b010111,
PStr = 0b011001,
CStr = 0b011011,
CutPoint = 0b011111,
F64Offset = 0b010101,
Fixnum = 0b011001,
CodeIndexOffset = 0b011011,
Atom = 0b011111,
CutPoint = 0b011101,
// trail elements.
TrailedHeapVar = 0b101111,
TrailedStackVar = 0b101011,
TrailedAttrVar = 0b100001,
TrailedAttrVarListLink = 0b100011,
TrailedAttachedValue = 0b100101,
TrailedBlackboardEntry = 0b100111,
TrailedBlackboardOffset = 0b110011,
TrailedHeapVar = 0b100001,
TrailedStackVar = 0b100011,
TrailedAttrVar = 0b100101,
TrailedAttrVarListLink = 0b101001,
TrailedAttachedValue = 0b101011,
TrailedBlackboardEntry = 0b101101,
TrailedBlackboardOffset = 0b110001,
}
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[bits = 1]
pub enum ConsPtrMaskTag {
Cons = 0b0,
Atom = 0b1,
}
#[bitfield]
@@ -84,7 +93,7 @@ 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_ptr(ptr.expose_provenance() as u64)
.with_f(false)
.with_m(false)
.with_tag(tag)
@@ -93,7 +102,7 @@ impl ConsPtr {
#[inline(always)]
pub fn as_ptr(self) -> *mut u8 {
let addr: u64 = self.ptr();
addr as usize as *mut _
std::ptr::with_exposed_provenance_mut(addr as usize)
}
#[inline(always)]
@@ -105,9 +114,9 @@ impl ConsPtr {
#[derive(BitfieldSpecifier, Copy, Clone, Debug)]
#[bits = 6]
pub(crate) enum RefTag {
HeapCell = 0b000111,
StackCell = 0b001001,
AttrVar = 0b001011,
HeapCell = 0b001011,
StackCell = 0b001101,
AttrVar = 0b010001,
}
#[bitfield]
@@ -245,15 +254,16 @@ pub struct HeapCellValue {
val: B56,
f: bool,
m: bool,
#[allow(dead_code)]
tag: HeapCellValueTag,
}
impl fmt::Debug for HeapCellValue {
fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
match self.get_tag() {
HeapCellValueTag::F64 => f
HeapCellValueTag::F64Offset => f
.debug_struct("HeapCellValue")
.field("tag", &HeapCellValueTag::F64)
.field("tag", &HeapCellValueTag::F64Offset)
.field("offset", &self.get_value())
.field("m", &self.m())
.field("f", &self.f())
@@ -279,16 +289,6 @@ impl fmt::Debug for HeapCellValue {
.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)
@@ -300,20 +300,89 @@ impl fmt::Debug for HeapCellValue {
}
}
impl From<Literal> for HeapCellValue {
#[inline]
fn from(literal: Literal) -> Self {
match literal {
Literal::Atom(name) => atom_as_cell!(name),
Literal::CodeIndexOffset(idx) => HeapCellValue::from(idx),
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::F64Offset(f) => HeapCellValue::from(f),
}
}
}
impl TryFrom<HeapCellValue> for Literal {
type Error = ();
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::Fixnum, n) => {
Ok(Literal::Fixnum(n))
}
(HeapCellValueTag::F64Offset, f) => {
Ok(Literal::F64Offset(f))
}
(HeapCellValueTag::CodeIndexOffset, idx) => {
Ok(Literal::CodeIndexOffset(idx))
}
(HeapCellValueTag::Cons, cons_ptr) => {
match_untyped_arena_ptr!(cons_ptr,
(ArenaHeaderTag::Integer, n) => {
Ok(Literal::Integer(n))
}
(ArenaHeaderTag::Rational, n) => {
Ok(Literal::Rational(n))
}
_ => {
Err(())
}
)
}
_ => {
Err(())
}
)
}
}
impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue
where
T::Payload: Sized,
{
#[inline]
fn from(arena_ptr: TypedArenaPtr<T>) -> HeapCellValue {
HeapCellValue::from(arena_ptr.header_ptr() as u64)
HeapCellValue::from(arena_ptr.header_ptr().expose_provenance() as u64)
}
}
impl From<F64Ptr> for HeapCellValue {
impl From<F64Offset> for HeapCellValue {
#[inline]
fn from(f64_ptr: F64Ptr) -> HeapCellValue {
HeapCellValue::build_with(HeapCellValueTag::F64, f64_ptr.as_offset().to_u64())
fn from(f64_offset: F64Offset) -> HeapCellValue {
HeapCellValue::build_with(HeapCellValueTag::F64Offset, f64_offset.to_u64())
}
}
impl From<CodeIndexOffset> for HeapCellValue {
#[inline]
fn from(code_index_offset: CodeIndexOffset) -> HeapCellValue {
HeapCellValue::build_with(
HeapCellValueTag::CodeIndexOffset,
code_index_offset.to_u64(),
)
}
}
@@ -321,7 +390,7 @@ impl From<ConsPtr> for HeapCellValue {
#[inline(always)]
fn from(cons_ptr: ConsPtr) -> HeapCellValue {
HeapCellValue::from_bytes(
ConsPtr::from(cons_ptr.as_ptr() as u64)
ConsPtr::from(cons_ptr.as_ptr().expose_provenance() as u64)
.with_tag(ConsPtrMaskTag::Cons)
.with_m(false)
.into_bytes(),
@@ -354,19 +423,15 @@ impl HeapCellValue {
}
#[inline]
pub fn is_string_terminator(mut self, heap: &[HeapCellValue]) -> bool {
use crate::machine::heap::*;
pub fn is_string_terminator(mut self, heap: &impl SizedHeap) -> bool {
loop {
return read_heap_cell!(self,
(HeapCellValueTag::Atom, (name, arity)) => {
name == atom!("[]") && arity == 0
}
(HeapCellValueTag::CStr) => {
true
}
(HeapCellValueTag::PStrLoc, h) => {
self = heap[h];
let HeapStringScan { tail_idx, .. } = heap.scan_slice_to_str(h);
self = heap[tail_idx];
continue;
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
@@ -379,9 +444,6 @@ impl HeapCellValue {
self = cell;
continue;
}
(HeapCellValueTag::PStrOffset, pstr_offset) => {
heap[pstr_offset].get_tag() == HeapCellValueTag::CStr
}
_ => {
false
}
@@ -399,16 +461,12 @@ impl HeapCellValue {
| HeapCellValueTag::StackVar
| HeapCellValueTag::AttrVar
| HeapCellValueTag::PStrLoc
| HeapCellValueTag::PStrOffset
)
}
#[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;
@@ -426,11 +484,9 @@ impl HeapCellValue {
pub fn is_constant(self) -> bool {
match self.get_tag() {
HeapCellValueTag::Cons
| HeapCellValueTag::F64
| HeapCellValueTag::F64Offset
| HeapCellValueTag::Fixnum
| HeapCellValueTag::CutPoint
| HeapCellValueTag::Char
| HeapCellValueTag::CStr => true,
| HeapCellValueTag::CutPoint => true,
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() == 0,
_ => false,
}
@@ -442,16 +498,12 @@ impl HeapCellValue {
}
#[inline]
pub fn is_compound(self, heap: &[HeapCellValue]) -> bool {
pub fn is_compound(self, heap: &Heap) -> bool {
match self.get_tag() {
HeapCellValueTag::Str => {
cell_as_atom_cell!(heap[self.get_value() as usize]).get_arity() > 0
}
HeapCellValueTag::Lis
| HeapCellValueTag::CStr
| HeapCellValueTag::PStr
| HeapCellValueTag::PStrLoc
| HeapCellValueTag::PStrOffset => true,
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => true,
HeapCellValueTag::Atom => cell_as_atom_cell!(self).get_arity() > 0,
_ => false,
}
@@ -502,6 +554,7 @@ impl HeapCellValue {
match self.tag_or_err() {
Ok(tag) => tag,
Err(_) => match ConsPtr::from_bytes(self.into_bytes()).tag() {
ConsPtrMaskTag::Atom => HeapCellValueTag::Atom,
ConsPtrMaskTag::Cons => HeapCellValueTag::Cons,
},
}
@@ -509,16 +562,8 @@ impl HeapCellValue {
#[inline]
pub fn to_atom(self) -> Option<Atom> {
match self.tag() {
HeapCellValueTag::Atom => Some(Atom::from(self.val() << 3)),
_ => None,
}
}
#[inline]
pub fn to_pstr(self) -> Option<PartialString> {
match self.tag() {
HeapCellValueTag::PStr => Some(PartialString::from(Atom::from(self.val() << 3))),
match self.get_tag() {
HeapCellValueTag::Atom => Some(AtomCell::from_bytes(self.into_bytes()).get_name()),
_ => None,
}
}
@@ -531,6 +576,16 @@ impl HeapCellValue {
}
}
// FIXME: someone that knows this better should check if this can be split into `to_fixnum_unchecked` and `to_cut_point_unchecked` assuming thats always unambigusly knowable
#[inline]
pub unsafe fn to_fixnum_or_cut_point_unchecked(self) -> Fixnum {
debug_assert!(matches!(
self.get_tag(),
HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint
));
Fixnum::from_bytes(self.into_bytes())
}
#[inline]
pub fn from_ptr_addr(ptr_bytes: usize) -> Self {
HeapCellValue::from_bytes((ptr_bytes as u64).to_ne_bytes())
@@ -593,28 +648,42 @@ impl HeapCellValue {
}
}
pub fn order_category(self, heap: &[HeapCellValue]) -> Option<TermOrderCategory> {
match Number::try_from(self).ok() {
Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => {
pub fn order_category(self, heap: &Heap) -> Option<TermOrderCategory> {
read_heap_cell!(self,
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Integer, _n) => {
Some(TermOrderCategory::Integer)
}
Some(Number::Float(_)) => Some(TermOrderCategory::FloatingPoint),
None => match self.get_tag() {
HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => {
(ArenaHeaderTag::Rational, _n) => {
Some(TermOrderCategory::Integer)
}
_ => {
None
}
)
}
(HeapCellValueTag::F64Offset) => {
Some(TermOrderCategory::FloatingPoint)
}
(HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint) => {
Some(TermOrderCategory::Integer)
}
(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 {
(HeapCellValueTag::Atom, (_name, arity)) => {
Some(if arity > 0 {
TermOrderCategory::Compound
} else {
TermOrderCategory::Atom
}),
HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => {
})
}
(HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => {
Some(TermOrderCategory::Compound)
}
HeapCellValueTag::Str => {
let value = heap[self.get_value() as usize];
let arity = cell_as_atom_cell!(value).get_arity();
(HeapCellValueTag::Str, s) => {
let arity = cell_as_atom_cell!(heap[s]).get_arity();
if arity == 0 {
Some(TermOrderCategory::Atom)
@@ -622,9 +691,10 @@ impl HeapCellValue {
Some(TermOrderCategory::Compound)
}
}
_ => None,
},
_ => {
None
}
)
}
#[inline(always)]
@@ -640,7 +710,7 @@ impl HeapCellValue {
}
}
const_assert!(mem::size_of::<HeapCellValue>() == 8);
const_assert!(size_of::<HeapCellValue>() == 8);
#[bitfield]
#[repr(u64)]
@@ -666,21 +736,21 @@ const_assert!(mem::size_of::<UntypedArenaPtr>() == 8);
impl From<*const ArenaHeader> for UntypedArenaPtr {
#[inline]
fn from(ptr: *const ArenaHeader) -> UntypedArenaPtr {
UntypedArenaPtr::build_with(ptr as usize)
UntypedArenaPtr::build_with(ptr.expose_provenance())
}
}
impl From<*const IndexPtr> for UntypedArenaPtr {
#[inline]
fn from(ptr: *const IndexPtr) -> UntypedArenaPtr {
UntypedArenaPtr::build_with(ptr as usize)
UntypedArenaPtr::build_with(ptr.expose_provenance())
}
}
impl From<UntypedArenaPtr> for *const ArenaHeader {
#[inline]
fn from(ptr: UntypedArenaPtr) -> *const ArenaHeader {
ptr.get_ptr() as *const ArenaHeader
ptr.get_ptr().cast::<ArenaHeader>()
}
}
@@ -693,21 +763,21 @@ impl UntypedArenaPtr {
#[inline]
pub fn get_ptr(self) -> *const u8 {
let addr: u64 = self.ptr();
addr as usize as *const u8
std::ptr::with_exposed_provenance(addr as usize)
}
#[inline]
pub fn get_tag(self) -> ArenaHeaderTag {
unsafe {
debug_assert!(!self.get_ptr().is_null());
let header = *(self.get_ptr() as *const ArenaHeader);
let header = *self.get_ptr().cast::<ArenaHeader>();
header.get_tag()
}
}
#[inline]
pub fn payload_offset(self) -> *const u8 {
unsafe { self.get_ptr().add(mem::size_of::<ArenaHeader>()) }
unsafe { self.get_ptr().add(size_of::<ArenaHeader>()) }
}
/// # Safety
@@ -734,12 +804,14 @@ impl Add<usize> for HeapCellValue {
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() as usize + rhs) as u64)
}
tag @ HeapCellValueTag::PStrLoc => {
let value = (self.get_value() as usize + heap_index!(rhs)) as u64;
HeapCellValue::build_with(tag, value)
}
_ => self,
}
}
@@ -752,12 +824,14 @@ impl Sub<usize> for HeapCellValue {
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() as usize - rhs) as u64)
}
tag @ HeapCellValueTag::PStrLoc => {
let value = self.get_value() as usize - heap_index!(rhs);
HeapCellValue::build_with(tag, value as u64)
}
_ => self,
}
}
@@ -778,12 +852,15 @@ impl Sub<i64> for HeapCellValue {
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.unsigned_abs())
}
tag @ HeapCellValueTag::PStrLoc => {
let value =
self.get_value() as usize + heap_index!(rhs.unsigned_abs() as usize);
HeapCellValue::build_with(tag, value as u64)
}
_ => self,
}
} else {
+1
View File
@@ -1,3 +1,4 @@
use crate::forms::GenContext;
use crate::parser::ast::*;
use bit_set::*;
+11
View File
@@ -0,0 +1,11 @@
:- use_module(library(sgml)).
test :-
load_html("<!DOCTYPE html><html><head><title>Hello!</title></head></html>", Es, []),
write(Es),
load_html("<!DOCTYPE html><html><head><title>Hello!</title><!-- comment --></head></html>", Es2, []),
write(Es2),
load_html("<!", Es3, []),
write(Es3).
:- initialization(test).
@@ -27,6 +27,7 @@ use_module(library(ordsets)).
use_module(library(os)).
use_module(library(pairs)).
use_module(library(pio)).
use_module(library(process)).
use_module(library(queues)).
use_module(library(random)).
use_module(library(reif)).
@@ -45,3 +45,4 @@
true.
true.
true.
true.
+59
View File
@@ -0,0 +1,59 @@
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid, process(P)]), process_kill(P), halt'
use_module(library(process)),process_create([],[],[invalid,process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [invalid(_Var), process(P)]), process_kill(P), halt'
use_module(library(process)),process_create([],[],[invalid(_Var),process(P)]),process_kill(P),halt causes: error(domain_error(process_create_option,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(null), stdin(null), process(P)]), process_kill(P), halt'
use_module(library(process)),process_create([],[],[stdin(null),stdin(null),process(P)]),process_kill(P),halt causes: error(domain_error(non_duplicate_options,stdin),[predicate-process_create/3,predicate-check_options/3,predicate-must_be_known_options/3])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [env([]), environment([]), process(P)]), process_kill(P), halt'
use_module(library(process)),process_create([],[],[env([]),environment([]),process(P)]),process_kill(P),halt causes: error(domain_error(non_conflicting_options,[env([]),environment([])]),[predicate-process_create/3,predicate-check_options/3,predicate-extract_options/2])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(pid, _Status, [invalid(_Var), timeout(0)]), halt'
use_module(library(process)),process_wait(pid,_Status,[invalid(_Var),timeout(0)]),halt causes: error(domain_error(process_wait_option,invalid),[predicate-process_wait/3,predicate-check_options/3,predicate-must_be_known_options/3])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("", [], [stdin(invalid), process(P)]), process_kill(P), halt'
use_module(library(process)),process_create([],[],[stdin(invalid),process(P)]),process_kill(P),halt causes: error(domain_error(stdio_spec,invalid),[predicate-process_create/3,predicate-check_options/3,predicate-extract_options/2,predicate-valid_stdio/1])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_wait(50, _Status), halt'
use_module(library(process)),process_wait(50,_Status),halt causes: error(type_error(process,50),[predicate-process_wait/2,predicate-process_wait/3|process_wait/3])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_kill(50), halt'
use_module(library(process)),process_kill(50),halt causes: error(type_error(process,50),[predicate-process_kill/1|process_kill/1])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_id(50,_Pid), halt'
use_module(library(process)),process_id(50,_Pid),halt causes: error(type_error(process,50),[predicate-process_id/2|process_id/2])
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_release(50), halt'
use_module(library(process)),process_release(50),halt causes: error(type_error(process,50),[predicate-process_release/1,predicate-process_wait/2,predicate-process_wait/3|process_wait/3])
```
+14
View File
@@ -0,0 +1,14 @@
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("false", [], [process(P)]), process_wait(P, exit(1)), halt'
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("sh", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, exit(1)), halt'
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("sh", ["-c", "sleep 5"], [process(P), stdout(null)]), process_kill(P), process_wait(P, killed(9)), halt'
```
+9
View File
@@ -0,0 +1,9 @@
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), process_create("cmd", ["/C", "exit", "1"], [process(P)]), process_wait(P, exit(1)), halt'
```
```trycmd
$ scryer-prolog -f --no-add-history -g 'use_module(library(process)), use_module(library(format)), process_create("cmd", [], [process(P), stdout(null), stdin(pipe(S))]), format(S, "exit 1~n", []), process_wait(P, exit(1)), halt'
```
+6
View File
@@ -20,6 +20,12 @@ fn issue2588_load_html() {
load_module_test("tests-pl/issue2588.pl", "[element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]])]),element(body,[],[])])]");
}
#[test]
#[cfg_attr(miri, ignore = "unsupported operation when isolation is enabled")]
fn issue2949_load_html() {
load_module_test("tests-pl/issue2949.pl", "[doctype([h,t,m,l]),element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]])]),element(body,[],[])])][doctype([h,t,m,l]),element(html,[],[element(head,[],[element(title,[],[[H,e,l,l,o,!]]),comment([ ,c,o,m,m,e,n,t, ])]),element(body,[],[])])][comment([]),element(html,[],[element(head,[],[]),element(body,[],[])])]");
}
// issue #2361
#[serial]
#[test]
+12 -1
View File
@@ -19,9 +19,20 @@ mod src_tests;
ignore = "miri isolation, unsupported operation: can't call foreign function"
)]
fn cli_tests() {
trycmd::TestCases::new()
let cases = trycmd::TestCases::new();
cases
.default_bin_name("scryer-prolog")
.case("tests/scryer/cli/issues/*.toml")
.case("tests/scryer/cli/src_tests/*.toml")
.case("tests/scryer/cli/src_tests/*.md");
#[cfg(windows)]
{
cases.case("tests/scryer/cli/windows/*.md");
}
#[cfg(unix)]
{
cases.case("tests/scryer/cli/unix/*.md");
}
}