From: Mark Thom Date: Tue, 14 May 2024 00:00:56 +0000 (-0600) Subject: introduce bespoke Heap type for in-heap partial strings X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=461e22023069042c2791a8018df00ccefb6ea954;p=scryer-prolog.git introduce bespoke Heap type for in-heap partial strings --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e0bde90..70f8d1a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,6 @@ jobs: # 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.77", 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: diff --git a/build/instructions_template.rs b/build/instructions_template.rs index 84d0abad..18102af8 100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@ -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; @@ -622,7 +624,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, 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 +647,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, 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 +877,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 +888,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 +900,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 +915,7 @@ fn generate_instruction_preface() -> TokenStream { functor!(atom!("intermediate"), [fixnum(i)]) } ArithmeticTerm::Number(n) => { - functor!(atom!("number"), [cell(HeapCellValue::from((n, arena)))]) + functor!(atom!("number"), [number(n, arena)]) } } } @@ -996,7 +1000,7 @@ fn generate_instruction_preface() -> TokenStream { IndexingCodePtr, IndexingCodePtr, ), - SwitchOnConstant(IndexMap), + SwitchOnConstant(IndexMap), SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>), } @@ -1016,7 +1020,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 +1034,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!()); - - functor!( - atom!("switch_on_constant"), - [str(orig_h, 0)], - [key_value_list_stub] + variadic_functor( + atom!("switch_on_constants"), + 1, + constants.iter().map(|(c, ptr)| { + functor!( + atom!(":"), + [cell((c.clone())), 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 +1100,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 +1119,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; @@ -1170,7 +1133,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 +1141,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 +1205,6 @@ fn generate_instruction_preface() -> TokenStream { pub fn enqueue_functors( &self, - mut h: usize, arena: &mut Arena, functors: &mut Vec, ) { @@ -1251,33 +1213,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 +1249,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 +1278,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 +1322,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 +1485,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 +1537,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 +1563,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 +1589,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 +1615,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 +1628,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 +1642,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 | @@ -1920,14 +1874,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 | @@ -2158,14 +2112,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 +2134,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 +2199,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)]) @@ -3204,14 +3132,6 @@ pub fn generate_instructions_rs() -> TokenStream { ) } - pub fn name(&self) -> Atom { - match self { - #( - #clause_type_name_arms, - )* - } - } - pub fn is_inlined(name: Atom, arity: usize) -> bool { matches!((name, arity), #(#is_inlined_arms)|* diff --git a/build/static_string_indexing.rs b/build/static_string_indexing.rs index c3d1701c..62e06f46 100644 --- a/build/static_string_indexing.rs +++ b/build/static_string_indexing.rs @@ -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 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { + 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::*; @@ -149,11 +161,26 @@ 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 indices: Vec = 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 = visitor.static_strs.len(); - let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); + let static_strs_len = static_strs.len(); // visitor.static_strs.len(); + //let static_strs: &Vec<_> = &visitor.static_strs.into_iter().collect(); quote! { static STRINGS: [&str; #static_strs_len] = [ @@ -163,11 +190,11 @@ 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 } };)* } 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 } },)* }; } } diff --git a/src/allocator.rs b/src/allocator.rs index 27def1d6..735b013f 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -2,6 +2,7 @@ use crate::parser::ast::*; use crate::forms::*; use crate::instructions::*; +use crate::machine::heap::Heap; use crate::targets::*; pub(crate) trait Allocator { @@ -45,7 +46,7 @@ pub(crate) trait Allocator { fn reset(&mut self); fn reset_arg(&mut self, arg_num: usize); - fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize); + fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize); fn reset_contents(&mut self); fn advance_arg(&mut self); diff --git a/src/arena.rs b/src/arena.rs index 113ff6f0..f9c2f274 100644 --- a/src/arena.rs +++ b/src/arena.rs @@ -905,7 +905,7 @@ mod tests { 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; @@ -988,7 +988,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() { @@ -1094,31 +1094,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)); @@ -1196,8 +1171,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!() } ); @@ -1206,8 +1181,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!() } ); diff --git a/src/arithmetic.rs b/src/arithmetic.rs index 9253ee49..f1256b66 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -9,7 +9,6 @@ use crate::instructions::*; use crate::iterators::*; use crate::machine::disjuncts::*; use crate::machine::stack::Stack; -use crate::parser::ast::FocusedHeap; use crate::targets::QueryInstruction; use crate::types::*; @@ -55,103 +54,6 @@ impl Default for ArithmeticTerm { pub(crate) type ArithCont = (CodeDeque, Option); -/* -#[derive(Debug)] -pub(crate) struct ArithInstructionIterator<'a> { - state_stack: Vec>, -} - -impl<'a> ArithInstructionIterator<'a> { - fn push_subterm(&mut self, lvl: Level, term: &'a Term) { - self.state_stack - .push(TermIterState::subterm_to_state(lvl, term)); - } - - fn from(term: &'a Term) -> Result { - let state = match term { - Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar), - Term::Clause(cell, name, terms) => { - TermIterState::Clause(Level::Shallow, 0, cell, *name, terms) - } - Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons), - Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => { - return Err(ArithmeticError::NonEvaluableFunctor( - Literal::Atom(atom!(".")), - 2, - )) - } - Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()), - }; - - Ok(ArithInstructionIterator { - state_stack: vec![state], - }) - } -} - -#[derive(Debug)] -pub(crate) enum ArithTermRef<'a> { - Literal(&'a Literal), - Op(Atom, usize), // name, arity. - Var(Level, &'a Cell, VarPtr), -} - -impl<'a> Iterator for ArithInstructionIterator<'a> { - type Item = Result, ArithmeticError>; - - fn next(&mut self) -> Option { - while let Some(iter_state) = self.state_stack.pop() { - match iter_state { - TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)), - TermIterState::Clause(lvl, child_num, cell, name, subterms) => { - let arity = subterms.len(); - - if child_num == arity { - return Some(Ok(ArithTermRef::Op(name, arity))); - } else { - self.state_stack.push(TermIterState::Clause( - lvl, - child_num + 1, - cell, - name, - subterms, - )); - - self.push_subterm(lvl.child_level(), &subterms[child_num]); - } - } - TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(c))), - TermIterState::Var(lvl, cell, var_ptr) => { - return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr))); - } - _ => { - return Some(Err(ArithmeticError::NonEvaluableFunctor( - Literal::Atom(atom!(".")), - 2, - ))); - } - }; - } - - None - } -} - -pub(crate) trait ArithmeticTermIter<'a> { - type Iter: Iterator, ArithmeticError>>; - - fn iter(self) -> Result; -} - -impl<'a> ArithmeticTermIter<'a> for &'a Term { - type Iter = ArithInstructionIterator<'a>; - - fn iter(self) -> Result { - ArithInstructionIterator::from(self) - } -} -*/ - #[derive(Debug)] pub(crate) struct ArithmeticEvaluator<'a> { marker: &'a mut DebrayAllocator, @@ -159,23 +61,45 @@ pub(crate) struct ArithmeticEvaluator<'a> { interm_c: usize, } -fn push_literal(interm: &mut Vec, 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::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)), - )), - Literal::Atom(name) if name == atom!("pi") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(std::f64::consts::PI)), - )), - Literal::Atom(name) if name == atom!("epsilon") => interm.push(ArithmeticTerm::Number( - Number::Float(OrderedFloat(f64::EPSILON)), - )), - _ => return Err(ArithmeticError::NonEvaluableFunctor(HeapCellValue::from(c), 0)), - } +fn push_literal(interm: &mut Vec, c: HeapCellValue) -> Result<(), ArithmeticError> { + read_heap_cell!(c, + (HeapCellValueTag::Fixnum, n) => { + interm.push(ArithmeticTerm::Number(Number::Fixnum(n))) + } + (HeapCellValueTag::Cons, cons_ptr) => { + match_untyped_arena_ptr!(cons_ptr, + (ArenaHeaderTag::Integer, n) => { + interm.push(ArithmeticTerm::Number(Number::Integer(n))); + } + (ArenaHeaderTag::Rational, n) => { + interm.push(ArithmeticTerm::Number(Number::Rational(n))); + } + _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)), + ); + } + (HeapCellValueTag::Atom, (name, arity)) => { + debug_assert_eq!(arity, 0); + + match name { + atom!("pi") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::consts::PI)), + )), + atom!("epsilon") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::EPSILON)), + )), + atom!("e") => interm.push(ArithmeticTerm::Number( + Number::Float(OrderedFloat(std::f64::consts::E)), + )), + _ => unreachable!(), + } + } + (HeapCellValueTag::F64, n) => { + interm.push(ArithmeticTerm::Number(Number::Float(*n))); + } + _ => { + return Err(ArithmeticError::NonEvaluableFunctor(c, 0)); + } + ); Ok(()) } @@ -313,7 +237,7 @@ impl<'a> ArithmeticEvaluator<'a> { pub(crate) fn compile_is( &mut self, - src: &mut FocusedHeap, + src: &mut FocusedHeapRefMut, term_loc: usize, context: GenContext, arg: usize, @@ -360,16 +284,13 @@ impl<'a> ArithmeticEvaluator<'a> { } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { - push_literal(&mut self.interm, Literal::Atom(name))?; + push_literal(&mut self.interm, atom_as_cell!(name))?; } else { code.push_back(self.instr_from_clause(name, arity)?); } } _ => { - match Literal::try_from(term) { - Ok(lit) => push_literal(&mut self.interm, lit)?, - _ => return Err(ArithmeticError::NonEvaluableFunctor(term, 0)), - } + push_literal(&mut self.interm, term)?; } ); } diff --git a/src/atom_table.rs b/src/atom_table.rs index 60b0b3c7..7c23349d 100644 --- a/src/atom_table.rs +++ b/src/atom_table.rs @@ -23,15 +23,117 @@ 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::()); +const_assert!(mem::size_of::() == 8); + +const_assert!(INLINED_ATOM_MAX_LEN < mem::size_of::()); +const_assert!(mem::size_of::() == 8); + +impl AtomCell { + #[inline] + pub fn new_static(index: u64) -> Self { + // upper 23 bits of index must be 0 + debug_assert!(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] + pub 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 { + 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::() == 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!("[]"); + impl<'a> From<&'a Atom> for Atom { #[inline] fn from(atom: &'a Atom) -> Self { @@ -39,17 +141,6 @@ impl<'a> From<&'a Atom> for Atom { } } -impl From for Atom { - #[inline] - fn from(value: bool) -> Self { - if value { - atom!("true") - } else { - atom!("false") - } - } -} - impl indexmap::Equivalent for str { fn equivalent(&self, key: &Atom) -> bool { &*key.as_str() == self @@ -120,24 +211,25 @@ impl Hash for Atom { #[inline] fn hash(&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), } -impl AtomString<'_> { - pub fn map(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)), - } +fn inlined_to_str<'a>(bytes: &'a [u8;8]) -> &'a str { + // allow the '\0\' atom to be represented as the 0-valued inlined atom + let slice_len = if bytes[0] == 0 { + 1 + } else { + bytes.iter().position(|&b| b == 0u8).unwrap_or(INLINED_ATOM_MAX_LEN) + }; + + unsafe { + str::from_utf8_unchecked(&bytes[..slice_len]) } } @@ -158,6 +250,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 +268,32 @@ impl rustyline::completion::Candidate for AtomString<'_> { } impl Atom { + #[inline] + fn new_inlined(string: &str) -> Self { + AtomCell::new_inlined(string, 0).get_name() + } + #[inline(always)] - pub fn is_static(self) -> bool { - (self.index as usize) < STRINGS.len() << 3 + 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)] - pub fn as_ptr(self) -> Option> { + fn as_ptr(self) -> Option> { if self.is_static() { None } else { @@ -192,7 +304,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 +320,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 +335,6 @@ impl Atom { self.len() == 0 } - #[inline(always)] - pub fn flat_index(self) -> u64 { - self.index >> 3 - } - pub fn as_char(self) -> Option { let s = self.as_str(); let mut it = s.chars(); @@ -239,14 +349,26 @@ impl Atom { } } + #[inline] + fn inlined_str<'a>(&self) -> Option> { + 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 +464,10 @@ impl AtomTable { } pub fn build_with(atom_table: &AtomTable, string: &str) -> Atom { + if 0 < string.len() && string.len() <= INLINED_ATOM_MAX_LEN { + return Atom::new_inlined(string); + } + loop { let mut block_epoch = atom_table.inner.read(); let mut table_epoch = block_epoch.table.read(); @@ -390,9 +516,14 @@ impl AtomTable { 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 as usize - 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); @@ -410,18 +541,21 @@ impl AtomTable { unsafe impl Send for AtomTable {} unsafe impl Sync for AtomTable {} +/* #[bitfield] #[repr(u64)] #[derive(Copy, Clone, Debug)] pub struct AtomCell { - name: B46, + name: B48, arity: B10, #[allow(unused)] f: bool, #[allow(unused)] m: bool, #[allow(unused)] - tag: B6, + inlined: bool, + #[allow(unused)] + tag: B3, } impl AtomCell { @@ -463,3 +597,4 @@ impl AtomCell { (Atom::from((self.get_index() as u64) << 3), self.get_arity()) } } +*/ diff --git a/src/codegen.rs b/src/codegen.rs index 06d8c8e4..4b27e448 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -7,7 +7,7 @@ use crate::forms::*; use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; -use crate::machine::heap::{heap_bound_deref, heap_bound_store}; +use crate::machine::heap::*; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -16,7 +16,6 @@ use crate::variable_records::*; use crate::machine::disjuncts::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::CodeIndex; -use crate::machine::machine_state::pstr_loc_and_offset; use crate::machine::stack::Stack; use fxhash::FxBuildHasher; @@ -24,6 +23,7 @@ use indexmap::IndexMap; use indexmap::IndexSet; use std::collections::VecDeque; +use std::rc::Rc; #[derive(Debug)] pub struct BranchCodeStack { @@ -274,33 +274,12 @@ impl CodeGenSettings { } #[derive(Debug)] -pub(crate) struct CodeGenerator<'a> { - pub(crate) atom_tbl: &'a AtomTable, +pub(crate) struct CodeGenerator { marker: DebrayAllocator, settings: CodeGenSettings, pub(crate) skeleton: PredicateSkeleton, } -fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { - let subterm = heap[subterm_loc]; - - if subterm.is_ref() { - let subterm = heap_bound_deref(heap, subterm); - let subterm_loc = subterm.get_value() as usize; - let subterm = heap_bound_store(heap, subterm); - - let subterm_loc = if subterm.is_ref() { - subterm.get_value() as usize - } else { - subterm_loc - }; - - (subterm_loc, subterm) - } else { - (subterm_loc, subterm) - } -} - impl DebrayAllocator { pub(crate) fn mark_non_callable( &mut self, @@ -337,7 +316,7 @@ trait AddToFreeList<'a, Target: CompilationTarget<'a>> { fn add_subterm_to_free_list(&mut self, r: RegType); } -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); } @@ -345,7 +324,7 @@ impl<'a, 'b> AddToFreeList<'a, FactInstruction> for CodeGenerator<'b> { fn add_subterm_to_free_list(&mut self, _r: RegType) {} } -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) {} @@ -357,19 +336,19 @@ impl<'a, 'b> AddToFreeList<'a, QueryInstruction> for CodeGenerator<'b> { fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( index_ptrs: &IndexMap, - heap: &[HeapCellValue], + heap: &Heap, arity: usize, heap_loc: usize, ) -> Option { match fetch_index_ptr(heap, arity, heap_loc) { Some(index_ptr) => { - let subterm = Literal::CodeIndex(index_ptr); + let subterm = HeapCellValue::from(index_ptr); return Some(Target::constant_subterm(subterm)); } None => { // if Level::Shallow == lvl { if let Some(index_ptr) = index_ptrs.get(&heap_loc) { - let subterm = Literal::CodeIndex(*index_ptr); + let subterm = HeapCellValue::from(*index_ptr); return Some(Target::constant_subterm(subterm)); } // } @@ -379,10 +358,9 @@ fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>( None } -impl<'b> CodeGenerator<'b> { - pub(crate) fn new(atom_tbl: &'b AtomTable, settings: CodeGenSettings) -> Self { +impl CodeGenerator { + pub(crate) fn new(settings: CodeGenSettings) -> Self { CodeGenerator { - atom_tbl, marker: DebrayAllocator::new(), settings, skeleton: PredicateSkeleton::new(), @@ -445,33 +423,26 @@ impl<'b> CodeGenerator<'b> { None } - (HeapCellValueTag::Atom, (name, arity)) => { - debug_assert_eq!(arity, 0); - + (HeapCellValueTag::Atom, (name, _arity)) => { if index_ptrs.contains_key(&heap_loc) { let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); target.push_back(Target::clause_arg_to_instr(r)); return Some(r); } else { - target.push_back(Target::constant_subterm(Literal::Atom(name))); + target.push_back(Target::constant_subterm(atom_as_cell!(name))); } None } (HeapCellValueTag::Str | HeapCellValueTag::Lis - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { + | HeapCellValueTag::PStrLoc) => { let r = self.marker.mark_non_var::(Level::Deep, heap_loc, context, target); target.push_back(Target::clause_arg_to_instr(r)); return Some(r); } _ => { - match Literal::try_from(subterm) { - Ok(lit) => target.push_back(Target::constant_subterm(lit)), - Err(_) => unreachable!(), - } - + target.push_back(Target::constant_subterm(subterm)); None } ) @@ -486,7 +457,7 @@ impl<'b> CodeGenerator<'b> { where Target: crate::targets::CompilationTarget<'a>, Iter: TermIterator, - CodeGenerator<'b>: AddToFreeList<'a, Target>, + CodeGenerator: AddToFreeList<'a, Target>, { let mut target = CodeDeque::new(); let chunk_num = context.chunk_num(); @@ -530,13 +501,13 @@ impl<'b> CodeGenerator<'b> { target.push_back(instr); } else if lvl == Level::Shallow { let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, Literal::Atom(name), r)); + target.push_back(Target::to_constant(lvl, atom_as_cell!(name), r)); } } else { let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); target.push_back(Target::to_structure(lvl, name, arity, r)); - as AddToFreeList<'a, Target>>::add_term_to_free_list( + >::add_term_to_free_list( self, r, ); @@ -557,7 +528,7 @@ impl<'b> CodeGenerator<'b> { for r_opt in free_list_regs { if let Some(r) = r_opt { - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + >::add_subterm_to_free_list( self, r, ); } @@ -572,7 +543,7 @@ impl<'b> CodeGenerator<'b> { target.push_back(Target::to_list(lvl, r)); - as AddToFreeList<'a, Target>>::add_term_to_free_list( + >::add_term_to_free_list( self, r, ); @@ -597,62 +568,36 @@ impl<'b> CodeGenerator<'b> { ); if let Some(r) = head_r_opt { - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + >::add_subterm_to_free_list( self, r, ); } if let Some(r) = tail_r_opt { - as AddToFreeList<'a, Target>>::add_subterm_to_free_list( + >::add_subterm_to_free_list( self, r, ); } } - (HeapCellValueTag::CStr, cstr_atom) => { - let heap_loc = iter.focus().value() as usize; - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - target.push_back(Target::to_pstr(lvl, cstr_atom, r, false)); - } - (HeapCellValueTag::PStr, pstr_atom) => { + (HeapCellValueTag::PStrLoc, pstr_loc) => { let heap_loc = iter.focus().value() as usize; let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); + let (pstr_str, tail_loc) = iter.scan_slice_to_str(pstr_loc); - target.push_back(Target::to_pstr(lvl, pstr_atom, r, true)); - - let (tail_loc, tail) = subterm_index(iter.deref(), heap_loc + 1); - self.subterm_to_instr::( - tail, tail_loc, context, index_ptrs, &mut target, - ); - } - (HeapCellValueTag::PStrOffset, l) => { - let heap_loc = iter.focus().value() as usize; - let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - - let (index, n) = pstr_loc_and_offset(&iter, l); - let n = n.get_num() as usize; - - let pstr_atom = cell_as_atom!(iter[index]); - let pstr_offset_atom = if n == 0 { - pstr_atom - } else { - AtomTable::build_with(self.atom_tbl, &pstr_atom.as_str()[n ..]) - }; - - let (tail_loc, tail) = subterm_index(iter.deref(), l+1); - target.push_back(Target::to_pstr(lvl, pstr_offset_atom, r, true)); + target.push_back(Target::to_pstr(lvl, Rc::new(pstr_str.to_owned()), r)); + let (tail_loc, tail) = subterm_index(iter.deref(), tail_loc); self.subterm_to_instr::( tail, tail_loc, context, index_ptrs, &mut target, ); } _ if lvl == Level::Shallow => { - if let Ok(lit) = Literal::try_from(term) { + if term.is_constant() { let heap_loc = iter.focus().value() as usize; let (heap_loc, _) = subterm_index(iter.deref(), heap_loc); let r = self.marker.mark_non_var::(lvl, heap_loc, context, &mut target); - target.push_back(Target::to_constant(lvl, lit, r)); + target.push_back(Target::to_constant(lvl, term, r)); } } _ => {} @@ -688,7 +633,7 @@ impl<'b> CodeGenerator<'b> { fn compile_inlined( &mut self, ct: &InlinedClauseType, - terms: &mut FocusedHeap, + terms: &mut FocusedHeapRefMut, term_loc: usize, context: GenContext, code: &mut CodeDeque, @@ -763,9 +708,6 @@ impl<'b> CodeGenerator<'b> { instr!("$fail") } } - (HeapCellValueTag::Char) => { - instr!("$succeed") - } _ => { instr!("$fail") } @@ -780,7 +722,6 @@ impl<'b> CodeGenerator<'b> { } else { read_heap_cell!(first_arg, (HeapCellValueTag::Fixnum | - HeapCellValueTag::Char | HeapCellValueTag::F64) => { instr!("$succeed") } @@ -803,12 +744,11 @@ impl<'b> CodeGenerator<'b> { } (HeapCellValueTag::Lis | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { + | HeapCellValueTag::PStrLoc) => { instr!("$fail") } _ => { - if Literal::try_from(first_arg).is_ok() { + if first_arg.is_constant() { instr!("$succeed") } else { instr!("$fail") @@ -833,8 +773,7 @@ impl<'b> CodeGenerator<'b> { } (HeapCellValueTag::Lis | HeapCellValueTag::Str - | HeapCellValueTag::PStrLoc - | HeapCellValueTag::CStr) => { + | HeapCellValueTag::PStrLoc) => { instr!("$succeed") } _ => { @@ -889,12 +828,10 @@ impl<'b> CodeGenerator<'b> { self.marker.reset_arg(1); if let Some(r) = variable_marker(&mut self.marker) { instr!("number", r) + } else if Number::try_from(first_arg).is_ok() { + instr!("$succeed") } else { - if Number::try_from(first_arg).is_ok() { - instr!("$succeed") - } else { - instr!("$fail") - } + instr!("$fail") } } InlinedClauseType::IsNonVar(..) => { @@ -902,12 +839,10 @@ impl<'b> CodeGenerator<'b> { if let Some(r) = variable_marker(&mut self.marker) { instr!("nonvar", r) + } else if first_arg.is_var() { + instr!("$fail") } else { - if first_arg.is_var() { - instr!("$fail") - } else { - instr!("$succeed") - } + instr!("$succeed") } } InlinedClauseType::IsInteger(..) => { @@ -931,12 +866,10 @@ impl<'b> CodeGenerator<'b> { if let Some(r) = variable_marker(&mut self.marker) { instr!("var", r) + } else if first_arg.is_var() { + instr!("$succeed") } else { - if first_arg.is_var() { - instr!("$succeed") - } else { - instr!("$fail") - } + instr!("$fail") } }, }; @@ -948,7 +881,7 @@ impl<'b> CodeGenerator<'b> { fn compile_arith_expr( &mut self, - terms: &mut FocusedHeap, + terms: &mut FocusedHeapRefMut, term_loc: usize, target_int: usize, context: GenContext, @@ -960,7 +893,7 @@ impl<'b> CodeGenerator<'b> { fn compile_is_call( &mut self, - terms: &mut FocusedHeap, + terms: &mut FocusedHeapRefMut, term_loc: usize, code: &mut CodeDeque, context: GenContext, @@ -977,12 +910,10 @@ impl<'b> CodeGenerator<'b> { self.marker.reset_arg(2); - let var = { - let var_cell = terms.heap[term_loc + 1]; - let terms = FocusedHeapRefMut::from_cell(&mut terms.heap, var_cell); - - terms.deref_loc(term_loc + 1) - }; + let var = heap_bound_store( + terms.heap, + heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)), + ); let at = read_heap_cell!(var, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { @@ -1029,7 +960,7 @@ impl<'b> CodeGenerator<'b> { fn compile_seq( &mut self, - focused_heap: &mut FocusedHeap, + mut focused_heap: FocusedHeapRefMut, clauses: &ChunkedTermVec, code: &mut CodeDeque, ) -> Result<(), CompilationError> { @@ -1108,7 +1039,7 @@ impl<'b> CodeGenerator<'b> { .. }, ) => self.compile_is_call( - focused_heap, + &mut focused_heap, clause.term_loc(), branch_code_stack.code(code), context, @@ -1121,7 +1052,7 @@ impl<'b> CodeGenerator<'b> { }, ) => self.compile_inlined( ct, - focused_heap, + &mut focused_heap, clause.term_loc(), context, branch_code_stack.code(code), @@ -1132,15 +1063,13 @@ impl<'b> CodeGenerator<'b> { &QueryTerm::Succeed => { let code = branch_code_stack.code(code); - if self.marker.in_tail_position { - if self.marker.var_data.allocates { - code.push_back(instr!("deallocate")); - } + if self.marker.in_tail_position && self.marker.var_data.allocates { + code.push_back(instr!("deallocate")); } code.push_back( if self.marker.in_tail_position { - instr!("$succeed").to_execute() + instr!("$succeed").into_execute() } else { instr!("$succeed") }, @@ -1148,7 +1077,7 @@ impl<'b> CodeGenerator<'b> { } QueryTerm::Clause(clause) => { self.compile_query_line( - focused_heap, + &mut focused_heap, clause, context, branch_code_stack.code(code), @@ -1208,24 +1137,23 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_rule( &mut self, + heap: &mut Heap, rule: &mut Rule, var_data: VarData, ) -> Result { - let Rule { - ref mut term, - clauses, - } = rule; + let Rule { term_loc, clauses } = rule; + self.marker.var_data = var_data; + let term = FocusedHeapRefMut { heap, focus: *term_loc }; let mut code = VecDeque::new(); + let head_loc = term.nth_arg(term.focus, 1).unwrap(); - self.marker.reset_at_head(term, head_loc); + self.marker.reset_at_head(term.heap, head_loc); let mut stack = Stack::uninitialized(); - let iter = fact_iterator::( - &mut term.heap, &mut stack, head_loc, - ); + let iter = fact_iterator::(term.heap, &mut stack, head_loc); let fact = self.compile_target::( iter, @@ -1247,20 +1175,18 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_fact( &mut self, + heap: &mut Heap, fact: &mut Fact, var_data: VarData, ) -> Result { let mut code = Vec::new(); - let fact_focus = fact.term.focus; let mut stack = Stack::uninitialized(); self.marker.var_data = var_data; - self.marker.reset_at_head(&mut fact.term, fact_focus); + self.marker.reset_at_head(heap, fact.term_loc); - let iter = fact_iterator::( - &mut fact.term.heap, &mut stack, fact_focus, - ); + let iter = fact_iterator::(heap, &mut stack, fact.term_loc); let compiled_fact = self.compile_target::( iter, @@ -1280,7 +1206,7 @@ impl<'b> CodeGenerator<'b> { fn compile_query_line( &mut self, - term: &mut FocusedHeap, + term: &mut FocusedHeapRefMut, clause: &QueryClause, context: GenContext, code: &mut CodeDeque, @@ -1300,15 +1226,16 @@ impl<'b> CodeGenerator<'b> { self.add_call(code, clause.ct.to_instr(), clause.call_policy); } - fn split_predicate(clauses: &[PredicateClause]) -> Vec { + fn split_predicate(heap: &mut Heap, clauses: &[PredicateClause]) -> Vec { let mut subseqs = Vec::new(); let mut left = 0; let mut optimal_index = 0; 'outer: for (right, clause) in clauses.iter().enumerate() { - if let Some(args) = clause.args() { - for (instantiated_arg_index, arg) in args.iter().cloned().enumerate() { - let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg)); + if let Some(args) = clause.args(heap) { + for (instantiated_arg_index, arg_idx) in args.enumerate() { + let arg = heap[arg_idx]; + let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); if !arg.is_var() { if optimal_index != instantiated_arg_index { @@ -1364,6 +1291,7 @@ impl<'b> CodeGenerator<'b> { fn compile_pred_subseq( &mut self, + heap: &mut Heap, clauses: &mut [PredicateClause], optimal_index: usize, ) -> Result { @@ -1382,11 +1310,11 @@ impl<'b> CodeGenerator<'b> { let clause_code = match clause { PredicateClause::Fact(fact, var_data) => { let var_data = std::mem::take(var_data); - self.compile_fact(fact, var_data)? + self.compile_fact(heap, fact, var_data)? } PredicateClause::Rule(rule, var_data) => { let var_data = std::mem::take(var_data); - self.compile_rule(rule, var_data)? + self.compile_rule(heap, rule, var_data)? } }; @@ -1414,19 +1342,19 @@ impl<'b> CodeGenerator<'b> { skip_stub_try_me_else = !self.settings.is_dynamic(); } - let arg = clause.args().and_then(|args| args.get(optimal_index)); + let arg = clause.args(heap) + .map(|r| heap[r.start() + optimal_index]); - if let Some(arg) = arg.cloned() { + if let Some(arg) = arg { let index = code.len(); if clauses_len > 1 || self.settings.is_extensible { - let arg = heap_bound_store(clause.heap(), heap_bound_deref(clause.heap(), arg)); + let arg = heap_bound_store(heap, heap_bound_deref(heap, arg)); code_offsets.index_term( - clause.heap(), + heap, arg, index, &mut clause_index_info, - self.atom_tbl, ); } } @@ -1457,11 +1385,12 @@ impl<'b> CodeGenerator<'b> { pub(crate) fn compile_predicate( &mut self, + heap: &mut Heap, mut clauses: Vec, ) -> Result { let mut code = Code::new(); - let split_pred = Self::split_predicate(&clauses); + let split_pred = Self::split_predicate(heap, &clauses); let multi_seq = split_pred.len() > 1; for ClauseSpan { @@ -1473,11 +1402,13 @@ impl<'b> CodeGenerator<'b> { let skel_lower_bound = self.skeleton.clauses.len(); let code_segment = if self.settings.is_dynamic() { self.compile_pred_subseq::( + heap, &mut clauses[left..right], instantiated_arg_index, )? } else { self.compile_pred_subseq::( + heap, &mut clauses[left..right], instantiated_arg_index, )? diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 4577b1e6..d1d01aa8 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -4,7 +4,7 @@ use crate::codegen::SubsumedBranchHits; use crate::forms::{GenContext, Level}; use crate::instructions::*; use crate::machine::disjuncts::*; -use crate::machine::heap::{heap_bound_deref, heap_bound_store}; +use crate::machine::heap::*; use crate::parser::ast::*; use crate::targets::*; use crate::types::*; @@ -920,19 +920,24 @@ impl Allocator for DebrayAllocator { self.arg_c += 1; } - fn reset_at_head(&mut self, term: &mut FocusedHeap, head_loc: usize) { - read_heap_cell!(term.deref_loc(head_loc), + fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) { + let head_cell = heap_bound_store( + heap, + heap_bound_deref(heap, heap_loc_as_cell!(head_loc)), + ); + + read_heap_cell!(head_cell, (HeapCellValueTag::Str, s) => { - let arity = cell_as_atom_cell!(term.heap[s]).get_arity(); + let arity = cell_as_atom_cell!(heap[s]).get_arity(); self.reset_arg(arity); self.arity = arity; - for (idx, arg) in term.heap[s+1 .. s+arity+1].iter().cloned().enumerate() { + for (idx, arg) in heap.splice(s+1 ..= s+arity).enumerate() { if arg.is_var() { let var = heap_bound_store( - &term.heap, - heap_bound_deref(&term.heap, arg), + heap, + heap_bound_deref(heap, arg), ); if !var.is_var() { diff --git a/src/forms.rs b/src/forms.rs index be96e30c..4053b5a9 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,9 +1,10 @@ use crate::arena::*; use crate::atom_table::*; use crate::instructions::*; +use crate::functor_macro::*; use crate::machine::disjuncts::VarData; use crate::machine::heap::*; -use crate::machine::loader::PredicateQueue; +// use crate::machine::loader::PredicateQueue; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::parser::ast::*; @@ -25,18 +26,6 @@ use std::path::PathBuf; pub type PredicateKey = (Atom, usize); // name, arity. -/* -// vars of predicate, toplevel offset. Vec is always a vector -// of vars (we get their adjoining cells this way). -pub type JumpStub = Vec; -*/ - -#[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, @@ -171,17 +160,6 @@ impl ChunkedTermVec { .push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity))); } - pub fn push_branch_arm(&mut self, branch: VecDeque) { - match self.chunk_vec.back_mut().unwrap() { - ChunkedTerms::Branch(branches) => { - branches.push(branch); - } - ChunkedTerms::Chunk { .. } => { - self.chunk_vec.push_back(ChunkedTerms::Branch(vec![branch])); - } - } - } - pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool { if self.current_chunk_type.is_last() { self.current_chunk_type = ChunkType::Mid; @@ -243,7 +221,6 @@ impl ChunkedTermVec { #[derive(Debug)] pub struct QueryClause { pub ct: ClauseType, - pub arity: usize, pub term: HeapCellValue, pub code_indices: IndexMap, pub call_policy: CallPolicy, @@ -266,14 +243,14 @@ pub enum QueryTerm { GetLevel(usize), // var_num } -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub struct Fact { - pub(crate) term: FocusedHeap, + pub(crate) term_loc: usize, } #[derive(Debug)] pub struct Rule { - pub(crate) term: FocusedHeap, + pub(crate) term_loc: usize, pub(crate) clauses: ChunkedTermVec, } @@ -290,138 +267,34 @@ impl ListingSource { } } -pub trait ClauseInfo { - fn is_consistent(&self, clauses: &PredicateQueue) -> bool { - match clauses.first() { - Some(cl) => { - self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl) - } - None => true, +pub fn clause_predicate_key_from_heap( + heap: &impl SizedHeap, + value: HeapCellValue, +) -> Option { + read_heap_cell!(value, + (HeapCellValueTag::Atom, (name, _arity)) => { + debug_assert_eq!(_arity, 0); + Some((name, 0)) } - } - - fn name(&self) -> Option; - fn arity(&self) -> usize; -} - -impl ClauseInfo for PredicateKey { - #[inline] - fn name(&self) -> Option { - Some(self.0) - } - - #[inline] - fn arity(&self) -> usize { - self.1 - } -} - -fn clause_name(heap: &[HeapCellValue], term_loc: usize) -> Option { - let name = term_name(heap, term_loc); - - if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) { - term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_name(heap, arg_loc)) - } else { - name - } -} - -fn clause_arity(heap: &[HeapCellValue], term_loc: usize) -> usize { - let name = term_name(heap, term_loc); - - if Some(atom!(":-")) == name && 2 == term_arity(heap, term_loc) { - term_nth_arg(heap, term_loc, 1) - .map(|arg_loc| term_arity(heap, arg_loc)) - .unwrap_or(0) - } else { - term_arity(heap, term_loc) - } -} - -impl ClauseInfo for FocusedHeap { - #[inline] - fn name(&self) -> Option { - clause_name(&self.heap, self.focus) - } - - #[inline] - fn arity(&self) -> usize { - clause_arity(&self.heap, self.focus) - } -} - -impl<'a> ClauseInfo for FocusedHeapRefMut<'a> { - #[inline] - fn name(&self) -> Option { - clause_name(self.heap, self.focus) - } - - #[inline] - fn arity(&self) -> usize { - clause_arity(self.heap, self.focus) - } -} - -/* -impl ClauseInfo for Term { - fn name(&self) -> Option { - match self { - Term::Clause(_, name, terms) => { - match name { - atom!(":-") => { - match terms.len() { - 1 => None, // a declaration. - 2 => terms[0].name(), - _ => Some(*name), - } - } - _ => Some(*name), //str_buf), - } + _ => { + if value.is_ref() { + clause_predicate_key(heap, value.get_value() as usize) + } else { + None } - Term::Literal(_, Literal::Atom(name)) => Some(*name), - _ => None, } - } - - fn arity(&self) -> usize { - match self { - Term::Clause(_, name, terms) => match &*name.as_str() { - ":-" => match terms.len() { - 1 => 0, - 2 => terms[0].arity(), - _ => terms.len(), - }, - _ => terms.len(), - }, - _ => 0, - } - } -} -*/ - -impl ClauseInfo for Rule { - fn name(&self) -> Option { - self.term.name(self.term.focus) - } - - fn arity(&self) -> usize { - self.term.arity(self.term.focus) - } + ) } -impl ClauseInfo for PredicateClause { - fn name(&self) -> Option { - match self { - PredicateClause::Fact(ref fact, ..) => fact.term.name(fact.term.focus), - PredicateClause::Rule(ref rule, ..) => rule.term.name(rule.term.focus), - } - } +pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option { + let key_opt = term_predicate_key(heap, term_loc); - fn arity(&self) -> usize { - match self { - PredicateClause::Fact(ref fact, ..) => fact.term.arity(fact.term.focus), - PredicateClause::Rule(ref rule, ..) => rule.term.arity(rule.term.focus), - } + if Some((atom!(":-"), 2)) == key_opt { + term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| { + term_predicate_key(heap, arg_loc) + }) + } else { + key_opt } } @@ -432,33 +305,27 @@ pub enum PredicateClause { } impl PredicateClause { - pub(crate) fn args(&self) -> Option<&[HeapCellValue]> { - let (term, focus) = match self { - PredicateClause::Fact(Fact { term }, _) => (term, term.focus), - PredicateClause::Rule(Rule { term, .. }, _) => { - let focus = term.nth_arg(term.focus, 1).unwrap(); - (term, focus) + pub(crate) fn args<'a>(&self, heap: &'a Heap) -> Option> { + let focus = match self { + &PredicateClause::Fact(Fact { term_loc }, _) => term_loc, + &PredicateClause::Rule(Rule { term_loc, .. }, _) => { + term_nth_arg(heap, term_loc, 1).unwrap() } }; - let arity = term.arity(focus); + let arity = clause_predicate_key(heap, focus) + .map(|(_name, arity)| arity) + .unwrap_or(0); - read_heap_cell!(term.deref_loc(focus), + read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])), (HeapCellValueTag::Str, s) => { - Some(&term.heap[s+1 .. s+arity+1]) + Some(s+1 ..= s+arity) } _ => { None } ) } - - pub(crate) fn heap(&self) -> &[HeapCellValue] { - match self { - PredicateClause::Fact(ref fact, ..) => &fact.term.heap, - PredicateClause::Rule(ref rule, ..) => &rule.term.heap, - } - } } #[derive(Debug)] @@ -477,10 +344,10 @@ pub enum ModuleSource { impl ModuleSource { pub(crate) fn as_functor_stub(&self) -> MachineStub { match self { - ModuleSource::Library(name) => { - functor!(atom!("library"), [atom(name)]) + &ModuleSource::Library(name) => { + functor!(atom!("library"), [atom_as_cell(name)]) } - ModuleSource::File(name) => { + &ModuleSource::File(name) => { functor!(name) } } @@ -813,6 +680,7 @@ impl ArenaFrom for Number { } } +/* impl ArenaFrom for Literal { #[inline] fn arena_from(value: Number, arena: &mut Arena) -> Literal { @@ -824,6 +692,21 @@ impl ArenaFrom for Literal { } } } +*/ + +impl ArenaFrom for HeapCellValue { + #[inline] + fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue { + fixnum!(value as i64, arena) + } +} + +impl ArenaFrom for HeapCellValue { + #[inline] + fn arena_from(value: usize, arena: &mut Arena) -> HeapCellValue { + HeapCellValue::arena_from(value as u64, arena) + } +} impl ArenaFrom for HeapCellValue { #[inline] @@ -896,8 +779,8 @@ impl Number { #[derive(Debug, Clone)] pub(crate) enum OptArgIndexKey { - Literal(usize, usize, Literal, Vec), // index, IndexingCode location, opt arg, alternatives - List(usize, usize), // index, IndexingCode location + Literal(usize, usize, HeapCellValue, Vec), // index, IndexingCode location, opt arg, alternatives + List(usize, usize), // index, IndexingCode location None, Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity } diff --git a/src/functor_macro.rs b/src/functor_macro.rs new file mode 100644 index 00000000..081a4417 --- /dev/null +++ b/src/functor_macro.rs @@ -0,0 +1,616 @@ +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 enum FunctorElement { + AbsoluteCell(HeapCellValue), + Cell(HeapCellValue), + InnerFunctor(u64, Vec), + 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),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(str_loc_as_cell!(1u64 + count!($($dt)*) + $res_len))], + 3 + $res_len, + [$($subfunctor, )* FunctorElement::InnerFunctor(2, indexing_code_ptr($e))]) + }); + ([fixnum($e:expr) $(, $dt:ident($($value:tt),*))*], + [$($res:expr),*], + $res_len:expr, + [$($subfunctor:expr),*]) => ({ + build_functor!([$($dt($($value),*)),*], + [$($res, )* FunctorElement::Cell(fixnum_as_cell!(Fixnum::build_with($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),*]) + }); + ([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),*]) => ({ + 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 { + match code_ptr { + 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![FunctorElement::Cell(atom_as_cell!(atom!("fail")))] + } + } +} + +pub(crate) fn variadic_functor( + name: Atom, + arity: usize, + iter: impl Iterator>, +) -> Vec { + 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(); + + for (idx, _) in key_value_pairs.iter().enumerate() { + arg_vec.push(FunctorElement::Cell(str_loc_as_cell!(2 + num_items * 2 + idx))); + arg_vec.push(FunctorElement::Cell(list_loc_as_cell!(5 + idx))); + } + + 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 FunctorElement::*; + use std::string::String; + + #[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(), 7); + + 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], pstr_loc_as_cell!(heap_index!(5))); + assert_eq!(heap.slice_to_str(heap_index!(5), " string".len()), " string"); + assert_eq!(heap[6], 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!()); + } + + #[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!()); + } +} diff --git a/src/heap_iter.rs b/src/heap_iter.rs index 5b621836..89f39281 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -116,24 +116,10 @@ impl<'a> EagerStackfulPreOrderHeapIter<'a> { } } (HeapCellValueTag::PStrLoc, h) => { - let h = if self.heap[h].get_tag() == HeapCellValueTag::PStr { - h - } else { - debug_assert_eq!(self.heap[h].get_tag(), HeapCellValueTag::PStrOffset); - self.heap[h].get_value() as usize - }; - - if self.heap[h].get_mark_bit() == self.mark_phase { - continue; - } + let (_, tail_loc) = self.heap.scan_slice_to_str(h); - self.heap[h].set_mark_bit(self.mark_phase); - - if self.heap[h].get_tag() == HeapCellValueTag::PStr { - let value = self.heap[h+1]; - self.heap[h+1].set_mark_bit(self.mark_phase); - self.iter_stack.push(value); - } + self.heap[tail_loc].set_mark_bit(self.mark_phase); + self.iter_stack.push(self.heap[tail_loc]); } _ => { } @@ -249,7 +235,7 @@ impl ListElisionPolicy for NonListElider { #[derive(Debug)] pub struct StackfulPreOrderHeapIter<'a, ElideLists> { - pub heap: &'a mut [HeapCellValue], + pub heap: &'a mut Heap, pub machine_stack: &'a mut Stack, stack: Vec, h: IterStackLoc, @@ -264,14 +250,10 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> { cell.set_forwarding_bit(false); cell.set_mark_bit(false); } - - // self.heap.pop(); } } -pub trait FocusedHeapIter: - Deref + Iterator -{ +pub trait FocusedHeapIter: Deref + Iterator { fn focus(&self) -> IterStackLoc; } @@ -285,7 +267,7 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter } impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { &self.heap @@ -368,7 +350,7 @@ impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> { #[inline] - fn new(heap: &'a mut [HeapCellValue], stack: &'a mut Stack, root_loc: usize) -> Self { + fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self { let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap); // heap.push(cell); @@ -395,8 +377,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } (HeapCellValueTag::Str | HeapCellValueTag::AttrVar | - HeapCellValueTag::Var | - HeapCellValueTag::PStrLoc, vh) => { + HeapCellValueTag::Var, vh) => { if self.heap[vh].get_mark_bit() { self.read_cell_mut(loc).set_forwarding_bit(true); } @@ -438,7 +419,7 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> } read_heap_cell!(*cell, - (HeapCellValueTag::Str | HeapCellValueTag::PStrLoc, vh) => { + (HeapCellValueTag::Str, vh) => { let loc = IterStackLoc::iterable_loc(vh, HeapOrStackTag::Heap); self.push_if_unmarked(loc); @@ -469,20 +450,30 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists> self.push_if_unmarked(loc); self.stack.push(IterStackLoc::mark_loc(vs, HeapOrStackTag::Stack)); } - (HeapCellValueTag::PStrOffset, offset) => { - self.push_if_unmarked(IterStackLoc::iterable_loc(offset, HeapOrStackTag::Heap)); - self.stack.push(IterStackLoc::iterable_loc((h.value()+1) as usize, HeapOrStackTag::Heap)); + (HeapCellValueTag::PStrLoc, vh) => { + let cell = *cell; + let (_, tail_loc) = self.heap.scan_slice_to_str(vh); + + // forward the current PStrLoc cell if the zero + // byte at the end of the string buffer + // is marked + let buf_bytes = self.heap[tail_loc - 1].into_bytes(); + + if buf_bytes[7] != 0u8 { + let cell = self.read_cell_mut(h); + cell.set_forwarding_bit(true); + } - return Some(self.read_cell(h)); - } - (HeapCellValueTag::PStr) => { - let tail_loc = IterStackLoc::iterable_loc((h.value()+1) as usize, HeapOrStackTag::Heap); + // now mark it as if were a HeapCellValue, even + // though it's not! this is fine as long as its tag + // is never inspected, which it isn't. - self.push_if_unmarked(IterStackLoc::iterable_loc(h.value() as usize, HeapOrStackTag::Heap)); - self.stack.push(tail_loc); - self.forward_if_referent_marked(tail_loc); + self.push_if_unmarked( + IterStackLoc::iterable_loc(tail_loc - 1, HeapOrStackTag::Heap), + ); + self.stack.push(IterStackLoc::mark_loc(tail_loc, HeapOrStackTag::Heap)); - return Some(self.read_cell(h)); + return Some(cell); } (HeapCellValueTag::Atom, (_name, arity)) => { let l = h.value() as usize; @@ -523,7 +514,7 @@ impl<'a, ElideLists: ListElisionPolicy> Iterator for StackfulPreOrderHeapIter<'a #[inline(always)] pub(crate) fn cycle_detecting_stackless_preorder_iter( - heap: &'_ mut [HeapCellValue], + heap: &'_ mut Heap, start: usize, ) -> CycleDetectingIter<'_, true> { // const generics argument of true so that cycle discovery stops @@ -533,7 +524,7 @@ pub(crate) fn cycle_detecting_stackless_preorder_iter( #[inline(always)] pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( - heap: &'a mut Vec, + heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize, ) -> StackfulPreOrderHeapIter<'a, ElideLists> { @@ -543,13 +534,13 @@ pub(crate) fn stackful_preorder_iter<'a, ElideLists: ListElisionPolicy>( #[derive(Debug)] pub(crate) struct PostOrderIterator { focus: IterStackLoc, - base_iter: Iter, + pub(crate) base_iter: Iter, base_iter_valid: bool, parent_stack: Vec<(usize, HeapCellValue, IterStackLoc)>, // number of children, parent node, focus. } impl Deref for PostOrderIterator { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { &self.base_iter @@ -592,7 +583,7 @@ impl Iterator for PostOrderIterator { (HeapCellValueTag::Lis) => { self.parent_stack.push((2, item, focus)); } - (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { self.parent_stack.push((1, item, focus)); } _ => { @@ -678,6 +669,8 @@ pub(crate) fn stackful_post_order_iter<'a, ElideLists: ListElisionPolicy>( #[cfg(test)] mod tests { use super::*; + + use crate::functor_macro::*; use crate::machine::gc::IteratorUMP; use crate::machine::mock_wam::*; @@ -686,7 +679,7 @@ mod tests { #[inline(always)] pub(crate) fn stackless_preorder_iter( - heap: &mut [HeapCellValue], + heap: &mut Heap, start: usize, ) -> StacklessPreOrderHeapIter { StacklessPreOrderHeapIter::::new(heap, start) @@ -705,15 +698,21 @@ mod tests { fn heap_stackless_iter_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)]), + ); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3); @@ -734,21 +733,23 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); 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) ] )); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + + wam.machine_st.heap.push_cell(cell).unwrap(); for _ in 0..20 { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5); @@ -757,51 +758,10 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(0)); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(a_atom) - ); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(b_atom) - ); - - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(a_atom) - ); - - assert_eq!(iter.next(), None); - } - - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap.clear(); - - wam.machine_st.heap.push(str_loc_as_cell!(1)); - - wam.machine_st.heap.extend(functor!( - f_atom, - [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) - ] - )); - - for _ in 0..200000 { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); - assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - atom_as_cell!(f_atom, 4) + str_loc_as_cell!(0) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) @@ -818,12 +778,12 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -834,16 +794,20 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -873,12 +837,10 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap.pop(); + all_cells_unmarked(wam.machine_st.heap.splice(..)); // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -909,181 +871,96 @@ mod tests { wam.machine_st.heap.clear(); - // first a 'dangling' partial string, later modified to be a two-part complete string, - // then a three-part cyclic string involving an uncompacted list of chars. - 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]; + // first a 'dangling' partial string, later modified to be a + // two-part complete string, then a three-part cyclic string + // involving an uncompacted list of chars. - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.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 mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(1), + pstr_loc_as_cell!(0) ); - - assert!(iter.next().is_none()); - } - - assert_eq!(wam.machine_st.heap[0], pstr_cell); - assert_eq!(wam.machine_st.heap[1], heap_loc_as_cell!(1)); - - wam.machine_st.heap[1] = pstr_loc_as_cell!(3); - - 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]; - - { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(4), + heap_loc_as_cell!(1), ); - assert!(iter.next().is_none()); } - assert_eq!(wam.machine_st.heap[0], pstr_cell); - assert_eq!(wam.machine_st.heap[1], pstr_loc_as_cell!(3)); - assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(0)); - assert_eq!(wam.machine_st.heap[3], pstr_second_cell); - assert_eq!(wam.machine_st.heap[4], heap_loc_as_cell!(4)); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); + wam.machine_st.allocate_pstr("def").unwrap(); - wam.machine_st.heap[2] = heap_loc_as_cell!(4); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 2); - - let pstr_offset_cell = pstr_offset_as_cell!(0); + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - fixnum_as_cell!(Fixnum::build_with(2)) + pstr_loc_as_cell!(0) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - - assert_eq!(iter.next(), None); - } - - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - - wam.machine_st.heap.truncate(4); - - 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))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6); - let pstr_offset_cell = pstr_offset_as_cell!(0); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_loc_as_cell!(4) + pstr_loc_as_cell!(heap_index!(3)) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - fixnum_as_cell!(Fixnum::build_with(0)) + heap_loc_as_cell!(4), ); - - assert_eq!(iter.next(), None); + assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); - - wam.machine_st.heap[5] = fixnum_as_cell!(Fixnum::build_with(1i64)); + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { - let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 6); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_loc_as_cell!(4) - ); + let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 5); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) + pstr_loc_as_cell!(0) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - fixnum_as_cell!(Fixnum::build_with(1)) + pstr_loc_as_cell!(heap_index!(3) + 2) ); - assert_eq!(iter.next(), None); } - assert_eq!(wam.machine_st.heap[4], pstr_offset_as_cell!(0)); - assert_eq!( - wam.machine_st.heap[5], - fixnum_as_cell!(Fixnum::build_with(1i64)) - ); - - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); 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 mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1126,7 +1003,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1167,7 +1044,7 @@ mod tests { // instance. } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); @@ -1197,7 +1074,7 @@ mod tests { // instance. } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], str_loc_as_cell!(5)); @@ -1249,15 +1126,19 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 4); @@ -1266,7 +1147,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1288,9 +1169,13 @@ mod tests { wam.machine_st.heap.clear(); // 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)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + 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 mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1308,7 +1193,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1326,21 +1211,25 @@ mod tests { wam.machine_st.heap.clear(); // term is [X,f(Y),Z]. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 - wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 - wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 - wam.machine_st.heap.push(heap_loc_as_cell!(8)); - wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 - wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 - wam.machine_st.heap.push(list_loc_as_cell!(9)); - wam.machine_st.heap.push(heap_loc_as_cell!(9)); - wam.machine_st.heap.push(empty_list_as_cell!()); - - wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. - wam.machine_st.heap.push(heap_loc_as_cell!(12)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(3)); // 2 + section.push_cell(list_loc_as_cell!(4)); // 3 + section.push_cell(str_loc_as_cell!(6)); // 4 + section.push_cell(heap_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(f_atom, 1)); // 6 + section.push_cell(heap_loc_as_cell!(11)); // 7 + section.push_cell(list_loc_as_cell!(9)); + section.push_cell(heap_loc_as_cell!(9)); + section.push_cell(empty_list_as_cell!()); + + section.push_cell(attr_var_as_cell!(11)); // linked from 7. + section.push_cell(heap_loc_as_cell!(12)); + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 13); @@ -1382,22 +1271,25 @@ mod tests { let clpz_atom = atom!("clpz"); let p_atom = atom!("p"); - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - - wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 - wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 - wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 - wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 - wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 - wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 - wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 - wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 - wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 - wam.machine_st.heap.push(empty_list_as_cell!()); // 21 - wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 - wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.truncate(12); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(13)); // 12 + section.push_cell(list_loc_as_cell!(14)); // 13 + section.push_cell(str_loc_as_cell!(16)); // 14 + section.push_cell(heap_loc_as_cell!(19)); // 15 + section.push_cell(atom_as_cell!(clpz_atom, 2)); // 16 + section.push_cell(atom_as_cell!(a_atom)); // 17 + section.push_cell(atom_as_cell!(b_atom)); // 18 + section.push_cell(list_loc_as_cell!(20)); // 19 + section.push_cell(str_loc_as_cell!(22)); // 20 + section.push_cell(empty_list_as_cell!()); // 21 + section.push_cell(atom_as_cell!(p_atom, 1)); // 22 + section.push_cell(heap_loc_as_cell!(23)); // 23 + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 24); @@ -1535,9 +1427,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); + wam.machine_st.heap.push_cell(fixnum_as_cell!(Fixnum::build_with(0))).unwrap(); let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1549,15 +1439,18 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 0); @@ -1580,14 +1473,18 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(str_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(str_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(str_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3); @@ -1607,20 +1504,24 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(8)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(atom!("X"))); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 7); @@ -1663,7 +1564,7 @@ mod tests { assert!(iter.next().is_none()); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], str_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(atom!("g"), 2)); @@ -1678,10 +1579,14 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("f"), 2)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(0)); + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 3); @@ -1710,18 +1615,21 @@ mod tests { wam.machine_st.heap.clear(); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + // representation of one of the heap terms as in issue #1384. - wam.machine_st.heap.push(list_loc_as_cell!(7)); // 0 - wam.machine_st.heap.push(heap_loc_as_cell!(0)); // 1 - wam.machine_st.heap.push(list_loc_as_cell!(3)); // 2 - wam.machine_st.heap.push(list_loc_as_cell!(5)); // 3 - wam.machine_st.heap.push(empty_list_as_cell!()); // 4 - wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 5 - wam.machine_st.heap.push(heap_loc_as_cell!(2)); // 6 - wam.machine_st.heap.push(empty_list_as_cell!()); // 7 - wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 8 - - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(7)); // 0 + section.push_cell(heap_loc_as_cell!(0)); // 1 + section.push_cell(list_loc_as_cell!(3)); // 2 + section.push_cell(list_loc_as_cell!(5)); // 3 + section.push_cell(empty_list_as_cell!()); // 4 + section.push_cell(heap_loc_as_cell!(2)); // 5 + section.push_cell(heap_loc_as_cell!(2)); // 6 + section.push_cell(empty_list_as_cell!()); // 7 + section.push_cell(heap_loc_as_cell!(3)); // 8 + section.push_cell(heap_loc_as_cell!(0)); // 9 + }); { let mut iter = stackless_preorder_iter(&mut wam.machine_st.heap, 9); @@ -1776,21 +1684,29 @@ mod tests { fn heap_stackful_iter_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)]), + ); + + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 3, + h, ); assert_eq!( @@ -1811,21 +1727,26 @@ 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(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(cell).unwrap(); + for _ in 0..20 { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 4, + h, ); assert_eq!( @@ -1852,7 +1773,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, @@ -1878,8 +1799,8 @@ mod tests { { // mutually referencing variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, @@ -1898,11 +1819,15 @@ mod tests { wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = StackfulPreOrderHeapIter::::new( @@ -1935,10 +1860,8 @@ mod tests { assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = StackfulPreOrderHeapIter::::new( @@ -2001,7 +1924,7 @@ mod tests { ); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -2015,156 +1938,112 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - 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]; + wam.machine_st.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 mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + 2, ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(1), + pstr_loc_as_cell!(0) ); - - assert_eq!(iter.next(), None); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(1) + ); + assert!(iter.next().is_none()); } - // here - - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); + wam.machine_st.allocate_pstr("def").unwrap(); - 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.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + 5, ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3), + pstr_loc_as_cell!(0) ); - - assert_eq!(iter.next(), None); - } - - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(pstr_loc_as_cell!(wam.machine_st.heap.len() + 1)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0i64))); - - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - - { - let mut iter = stackful_preorder_iter::( - &mut wam.machine_st.heap, - &mut wam.machine_st.stack, - h, + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) ); - - let pstr_offset_cell = pstr_offset_as_cell!(0); - - // pstr_offset_cell.set_forwarding_bit(true); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(0i64)) + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(4), ); - assert_eq!(iter.next(), None); } - /* - { - let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); - let string: String = iter.chars().collect(); - assert_eq!(string, "abc def"); - } - */ - - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1i64))); - - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); - let pstr_offset_cell = pstr_offset_as_cell!(0); - - // pstr_offset_cell.set_forwarding_bit(true); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_offset_cell); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(1i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) ); - - let h = iter.focus(); - - assert_eq!(h.value(), 5); - assert_eq!(unmark_cell_bits!(iter.heap[4]), pstr_offset_as_cell!(0)); assert_eq!( - unmark_cell_bits!(iter.heap[5]), - fixnum_as_cell!(Fixnum::build_with(1i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) ); - assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let functor = functor!( + f_atom, + [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)] + ); - 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!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.extend(functor); + 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!()); + }); - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut functor_writer = Heap::functor_writer(functor); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = StackfulPreOrderHeapIter::::new( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 0, ); assert_eq!( @@ -2219,7 +2098,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2227,7 +2106,7 @@ mod tests { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 0, ); assert_eq!( @@ -2284,13 +2163,17 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - 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)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + 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 mut iter = StackfulPreOrderHeapIter::::new( @@ -2319,13 +2202,17 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(pstr_as_cell!(atom!("a string"))); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_pstr("a string"); + section.push_cell(empty_list_as_cell!()); + section.push_cell(pstr_loc_as_cell!(0)); + }); { let mut iter = stackful_preorder_iter::( @@ -2335,38 +2222,41 @@ mod tests { ); assert_eq!( - unmark_cell_bits!(iter.next().unwrap()), - pstr_as_cell!(atom!("a string")) + iter.heap.slice_to_str(0, "a string".len()), + "a string" + ); + assert_eq!( + iter.next().unwrap(), + empty_list_as_cell!() ); - - assert_eq!(iter.next().unwrap(), empty_list_as_cell!()); - assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(8)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st.heap.push(empty_list_as_cell!()); - - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(atom!("X"))); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(0)); + }); { let mut iter = stackful_preorder_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 10, ); assert_eq!( @@ -2392,21 +2282,29 @@ mod tests { fn heap_stackful_post_order_iter() { 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.push(str_loc_as_cell!(1)); + 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(); + let h = wam.machine_st.heap.cell_len(); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + h, ); assert_eq!( @@ -2427,23 +2325,28 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - 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!(1)) + 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(); + let h = wam.machine_st.heap.cell_len(); + + wam.machine_st.heap.push_cell(cell).unwrap(); + for _ in 0..20 { // 0000 { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - 0, + h, ); assert_eq!( @@ -2458,9 +2361,10 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(a_atom) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), str_loc_as_cell!(1)); - + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + str_loc_as_cell!(0) + ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), atom_as_cell!(f_atom, 4) @@ -2472,7 +2376,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, @@ -2498,8 +2402,8 @@ mod tests { { // mutually referencing variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, @@ -2518,20 +2422,21 @@ mod tests { wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - let h = wam.machine_st.heap.len(); - wam.machine_st.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!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 0, ); assert_eq!( @@ -2558,18 +2463,14 @@ mod tests { assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - // now make the list cyclic. - let h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 4, ); // the cycle will be iterated twice before being detected. @@ -2618,7 +2519,7 @@ mod tests { ); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -2632,140 +2533,106 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - 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]; + wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; + 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 mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 2, ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - - assert_eq!(iter.next(), None); - } - - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &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.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; - - { - let mut iter = stackful_post_order_iter::( - &mut wam.machine_st.heap, - &mut wam.machine_st.stack, - h, - ); - assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3), + pstr_loc_as_cell!(0) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - 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))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); + wam.machine_st.allocate_pstr("def").unwrap(); - let h = wam.machine_st.heap.len() - 1; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(0i64)) + unmark_cell_bits!(iter.next().unwrap()), + heap_loc_as_cell!(4), ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1i64))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - let h = wam.machine_st.heap.len() - 1; + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { let mut iter = stackful_post_order_iter::( &mut wam.machine_st.heap, &mut wam.machine_st.stack, - h, + 5, ); assert_eq!( - iter.next().unwrap(), - fixnum_as_cell!(Fixnum::build_with(1i64)) + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3) + 2) ); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - pstr_offset_as_cell!(0) + pstr_loc_as_cell!(heap_index!(3) + 2) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(heap_index!(3)) + ); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let functor = functor!( + f_atom, + [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)] + ); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + 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.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!()); + let mut functor_writer = Heap::functor_writer(functor); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); - wam.machine_st.heap.extend(functor); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackful_post_order_iter::( @@ -2827,7 +2694,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -2894,7 +2761,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); } @@ -2902,15 +2769,21 @@ mod tests { fn heap_stackless_post_order_iter() { 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)]), + ); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 3); @@ -2933,17 +2806,18 @@ 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) ] )); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + wam.machine_st.heap.push_cell(cell).unwrap(); for _ in 0..20 { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 5); @@ -2974,7 +2848,7 @@ mod tests { wam.machine_st.heap.clear(); { - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -2989,8 +2863,8 @@ mod tests { { // mutually referencing variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -3010,11 +2884,15 @@ mod tests { wam.machine_st.heap.clear(); // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -3043,10 +2921,8 @@ mod tests { assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); @@ -3093,7 +2969,7 @@ mod tests { ); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(wam.machine_st.heap[0], list_loc_as_cell!(1)); assert_eq!(wam.machine_st.heap[1], atom_as_cell!(a_atom)); @@ -3107,11 +2983,10 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - 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]; + wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + 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 mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 2); @@ -3120,108 +2995,68 @@ mod tests { unmark_cell_bits!(iter.next().unwrap()), heap_loc_as_cell!(1), ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); + assert_eq!( + unmark_cell_bits!(iter.next().unwrap()), + pstr_loc_as_cell!(0) + ); assert_eq!(iter.next(), None); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &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[2] = heap_loc_as_cell!(2); + wam.machine_st.allocate_pstr("def").unwrap(); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); { let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3), + heap_loc_as_cell!(1), ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - - assert_eq!(iter.next(), None); - } - - all_cells_unmarked(&wam.machine_st.heap); - - 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(0))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - - { - let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7); - let mut pstr_loc_cell = pstr_loc_as_cell!(0); - - pstr_loc_cell.set_forwarding_bit(true); - - // assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(0i64))); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3) + pstr_loc_as_cell!(0) ); - - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); - assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); - wam.machine_st.heap.pop(); - wam.machine_st.heap.pop(); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(3) + 2); { - let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 7); + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 4); - //assert_eq!(iter.next().unwrap(), fixnum_as_cell!(Fixnum::build_with(1))); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), - heap_loc_as_cell!(3) + pstr_loc_as_cell!(heap_index!(3) + 2) ); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_second_cell); - assert_eq!(unmark_cell_bits!(iter.next().unwrap()), pstr_cell); assert_eq!(iter.next(), None); } + all_cells_unmarked(wam.machine_st.heap.splice(..)); + wam.machine_st.heap.clear(); - let functor = functor!(f_atom, [atom(a_atom), atom(b_atom), atom(b_atom)]); + let functor = functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom), atom_as_cell(b_atom)]); - 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!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.extend(functor); + 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.push(heap_loc_as_cell!(0)); + let mut functor_writer = Heap::functor_writer(functor); + functor_writer(&mut wam.machine_st.heap).unwrap(); { - let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 9); + let mut iter = stackless_post_order_iter(&mut wam.machine_st.heap, 0); assert_eq!( unmark_cell_bits!(iter.next().unwrap()), @@ -3264,7 +3099,7 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = list_loc_as_cell!(1); @@ -3312,6 +3147,6 @@ mod tests { assert_eq!(iter.next(), None); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); } } diff --git a/src/heap_print.rs b/src/heap_print.rs index 8d434b15..2bc1706b 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -9,7 +9,6 @@ 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::*; @@ -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, + // end_cell: HeapCellValue, + // end_h: Option, } #[derive(Debug, Clone)] @@ -473,7 +472,6 @@ pub fn fmt_float(mut fl: f64) -> String { pub struct HCPrinter<'a, Outputter> { outputter: Outputter, iter: StackfulPreOrderHeapIter<'a, ListElider>, - atom_tbl: Arc, op_dir: &'a OpDir, state_stack: Vec, toplevel_spec: Option, @@ -488,9 +486,19 @@ 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 { @@ -528,7 +536,6 @@ pub(crate) fn numbervar(offset: &Integer, addr: HeapCellValue) -> Option impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { pub fn new( heap: &'a mut Heap, - atom_tbl: Arc, stack: &'a mut Stack, op_dir: &'a OpDir, output: Outputter, @@ -537,7 +544,6 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { HCPrinter { outputter: output, iter: stackful_preorder_iter(heap, stack, root_loc), - atom_tbl, op_dir, state_stack: vec![], toplevel_spec: None, @@ -553,17 +559,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) { if let Some(op) = parent_op { if op.is_left() && op.is_prefix() { @@ -1123,9 +1118,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 +1131,31 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { return true; } - append_str!(self, "'.'"); - push_char!(self, '('); + macro_rules! emit_char { + ($c:expr) => ({ + append_str!(self, "'.'"); + push_char!(self, '('); - print_char!(self, self.quoted, c); - push_char!(self, ','); + print_char!(self, self.quoted, $c); + push_char!(self, ','); - self.state_stack.push(TokenOrRedirect::Close); + 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 +1166,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,19 +1179,43 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { }; if max_depth == 0 { - for c in iter.chars() { - for c in char_to_string(c).chars() { - push_char!(self, c); + while let Some(iteratee) = iter.next() { + let iter: Box> = 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) { - char_count += 1; + while let Some(iteratee) = iter.next() { + let iter: Box> = 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 char_to_string(c).chars() { - push_char!(self, c); + for c in iter.take(max_depth - char_count) { + char_count += 1; + + for c in char_to_string(c).chars() { + push_char!(self, c); + } } } @@ -1194,10 +1233,10 @@ 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 => {} + // HeapCellValueTag::CStr => {} _ => { unreachable!(); } @@ -1208,19 +1247,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,9 +1265,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) { - self.remove_list_children(focus.value() as usize); - return self.print_proper_string(focus.value() as usize, max_depth); + if self.double_quotes && !self.ignore_ops && !is_cyclic { + if 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); + } } if self.ignore_ops { @@ -1261,37 +1298,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!() + } ); } } @@ -1521,32 +1548,29 @@ 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}' || pstr_loc % std::mem::size_of::() == 0 { + // if a null character in a pstr has location aligned + // to a cell boundary, the string is ['\\x0\\']. 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,14 +1582,23 @@ 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 { + /* + let end_cell_h = Heap::neighboring_cell_offset(pstr_loc); + let end_cell = self.iter.heap[end_cell_h]; + let end_cell = heap_bound_store( + self.iter.heap, + heap_bound_deref(self.iter.heap, end_cell), + ); + + if end_cell != empty_list_as_cell!() { + self.iter.push_stack( + IterStackLoc::iterable_loc(end_cell_h, HeapOrStackTag::Heap), + ); } + */ - self.state_stack - .push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); + self.state_stack.push(TokenOrRedirect::FunctorRedirect(max_depth + 1)); self.state_stack.push(TokenOrRedirect::HeadTailSeparator); } } @@ -1658,10 +1691,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(); @@ -1688,7 +1717,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { (HeapCellValueTag::F64, f) => { self.print_number(max_depth, NumberFocus::Unfocused(Number::Float(*f)), &op); } - (HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + (HeapCellValueTag::PStrLoc) => { // HeapCellValueTag::CStr | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { self.print_list_like(max_depth); } (HeapCellValueTag::Lis) => { @@ -1825,6 +1854,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { mod tests { use super::*; + use crate::functor_macro::*; use crate::machine::mock_wam::*; #[test] @@ -1832,25 +1862,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)]), + ); - wam.machine_st.heap.push(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.op_dir, PrinterOutputter::new(), - 0, + 3, ); let output = printer.print(); @@ -1858,31 +1893,31 @@ mod tests { assert_eq!(output.result(), "f(a,b)"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); 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 h = wam.machine_st.heap.len(); - wam.machine_st.heap.push(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.op_dir, PrinterOutputter::new(), - h, + 5, ); let output = printer.print(); @@ -1890,19 +1925,22 @@ mod tests { assert_eq!(output.result(), "f(a,b,a,...)"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); 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.op_dir, PrinterOutputter::new(), @@ -1915,7 +1953,6 @@ 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.op_dir, PrinterOutputter::new(), @@ -1931,24 +1968,32 @@ mod tests { assert_eq!(output.result(), "[L|L]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); 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(); + + 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.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!()); + 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)] + )); - wam.machine_st.heap.extend(functor); + 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.op_dir, PrinterOutputter::new(), @@ -1960,14 +2005,13 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap[4] = 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.op_dir, PrinterOutputter::new(), @@ -1979,12 +2023,11 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|...]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); { let mut printer = HCPrinter::new( &mut wam.machine_st.heap, - Arc::clone(&wam.machine_st.atom_tbl), &mut wam.machine_st.stack, &wam.op_dir, PrinterOutputter::new(), @@ -2000,23 +2043,27 @@ mod tests { assert_eq!(output.result(), "[f(a,b,b),f(a,b,b)|L]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); // issue #382 wam.machine_st.heap.clear(); - wam.machine_st.heap.push(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)); - } + let mut writer = wam.machine_st.heap.reserve(6002).unwrap(); - wam.machine_st.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + + for idx in 0..3000 { + section.push_cell(heap_loc_as_cell!(2 * idx + 1)); + section.push_cell(list_loc_as_cell!(2 * idx + 2 + 1)); + } + + 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.op_dir, PrinterOutputter::new(), @@ -2030,24 +2077,22 @@ mod tests { assert_eq!(output.result(), "[_1,_3,_5,_7,_9|...]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - put_partial_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); + wam.machine_st.allocate_pstr("abc").unwrap(); - let h = wam.machine_st.heap.len() - 1; + 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.op_dir, PrinterOutputter::new(), - h, + 2, ); let output = printer.print(); @@ -2055,28 +2100,28 @@ mod tests { assert_eq!(output.result(), "[a,b,c|_1]"); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); - wam.machine_st.heap.pop(); - 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.op_dir, PrinterOutputter::new(), - 0, + 2, ); printer.double_quotes = true; @@ -2086,7 +2131,7 @@ mod tests { assert_eq!(output.result(), "\"abcabc\""); } - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); @@ -2095,14 +2140,14 @@ mod tests { "=(X,[a,b,c|X])" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( &wam.parse_and_print_term("[a,b,\"a\",[a,b,c]].").unwrap(), "[a,b,[a],[a,b,c]]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( &wam.parse_and_print_term("[\"abc\",e,f,[g,e,h,Y,v|[X,Y]]].") @@ -2110,11 +2155,11 @@ mod tests { "[[a,b,c],e,f,[g,e,h,Y,v,X,Y]]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!(&wam.parse_and_print_term("f((a,b)).").unwrap(), "f((a,b))"); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.op_dir .insert((atom!("+"), Fixity::In), OpDesc::build_with(500, YFX)); @@ -2126,14 +2171,14 @@ mod tests { "[a|[]+b]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); assert_eq!( &wam.parse_and_print_term("[a|[b|c]*d].").unwrap(), "[a|[b|c]*d]" ); - all_cells_unmarked(&wam.machine_st.heap); + all_cells_unmarked(wam.machine_st.heap.splice(..)); wam.op_dir .insert((atom!("fy"), Fixity::Pre), OpDesc::build_with(9, FY)); diff --git a/src/indexing.rs b/src/indexing.rs index a199e625..d9a4f036 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,7 +1,8 @@ use crate::atom_table::*; use crate::forms::*; use crate::instructions::*; -use crate::parser::ast::*; +use crate::machine::heap::*; +use crate::parser::ast::Fixnum; use crate::types::*; use fxhash::FxBuildHasher; @@ -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(); @@ -663,8 +664,8 @@ pub(crate) fn merge_clause_index( } pub(crate) fn remove_constant_indices( - constant: Literal, - overlapping_constants: &[Literal], + constant: HeapCellValue, + overlapping_constants: &[HeapCellValue], indexing_code: &mut [IndexingLine], offset: usize, ) { @@ -1096,12 +1097,28 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { } pub(crate) fn constant_key_alternatives( - constant: Literal, - atom_tbl: &AtomTable, + constant: HeapCellValue, + // atom_tbl: &AtomTable, // arena: &mut Arena, -) -> Vec { +) -> Vec { let mut constants = vec![]; + match Number::try_from(constant) { + Ok(Number::Integer(n)) => { + let result = (&*n).try_into(); + if let Ok(value) = result { + constants.push( + Fixnum::build_with_checked(value) + .map(|n| fixnum_as_cell!(n)) + .unwrap() + ); + } + } + _ => { + } + } + + /* match constant { Literal::Atom(ref name) => { if let Some(c) = name.as_char() { @@ -1131,20 +1148,21 @@ pub(crate) fn constant_key_alternatives( } _ => {} } + */ constants } #[derive(Debug)] pub(crate) struct StaticCodeIndices { - constants: IndexMap, FxBuildHasher>, + constants: IndexMap, FxBuildHasher>, lists: VecDeque, structures: IndexMap<(Atom, usize), VecDeque, FxBuildHasher>, } #[derive(Debug)] pub(crate) struct DynamicCodeIndices { - constants: IndexMap, FxBuildHasher>, + constants: IndexMap, FxBuildHasher>, lists: VecDeque, structures: IndexMap<(Atom, usize), VecDeque, FxBuildHasher>, } @@ -1156,7 +1174,7 @@ pub(crate) trait Indexer { fn constants( &mut self, - ) -> &mut IndexMap, FxBuildHasher>; + ) -> &mut IndexMap, FxBuildHasher>; fn lists(&mut self) -> &mut VecDeque; fn structures( &mut self, @@ -1204,7 +1222,7 @@ impl Indexer for StaticCodeIndices { #[inline] fn constants( &mut self, - ) -> &mut IndexMap, FxBuildHasher> { + ) -> &mut IndexMap, FxBuildHasher> { &mut self.constants } @@ -1328,7 +1346,7 @@ impl Indexer for DynamicCodeIndices { } #[inline] - fn constants(&mut self) -> &mut IndexMap, FxBuildHasher> { + fn constants(&mut self) -> &mut IndexMap, FxBuildHasher> { &mut self.constants } @@ -1449,11 +1467,10 @@ impl CodeOffsets { fn index_constant( &mut self, - atom_tbl: &AtomTable, - constant: Literal, + constant: HeapCellValue, index: usize, - ) -> Vec { - let overlapping_constants = constant_key_alternatives(constant, atom_tbl); + ) -> Vec { + let overlapping_constants = constant_key_alternatives(constant); let code = self.indices.constants().entry(constant).or_default(); let is_initial_index = code.is_empty(); @@ -1491,11 +1508,10 @@ impl CodeOffsets { pub(crate) fn index_term( &mut self, - heap: &[HeapCellValue], + heap: &Heap, optimal_arg: HeapCellValue, index: usize, clause_index_info: &mut ClauseIndexInfo, - atom_tbl: &AtomTable, ) { read_heap_cell!(optimal_arg, (HeapCellValueTag::Str, s) => { @@ -1514,36 +1530,32 @@ impl CodeOffsets { (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); - let overlapping_constants = self.index_constant(atom_tbl, Literal::Atom(name), index); + let overlapping_constants = self.index_constant(atom_as_cell!(name), index); clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( self.optimal_index, 0, - Literal::Atom(name), + atom_as_cell!(name), overlapping_constants, ); } (HeapCellValueTag::Lis - | HeapCellValueTag::CStr + // | HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0); self.index_list(index); } - _ => { - match Literal::try_from(optimal_arg) { - Ok(lit) => { - let overlapping_constants = self.index_constant(atom_tbl, lit, index); - - clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( - self.optimal_index, - 0, - lit, - overlapping_constants, - ); - } - _ => {} - } + _ if optimal_arg.is_constant() => { + let overlapping_constants = self.index_constant(optimal_arg, index); + + clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal( + self.optimal_index, + 0, + optimal_arg, + overlapping_constants, + ); } + _ => {} ); } diff --git a/src/iterators.rs b/src/iterators.rs index c139f006..b641c756 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -14,9 +14,7 @@ use std::iter::*; use std::ops::Deref; use std::vec::Vec; -pub(crate) trait TermIterator: - Deref + Iterator -{ +pub(crate) trait TermIterator: Deref + Iterator { fn focus(&self) -> IterStackLoc; fn level(&mut self) -> Level; } @@ -30,7 +28,7 @@ pub(crate) struct TargetIterator { } fn record_path( - heap: &[HeapCellValue], + heap: &impl SizedHeap, root_terms: &mut BitSet, mut root_loc: usize, ) -> usize { @@ -47,9 +45,9 @@ fn record_path( } } (HeapCellValueTag::Lis) => { - root_terms.insert(root_loc); - break; - } + root_terms.insert(root_loc); + break; + } _ => { if cell.is_ref() { root_terms.insert(cell.get_value() as usize); @@ -63,14 +61,14 @@ fn record_path( root_loc } -fn find_root_terms(heap: &[HeapCellValue], root_loc: usize) -> (usize, BitSet) { +fn find_root_terms(heap: &impl SizedHeap, root_loc: usize) -> (usize, BitSet) { let mut root_terms = BitSet::::default(); let root_loc = record_path(heap, &mut root_terms, root_loc); (root_loc, root_terms) } fn find_shallow_terms( - heap: &[HeapCellValue], + heap: &impl SizedHeap, root_loc: usize, ) -> IndexMap, FxBuildHasher> { let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default()); @@ -101,8 +99,8 @@ fn find_shallow_terms( impl TargetIterator { fn new(iter: I, root_loc: usize, arg_c: usize) -> Self { - let (derefed_root_loc, root_terms) = find_root_terms(&iter, root_loc); - let shallow_terms = find_shallow_terms(&iter, derefed_root_loc); + let (derefed_root_loc, root_terms) = find_root_terms(iter.deref(), root_loc); + let shallow_terms = find_shallow_terms(iter.deref(), derefed_root_loc); Self { shallow_terms, @@ -184,7 +182,7 @@ impl Iterator for TargetIterator Deref for TargetIterator { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { self.iter.deref() @@ -205,7 +203,6 @@ pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>( stack: &'a mut Stack, root_loc: usize, ) -> FactIterator<'a, SKIP_ROOT> { - // let cell = heap[root_loc]; TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0) } @@ -217,7 +214,6 @@ pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>( stack: &'a mut Stack, root_loc: usize, ) -> QueryIterator<'a, SKIP_ROOT> { - // let cell = heap[root_loc]; TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1) } diff --git a/src/lib.rs b/src/lib.rs index fcb65ff0..ffd532f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ #![recursion_limit = "4112"] #![deny(missing_docs)] + #[macro_use] extern crate static_assertions; @@ -13,6 +14,8 @@ pub(crate) mod atom_table; pub(crate) mod arena; #[macro_use] pub(crate) mod parser; +#[macro_use] +pub(crate) mod functor_macro; mod allocator; mod arithmetic; pub(crate) mod codegen; diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index e5911d99..2b974228 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -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. diff --git a/src/loader.pl b/src/loader.pl index 26b6afc8..f2d77009 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -205,7 +205,6 @@ load_loop(Stream, Evacuable) :- read_term(Stream, Term, [singletons(Singletons)]) ; Term = end_of_file ), - % write('Term: '), writeq(Term), nl, ( Term == end_of_file -> close(Stream), '$conclude_load'(Evacuable) @@ -220,7 +219,6 @@ load_loop(Stream, Evacuable) :- compile_term(Term, Evacuable) :- expand_terms_and_goals(Term, Terms), - % write('Terms: '), writeq(Terms),nl, !, ( var(Terms) -> instantiation_error(load/1) @@ -301,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) @@ -311,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) diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 496007bd..a779411d 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -48,7 +48,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 +57,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 +69,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); @@ -528,7 +528,7 @@ pub(crate) fn min(n1: Number, n2: Number) -> Result { pub fn rational_from_number( n: Number, - stub_gen: impl Fn() -> FunctorStub + 'static, + stub_gen: impl Fn() -> MachineStub + 'static, arena: &mut Arena, ) -> Result, MachineStubGen> { match n { @@ -1140,7 +1140,7 @@ impl MachineState { pub fn get_rational( &mut self, at: &ArithmeticTerm, - caller: impl Fn() -> FunctorStub + 'static, + caller: impl Fn() -> MachineStub + 'static, ) -> Result, MachineStub> { let n = self.get_number(at)?; @@ -1154,6 +1154,8 @@ impl MachineState { &mut self, value: HeapCellValue, ) -> Result { + debug_assert!(value.is_ref()); + let stub_gen = || functor_stub(atom!("is"), 2); let root_loc = if value.is_ref() && !value.is_stack_var() { @@ -1178,7 +1180,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) } @@ -1458,7 +1460,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(heap_loc_as_cell!(term_write_result.focus)), Ok(Number::Fixnum(Fixnum::build_with(8))), ); @@ -1468,7 +1470,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(heap_loc_as_cell!(term_write_result.focus)), Ok(Number::Fixnum(Fixnum::build_with(19))), ); @@ -1478,7 +1480,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(heap_loc_as_cell!(term_write_result.focus)), Ok(Number::Fixnum(Fixnum::build_with(-1))) ); } diff --git a/src/machine/attributed_variables.pl b/src/machine/attributed_variables.pl index c288511b..584abc80 100644 --- a/src/machine/attributed_variables.pl +++ b/src/machine/attributed_variables.pl @@ -38,6 +38,7 @@ verify_attrs([], _, _, []). call_goals([ListOfGoalLists | ListsCubed]) :- + '$debug_hook', call_goals_0(ListOfGoalLists), call_goals(ListsCubed). call_goals([]). diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 794c0e76..6b5ae9b3 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -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 { + pub(super) fn gather_attr_vars_created_since(&mut self, b: usize) -> Vec { 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; @@ -121,14 +124,18 @@ impl MachineState { and_frame[arity + 2] = fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64)); and_frame[arity + 3] = fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64)); - self.verify_attributes(); + self.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 { + debug_assert!(cell.is_ref()); + let mut seen_set = IndexSet::new(); let mut seen_vars = vec![]; let root_loc = if cell.is_ref() { diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 983f5961..71beaa47 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1232,15 +1232,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { fn compile_standalone_clause( &mut self, - term: FocusedHeap, + term: TermWriteResult, settings: CodeGenSettings, ) -> Result { let mut preprocessor = Preprocessor::new(settings); - let clause = self.try_term_to_tl(term, &mut preprocessor)?; - let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings); + let clause = preprocessor.try_term_to_tl(self, term)?; + let machine_st = LS::machine_st(&mut self.payload); + let mut cg = CodeGenerator::new(settings); - let clause_code = cg.compile_predicate(vec![clause])?; + let clause_code = cg.compile_predicate(&mut machine_st.heap, vec![clause])?; Ok(StandaloneCompileResult { clause_code, @@ -1265,11 +1266,13 @@ 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 mut code = cg.compile_predicate(clauses)?; + let machine_st = LS::machine_st(&mut self.payload); + + let mut cg = CodeGenerator::new(settings); + let mut code = cg.compile_predicate(&mut machine_st.heap, clauses)?; if settings.is_extensible { let mut clause_clause_locs = VecDeque::new(); @@ -1466,7 +1469,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { pub(super) fn incremental_compile_clause( &mut self, key: PredicateKey, - clause: FocusedHeap, + clause: TermWriteResult, compilation_target: CompilationTarget, non_counted_bt: bool, append_or_prepend: AppendOrPrepend, @@ -2005,7 +2008,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { &mut self, key: PredicateKey, compilation_target: CompilationTarget, - clause_clauses: Vec, + clause_clauses: Vec, append_or_prepend: AppendOrPrepend, ) -> Result<(), SessionError> { let clause_clause_compilation_target = match compilation_target { @@ -2099,15 +2102,19 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { - let key = self + let key = match self .payload .predicates .first() - .and_then(|cl| { - let arity = ClauseInfo::arity(cl); - ClauseInfo::name(cl).map(|name| (name, arity)) - }) - .ok_or(SessionError::NamelessEntry)?; + .map(|term| term.focus) { + Some(focus) => { + clause_predicate_key(self.machine_heap(), focus) + .ok_or(SessionError::NamelessEntry)? + } + None => { + return Err(SessionError::NamelessEntry); + } + }; let listing_src_file_name = self.listing_src_file_name(); @@ -2285,34 +2292,40 @@ impl Machine { ) -> Result<(), SessionError> { let body_cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg])); - let new_header_loc = self.machine_st.heap.len(); + let new_header_loc = self.machine_st.heap.cell_len(); let arity = vars.len(); + let term_loc = self.machine_st.heap.cell_len() + 1 + arity; - self.machine_st.heap.push(atom_as_cell!(atom!(""), arity)); + let mut writer = self.machine_st.heap.reserve(4 + arity) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - for var in vars { - self.machine_st.heap.push(var); - } + writer.write_with(move |section| { + section.push_cell(atom_as_cell!(atom!(""), arity)); - let head_loc = if arity > 0 { - str_loc_as_cell!(new_header_loc) - } else { - heap_loc_as_cell!(new_header_loc) - }; + for var in vars { + section.push_cell(var); + } - let term_loc = self.machine_st.heap.len(); + let head_loc = if arity > 0 { + str_loc_as_cell!(new_header_loc) + } else { + heap_loc_as_cell!(new_header_loc) + }; - self.machine_st.heap.push(atom_as_cell!(atom!(":-"), 2)); - self.machine_st.heap.push(head_loc); - self.machine_st.heap.push(body_cell); + section.push_cell(atom_as_cell!(atom!(":-"), 2)); + section.push_cell(head_loc); + section.push_cell(body_cell); + }); let mut compile = || { - use crate::heap_iter::eager_stackful_preorder_iter; - let mut loader: Loader<'_, InlineLoadState<'_>> = Loader::new(self, InlineTermStream {}); - let mut term = loader.copy_term_from_heap(str_loc_as_cell!(term_loc)); + let machine_st = InlineLoadState::machine_st(&mut loader.payload); + + let term_loc = str_loc_as_cell!(term_loc); + let term = TermWriteResult::from(&mut machine_st.heap, term_loc) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; let settings = CodeGenSettings { global_clock_tick: None, @@ -2320,12 +2333,6 @@ impl Machine { non_counted_bt: true, }; - let value = term.heap[term.focus]; - - term.inverse_var_locs = inverse_var_locs_from_iter( - eager_stackful_preorder_iter(&mut term.heap, value), - ); - loader.compile_standalone_clause(term, settings) }; diff --git a/src/machine/copier.rs b/src/machine/copier.rs index c02854ff..5bb2fe90 100644 --- a/src/machine/copier.rs +++ b/src/machine/copier.rs @@ -1,10 +1,11 @@ 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 std::ops::{IndexMut, Range}; type Trail = Vec<(Ref, HeapCellValue)>; @@ -17,22 +18,31 @@ pub enum AttrVarPolicy { pub trait CopierTarget: IndexMut { fn store(&self, value: HeapCellValue) -> HeapCellValue; fn deref(&self, value: HeapCellValue) -> HeapCellValue; - fn push(&mut self, value: HeapCellValue); + // fn push_cell(&mut self, value: HeapCellValue) -> Result<(), usize>; 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 copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result; + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize; + fn pstr_at(&self, loc: usize) -> bool; + fn next_non_pstr_cell_index(&self, loc: usize) -> usize; + fn reserve(&mut self, num_cells: usize) -> Result; + fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize>; } pub(crate) fn copy_term( target: T, addr: HeapCellValue, attr_var_policy: AttrVarPolicy, -) { +) -> Result<(), usize> { let mut copy_term_state = CopyTermState::new(target, attr_var_policy); - 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(); + + Ok(()) } #[derive(Debug)] @@ -67,14 +77,14 @@ impl CopyTermState { self.trail.push((Ref::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 +93,10 @@ impl CopyTermState { } 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 +119,72 @@ impl CopyTermState { } 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); + /* + * write a null byte to the first word of a partial string to + * flag that it has been copied followed by the copied + * string's index in the next 7 bytes. write the bytes in big + * endian order so that the null byte is at index 0. + */ + fn write_pstr_index(&mut self, head_cell_idx: usize, threshold: usize) { + let bytes = u64::to_be_bytes(threshold as u64); + debug_assert_eq!(bytes[0], 0); + self.target[head_cell_idx] = HeapCellValue::from_bytes(bytes); + } - *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> { + let head_cell_idx = self.target.pstr_head_cell_index(pstr_loc); + let head_byte_idx = heap_index!(head_cell_idx); + let pstr_offset = pstr_loc - head_byte_idx; - self.scan += 1; - return; - } - (HeapCellValueTag::Var, h) => { - debug_assert!(h >= self.old_h); - debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); + // if a partial string has been copied previously, we + // track it by writing a null byte to its first word, which is trailed, + // and then the new pstr_loc in the word's remaining 7 bytes. see write_pstr_index + // comment. - *self.value_at_scan() = pstr_offset_as_cell!(h); - self.scan += 1; + if self.target[head_cell_idx].into_bytes()[0] == 0u8 { + let head_bytes = self.target[head_cell_idx].into_bytes(); + let new_pstr_loc = u64::from_be_bytes(head_bytes) as usize; - return; - } - _ => {} - ); + *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(new_pstr_loc) + pstr_offset); + self.scan += 1; + return Ok(()); + } let threshold = self.target.threshold(); + let tail_loc = self.target.copy_pstr_to_threshold(head_byte_idx)?; - let replacement = read_heap_cell!(self.target[pstr_loc], - (HeapCellValueTag::CStr) => { - debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); + *self.value_at_scan() = pstr_loc_as_cell!(heap_index!(threshold) + pstr_offset); - *self.value_at_scan() = pstr_offset_as_cell!(threshold); - self.target.push(self.target[pstr_loc]); + self.trail.push((Ref::heap_cell(head_cell_idx), self.target[head_cell_idx])); + self.write_pstr_index(head_cell_idx, threshold); - heap_loc_as_cell!(threshold) - } - _ => { - *self.value_at_scan() = if scan_tag == HeapCellValueTag::PStrLoc { - pstr_loc_as_cell!(threshold) - } else { - debug_assert_eq!(scan_tag, HeapCellValueTag::PStrOffset); - pstr_offset_as_cell!(threshold) - }; + let tail_cell = self.target[tail_loc]; + let mut writer = self.target.reserve(1)?; - self.target.push(self.target[pstr_loc]); - self.target.push(self.target[pstr_loc + 1]); - - pstr_loc_as_cell!(threshold) - } - ); + writer.write_with(|section| { + section.push_cell(tail_cell); + }); 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,36 +192,36 @@ impl CopyTermState { * 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]); - } - (HeapCellValueTag::Str) => { - self.copy_term_impl(self.target[str_loc]); - } - _ => { - unreachable!(); + if str_cell.to_atom().is_some() { + section.push_cell(str_cell); } - ); + }); + 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); @@ -250,8 +248,12 @@ impl CopyTermState { self.trail.push((Ref::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).unwrap(); + + 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)); @@ -266,9 +268,11 @@ impl CopyTermState { 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 +282,7 @@ impl CopyTermState { if h >= self.old_h { *self.value_at_scan() = ra; self.scan += 1; - return; + return Ok(()); } } (HeapCellValueTag::Lis, h) => { @@ -292,46 +296,57 @@ impl CopyTermState { ); 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); + self.target.copy_slice_to_end(addr .. addr + 1 + arity)?; + let trail_item = mem::replace( &mut self.target[addr], str_loc_as_cell!(threshold), ); 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); +*/ + if !self.target.pstr_at(addr + 1 + arity) { + 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. + let mut writer = self.target.reserve(1).unwrap(); + + writer.write_with(|section| { + section.push_cell(index_cell); + }); + } } } (HeapCellValueTag::Str, h) => { @@ -343,37 +358,51 @@ impl CopyTermState { ); 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() { + if self.target.pstr_at(self.scan) { + self.scan = self.target.next_non_pstr_cell_index(self.scan); + continue; + } + let addr = *self.value_at_scan(); read_heap_cell!(addr, (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; } - ); + )?; } + + Ok(()) } fn unwind_trail(mut self) { @@ -395,19 +424,25 @@ impl CopyTermState { #[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 +450,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 +465,62 @@ 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[5], - fixnum_as_cell!(Fixnum::build_with(0i64)) + 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.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!(5))); - 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!(5), "abc ".len()), + "abc " ); + assert_eq!(wam.machine_st.heap[6], pstr_loc_as_cell!(heap_index!(7))); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(7), "def".len()), + "def" + ); + assert_eq!(wam.machine_st.heap[8], pstr_loc_as_cell!(heap_index!(5))); 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) ] )); + functor_writer(&mut wam.machine_st.heap).unwrap(); + { 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(); } assert_eq!(wam.machine_st.heap[0], atom_as_cell!(f_atom, 4)); diff --git a/src/machine/cycle_detection.rs b/src/machine/cycle_detection.rs index 6df242ac..99ae40b4 100644 --- a/src/machine/cycle_detection.rs +++ b/src/machine/cycle_detection.rs @@ -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)); } } @@ -205,8 +206,7 @@ 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 (_, last_cell_loc) = self.heap.scan_slice_to_str(h); if self.heap[last_cell_loc].get_forwarding_bit() { if self.cycle_detection_active() { @@ -225,39 +225,7 @@ impl<'a, const STOP_AT_CYCLES: bool> CycleDetectingIter<'a, STOP_AT_CYCLES> { self.heap[last_cell_loc].set_value(self.current as u64); self.current = last_cell_loc; - 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 +237,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()); } diff --git a/src/machine/disjuncts.rs b/src/machine/disjuncts.rs index d7f35155..a7b2a128 100644 --- a/src/machine/disjuncts.rs +++ b/src/machine/disjuncts.rs @@ -3,6 +3,7 @@ use crate::forms::*; use crate::instructions::*; use crate::iterators::fact_iterator; use crate::machine::Stack; +use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::CompilationError; use crate::machine::preprocessor::*; @@ -320,13 +321,12 @@ impl VariableClassifier { } } - pub fn classify_fact( + pub fn classify_fact<'a, LS: LoadState<'a>>( mut self, - term: &mut FocusedHeap, + loader: &mut Loader<'a, LS>, + term: &TermWriteResult, ) -> Result { - let focus = term.focus; - self.classify_head_variables(term, focus)?; - + self.classify_head_variables(loader, &term, term.focus)?; Ok(self.branch_map.separate_and_classify_variables( self.var_num, self.global_cut_var_num, @@ -337,12 +337,14 @@ impl VariableClassifier { pub fn classify_rule<'a, LS: LoadState<'a>>( mut self, loader: &mut Loader<'a, LS>, - term: &mut FocusedHeap, + term: &TermWriteResult, ) -> Result { - let head_loc = term.nth_arg(term.focus, 1).unwrap(); - let body_loc = term.nth_arg(term.focus, 2).unwrap(); + let heap = &mut LS::machine_st(&mut loader.payload).heap; + + let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); + let body_loc = term_nth_arg(heap, term.focus, 2).unwrap(); - self.classify_head_variables(term, head_loc)?; + self.classify_head_variables(loader, &term, head_loc)?; self.root_set.insert(self.current_branch_num.clone()); let mut query_terms = self.classify_body_variables(loader, term, body_loc)?; @@ -385,8 +387,8 @@ impl VariableClassifier { &mut self, arg_c: usize, arity: usize, - term: &mut FocusedHeap, - term_loc: usize, + term: &mut FocusedHeapRefMut, + inverse_var_locs: &InverseVarLocs, context: GenContext, ) { let classify_info = ClassifyInfo { arg_c, arity }; @@ -394,9 +396,9 @@ impl VariableClassifier { let mut lvl = Level::Shallow; let mut stack = Stack::uninitialized(); let mut iter = fact_iterator::( - &mut term.heap, + term.heap, &mut stack, - term_loc, + term.focus, ); // second arg is true to iterate the root, which may be a variable @@ -407,7 +409,7 @@ impl VariableClassifier { } let var_loc = subterm.get_value() as usize; - let var = to_classified_var(&term.inverse_var_locs, var_loc); + let var = to_classified_var(inverse_var_locs, var_loc); self.probe_body_var( context, @@ -468,27 +470,21 @@ impl VariableClassifier { self.probe_body_var(context, var_info); } - fn classify_head_variables( + fn classify_head_variables<'a, LS: LoadState<'a>>( &mut self, - term: &mut FocusedHeap, + loader: &mut Loader<'a, LS>, + term: &TermWriteResult, head_loc: usize, ) -> Result<(), CompilationError> { - let arity = read_heap_cell!(term.deref_loc(head_loc), - (HeapCellValueTag::Str, s) => { - cell_as_atom_cell!(term.heap[s]).get_arity() - } - (HeapCellValueTag::Atom) => { - return Ok(()); - } - _ => { - return Err(CompilationError::InvalidRuleHead); - } - ); + let heap = &mut LS::machine_st(&mut loader.payload).heap; + let arity = term_predicate_key(heap, head_loc) + .and_then(|(_, arity)| Some(arity)) + .ok_or(CompilationError::InvalidRuleHead)?; let mut classify_info = ClassifyInfo { arg_c: 1, arity }; if arity > 0 { - let (_term_loc, value) = subterm_index(&term.heap, head_loc); + let (_term_loc, value) = subterm_index(heap, head_loc); let str_offset = value.get_value() as usize; debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str); @@ -497,7 +493,7 @@ impl VariableClassifier { let mut lvl = Level::Shallow; let mut stack = Stack::uninitialized(); let mut iter = fact_iterator::( - &mut term.heap, + heap, &mut stack, idx, ); @@ -571,11 +567,11 @@ impl VariableClassifier { fn classify_body_variables<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - terms: &mut FocusedHeap, + terms: &TermWriteResult, term_loc: usize, ) -> Result { let mut state_stack = vec![TraversalState::Term { - subterm: terms.heap[term_loc], + subterm: loader.machine_heap()[term_loc], term_loc, }]; let mut build_stack = ChunkedTermVec::new(); @@ -684,13 +680,21 @@ impl VariableClassifier { for (arg_c, term_loc) in ($term_loc + 1 ..= $term_loc + $key.1).enumerate() { - self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context); + let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + + self.probe_body_term( + arg_c + 1, + $key.1, + &mut term, + &terms.inverse_var_locs, + context, + ); } build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( loader, $key, - terms.as_ref_mut($term_loc), + &terms, HeapCellValue::build_with($tag, $term_loc as u64), self.call_policy, ))); @@ -706,9 +710,17 @@ impl VariableClassifier { let context = build_stack.current_gen_context(); for (arg_c, term_loc) in - ($term_loc + 1..$term_loc + $key.1 + 1).enumerate() + ($term_loc + 1 ..= $term_loc + $key.1).enumerate() { - self.probe_body_term(arg_c + 1, $key.1, terms, term_loc, context); + let mut term = FocusedHeapRefMut::from(loader.machine_heap(), term_loc); + + self.probe_body_term( + arg_c + 1, + $key.1, + &mut term, + &terms.inverse_var_locs, + context, + ); } build_stack.push_chunk_term(QueryTerm::Clause( @@ -716,7 +728,7 @@ impl VariableClassifier { loader, $key, $module_name, - terms.as_ref_mut($term_loc), + &terms, HeapCellValue::build_with($tag, $term_loc as u64), self.call_policy, ), @@ -725,26 +737,28 @@ impl VariableClassifier { } loop { + let heap = loader.machine_heap(); + read_heap_cell!(subterm, (HeapCellValueTag::Str, subterm_loc) => { - let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc]) + let (name, arity) = cell_as_atom_cell!(heap[subterm_loc]) .get_name_and_arity(); match (name, arity) { (atom!("->") | atom!(";") | atom!(","), 3) => { - if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) { - subterm = terms.heap[subterm_loc]; + if blunt_index_ptr(heap, (name, 2), subterm_loc) { + subterm = heap[subterm_loc]; continue; } add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc); } (atom!(","), 2) => { - let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); - let head = terms.heap[head_loc]; + let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); + let head = heap[head_loc]; - let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(",")) + let iter = unfold_by_str_locs(heap, tail_loc, atom!(",")) .into_iter() .rev() .chain(std::iter::once((head, head_loc))) @@ -754,15 +768,15 @@ impl VariableClassifier { state_stack.extend(iter); } (atom!(";"), 2) => { - let head_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let head = terms.heap[head_loc]; + let head = heap[head_loc]; let first_branch_num = self.current_branch_num.split(); let branches: Vec<_> = std::iter::once((head, head_loc)) .chain( - unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(";")) + unfold_by_str_locs(heap, tail_loc, atom!(";")) .into_iter(), ) .collect(); @@ -807,11 +821,11 @@ impl VariableClassifier { build_stack.current_chunk_num += 1; } (atom!("->"), 2) => { - let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let if_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let then_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); - let if_term = terms.heap[if_term_loc]; - let then_term = terms.heap[then_term_loc]; + let if_term = heap[if_term_loc]; + let then_term = heap[then_term_loc]; let prev_b = if matches!( state_stack.last(), @@ -851,8 +865,8 @@ impl VariableClassifier { self.var_num += 1; } (atom!("\\+"), 1) => { - let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let not_term = terms.heap[not_term_loc]; + let not_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let not_term = heap[not_term_loc]; let build_stack_len = build_stack.len(); build_stack.reserve_branch(2); @@ -886,18 +900,19 @@ impl VariableClassifier { self.var_num += 1; } (atom!(":"), 2) => { - let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap(); + let module_name_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let predicate_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap(); + let mut focused = FocusedHeapRefMut::from(heap, module_name_loc); - let module_name = terms.deref_loc(module_name_loc); - let predicate_term = terms.deref_loc(predicate_term_loc); + let module_name = focused.deref_loc(module_name_loc); + let predicate_term = focused.deref_loc(predicate_term_loc); read_heap_cell!(module_name, (HeapCellValueTag::Atom, (module_name, arity)) => { if arity == 0 { read_heap_cell!(predicate_term, (HeapCellValueTag::Str, s) => { - let key = cell_as_atom_cell!(terms.heap[s]) + let key = cell_as_atom_cell!(heap[s]) .get_name_and_arity(); add_qualified_chunk!( @@ -933,25 +948,40 @@ impl VariableClassifier { let context = build_stack.current_gen_context(); - self.probe_body_term(1, 0, terms, module_name_loc, context); - self.probe_body_term(2, 0, terms, predicate_term_loc, context); + focused.focus = module_name_loc; - let h = terms.heap.len(); + self.probe_body_term( + 1, 0, &mut focused, &terms.inverse_var_locs, context, + ); + + focused.focus = predicate_term_loc; + + self.probe_body_term( + 2, 0, &mut focused, &terms.inverse_var_locs, context, + ); + + let h = heap.cell_len(); - terms.heap.push(atom_as_cell!(atom!("call"), 1)); - terms.heap.push(str_loc_as_cell!(subterm_loc)); + heap.push_cell(atom_as_cell!(atom!("call"), 1)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + heap.push_cell(str_loc_as_cell!(subterm_loc)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term( loader, (atom!("call"), 1), - terms.as_ref_mut(h), + terms, str_loc_as_cell!(h), self.call_policy, ))); } (atom!("$call_with_inference_counting"), 1) => { - let term_loc = terms.nth_arg(subterm_loc, 1).unwrap(); - let subterm = terms.deref_loc(term_loc); + let term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap(); + let heap = loader.machine_heap(); + let subterm = heap_bound_store( + heap, + heap_bound_deref(heap, heap[term_loc]), + ); state_stack.push(TraversalState::ResetCallPolicy(self.call_policy)); state_stack.push(TraversalState::Term { subterm, term_loc }); @@ -973,17 +1003,9 @@ impl VariableClassifier { add_chunk!((name, 0), HeapCellValueTag::Var, term_loc); } } - (HeapCellValueTag::Char, c) => { - if c == '!' { - let context = build_stack.current_gen_context(); - state_stack.push(self.new_cut_state(context)); - } else { - return Err(CompilationError::InadmissibleQueryTerm); - } - } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h != term_loc { - subterm = terms.heap[h]; + subterm = heap[h]; term_loc = h; continue; } diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 729c6974..ad0ebc7d 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -1,5 +1,6 @@ use crate::arena::*; use crate::atom_table::*; +use crate::functor_macro::*; use crate::instructions::*; use crate::machine::arithmetic_ops::*; use crate::machine::machine_errors::*; @@ -24,7 +25,10 @@ macro_rules! try_or_throw { match $e { Ok(val) => val, Err(msg) => { - $s.throw_exception(msg); + if !msg.is_empty() { + $s.throw_exception(msg); + } + $s.backtrack(); continue; } @@ -32,6 +36,15 @@ macro_rules! try_or_throw { }}; } +macro_rules! backtrack_on_resource_error { + ($machine_st:expr, $val:expr) => { + step_or_resource_error!($machine_st, $val, { + $machine_st.backtrack(); + continue; + }) + }; +} + macro_rules! increment_call_count { ($s:expr) => {{ if !$s.increment_call_count() { @@ -55,6 +68,15 @@ macro_rules! try_or_throw_gen { }}; } +macro_rules! push_cell { + ($machine_st:expr, $cell:expr) => {{ + step_or_resource_error!($machine_st, $machine_st.heap.push_cell($cell), { + $machine_st.backtrack(); + continue; + }) + }}; +} + static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256; impl MachineState { @@ -113,12 +135,15 @@ impl MachineState { } pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) { - let old_h = self.heap.len(); + let old_h = self.heap.cell_len(); let a1 = self.registers[1]; let a2 = self.registers[2]; - copy_term(CopyTerm::new(self), a1, attr_var_policy); + step_or_resource_error!( + self, + copy_term(CopyTerm::new(self), a1, attr_var_policy) + ); unify_fn!(*self, heap_loc_as_cell!(old_h), a2); } @@ -135,10 +160,16 @@ impl MachineState { list.dedup_by(|v1, v2| compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal)); - let heap_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, list.into_iter())); + let heap_addr = resource_error_call_result!( + self, + sized_iter_to_heap_list( + &mut self.heap, + list.len(), + list.into_iter(), + ) + ); let target_addr = self.registers[2]; - unify_fn!(*self, target_addr, heap_addr); Ok(()) } @@ -160,8 +191,14 @@ impl MachineState { compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less) }); - let key_pairs = key_pairs.into_iter().map(|kp| kp.1); - let heap_addr = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, key_pairs)); + let heap_addr = resource_error_call_result!( + self, + sized_iter_to_heap_list( + &mut self.heap, + key_pairs.len(), + key_pairs.into_iter().map(|kp| kp.1), + ) + ); let target_addr = self.registers[2]; @@ -201,13 +238,13 @@ impl MachineState { v } (HeapCellValueTag::PStrLoc | - HeapCellValueTag::Lis | - HeapCellValueTag::CStr) => { + HeapCellValueTag::Lis) => { + // HeapCellValueTag::CStr) => { l } (HeapCellValueTag::Fixnum | HeapCellValueTag::CutPoint | - HeapCellValueTag::Char | + // HeapCellValueTag::Char | HeapCellValueTag::F64) => { c } @@ -242,6 +279,7 @@ impl MachineState { ) } + /* #[inline(always)] pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal { read_heap_cell!(addr, @@ -288,6 +326,7 @@ impl MachineState { } ) } + */ #[inline(always)] pub(crate) fn select_switch_on_structure_index( @@ -464,9 +503,9 @@ impl Machine { } } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => { - let lit = self.machine_st.constant_to_literal(addr); + // let lit = self.machine_st.constant_to_literal(addr); - let offset = match hm.get(&lit) { + let offset = match hm.get(&addr) { Some(offset) => *offset, _ => IndexingCodePtr::Fail, }; @@ -1245,22 +1284,32 @@ impl Machine { self.machine_st.allocate(num_cells); } &Instruction::DefaultCallAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - self.machine_st.p += 1; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + self.machine_st.p += 1; } &Instruction::DefaultExecuteAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - self.machine_st.p = self.machine_st.cp; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + self.machine_st.p = self.machine_st.cp; } &Instruction::DefaultCallArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg()); @@ -1497,24 +1546,34 @@ impl Machine { step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - increment_call_count!(self.machine_st); - self.machine_st.p += 1; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + increment_call_count!(self.machine_st); + self.machine_st.p += 1; } &Instruction::ExecuteAcyclicTerm => { - let addr = self.machine_st.registers[1]; + let addr = self.deref_register(1); - if self.machine_st.is_cyclic_term(addr) { - self.machine_st.backtrack(); - } else { - increment_call_count!(self.machine_st); - self.machine_st.p = self.machine_st.cp; + if addr.is_ref() { + self.machine_st.heap[0] = addr; + + if self.machine_st.is_cyclic_term(0) { + self.machine_st.backtrack(); + continue; + } } + + increment_call_count!(self.machine_st); + self.machine_st.p = self.machine_st.cp; } &Instruction::CallArg => { try_or_throw!(self.machine_st, self.machine_st.try_arg()); @@ -2282,9 +2341,6 @@ impl Machine { self.machine_st.backtrack(); } } - (HeapCellValueTag::Char) => { - self.machine_st.p += 1; - } _ => { self.machine_st.backtrack(); } @@ -2313,9 +2369,6 @@ impl Machine { self.machine_st.backtrack(); } } - (HeapCellValueTag::Char) => { - self.machine_st.p = self.machine_st.cp; - } _ => { self.machine_st.backtrack(); } @@ -2327,7 +2380,7 @@ impl Machine { .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, - (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | HeapCellValueTag::Cons) => { self.machine_st.p += 1; } @@ -2359,7 +2412,7 @@ impl Machine { .store(self.machine_st.deref(self.machine_st[r])); read_heap_cell!(d, - (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | + (HeapCellValueTag::Fixnum | HeapCellValueTag::F64 | HeapCellValueTag::Cons) => { self.machine_st.p = self.machine_st.cp; } @@ -2392,8 +2445,8 @@ impl Machine { read_heap_cell!(d, (HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | - HeapCellValueTag::CStr) => { + HeapCellValueTag::PStrLoc) => { + // HeapCellValueTag::CStr) => { self.machine_st.p += 1; } (HeapCellValueTag::Str, s) => { @@ -2425,8 +2478,8 @@ impl Machine { read_heap_cell!(d, (HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | - HeapCellValueTag::CStr) => { + HeapCellValueTag::PStrLoc) => { + // HeapCellValueTag::CStr) => { self.machine_st.p = self.machine_st.cp; } (HeapCellValueTag::Str, s) => { @@ -2664,8 +2717,6 @@ impl Machine { &Instruction::CallNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("calling {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { @@ -2677,8 +2728,6 @@ impl Machine { &Instruction::ExecuteNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("executing {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { @@ -2690,8 +2739,6 @@ impl Machine { &Instruction::DefaultCallNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("calling {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_call(name, arity, idx)); if self.machine_st.fail { @@ -2701,8 +2748,6 @@ impl Machine { &Instruction::DefaultExecuteNamed(arity, name, ref idx) => { let idx = idx.get(); - // println!("executing {}/{}", name.as_str(), arity); - try_or_throw!(self.machine_st, self.try_execute(name, arity, idx)); if self.machine_st.fail { @@ -2720,8 +2765,7 @@ impl Machine { self.machine_st.p = self.machine_st.cp; } &Instruction::GetConstant(_, c, reg) => { - let value = self.machine_st.deref(self.machine_st[reg]); - self.machine_st.write_literal_to_var(value, c); + unify!(self.machine_st, self.machine_st[reg], c); step_or_fail!(self, self.machine_st.p += 1); } &Instruction::GetList(_, reg) => { @@ -2730,17 +2774,7 @@ impl Machine { read_heap_cell!(store_v, (HeapCellValueTag::PStrLoc, h) => { - let (h, n) = pstr_loc_and_offset(&self.machine_st.heap, h); - - self.machine_st.s = HeapPtr::PStrChar(h, n.get_num() as usize); - self.machine_st.s_offset = 0; - self.machine_st.mode = MachineMode::Read; - } - (HeapCellValueTag::CStr) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(store_v); - - self.machine_st.s = HeapPtr::PStrChar(h, 0); + self.machine_st.s = HeapPtr::PStr(h); self.machine_st.s_offset = 0; self.machine_st.mode = MachineMode::Read; } @@ -2763,9 +2797,9 @@ impl Machine { self.machine_st.mode = MachineMode::Read; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(list_loc_as_cell!(h+1)); + push_cell!(self.machine_st, list_loc_as_cell!(h+1)); self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.machine_st.mode = MachineMode::Write; @@ -2778,29 +2812,61 @@ impl Machine { self.machine_st.p += 1; } - &Instruction::GetPartialString(_, string, reg, has_tail) => { + &Instruction::GetPartialString(_, ref string, reg) => { + use crate::machine::partial_string::{HeapPStrIter, PStrCmpResult}; + let deref_v = self.machine_st.deref(self.machine_st[reg]); let store_v = self.machine_st.store(deref_v); read_heap_cell!(store_v, (HeapCellValueTag::Str | HeapCellValueTag::Lis | - HeapCellValueTag::PStrLoc | - HeapCellValueTag::CStr) => { - self.machine_st.match_partial_string(store_v, string, has_tail); + HeapCellValueTag::PStrLoc) => { + debug_assert!(store_v.is_ref()); + + self.machine_st.heap[0] = store_v; + let heap_pstr_iter = HeapPStrIter::new(&self.machine_st.heap, 0); + + match heap_pstr_iter.compare_pstr_to_string(string) { + Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc }) => { + self.machine_st.s_offset = chars_matched; + self.machine_st.s = HeapPtr::PStr(pstr_loc); + self.machine_st.mode = MachineMode::Read; + } + Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => { + let cell = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(string) + ); + + self.machine_st.mode = MachineMode::Write; + unify!(self.machine_st, cell, heap_loc_as_cell!(var_loc)); + } + Some(PStrCmpResult::ListMatch { list_loc }) => { + self.machine_st.s_offset = 0; + self.machine_st.s = HeapPtr::HeapCell(list_loc); + self.machine_st.mode = MachineMode::Read; + } + None => { + self.machine_st.backtrack(); + continue; + } + } } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - let target_cell = self.machine_st.push_str_to_heap( - &string.as_str(), - has_tail, + let target_cell = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(string) ); self.machine_st.bind( store_v.as_var().unwrap(), target_cell, ); + + self.machine_st.mode = MachineMode::Write; } _ => { self.machine_st.backtrack(); @@ -2833,10 +2899,10 @@ impl Machine { ); } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(str_loc_as_cell!(h+1)); - self.machine_st.heap.push(atom_as_cell!(name, arity)); + push_cell!(self.machine_st, str_loc_as_cell!(h+1)); + push_cell!(self.machine_st, atom_as_cell!(name, arity)); self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h)); self.machine_st.mode = MachineMode::Write; @@ -2870,8 +2936,7 @@ impl Machine { match self.machine_st.mode { MachineMode::Read => { let addr = self.machine_st.read_s(); - - self.machine_st.write_literal_to_var(addr, v); + unify!(&mut self.machine_st, addr, v); if self.machine_st.fail { self.machine_st.backtrack(); @@ -2881,7 +2946,7 @@ impl Machine { } } MachineMode::Write => { - self.machine_st.heap.push(v); + push_cell!(self.machine_st, v); } } @@ -2906,17 +2971,17 @@ impl Machine { let value = self .machine_st .store(self.machine_st.deref(self.machine_st[reg])); - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); read_heap_cell!(value, (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => { let value = self.machine_st.heap[hc]; - self.machine_st.heap.push(value); + push_cell!(self.machine_st, value); self.machine_st.s_offset += 1; } _ => { - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); (self.machine_st.bind_fn)( &mut self.machine_st, Ref::heap_cell(h), @@ -2932,13 +2997,14 @@ impl Machine { &Instruction::UnifyVariable(reg) => { match self.machine_st.mode { MachineMode::Read => { - self.machine_st[reg] = self.machine_st.read_s(); + let value = self.machine_st.read_s(); + self.machine_st[reg] = value; self.machine_st.s_offset += 1; } MachineMode::Write => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[reg] = heap_loc_as_cell!(h); } } @@ -2961,8 +3027,8 @@ impl Machine { } } MachineMode::Write => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let h = self.machine_st.heap.cell_len(); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); let addr = self.machine_st.store(self.machine_st[reg]); (self.machine_st.bind_fn)( @@ -2974,7 +3040,7 @@ impl Machine { // the former code of this match arm was: // let addr = self.machine_st.store(self.machine_st[reg]); - // self.machine_st.heap.push(HeapCellValue::Addr(addr)); + // push_cell!(self.machine_st, HeapCellValue::Addr(addr)); // the old code didn't perform the occurs // check when enabled and so it was changed to @@ -2991,10 +3057,10 @@ impl Machine { self.machine_st.s_offset += n; } MachineMode::Write => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); for i in h..h + n { - self.machine_st.heap.push(heap_loc_as_cell!(i)); + push_cell!(self.machine_st, heap_loc_as_cell!(i)); } } } @@ -3126,38 +3192,26 @@ impl Machine { } } } - &Instruction::PutConstant(_, c, reg) => { - self.machine_st[reg] = c; + &Instruction::PutConstant(_, cell, reg) => { + self.machine_st[reg] = cell; self.machine_st.p += 1; } &Instruction::PutList(_, reg) => { - self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len()); + self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.cell_len()); self.machine_st.p += 1; } - &Instruction::PutPartialString(_, string, reg, has_tail) => { - let pstr_addr = if has_tail { - if string != atom!("") { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(string_as_pstr_cell!(string)); - - // the tail will be pushed by the next - // instruction, so don't push one here. - - pstr_loc_as_cell!(h) - } else { - empty_list_as_cell!() - } - } else { - string_as_cstr_cell!(string) - }; + &Instruction::PutPartialString(_, ref string, reg) => { + self.machine_st[reg] = backtrack_on_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(&string) + ); - self.machine_st[reg] = pstr_addr; self.machine_st.p += 1; } &Instruction::PutStructure(name, arity, reg) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(atom_as_cell!(name, arity)); + push_cell!(self.machine_st, atom_as_cell!(name, arity)); self.machine_st[reg] = str_loc_as_cell!(h); self.machine_st.p += 1; @@ -3171,9 +3225,9 @@ impl Machine { if addr.is_protected(self.machine_st.e) { self.machine_st.registers[arg] = addr; } else { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); (self.machine_st.bind_fn)( &mut self.machine_st, Ref::heap_cell(h), @@ -3197,8 +3251,8 @@ impl Machine { self.machine_st.registers[arg] = self.machine_st[norm]; } RegType::Temp(_) => { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let h = self.machine_st.heap.cell_len(); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[norm] = heap_loc_as_cell!(h); self.machine_st.registers[arg] = heap_loc_as_cell!(h); @@ -3208,7 +3262,7 @@ impl Machine { self.machine_st.p += 1; } &Instruction::SetConstant(c) => { - self.machine_st.heap.push(c); + push_cell!(self.machine_st, c); self.machine_st.p += 1; } &Instruction::SetLocalValue(reg) => { @@ -3216,37 +3270,37 @@ impl Machine { let stored_v = self.machine_st.store(addr); if stored_v.is_stack_var() { - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + let h = self.machine_st.heap.cell_len(); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); (self.machine_st.bind_fn)( &mut self.machine_st, Ref::heap_cell(h), stored_v, ); } else { - self.machine_st.heap.push(stored_v); + push_cell!(self.machine_st, stored_v); } self.machine_st.p += 1; } &Instruction::SetVariable(reg) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + push_cell!(self.machine_st, heap_loc_as_cell!(h)); self.machine_st[reg] = heap_loc_as_cell!(h); self.machine_st.p += 1; } &Instruction::SetValue(reg) => { let heap_val = self.machine_st.store(self.machine_st[reg]); - self.machine_st.heap.push(heap_val); + push_cell!(self.machine_st, heap_val); self.machine_st.p += 1; } &Instruction::SetVoid(n) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); for i in h..h + n { - self.machine_st.heap.push(heap_loc_as_cell!(i)); + push_cell!(self.machine_st, heap_loc_as_cell!(i)); } self.machine_st.p += 1; @@ -3363,11 +3417,11 @@ impl Machine { } &Instruction::CallCopyToLiftedHeap => { self.copy_to_lifted_heap(); - self.machine_st.p += 1; + step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteCopyToLiftedHeap => { self.copy_to_lifted_heap(); - self.machine_st.p = self.machine_st.cp; + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallCreatePartialString => { self.create_partial_string(); @@ -3519,15 +3573,6 @@ impl Machine { self.dynamic_module_resolution(arity - 2) ); - /* - println!( - "(slow) calling {}:{}/{}", - module_name.as_str(), - key.0.as_str(), - key.1, - ); - */ - try_or_throw!(self.machine_st, self.call_clause(module_name, key)); if self.machine_st.fail { @@ -3540,15 +3585,6 @@ impl Machine { self.dynamic_module_resolution(arity - 2) ); - /* - println!( - "(slow) executing {}:{}/{}", - module_name.as_str(), - key.0.as_str(), - key.1, - ); - */ - try_or_throw!(self.machine_st, self.execute_clause(module_name, key)); if self.machine_st.fail { @@ -4291,11 +4327,11 @@ impl Machine { } &Instruction::CallSetBall => { self.set_ball(); - self.machine_st.p += 1; + step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteSetBall => { self.set_ball(); - self.machine_st.p = self.machine_st.cp; + step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallPushBallStack => { self.push_ball_stack(); @@ -4630,19 +4666,19 @@ impl Machine { step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadHTML => { - self.load_html(); + backtrack_on_resource_error!(self.machine_st, self.load_html()); step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteLoadHTML => { - self.load_html(); + backtrack_on_resource_error!(self.machine_st, self.load_html()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallLoadXML => { - self.load_xml(); + backtrack_on_resource_error!(self.machine_st, self.load_xml()); step_or_fail!(self, self.machine_st.p += 1); } &Instruction::ExecuteLoadXML => { - self.load_xml(); + backtrack_on_resource_error!(self.machine_st, self.load_xml()); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } &Instruction::CallGetEnv => { @@ -5119,13 +5155,18 @@ impl Machine { let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); - let h = self.machine_st.heap.len(); - self.machine_st - .heap - .extend(functor!(atom!("-"), [fixnum(n), fixnum(p)])); + let mut writer = Heap::functor_writer( + functor!(atom!("-"), [fixnum(n), fixnum(p)]), + ); + + let str_cell = backtrack_on_resource_error!( + &mut self.machine_st, + writer(&mut self.machine_st.heap) + ); let r = r.as_var().unwrap(); - self.machine_st.bind(r, str_loc_as_cell!(h)); + + self.machine_st.bind(r, str_cell); step_or_fail!(self, self.machine_st.p += 1); } @@ -5137,13 +5178,18 @@ impl Machine { let r = self.machine_st.registers[2]; let r = self.machine_st.store(self.machine_st.deref(r)); - let h = self.machine_st.heap.len(); - self.machine_st - .heap - .extend(functor!(atom!("-"), [fixnum(n), fixnum(p)])); + let mut writer = Heap::functor_writer( + functor!(atom!("-"), [fixnum(n), fixnum(p)]), + ); + + let str_cell = backtrack_on_resource_error!( + &mut self.machine_st, + writer(&mut self.machine_st.heap) + ); let r = r.as_var().unwrap(); - self.machine_st.bind(r, str_loc_as_cell!(h)); + + self.machine_st.bind(r, str_cell); step_or_fail!(self, self.machine_st.p = self.machine_st.cp); } diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 456f075f..f0f480f3 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -1,15 +1,22 @@ -#![allow(dead_code)] - +#[cfg(test)] use crate::atom_table::*; +#[cfg(test)] use crate::machine::heap::*; +#[cfg(test)] use crate::types::*; +#[cfg(test)] +use fxhash::FxBuildHasher; +#[cfg(test)] +use indexmap::IndexMap; + #[cfg(test)] use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; #[cfg(test)] use std::ops::Deref; +#[cfg(test)] pub(crate) trait UnmarkPolicy { fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option where @@ -29,8 +36,7 @@ pub(crate) trait UnmarkPolicy { fn record_focus(_iter: &mut StacklessPreOrderHeapIter) where Self: Sized, - { - } + {} } #[cfg(test)] @@ -71,8 +77,10 @@ impl UnmarkPolicy for IteratorUMP { } } +#[cfg(test)] struct MarkerUMP {} +#[cfg(test)] impl UnmarkPolicy for MarkerUMP { #[inline(always)] fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter) -> Option { @@ -100,18 +108,23 @@ impl UnmarkPolicy for MarkerUMP { } } +#[cfg(test)] +type PStrLocValuesMap = IndexMap; + +#[cfg(test)] #[derive(Debug)] pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> { - pub(crate) heap: &'a mut [HeapCellValue], + pub(crate) heap: &'a mut Heap, start: usize, current: usize, next: u64, iter_state: UMP, + pstr_loc_values: PStrLocValuesMap, } #[cfg(test)] impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> { - type Target = [HeapCellValue]; + type Target = Heap; fn deref(&self) -> &Self::Target { self.heap @@ -126,6 +139,7 @@ impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> { } } +#[cfg(test)] impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { fn drop(&mut self) { UMP::invert_marker(self); @@ -138,8 +152,9 @@ impl<'a, UMP: UnmarkPolicy> Drop for StacklessPreOrderHeapIter<'a, UMP> { } } +#[cfg(test)] impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> { - 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(); @@ -149,13 +164,15 @@ impl<'a> StacklessPreOrderHeapIter<'a, MarkerUMP> { current: start, next, iter_state: MarkerUMP {}, + pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()), } } } #[cfg(test)] impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> { - pub(crate) fn new(heap: &'a mut [HeapCellValue], start: usize) -> Self { + #[cfg(test)] + pub(crate) fn new(heap: &'a mut Heap, start: usize) -> Self { heap[start].set_forwarding_bit(true); let next = heap[start].get_value(); @@ -165,10 +182,12 @@ impl<'a> StacklessPreOrderHeapIter<'a, IteratorUMP> { current: start, next, iter_state: IteratorUMP { mark_phase: true }, + pstr_loc_values: PStrLocValuesMap::with_hasher(FxBuildHasher::default()), } } } +#[cfg(test)] impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { fn backward_and_return(&mut self) -> HeapCellValue { let mut current = self.heap[self.current]; @@ -214,7 +233,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return Some(cell); } - if self.next < self.heap.len() as u64 && UMP::report_var_link(self) { + if self.next < self.heap.cell_len() as u64 && UMP::report_var_link(self) { let tag = HeapCellValueTag::AttrVar; return Some(HeapCellValue::build_with(tag, next as u64)); } @@ -226,7 +245,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return Some(cell); } - if self.next < self.heap.len() as u64 && UMP::report_var_link(self) { + if self.next < self.heap.cell_len() as u64 && UMP::report_var_link(self) { let tag = HeapCellValueTag::Var; return Some(HeapCellValue::build_with(tag, next as u64)); } @@ -241,7 +260,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { let arity = cell_as_atom_cell!(self.heap[h]).get_arity(); - for cell in &mut self.heap[h + 1..h + arity + 1] { + for cell in &mut self.heap.splice_mut(h + 1..h + arity + 1) { cell.set_forwarding_bit(true); } @@ -270,48 +289,21 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { } HeapCellValueTag::PStrLoc => { let h = self.next as usize; + let (_, last_cell_loc) = self.heap.scan_slice_to_str(h); + + self.pstr_loc_values.insert(self.current, h); - if self.heap[h + 1].get_forwarding_bit() { + if self.heap[last_cell_loc].get_forwarding_bit() { return Some(self.backward_and_return()); } - let cell = self.heap[h]; - - let last_cell_loc = h + 1; - 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.heap[last_cell_loc].set_forwarding_bit(true); - 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[last_cell_loc].get_forwarding_bit() { - return Some(self.backward_and_return()); - } - - if self.heap[h].get_tag() == HeapCellValueTag::PStr { - 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); @@ -323,7 +315,15 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { return None; } } - HeapCellValueTag::PStr => { + HeapCellValueTag::Cons if self.heap.pstr_at(self.current) => { + let pstr_loc_loc = self.heap[self.current].get_value() as usize; + let pstr_loc_val = self.pstr_loc_values.get(&pstr_loc_loc).unwrap(); + + self.heap[self.current].set_value(self.next); + + self.next = *pstr_loc_val as u64; + self.current = pstr_loc_loc; + if self.backward() { return None; } @@ -366,6 +366,7 @@ impl<'a, UMP: UnmarkPolicy> StacklessPreOrderHeapIter<'a, UMP> { } } +#[cfg(test)] impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> { type Item = HeapCellValue; @@ -375,157 +376,167 @@ impl<'a, UMP: UnmarkPolicy> Iterator for StacklessPreOrderHeapIter<'a, UMP> { } } -pub fn mark_cells(heap: &mut Heap, start: usize) { - let mut iter = StacklessPreOrderHeapIter::::new(heap, start); - while iter.forward().is_some() {} -} - #[cfg(test)] mod tests { use super::*; + use crate::functor_macro::*; use crate::machine::mock_wam::*; + fn mark_cells(heap: &mut Heap, start: usize) { + let mut iter = StacklessPreOrderHeapIter::::new(heap, start); + while iter.forward().is_some() {} + } + #[test] fn heap_marking_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.push(str_loc_as_cell!(1)); + let mut functor_writer = Heap::functor_writer( + functor!(f_atom, [atom_as_cell(a_atom), atom_as_cell(b_atom)]), + ); - wam.machine_st - .heap - .extend(functor!(f_atom, [atom(a_atom), atom(b_atom)])); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - mark_cells(&mut wam.machine_st.heap, 0); + wam.machine_st.heap.push_cell(cell).unwrap(); + + mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[3]), + str_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom) ); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + 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(1) + ] + ), + ); - wam.machine_st.heap.extend(functor!( - f_atom, - [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) - ] - )); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - mark_cells(&mut wam.machine_st.heap, 0); + wam.machine_st.heap.push_cell(cell).unwrap(); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, h); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[5]), + str_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 4) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), + unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom) ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - str_loc_as_cell!(1) - ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); // make the structure doubly cyclic. - wam.machine_st.heap[2] = str_loc_as_cell!(1); + wam.machine_st.heap[1] = str_loc_as_cell!(0); - mark_cells(&mut wam.machine_st.heap, 0); + mark_cells(&mut wam.machine_st.heap, h); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); + 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) + ] + ), + ); - wam.machine_st.heap.extend(functor!( - f_atom, - [ - atom(a_atom), - atom(b_atom), - atom(a_atom), - cell(str_loc_as_cell!(1)) - ] - )); + let cell = functor_writer(&mut wam.machine_st.heap).unwrap(); + let h = wam.machine_st.heap.cell_len(); - mark_cells(&mut wam.machine_st.heap, 0); + wam.machine_st.heap.push_cell(cell).unwrap(); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, h); + + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[5]), + str_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + unmark_cell_bits!(wam.machine_st.heap[0]), atom_as_cell!(f_atom, 4) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + unmark_cell_bits!(wam.machine_st.heap[1]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + unmark_cell_bits!(wam.machine_st.heap[2]), atom_as_cell!(b_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), + unmark_cell_bits!(wam.machine_st.heap[3]), atom_as_cell!(a_atom) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - str_loc_as_cell!(1) + unmark_cell_bits!(wam.machine_st.heap[4]), + str_loc_as_cell!(0) ); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(0)).unwrap(); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -534,16 +545,20 @@ mod tests { wam.machine_st.heap.clear(); - // term is: [a, b] - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(atom_as_cell!(b_atom)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + // term is: [a, b] + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(atom_as_cell!(b_atom)); + section.push_cell(empty_list_as_cell!()); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -566,18 +581,14 @@ mod tests { empty_list_as_cell!() ); - wam.machine_st.heap.pop(); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); // now make the list cyclic. - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + wam.machine_st.heap[4] = heap_loc_as_cell!(0); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -600,7 +611,7 @@ mod tests { heap_loc_as_cell!(0) ); - for cell in &mut wam.machine_st.heap { + for cell in &mut wam.machine_st.heap.splice_mut(..) { cell.set_mark_bit(false); } @@ -609,24 +620,29 @@ mod tests { mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); // term is: [a, ] let stream = Stream::from_static_string("test", &mut wam.machine_st.arena); - let stream_cell = - HeapCellValue::from(ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons)); + let stream_cell = HeapCellValue::from( + ConsPtr::build_with(stream.as_ptr(), ConsPtrMaskTag::Cons), + ); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(a_atom)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(stream_cell); - wam.machine_st.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(a_atom)); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(stream_cell); + section.push_cell(empty_list_as_cell!()); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -650,14 +666,18 @@ mod tests { // now a cycle of variables. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -682,313 +702,231 @@ mod tests { // two-part complete string, then a three-part cyclic string // involving an uncompacted list of chars. - wam.machine_st.heap.push(pstr_loc_as_cell!(1)); - - 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]; - - mark_cells(&mut wam.machine_st.heap, 0); - - all_cells_marked_and_unforwarded(&wam.machine_st.heap); - - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - pstr_loc_as_cell!(1) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - heap_loc_as_cell!(2) - ); + let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); - wam.machine_st.heap.pop(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap(); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + let pstr_cell_loc = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(pstr_loc_as_cell!(3)); + wam.machine_st.heap.push_cell(pstr_loc_as_cell!(heap_index!(0))).unwrap(); - 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]; + mark_cells(&mut wam.machine_st.heap, pstr_cell_loc); - mark_cells(&mut wam.machine_st.heap, 0); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); + assert_eq!(unmark_cell_bits!(wam.machine_st.heap[pstr_cell_loc]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - heap_loc_as_cell!(4) + unmark_cell_bits!(wam.machine_st.heap[1]), + heap_loc_as_cell!(1) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_offset_as_cell!(1)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); + wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 7); + mark_cells(&mut wam.machine_st.heap, 2); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_loc_as_cell!(5) + wam.machine_st.heap[4], + heap_loc_as_cell!(4) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + // create a cycle offset two characters into the partial string at 0 + wam.machine_st.heap[4] = pstr_loc_as_cell!(heap_index!(0) + 2); - wam.machine_st.heap[7] = heap_loc_as_cell!(2); + mark_cells(&mut wam.machine_st.heap, 2); - mark_cells(&mut wam.machine_st.heap, 7); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - heap_loc_as_cell!(2) + wam.machine_st.heap[4], + pstr_loc_as_cell!(heap_index!(0) + 2) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap[4] = heap_loc_as_cell!(2); - wam.machine_st.heap[7] = pstr_loc_as_cell!(1); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(2)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 7); + mark_cells(&mut wam.machine_st.heap, 5); + + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_loc_as_cell!(1) + wam.machine_st.heap[4], + heap_loc_as_cell!(2) + ); + assert_eq!( + wam.machine_st.heap[5], + heap_loc_as_cell!(2) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap[4] = pstr_loc_as_cell!(0); - wam.machine_st.heap[7] = heap_loc_as_cell!(0); + mark_cells(&mut wam.machine_st.heap, 2); - mark_cells(&mut wam.machine_st.heap, 7); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(.. 5)); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[1..]); + unmark_all_cells(wam.machine_st.heap.splice_mut(.. 5)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - pstr_loc_as_cell!(5) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - heap_loc_as_cell!(0) + wam.machine_st.heap[4], + pstr_loc_as_cell!(heap_index!(0)) + ); + assert_eq!( + wam.machine_st.heap[5], + heap_loc_as_cell!(2) ); wam.machine_st.heap.truncate(4); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + let mut writer = wam.machine_st.heap.reserve(2).unwrap(); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_offset_as_cell!(1)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 2)); // offset two chars into pstr at 0 + }); - // this is at index 7 - wam.machine_st.heap.push(pstr_loc_as_cell!(5)); + wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap(); - mark_cells(&mut wam.machine_st.heap, 7); + mark_cells(&mut wam.machine_st.heap, 6); - assert!(!wam.machine_st.heap[0].get_mark_bit()); + // indices 0 and 3 are the beginning of one-cell partial + // strings, and they should be marked! despite the HeapCellValue casts + // otherwise not being sensible. + assert!(wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); + assert!(!wam.machine_st.heap[2].get_mark_bit()); assert!(wam.machine_st.heap[3].get_mark_bit()); assert!(wam.machine_st.heap[4].get_mark_bit()); assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(wam.machine_st.heap[6].get_mark_bit()); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(3) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[3]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_offset_as_cell!(1) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_loc_as_cell!(5) - ); - - wam.machine_st.heap.clear(); - - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(4)); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_second_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(7)); - wam.machine_st - .heap - .push(atom_as_cell!(atom!("irrelevant stuff"))); - wam.machine_st.heap.push(pstr_offset_as_cell!(1)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); - - wam.machine_st.heap.push(pstr_loc_as_cell!(7)); - - mark_cells(&mut wam.machine_st.heap, 9); - - assert!(!wam.machine_st.heap[0].get_mark_bit()); - assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); - assert!(!wam.machine_st.heap[3].get_mark_bit()); - assert!(wam.machine_st.heap[4].get_mark_bit()); - assert!(wam.machine_st.heap[5].get_mark_bit()); - assert!(!wam.machine_st.heap[6].get_mark_bit()); - assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap.slice_to_str(0, "abc ".len()), + "abc " ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(3)) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(0)) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) + wam.machine_st.heap.slice_to_str(heap_index!(3), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[4], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(0) + 2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[6], + heap_loc_as_cell!(5) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + wam.machine_st.heap.clear(); - wam.machine_st.heap[9] = heap_loc_as_cell!(5); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - mark_cells(&mut wam.machine_st.heap, 9); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_pstr("abc "); + section.push_cell(pstr_loc_as_cell!(heap_index!(4))); + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_pstr("def"); + section.push_cell(pstr_loc_as_cell!(heap_index!(1) + 2)); + section.push_cell(atom_as_cell!(atom!("irrelevant stuff"))); + section.push_cell(pstr_loc_as_cell!(heap_index!(1) + 2)); + }); + + mark_cells(&mut wam.machine_st.heap, 7); assert!(!wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); @@ -997,104 +935,49 @@ mod tests { assert!(wam.machine_st.heap[4].get_mark_bit()); assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(!wam.machine_st.heap[6].get_mark_bit()); - assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) - ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(4)) ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - wam.machine_st.heap[9] = pstr_loc_as_cell!(4); - - mark_cells(&mut wam.machine_st.heap, 9); - - assert!(!wam.machine_st.heap[0].get_mark_bit()); - assert!(wam.machine_st.heap[1].get_mark_bit()); - assert!(wam.machine_st.heap[2].get_mark_bit()); - assert!(!wam.machine_st.heap[3].get_mark_bit()); - assert!(wam.machine_st.heap[4].get_mark_bit()); - assert!(wam.machine_st.heap[5].get_mark_bit()); - assert!(!wam.machine_st.heap[6].get_mark_bit()); - assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), + wam.machine_st.heap[3], atom_as_cell!(atom!("irrelevant stuff")) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) + wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + "def" ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(1) + 2) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[6], atom_as_cell!(atom!("irrelevant stuff")) ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) - ); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - mark_cells(&mut wam.machine_st.heap, 9); + wam.machine_st.heap[7] = heap_loc_as_cell!(2); - wam.machine_st.heap[9] = heap_loc_as_cell!(2); + mark_cells(&mut wam.machine_st.heap, 7); assert!(!wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); @@ -1104,50 +987,49 @@ mod tests { assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(!wam.machine_st.heap[6].get_mark_bit()); assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), + wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) + wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(4)) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) + wam.machine_st.heap[3], + atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + "def" ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(1) + 2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[6], + atom_as_cell!(atom!("irrelevant stuff")) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - wam.machine_st.heap[9] = pstr_loc_as_cell!(1); + wam.machine_st.heap[7] = pstr_loc_as_cell!(heap_index!(4)); - mark_cells(&mut wam.machine_st.heap, 9); + mark_cells(&mut wam.machine_st.heap, 7); assert!(!wam.machine_st.heap[0].get_mark_bit()); assert!(wam.machine_st.heap[1].get_mark_bit()); @@ -1157,181 +1039,143 @@ mod tests { assert!(wam.machine_st.heap[5].get_mark_bit()); assert!(!wam.machine_st.heap[6].get_mark_bit()); assert!(wam.machine_st.heap[7].get_mark_bit()); - assert!(wam.machine_st.heap[8].get_mark_bit()); - for cell in &wam.machine_st.heap { - assert!(!cell.get_forwarding_bit()); - } + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); + + assert!(!wam.machine_st.heap[0].get_forwarding_bit()); + assert!(!wam.machine_st.heap[1].get_forwarding_bit()); + assert!(!wam.machine_st.heap[2].get_forwarding_bit()); + assert!(!wam.machine_st.heap[3].get_forwarding_bit()); + assert!(!wam.machine_st.heap[4].get_forwarding_bit()); + assert!(!wam.machine_st.heap[5].get_forwarding_bit()); + assert!(!wam.machine_st.heap[6].get_forwarding_bit()); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), + wam.machine_st.heap[0], atom_as_cell!(atom!("irrelevant stuff")) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[1]), pstr_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_loc_as_cell!(4) + wam.machine_st.heap.slice_to_str(heap_index!(1), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap[2], + pstr_loc_as_cell!(heap_index!(4)) ); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[4]), pstr_second_cell); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(7) + wam.machine_st.heap[3], + atom_as_cell!(atom!("irrelevant stuff")) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - atom_as_cell!(atom!("irrelevant stuff")) + wam.machine_st.heap.slice_to_str(heap_index!(4), "def".len()), + "def" ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[7]), - pstr_offset_as_cell!(1) + wam.machine_st.heap[5], + pstr_loc_as_cell!(heap_index!(1) + 2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[8]), - fixnum_as_cell!(Fixnum::build_with(2)) + wam.machine_st.heap[6], + atom_as_cell!(atom!("irrelevant stuff")) ); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - wam.machine_st.heap.clear(); - // embedded cyclic partial string. + // embedded cyclic partial string - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(8).unwrap(); - mark_cells(&mut wam.machine_st.heap, 4); + writer.write_with(|section| { + section.push_pstr("abc "); + section.push_cell(pstr_loc_as_cell!(heap_index!(0) + 3)); // 3 character offset into pstr_cell + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(pstr_loc_as_cell!(0)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(2)); + }); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + mark_cells(&mut wam.machine_st.heap, 5); - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), - pstr_loc_as_cell!(2) - ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_offset_as_cell!(0) + wam.machine_st.heap.slice_to_str(heap_index!(0), "abc ".len()), + "abc " ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - fixnum_as_cell!(Fixnum::build_with(3)) + wam.machine_st.heap[1], + pstr_loc_as_cell!(heap_index!(0) + 3) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - list_loc_as_cell!(5) + wam.machine_st.heap[2], + list_loc_as_cell!(3) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), + wam.machine_st.heap[3], pstr_loc_as_cell!(0) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), + wam.machine_st.heap[4], empty_list_as_cell!() ); - - wam.machine_st.heap.clear(); - - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(pstr_loc_as_cell!(0)); - wam.machine_st.heap.push(heap_loc_as_cell!(4)); - - mark_cells(&mut wam.machine_st.heap, 4); - - all_cells_marked_and_unforwarded(&wam.machine_st.heap); - - for cell in &mut wam.machine_st.heap { - cell.set_mark_bit(false); - } - - assert_eq!(unmark_cell_bits!(wam.machine_st.heap[0]), pstr_cell); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), - pstr_loc_as_cell!(2) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), - pstr_offset_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), - fixnum_as_cell!(Fixnum::build_with(3)) - ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[4]), - list_loc_as_cell!(5) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[5]), - pstr_loc_as_cell!(0) - ); - assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[6]), - heap_loc_as_cell!(4) + wam.machine_st.heap[5], + heap_loc_as_cell!(2) ); wam.machine_st.heap.clear(); // a chain of variables, ending in a self-referential variable. - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(3)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); + + unmark_all_cells(wam.machine_st.heap.splice_mut(..)); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[0]), + wam.machine_st.heap[0], heap_loc_as_cell!(1) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[1]), + wam.machine_st.heap[1], heap_loc_as_cell!(2) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[2]), + wam.machine_st.heap[2], heap_loc_as_cell!(3) ); assert_eq!( - unmark_cell_bits!(wam.machine_st.heap[3]), + wam.machine_st.heap[3], heap_loc_as_cell!(3) ); wam.machine_st.heap.clear(); // 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)); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + 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)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1350,23 +1194,28 @@ mod tests { // term is [X,f(Y),Z]. // Z is an attributed variable, but has a variable attributes list. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); // 2 - wam.machine_st.heap.push(list_loc_as_cell!(4)); // 3 - wam.machine_st.heap.push(str_loc_as_cell!(6)); // 4 - wam.machine_st.heap.push(heap_loc_as_cell!(8)); - wam.machine_st.heap.push(atom_as_cell!(f_atom, 1)); // 6 - wam.machine_st.heap.push(heap_loc_as_cell!(11)); // 7 - wam.machine_st.heap.push(list_loc_as_cell!(9)); - wam.machine_st.heap.push(heap_loc_as_cell!(9)); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(attr_var_as_cell!(11)); // linked from 7. - wam.machine_st.heap.push(heap_loc_as_cell!(12)); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(3)); // 2 + section.push_cell(list_loc_as_cell!(4)); // 3 + section.push_cell(str_loc_as_cell!(6)); // 4 + section.push_cell(heap_loc_as_cell!(8)); + section.push_cell(atom_as_cell!(f_atom, 1)); // 6 + section.push_cell(heap_loc_as_cell!(11)); // 7 + section.push_cell(list_loc_as_cell!(9)); + section.push_cell(heap_loc_as_cell!(9)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(attr_var_as_cell!(11)); // linked from 7. + section.push_cell(heap_loc_as_cell!(12)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1425,29 +1274,32 @@ mod tests { let clpz_atom = atom!("clpz"); let p_atom = atom!("p"); - for cell in &mut wam.machine_st.heap { + for cell in &mut wam.machine_st.heap.splice_mut(..) { cell.set_mark_bit(false); cell.set_forwarding_bit(false); } - wam.machine_st.heap.pop(); - - wam.machine_st.heap.push(heap_loc_as_cell!(13)); // 12 - wam.machine_st.heap.push(list_loc_as_cell!(14)); // 13 - wam.machine_st.heap.push(str_loc_as_cell!(16)); // 14 - wam.machine_st.heap.push(heap_loc_as_cell!(19)); // 15 - wam.machine_st.heap.push(atom_as_cell!(clpz_atom, 2)); // 16 - wam.machine_st.heap.push(atom_as_cell!(a_atom)); // 17 - wam.machine_st.heap.push(atom_as_cell!(b_atom)); // 18 - wam.machine_st.heap.push(list_loc_as_cell!(20)); // 19 - wam.machine_st.heap.push(str_loc_as_cell!(22)); // 20 - wam.machine_st.heap.push(empty_list_as_cell!()); // 21 - wam.machine_st.heap.push(atom_as_cell!(p_atom, 1)); // 22 - wam.machine_st.heap.push(heap_loc_as_cell!(23)); // 23 + wam.machine_st.heap[12] = heap_loc_as_cell!(13); + + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(14)); // 13 + section.push_cell(str_loc_as_cell!(16)); // 14 + section.push_cell(heap_loc_as_cell!(19)); // 15 + section.push_cell(atom_as_cell!(clpz_atom, 2)); // 16 + section.push_cell(atom_as_cell!(a_atom)); // 17 + section.push_cell(atom_as_cell!(b_atom)); // 18 + section.push_cell(list_loc_as_cell!(20)); // 19 + section.push_cell(str_loc_as_cell!(22)); // 20 + section.push_cell(empty_list_as_cell!()); // 21 + section.push_cell(atom_as_cell!(p_atom, 1)); // 22 + section.push_cell(heap_loc_as_cell!(23)); // 23 + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1546,22 +1398,26 @@ mod tests { heap_loc_as_cell!(23) ); - for cell in &mut wam.machine_st.heap { + for cell in &mut wam.machine_st.heap.splice_mut(..) { cell.set_mark_bit(false); cell.set_forwarding_bit(false); } // push some unrelated nonsense cells to the heap and check that they // are unmarked after the marker has finished at 0. - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(5)); + section.push_cell(heap_loc_as_cell!(5)); + section.push_cell(list_loc_as_cell!(5)); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[0..24]); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(0..24)); - for cell in &wam.machine_st.heap[24..] { + for cell in wam.machine_st.heap.splice(24..) { assert!(!cell.get_mark_bit()); } @@ -1677,32 +1533,37 @@ mod tests { wam.machine_st.heap.clear(); wam.machine_st .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); + .push_cell(fixnum_as_cell!(Fixnum::build_with(0))) + .unwrap(); mark_cells(&mut wam.machine_st.heap, 0); - assert_eq!(wam.machine_st.heap.len(), 1); + assert_eq!(wam.machine_st.heap.cell_len(), 1); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("g"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(atom_as_cell!(atom!("y"))); - wam.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - wam.machine_st.heap.push(atom_as_cell!(atom!("X"))); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(8)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("g"), 2)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(atom_as_cell!(atom!("y"))); + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(atom!("X"))); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(8)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(empty_list_as_cell!()); + }); mark_cells(&mut wam.machine_st.heap, 7); - assert_eq!(wam.machine_st.heap.len(), 10); + assert_eq!(wam.machine_st.heap.cell_len(), 10); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1747,14 +1608,18 @@ mod tests { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cell!(atom!("f"), 2)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(str_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("f"), 2)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(heap_loc_as_cell!(1)); + section.push_cell(str_loc_as_cell!(0)); + }); mark_cells(&mut wam.machine_st.heap, 3); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1773,19 +1638,22 @@ mod tests { // representation of one of the heap terms as in issue #1384. - wam.machine_st.heap.push(list_loc_as_cell!(1)); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(5)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(list_loc_as_cell!(5)); + }); mark_cells(&mut wam.machine_st.heap, 7); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1820,23 +1688,27 @@ mod tests { // representation of one of the heap terms as in issue #1384. - wam.machine_st.heap.push(list_loc_as_cell!(7)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); // A = [B|[]]. - wam.machine_st.heap.push(list_loc_as_cell!(5)); // B = [A|A]. - wam.machine_st.heap.push(empty_list_as_cell!()); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); - wam.machine_st.heap.push(empty_list_as_cell!()); // C = [[]|B]. - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(7)); + section.push_cell(heap_loc_as_cell!(0)); + section.push_cell(list_loc_as_cell!(3)); // A = [B|[]]. + section.push_cell(list_loc_as_cell!(5)); // B = [A|A]. + section.push_cell(empty_list_as_cell!()); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(heap_loc_as_cell!(2)); + section.push_cell(empty_list_as_cell!()); // C = [[]|B]. + section.push_cell(heap_loc_as_cell!(3)); + section.push_cell(heap_loc_as_cell!(0)); + }); mark_cells(&mut wam.machine_st.heap, 9); assert!(wam.machine_st.heap[0].get_mark_bit()); assert!(!wam.machine_st.heap[1].get_mark_bit()); - all_cells_marked_and_unforwarded(&wam.machine_st.heap[2..]); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(2..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), @@ -1874,31 +1746,31 @@ mod tests { unmark_cell_bits!(wam.machine_st.heap[8]), heap_loc_as_cell!(3) ); + assert_eq!( + unmark_cell_bits!(wam.machine_st.heap[9]), + heap_loc_as_cell!(0) + ); wam.machine_st.heap.clear(); - wam.machine_st.heap.push(str_loc_as_cell!(1)); - wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2)); - wam.machine_st.heap.push(str_loc_as_cell!(4)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.machine_st.heap.push(atom_as_cell!(atom!("-"), 2)); - wam.machine_st.heap.push(str_loc_as_cell!(7)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1))); - wam.machine_st.heap.push(atom_as_cell!(atom!("+"), 2)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(4))); + let mut writer = wam.machine_st.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(1)); + section.push_cell(atom_as_cell!(atom!("+"), 2)); + section.push_cell(str_loc_as_cell!(4)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(2))); + section.push_cell(atom_as_cell!(atom!("-"), 2)); + section.push_cell(str_loc_as_cell!(7)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(1))); + section.push_cell(atom_as_cell!(atom!("+"), 2)); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(3))); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(4))); + }); mark_cells(&mut wam.machine_st.heap, 0); - all_cells_marked_and_unforwarded(&wam.machine_st.heap); + all_cells_marked_and_unforwarded(wam.machine_st.heap.splice(..)); assert_eq!( unmark_cell_bits!(wam.machine_st.heap[0]), diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 0f42b8c6..5dd33a9b 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,245 +1,1333 @@ -use crate::arena::*; use crate::atom_table::*; use crate::forms::*; -use crate::machine::machine_indices::*; -use crate::machine::partial_string::*; -use crate::parser::ast::*; +use crate::functor_macro::*; use crate::types::*; -use crate::parser::dashu::{Integer, Rational}; - +use std::alloc; use std::convert::TryFrom; +use std::mem; +use std::ops::{Bound, Index, IndexMut, Range, RangeBounds}; +use std::ptr; +use std::sync::Once; -pub(crate) type Heap = Vec; +use super::MachineState; -impl From for HeapCellValue { - #[inline] - fn from(literal: Literal) -> Self { - match literal { - Literal::Atom(name) => atom_as_cell!(name), - Literal::Char(c) => char_as_cell!(c), - Literal::CodeIndex(ptr) => { - untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr)) +use bitvec::prelude::*; +use bitvec::slice::BitSlice; + +#[derive(Debug)] +pub struct Heap { + inner: InnerHeap, + pstr_vec: BitVec, + resource_err_loc: usize, +} + +impl Drop for Heap { + fn drop(&mut self) { + unsafe { + let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + alloc::dealloc(self.inner.ptr, layout); + } + } +} + +#[derive(Debug)] +struct InnerHeap { + ptr: *mut u8, + byte_len: usize, + byte_cap: usize, +} + +impl InnerHeap { + unsafe fn grow(&mut self) -> bool { + let new_cap = if self.byte_cap == 0 { + 256 * 256 * 8 + } else { + 2 * self.byte_cap + }; + + let new_layout = alloc::Layout::array::(new_cap).unwrap(); + + assert!( + new_layout.size() <= isize::MAX as usize, + "Allocation too large. We should probably GC (TODO)" + ); + + let new_ptr = if self.byte_cap == 0 { + alloc::alloc(new_layout) + } else { + let old_layout = alloc::Layout::array::(self.byte_cap).unwrap(); + alloc::realloc(self.ptr, old_layout, new_layout.size()) + }; + + if !new_ptr.is_null() { + self.ptr = new_ptr; + self.byte_cap = new_cap; + + true + } else { + false + } + } +} + +unsafe impl Send for Heap {} +unsafe impl Sync for Heap {} + +static RESOURCE_ERROR_OFFSET_INIT: Once = Once::new(); + +// return the string at ptr and the tail location relative to ptr. +// pstr_vec records the location of each string cell starting at index +// 0. +fn scan_slice_to_str(orig_ptr: *const u8, pstr_vec: &BitSlice) -> (&str, usize) { + unsafe { + debug_assert_eq!(pstr_vec[0], true); + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + let tail_cell_offset = pstr_vec[0..].first_zero().unwrap(); + let offset = (ALIGN_CELL - orig_ptr.align_offset(ALIGN_CELL)) % 8; + let buf_len = heap_index!(tail_cell_offset) - offset; + let slice = std::slice::from_raw_parts(orig_ptr, buf_len); + + // skip the final buffer byte which may not be 0 depending on + // the context, i.e. marking by an iterator. it is counted by + // the initial 1 as part of the padding but for this reason + // mustn't be allowed to stop the count. + + let padding_len = 1 + slice.iter() + .rev() + .skip(1) + .position(|b| *b != 0u8) + .unwrap(); + + let s_len = slice.len() - padding_len; + (std::str::from_utf8_unchecked(&slice[0 .. s_len]), tail_cell_offset) + } +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum PStrSegmentCmpResult { + Mismatch { c1: char, c2: char }, + FirstMatch { pstr_loc1: usize, pstr_loc2: usize, l1_offset: usize }, + SecondMatch { pstr_loc1: usize, pstr_loc2: usize, l2_offset: usize }, + BothMatch { pstr_loc1: usize, pstr_loc2: usize, null_offset: usize }, +} + +impl PStrSegmentCmpResult { + pub(crate) fn continue_pstr_compare( + self, + pdl: &mut Vec, + ) -> Option { + match self { + PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset } => { + let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + l1_offset); + let rest_of_l2 = pstr_loc_as_cell!(pstr_loc2 + l1_offset); + + pdl.push(heap_loc_as_cell!(tail1)); + pdl.push(rest_of_l2); + } + PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset } => { + let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + l2_offset); + let rest_of_l1 = pstr_loc_as_cell!(pstr_loc1 + l2_offset); + + pdl.push(rest_of_l1); + pdl.push(heap_loc_as_cell!(tail2)); } - Literal::Fixnum(n) => fixnum_as_cell!(n), - Literal::Integer(bigint_ptr) => { - typed_arena_ptr_as_cell!(bigint_ptr) + PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset } => { + // exhaustive match + let tail1 = Heap::neighboring_cell_offset(pstr_loc1 + null_offset); + let tail2 = Heap::neighboring_cell_offset(pstr_loc2 + null_offset); + + pdl.push(heap_loc_as_cell!(tail1)); + pdl.push(heap_loc_as_cell!(tail2)); } - Literal::Rational(bigint_ptr) => { - typed_arena_ptr_as_cell!(bigint_ptr) + PStrSegmentCmpResult::Mismatch { c1, c2 } => { + return Some(c1.cmp(&c2)); } - Literal::Float(f) => HeapCellValue::from(f.as_ptr()), - Literal::String(s) => { - if s == atom!("") { - empty_list_as_cell!() - } else { - string_as_cstr_cell!(s) + } + + None + } +} + +#[derive(Debug)] +pub(crate) struct HeapView<'a> { + slice: *const u8, + cell_offset: usize, + slice_cell_len: usize, + pstr_slice: &'a BitSlice, +} + +impl<'a> HeapView<'a> { + /* + pub fn get(&self, idx: usize) -> Option { + if idx < self.slice_cell_len { + Some(*self.index(idx)) + } else { + None + } + } + */ + + fn iter_follow(&mut self) -> Option { + if self.slice_cell_len == 0 { + None + } else { + let cell; + + if self.pstr_slice[0] { + cell = pstr_loc_as_cell!(heap_index!(self.cell_offset)); + let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap(); + + unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); } + self.slice_cell_len -= next_cell_idx; + self.cell_offset += next_cell_idx; + self.pstr_slice = &self.pstr_slice[next_cell_idx ..]; + } else { + unsafe { + cell = ptr::read(self.slice as *mut HeapCellValue); + self.slice = self.slice.add(heap_index!(1)); } + + self.cell_offset += 1; + self.slice_cell_len -= 1; + self.pstr_slice = &self.pstr_slice[1 ..]; } + + Some(cell) } } } -impl TryFrom for Literal { - type Error = (); +impl<'a> Iterator for HeapView<'a> { + type Item = HeapCellValue; - fn try_from(value: HeapCellValue) -> Result { - read_heap_cell!(value, - (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - Ok(Literal::Atom(name)) + #[inline] + fn next(&mut self) -> Option { + self.iter_follow() + } +} + +impl<'a> Index for HeapView<'a> { + type Output = HeapCellValue; + + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(idx < self.slice_cell_len); + unsafe { + &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +#[derive(Debug)] +pub(crate) struct HeapViewMut<'a> { + slice: *mut u8, + cell_offset: usize, + slice_cell_len: usize, + pstr_slice: &'a BitSlice, +} + +impl<'a> HeapViewMut<'a> { + fn iter_follow(&mut self) -> Option<&'a mut HeapCellValue> { + if self.slice_cell_len == 0 { + None + } else { + let cell; + + loop { + if self.pstr_slice[0] { + let next_cell_idx = self.pstr_slice[0 ..].first_zero().unwrap(); + + unsafe { self.slice = self.slice.add(heap_index!(next_cell_idx)); } + + self.slice_cell_len -= next_cell_idx; + self.cell_offset += next_cell_idx; + self.pstr_slice = &self.pstr_slice[next_cell_idx ..]; } else { - Err(()) + unsafe { + cell = &mut *(self.slice as *mut HeapCellValue); + self.slice = self.slice.add(heap_index!(1)); + } + + self.cell_offset += 1; + self.slice_cell_len -= 1; + self.pstr_slice = &self.pstr_slice[1 ..]; + + break; } } - (HeapCellValueTag::Char, c) => { - Ok(Literal::Char(c)) + + Some(cell) + } + } +} + + + +impl<'a> Index for HeapViewMut<'a> { + type Output = HeapCellValue; + + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(idx < self.slice_cell_len); + unsafe { + &*(self.slice.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +impl<'a> IndexMut for HeapViewMut<'a> { + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + debug_assert!(idx < self.slice_cell_len); + unsafe { + &mut *(self.slice.add(heap_index!(idx)) as *mut HeapCellValue) + } + } +} + +impl<'a> Iterator for &'a mut HeapViewMut<'a> { + type Item = &'a mut HeapCellValue; + + #[inline] + fn next(&mut self) -> Option { + self.iter_follow() + } +} + +#[derive(Debug)] +pub struct PStrWriteInfo { + pstr_loc: usize, +} + +#[derive(Debug)] +pub(crate) struct ReservedHeapSection<'a> { + heap_ptr: *mut u8, + heap_cell_len: usize, + pstr_vec: &'a mut BitVec, +} + +impl<'a> ReservedHeapSection<'a> { + #[inline] + pub(crate) fn cell_len(&self) -> usize { + self.heap_cell_len + } + + pub(crate) fn push_cell(&mut self, cell: HeapCellValue) { + unsafe { + ptr::write(self.heap_ptr.add(heap_index!(self.heap_cell_len)) as *mut _, cell); + } + self.pstr_vec.push(false); + self.heap_cell_len += 1; + } + + fn push_pstr_segment( + &mut self, + src: &str, + ) -> usize { + if src.is_empty() { + return 0; + } + + let cells_written; + let str_byte_len = src.len(); + + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), + self.heap_ptr.add(heap_index!(self.heap_cell_len)), + str_byte_len, + ); + + let zero_region_idx = heap_index!(self.heap_cell_len) + str_byte_len; + + let align_offset = self.heap_ptr + .add(zero_region_idx) + .align_offset(ALIGN_CELL); + + let align_offset = if align_offset == 0 { + ALIGN_CELL + } else { + align_offset + }; + + ptr::write_bytes( + self.heap_ptr.add(zero_region_idx), + 0u8, + align_offset, + ); + + cells_written = cell_index!(src.len() + align_offset); + self.heap_cell_len += cells_written; + } + + cells_written + } + + pub(crate) fn push_pstr( + &mut self, + mut src: &str, + ) -> Option { + let orig_h = self.cell_len(); + + if src.is_empty() { + return if orig_h == self.heap_cell_len { + // src is empty and always was. nothing allocated + // in this case, so nothing to point to in heap. + None + } else { + self.push_cell(heap_loc_as_cell!(orig_h)); + Some(heap_loc_as_cell!(orig_h)) + }; + } + + loop { + let null_char_idx = src.find('\u{0}').unwrap_or_else(|| src.len()); + + let cell_len = self.cell_len(); + let cells_written = self.push_pstr_segment(&src[0..null_char_idx]); + let tail_idx = self.cell_len(); + + self.pstr_vec.resize(cell_len + cells_written, true); + + if cells_written == 0 { + return None; + } else if null_char_idx + 1 < src.len() { + self.push_cell(pstr_loc_as_cell!(heap_index!(tail_idx + 1))); + src = &src[null_char_idx + 1 ..]; + } else { + return Some(pstr_loc_as_cell!(heap_index!(orig_h))); } - (HeapCellValueTag::Fixnum, n) => { - Ok(Literal::Fixnum(n)) + } + } + + pub(crate) fn functor_writer( + functor: Vec, + ) -> impl FnMut(&mut ReservedHeapSection) { + struct FunctorData<'a> { + functor: &'a Vec, + cell_offset: usize, + cursor: usize, + } + + move |section| { + let mut functor_stack = vec![FunctorData { + functor: &functor, + cell_offset: section.heap_cell_len, + cursor: 0, + }]; + + while let Some(FunctorData { functor, cell_offset, mut cursor }) = functor_stack.pop() { + while cursor < functor.len() { + match &functor[cursor] { + &FunctorElement::AbsoluteCell(cell) => { + section.push_cell(cell); + } + &FunctorElement::Cell(cell) => { + section.push_cell(cell + cell_offset); + } + &FunctorElement::String(_cell_len, ref string) => { + if section.push_pstr(&string).is_some() { + section.push_cell(empty_list_as_cell!()); + } + } + FunctorElement::InnerFunctor(_inner_size, succ_functor) => { + if cursor + 1 < functor.len() { + functor_stack.push(FunctorData { + functor: &functor, + cell_offset, + cursor: cursor + 1, + }); + } + + functor_stack.push(FunctorData { + functor: succ_functor, + cell_offset: section.heap_cell_len, + cursor: 0, + }); + + break; + } + } + + cursor += 1; + } } - (HeapCellValueTag::F64, f) => { - Ok(Literal::Float(f.as_offset())) + } + } +} + +impl<'a> Index for ReservedHeapSection<'a> { + type Output = HeapCellValue; + + #[inline] + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(idx < self.heap_cell_len); + unsafe { + &*(self.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +#[must_use] +#[derive(Debug)] +pub struct HeapWriter<'a> { + section: ReservedHeapSection<'a>, + heap_byte_len: &'a mut usize, +} + +impl<'a> HeapWriter<'a> { + #[allow(dead_code)] + pub(crate) fn write_with_error_handling( + &mut self, + writer: impl FnOnce(&mut ReservedHeapSection) -> Result<(), E>, + ) -> Result { + let old_section_cell_len = self.section.heap_cell_len; + writer(&mut self.section)?; + *self.heap_byte_len = heap_index!(self.section.heap_cell_len); + + // return the number of bytes written + Ok(heap_index!(self.section.heap_cell_len - old_section_cell_len)) + } + + pub(crate) fn write_with( + &mut self, + writer: impl FnOnce(&mut ReservedHeapSection), + ) -> usize { + let old_section_cell_len = self.section.heap_cell_len; + writer(&mut self.section); + *self.heap_byte_len = heap_index!(self.section.heap_cell_len); + + // return the number of bytes written + heap_index!(self.section.heap_cell_len - old_section_cell_len) + } + + #[inline] + pub(crate) fn truncate(&mut self, cell_offset: usize) { + self.section.heap_cell_len = cell_offset; + self.section.pstr_vec.truncate(cell_offset); + *self.heap_byte_len = heap_index!(cell_offset); + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.section.heap_cell_len == 0 + } + + #[inline] + pub(crate) fn cell_len(&self) -> usize { + self.section.heap_cell_len + } +} + +impl<'a> Index for HeapWriter<'a> { + type Output = HeapCellValue; + + #[inline] + fn index(&self, idx: usize) -> &Self::Output { + debug_assert!(heap_index!(idx) < *self.heap_byte_len); + unsafe { + &*(self.section.heap_ptr.add(heap_index!(idx)) as *const HeapCellValue) + } + } +} + +impl<'a> IndexMut for HeapWriter<'a> { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + debug_assert!(heap_index!(idx) < *self.heap_byte_len); + unsafe { + &mut *(self.section.heap_ptr.add(heap_index!(idx)) as *mut HeapCellValue) + } + } +} + +impl<'a> SizedHeap for HeapWriter<'a> { + fn cell_len(&self) -> usize { + self.section.cell_len() + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.section.heap_ptr.add(slice_loc) }, + &self.section.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.section.pstr_vec[cell_offset] + } +} + +impl<'a> SizedHeapMut for HeapWriter<'a> {} + +impl Heap { + pub(crate) fn new() -> Self { + Self { + inner: InnerHeap { + ptr: ptr::null_mut(), + byte_len: 0, + byte_cap: 0, + }, + pstr_vec: bitvec![], + resource_err_loc: 0, + } + } + + #[inline(always)] + unsafe fn grow(&mut self) -> bool { + let result = self.inner.grow(); + + if result { + self.pstr_vec.reserve(cell_index!(self.inner.byte_cap)); + } + + result + } + + #[inline] + fn resource_error_offset(&self) -> usize { + self.resource_err_loc + } + + pub(crate) fn with_cell_capacity(cap: usize) -> Result { + let ptr = unsafe { + let layout = alloc::Layout::array::(cap).unwrap(); + alloc::alloc(layout) + }; + + if ptr.is_null() { + panic!("could not allocate {} bytes for heap!", heap_index!(cap)) + } else { + Ok(Self { + inner: InnerHeap { + ptr, + byte_len: 0, + byte_cap: heap_index!(cap), + }, + pstr_vec: bitvec![], + resource_err_loc: 0, + }) + } + } + + #[must_use] + pub fn reserve(&mut self, num_cells: usize) -> Result { + let section; + let len = heap_index!(num_cells); + + loop { + unsafe { + if self.free_space() >= len { + section = ReservedHeapSection { + heap_ptr: self.inner.ptr, + heap_cell_len: cell_index!(self.inner.byte_len), + pstr_vec: &mut self.pstr_vec, + }; + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } } - (HeapCellValueTag::Cons, cons_ptr) => { - match_untyped_arena_ptr!(cons_ptr, - (ArenaHeaderTag::Integer, n) => { - Ok(Literal::Integer(n)) - } - (ArenaHeaderTag::Rational, n) => { - Ok(Literal::Rational(n)) - } - (ArenaHeaderTag::IndexPtr, ip) => { - Ok(Literal::CodeIndex(CodeIndex::from(ip))) - } - _ => { - Err(()) - } - ) + } + + Ok(HeapWriter { + section, + heap_byte_len: &mut self.inner.byte_len, + }) + } + + pub(crate) fn last_cell_mut(&mut self) -> Option<&mut HeapCellValue> { + if self.inner.byte_len == 0 { + None + } else { + unsafe { + Some(&mut *(self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) + as *mut HeapCellValue)) } - (HeapCellValueTag::CStr, cstr_atom) => { - Ok(Literal::String(cstr_atom)) + } + } + + pub(crate) fn last_cell(&mut self) -> Option { + if self.inner.byte_len == 0 { + None + } else { + unsafe { + Some(ptr::read(self.inner.ptr.add(self.inner.byte_len - heap_index!(1)) + as *const HeapCellValue)) } - _ => { - Err(()) + } + } + + #[inline] + pub(crate) fn is_empty(&self) -> bool { + self.inner.byte_len == 0 + } + + pub(crate) fn index_of(&mut self, cell: HeapCellValue) -> Result { + Ok(if cell.is_var() { + cell.get_value() as usize + } else { + let focus = self.cell_len(); + self.push_cell(cell)?; + focus + }) + } + + pub(crate) fn clear(&mut self) { + unsafe { + let layout = alloc::Layout::array::(self.inner.byte_cap).unwrap(); + alloc::dealloc(self.inner.ptr, layout); + } + + self.inner.ptr = ptr::null_mut(); + self.inner.byte_len = 0; + self.inner.byte_cap = 0; + + self.pstr_vec.clear(); + } + + pub(crate) fn append(&mut self, heap_slice: HeapView) -> Result<(), usize> { + unsafe { + loop { + if self.free_space() >= heap_index!(heap_slice.slice_cell_len) { + ptr::copy_nonoverlapping( + heap_slice.slice, + self.inner.ptr.add(self.inner.byte_len), + heap_index!(heap_slice.slice_cell_len), + ); + + self.inner.byte_len += heap_index!(heap_slice.slice_cell_len); + self.pstr_vec.extend(heap_slice.pstr_slice.iter()); + + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } } - ) + } + + Ok(()) } -} -// sometimes we need to dereference variables that are found only in -// the heap without access to the full WAM (e.g., while detecting -// cycles in terms), and which therefore may only point other cells in -// the heap (thanks to the design of the WAM). -pub fn heap_bound_deref(heap: &[HeapCellValue], mut value: HeapCellValue) -> HeapCellValue { - loop { - let new_value = read_heap_cell!(value, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - heap[h] + pub(crate) fn store_resource_error(&mut self) { + RESOURCE_ERROR_OFFSET_INIT.call_once(move || { + let stub = functor!(atom!("resource_error"), [atom_as_cell((atom!("memory")))]); + self.resource_err_loc = cell_index!(self.inner.byte_len); + + let mut writer = Heap::functor_writer(stub); + writer(self).unwrap(); + }); + } + + pub(crate) fn compare_pstr_segments( + &self, + pstr_loc1: usize, + pstr_loc2: usize, + ) -> PStrSegmentCmpResult { + unsafe { + let slice1 = std::slice::from_raw_parts( + self.inner.ptr.add(pstr_loc1), + self.inner.byte_len - pstr_loc1, + ); + + let slice2 = std::slice::from_raw_parts( + self.inner.ptr.add(pstr_loc2), + self.inner.byte_len - pstr_loc2, + ); + + let str1 = std::str::from_utf8_unchecked(&slice1); + let str2 = std::str::from_utf8_unchecked(&slice2); + + debug_assert!(!str1.is_empty()); + debug_assert!(!str2.is_empty()); + + for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) { + if c1 == '\u{0}' && c2 == '\u{0}' { + return PStrSegmentCmpResult::BothMatch { pstr_loc1, pstr_loc2, null_offset: idx }; + } else if c1 == '\u{0}' { + return PStrSegmentCmpResult::FirstMatch { pstr_loc1, pstr_loc2, l1_offset: idx }; + } else if c2 == '\u{0}' { + return PStrSegmentCmpResult::SecondMatch { pstr_loc1, pstr_loc2, l2_offset: idx }; + } else if c1 != c2 { + return PStrSegmentCmpResult::Mismatch { c1, c2 }; + } } - _ => { - value + + unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len())) + } + } + + #[inline] + pub(crate) fn slice_to_str(&self, slice_loc: usize, slice_len: usize) -> &str { + unsafe { + let slice = std::slice::from_raw_parts(self.inner.ptr.add(slice_loc), slice_len); + std::str::from_utf8_unchecked(&slice) + } + } + + #[inline] + pub(crate) fn byte_len(&self) -> usize { + self.inner.byte_len + } + + #[inline] + pub(crate) fn cell_len(&self) -> usize { + cell_index!(self.inner.byte_len) + } + + // free space in bytes. + #[inline] + fn free_space(&self) -> usize { + self.inner.byte_cap - self.inner.byte_len + } + + pub(crate) fn char_iter<'a>(&'a self, pstr_loc: usize) -> PStrSegmentIter<'a> { + PStrSegmentIter::from(self, pstr_loc) + } + + // either succeed & return nothing or fail & return an offset into + // the heap to a pre-allocated resource error + pub(crate) fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), usize> { + unsafe { + if self.inner.byte_len == self.inner.byte_cap { + if !self.grow() { + return Err(self.resource_error_offset()); + } } - ); - if new_value != value && new_value.is_var() { - value = new_value; - continue; + let cell_ptr = (self.inner.ptr as *mut HeapCellValue).add(self.cell_len()); + cell_ptr.write(cell); + self.pstr_vec.push(false); + self.inner.byte_len += heap_index!(1); } - return value; + Ok(()) } -} -pub fn heap_bound_store(heap: &[HeapCellValue], value: HeapCellValue) -> HeapCellValue { - read_heap_cell!(value, - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - heap[h] + /* + pub(crate) fn pop_cell(&mut self) -> Option { + unsafe { + if self.inner.byte_len > 0 { + let cell_ptr = (self.inner.ptr as *const HeapCellValue) + .add(self.cell_len()) + .sub(1); + let cell = ptr::read(cell_ptr); + + self.inner.byte_len -= heap_index!(1); + self.pstr_vec.pop(); + + Some(cell) + } else { + None + } } - _ => { - value + } + */ + + fn slice_range>(&self, range: R) -> Range { + let start = match range.start_bound() { + Bound::Included(lower_bound) => *lower_bound, + Bound::Excluded(lower_bound) => *lower_bound + 1, + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(upper_bound) => *upper_bound + 1, + Bound::Excluded(0) => 0, + Bound::Excluded(upper_bound) => *upper_bound, + Bound::Unbounded => self.cell_len(), + }; + + Range { start, end } + } + + pub(crate) fn splice>( + &self, + range: R, + ) -> HeapView { + let range = self.slice_range(range); + + HeapView { + slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, + cell_offset: range.start, + slice_cell_len: range.end - range.start, + pstr_slice: &self.pstr_vec.as_bitslice()[range], } - ) -} + } -#[allow(dead_code)] -pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { - for (index, term) in heap.enumerate() { - println!("{} : {:?}", h + index, term); + pub(crate) fn splice_mut>( + &self, + range: R, + ) -> HeapViewMut { + let range = self.slice_range(range); + + HeapViewMut { + slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) }, + cell_offset: range.start, + slice_cell_len: range.end - range.start, + pstr_slice: &self.pstr_vec.as_bitslice()[range], + } } -} -#[inline] -pub(crate) fn put_complete_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue { - match allocate_pstr(heap, s, atom_tbl) { - Some(h) => { - heap.pop(); // pop the trailing variable cell from the heap planted by allocate_pstr. + pub fn allocate_pstr(&mut self, src: &str) -> Result, usize> { + let size_in_heap = Self::compute_pstr_size(src); + let pstr_loc = heap_index!(self.cell_len()); + + Ok(if size_in_heap > 0 { + let mut writer = self.reserve(size_in_heap)?; + + writer.write_with(|section| { + section.push_pstr(src); + }); + + Some(PStrWriteInfo { pstr_loc }) + } else { + None + }) + } + + const fn heap_cell_alignment() -> usize { + // yes, size_of, not align_of. the alignment of HeapCellValue + // is 1 byte. In the heap, though, its alignment must be its + // size. + mem::size_of::() + } + + // takes a byte offset into the Heap ptr. + #[inline(always)] + pub(crate) const fn neighboring_cell_offset(offset: usize) -> usize { + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + cell_index!((offset & !(ALIGN_CELL - 1)) + ALIGN_CELL) + } + + #[inline] + pub(crate) fn iter(&self) -> HeapView { + HeapView { + slice: self.inner.ptr, + cell_offset: 0, + slice_cell_len: cell_index!(self.inner.byte_len), + pstr_slice: &self.pstr_vec.as_bitslice(), + } + } + + #[inline] + pub(crate) fn pstr_vec(&self) -> &BitSlice { + self.pstr_vec.as_bitslice() + } + + #[inline] + pub(crate) fn char_at(&self, byte_idx: usize) -> char { + let s = unsafe { + let char_ptr = self.inner.ptr.add(byte_idx); + let slice = std::slice::from_raw_parts(char_ptr, mem::size_of::()); + std::str::from_utf8_unchecked(&slice) + }; + + s.chars().next().unwrap() + } + + pub(crate) fn last_str_char_and_tail(&self, loc: usize) -> (char, HeapCellValue) { + unsafe { + let char_ptr = self.inner.ptr.add(loc); + let slice = std::slice::from_raw_parts(char_ptr, self.inner.byte_len - loc); - if heap.len() == h + 1 { - let pstr_atom = cell_as_atom!(heap[h]); - heap[h] = atom_as_cstr_cell!(pstr_atom); - heap_loc_as_cell!(h) + let s = std::str::from_utf8_unchecked(&slice); + let mut chars_iter = s.chars(); + let c = chars_iter.next().unwrap(); + let succ_len = loc + c.len_utf8(); + + if chars_iter.next() == Some('\u{0}') { + (c, heap_loc_as_cell!(Self::neighboring_cell_offset(succ_len))) } else { - heap.push(empty_list_as_cell!()); - pstr_loc_as_cell!(h) + (c, pstr_loc_as_cell!(succ_len)) } } - None => { - let h = heap.len(); - heap.push(empty_list_as_cell!()); - heap_loc_as_cell!(h) - } } -} -#[inline] -pub(crate) fn put_partial_string(heap: &mut Heap, s: &str, atom_tbl: &AtomTable) -> HeapCellValue { - match allocate_pstr(heap, s, atom_tbl) { - Some(h) => { - pstr_loc_as_cell!(h) + // copies only the string, not its tail. returns the cell index of + // the tail location + pub(crate) fn copy_pstr_within(&mut self, pstr_loc: usize) -> Result { + let (s, tail_loc) = self.scan_slice_to_str(pstr_loc); + let s_len = s.len(); + + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); + + let align_offset = unsafe { + self.inner.ptr + .add(self.inner.byte_len + s_len) + .align_offset(ALIGN_CELL) + }; + + let align_offset = if align_offset == 0 { + ALIGN_CELL + } else { + align_offset + }; + + let copy_size = s_len + align_offset; + + unsafe { + loop { + if self.free_space() >= copy_size { + let slice = std::slice::from_raw_parts_mut( + self.inner.ptr, + self.inner.byte_len + s_len, + ); + + slice.copy_within( + pstr_loc .. pstr_loc + s_len, + self.inner.byte_len, + ); + + ptr::write_bytes( + self.inner.ptr.add(self.inner.byte_len + s_len), + 0u8, + align_offset, + ); + + self.inner.byte_len += copy_size; + self.pstr_vec.resize(self.cell_len(), true); + + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } + } } - None => { - empty_list_as_cell!() + + Ok(tail_loc) + } + + // src is a cell-indexed range. + pub(crate) fn copy_slice_to_end>(&mut self, src: R) -> Result<(), usize> { + let range = self.slice_range(src); + let len = range.end - range.start; + + unsafe { + loop { + if self.free_space() >= len { + ptr::copy_nonoverlapping( + self.inner.ptr.add(heap_index!(range.start)), + self.inner.ptr.add(self.inner.byte_len), + heap_index!(len), + ); + + self.pstr_vec.resize(self.cell_len() + len, false); + self.inner.byte_len += heap_index!(len); + + break; + } else if !self.grow() { + return Err(self.resource_error_offset()); + } + } } + + Ok(()) } -} -#[inline] -pub(crate) fn allocate_pstr(heap: &mut Heap, mut src: &str, atom_tbl: &AtomTable) -> Option { - let orig_h = heap.len(); + // assumes the string will be allocated on a ALIGN_CELL-byte boundary + pub(crate) const fn compute_pstr_size(src: &str) -> usize { + const ALIGN_CELL: usize = Heap::heap_cell_alignment(); - loop { if src.is_empty() { - return if orig_h == heap.len() { - None + return 0; + } + + let mut byte_size = 0; + let mut null_idx = 0; + + loop { + let src_bytes = src.as_bytes(); + + while null_idx < src_bytes.len() { + if src_bytes[null_idx] == 0u8 { + break; + } + + null_idx += 1; + } + + byte_size += (null_idx & !(ALIGN_CELL - 1)) + ALIGN_CELL; + + if (null_idx + 1) % ALIGN_CELL == 0 { + byte_size += 2 * mem::size_of::(); } else { - let tail_h = heap.len() - 1; - heap[tail_h] = heap_loc_as_cell!(tail_h); + byte_size += mem::size_of::(); + } - Some(orig_h) - }; + if null_idx + 1 >= src.len() { + break; + } else { + null_idx += 1; + } } - let h = heap.len(); + byte_size + } + + pub(crate) const fn compute_functor_byte_size(functor: &[FunctorElement]) -> usize { + let mut byte_size = 0; + let mut idx = 0; - let (pstr, rest_src) = match PartialString::new(src, atom_tbl) { - Some(tuple) => tuple, - None => { - if src.len() > '\u{0}'.len_utf8() { - src = &src['\u{0}'.len_utf8()..]; - continue; - } else if orig_h == h { - return None; - } else { - heap[h - 1] = heap_loc_as_cell!(h - 1); - return Some(orig_h); + while idx < functor.len() { + match &functor[idx] { + &FunctorElement::InnerFunctor(inner_cell_size, ref _inner_functor) => { + byte_size += inner_cell_size as usize * mem::size_of::(); + } + FunctorElement::AbsoluteCell(_cell) | FunctorElement::Cell(_cell) => { + byte_size += mem::size_of::(); + } + &FunctorElement::String(cell_len, _) => { + byte_size += cell_len as usize * mem::size_of::(); } } + + idx += 1; + } + + byte_size + } + + pub(crate) fn functor_writer( + functor: Vec, + ) -> impl FnMut(&mut Heap) -> Result { + let size = Heap::compute_functor_byte_size(&functor); + let mut functor_writer = ReservedHeapSection::functor_writer(functor); + + move |heap| { + let mut writer = heap.reserve(size)?; + let heap_byte_len = *writer.heap_byte_len; + let bytes_written = writer.write_with(&mut functor_writer); + + Ok(if cell_index!(bytes_written) > 1 { + str_loc_as_cell!(cell_index!(heap_byte_len)) + } else { + heap_loc_as_cell!(cell_index!(heap_byte_len)) + }) + } + } + + #[inline] + pub(crate) fn truncate(&mut self, cell_offset: usize) { + self.inner.byte_len = heap_index!(cell_offset); + self.pstr_vec.truncate(cell_offset); + } +} + + + +pub(crate) struct PStrSegmentIter<'a> { + string_buf: &'a str, +} + +impl<'a> PStrSegmentIter<'a> { + fn from(heap: &'a Heap, pstr_loc: usize) -> Self { + debug_assert!(pstr_loc <= heap.inner.byte_len); + + let string_buf = unsafe { + let char_ptr = heap.inner.ptr.add(pstr_loc); + let slice = std::slice::from_raw_parts(char_ptr, heap.inner.byte_len - pstr_loc); + std::str::from_utf8_unchecked(&slice) }; - heap.push(string_as_pstr_cell!(pstr)); + PStrSegmentIter { string_buf } + } +} - if !rest_src.is_empty() { - heap.push(pstr_loc_as_cell!(h + 2)); - src = rest_src; - } else { - heap.push(heap_loc_as_cell!(h + 1)); - return Some(orig_h); +impl<'a> Iterator for PStrSegmentIter<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + self.string_buf.chars().next().and_then(|c| { + if c == '\u{0}' { + None + } else { + self.string_buf = &self.string_buf[c.len_utf8() ..]; + Some(c) + } + }) + } +} + +impl MachineState { + pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result { + match self.heap.allocate_pstr(src)? { + None => Ok(empty_list_as_cell!()), + Some(PStrWriteInfo { pstr_loc, .. }) => Ok(pstr_loc_as_cell!(pstr_loc)), + } + } + + // note that allocate_cstr does emit a tail cell to the string + // (completing it with the empty list), allocate_pstr does not, in + // any incarnation. + pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result { + match self.heap.allocate_pstr(src)? { + None => Ok(empty_list_as_cell!()), + Some(PStrWriteInfo { pstr_loc, .. }) => { + self.heap.push_cell(empty_list_as_cell!())?; + Ok(pstr_loc_as_cell!(pstr_loc)) + } } } } -pub fn filtered_iter_to_heap_list>( - heap: &mut Heap, - values: impl Iterator, - filter_fn: impl Fn(&Heap, HeapCellValue) -> bool, -) -> usize { - let head_addr = heap.len(); - let mut h = head_addr; +pub trait SizedHeap: Index { + // return the size of the instance in cells + fn cell_len(&self) -> usize; + + // return a pointer to the heap string and the cell index of its tail + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize); + + // return true iff a partial string is stored at cell_offset. + fn pstr_at(&self, cell_offset: usize) -> bool; +} + +pub trait SizedHeapMut: IndexMut + SizedHeap { +} + +impl Index for Heap { + type Output = HeapCellValue; + + fn index(&self, idx: usize) -> &Self::Output { + unsafe { &*(self.inner.ptr as *const HeapCellValue).add(idx) } + } +} + +impl IndexMut for Heap { + fn index_mut(&mut self, idx: usize) -> &mut Self::Output { + unsafe { &mut *(self.inner.ptr as *mut HeapCellValue).add(idx) } + } +} + +impl SizedHeap for Heap { + fn cell_len(&self) -> usize { + self.cell_len() + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.inner.ptr.add(slice_loc) }, + &self.pstr_vec.as_bitslice()[cell_index!(slice_loc) ..], + ); - for value in values { - let value = value.into(); + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.pstr_vec[cell_offset] + } +} + +impl SizedHeapMut for Heap {} + +impl<'a> SizedHeap for HeapView<'a> { + fn cell_len(&self) -> usize { + self.slice_cell_len + } + + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.slice.add(slice_loc) }, + &self.pstr_slice[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.pstr_slice[cell_offset] + } +} + +impl<'a> SizedHeap for HeapViewMut<'a> { + fn cell_len(&self) -> usize { + self.slice_cell_len + } - if filter_fn(heap, value) { - heap.push(list_loc_as_cell!(h + 1)); - heap.push(value); + fn scan_slice_to_str(&self, slice_loc: usize) -> (&str, usize) { + let (s, tail_cell_offset) = scan_slice_to_str( + unsafe { self.slice.add(slice_loc) }, + &self.pstr_slice[cell_index!(slice_loc) ..], + ); + + (s, cell_index!(slice_loc) + tail_cell_offset) + } + + fn pstr_at(&self, cell_offset: usize) -> bool { + self.pstr_slice[cell_offset] + } +} - h += 2; +impl<'a> SizedHeapMut for HeapViewMut<'a> {} + +// sometimes we need to dereference variables that are found only in +// the heap without access to the full WAM (e.g., while detecting +// cycles in terms), and which therefore may only point other cells in +// the heap (thanks to the design of the WAM). +pub fn heap_bound_deref(heap: &impl SizedHeap, mut value: HeapCellValue) -> HeapCellValue { + loop { + let new_value = read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + heap[h] + } + _ => { + value + } + ); + + if new_value != value && new_value.is_var() { + value = new_value; + continue; } + + return value; } +} - heap.push(empty_list_as_cell!()); +pub fn heap_bound_store(heap: &impl SizedHeap, value: HeapCellValue) -> HeapCellValue { + read_heap_cell!(value, + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + heap[h] + } + _ => { + value + } + ) +} - head_addr +#[allow(dead_code)] +pub fn print_heap_terms<'a, I: Iterator>(heap: I, h: usize) { + for (index, term) in heap.enumerate() { + println!("{} : {:?}", h + index, term); + } } -#[inline(always)] -pub fn iter_to_heap_list(heap: &mut Heap, values: Iter) -> usize -where - Iter: Iterator, - SrcT: Into, -{ - filtered_iter_to_heap_list(heap, values, |_, _| true) +pub fn sized_iter_to_heap_list>( + heap: &mut Heap, + size: usize, + values: impl Iterator, +) -> Result { + if size > 0 { + let h = heap.cell_len(); + let mut writer = heap.reserve(1 + 2 * size)?; + + writer.write_with(|section| { + for (idx, value) in values.enumerate() { + section.push_cell(list_loc_as_cell!(h + 1 + 2 * idx)); + section.push_cell(value.into()); + } + + section.push_cell(empty_list_as_cell!()); + }); + + Ok(heap_loc_as_cell!(h)) + } else { + Ok(empty_list_as_cell!()) + } } pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index bd4ea36e..eef64f96 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -3,15 +3,14 @@ use std::collections::BTreeMap; 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, }; -use crate::parser::ast::{Var, VarPtr}; -use crate::parser::parser::{Parser, Tokens}; -use crate::read::{write_term_to_heap, TermWriteResult}; +use crate::parser::ast::{TermWriteResult, Var}; +use crate::parser::lexer::LexerParser; +use crate::parser::parser::Tokens; use crate::types::UntypedArenaPtr; use dashu::{Integer, Rational}; @@ -171,29 +170,22 @@ impl Term { pub(crate) fn from_heapcell( machine: &mut Machine, heap_cell: HeapCellValue, - var_names: &mut IndexMap, + var_names: &mut IndexMap, ) -> Self { // Adapted from MachineState::read_term_from_heap let mut term_stack = vec![]; - let iter = stackful_post_order_iter::( + + machine.machine_st.heap[0] = heap_cell; + + let mut iter = stackful_post_order_iter::( &mut machine.machine_st.heap, &mut machine.machine_st.stack, - heap_cell, + 0, ); let mut anon_count: usize = 0; - let var_ptr_cmp = |a, b| match a { - Var::Named(name_a) => match b { - Var::Named(name_b) => name_a.cmp(&name_b), - _ => Ordering::Less, - }, - _ => match b { - Var::Named(_) => Ordering::Greater, - _ => Ordering::Equal, - }, - }; - - for addr in iter { + + while let Some(addr) = iter.next() { let addr = unmark_cell_bits!(addr); read_heap_cell!(addr, @@ -242,29 +234,28 @@ impl Term { term_stack.push(list); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { - let var = var_names.get(&addr).map(|x| x.borrow().clone()); + let var = var_names.get(&addr).cloned(); match var { - Some(Var::Named(name)) => term_stack.push(Term::Var(name)), + Some(name) => term_stack.push(Term::Var(name.to_string())), _ => { let anon_name = loop { // Generate a name for the anonymous variable let anon_name = count_to_letter_code(anon_count); // Find if this name is already being used - var_names.sort_by(|_, a, _, b| { - var_ptr_cmp(a.borrow().clone(), b.borrow().clone()) - }); + var_names.sort_by(|_, a, _, b| a.cmp(b)); + let binary_result = var_names.binary_search_by(|_,a| { - let var_ptr = Var::Named(anon_name.clone()); - var_ptr_cmp(a.borrow().clone(), var_ptr.clone()) + let a: &String = a.as_ref(); + a.cmp(&anon_name) }); match binary_result { Ok(_) => anon_count += 1, // Name already used Err(_) => { // Name not used, assign it to this variable - let var_ptr = VarPtr::from(Var::Named(anon_name.clone())); - var_names.insert(addr, var_ptr); + let var = anon_name.clone(); + var_names.insert(addr, Var::from(var)); break anon_name; }, } @@ -276,9 +267,6 @@ impl Term { (HeapCellValueTag::F64, f) => { term_stack.push(Term::Float((*f).into())); } - (HeapCellValueTag::Char, c) => { - term_stack.push(Term::Atom(c.into())); - } (HeapCellValueTag::Fixnum, n) => { term_stack.push(Term::Integer(n.into())); } @@ -310,9 +298,6 @@ 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; @@ -354,8 +339,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 +349,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 = atom - .as_str() - .to_string() - .chars() + let mut list: Vec = 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 = atom - .as_str() - .to_string() - .chars() + let mut list: Vec = char_iter .map(|x| Term::Atom(x.to_string())) .collect(); @@ -403,19 +386,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!(); } @@ -432,7 +402,7 @@ pub struct QueryState<'a> { machine: &'a mut Machine, term: TermWriteResult, stub_b: usize, - var_names: IndexMap, + var_names: IndexMap, called: bool, } @@ -472,7 +442,7 @@ impl Iterator for QueryState<'_> { if let Err(resource_err_loc) = machine .machine_st .heap - .append(&machine.machine_st.ball.stub) + .append(machine.machine_st.ball.stub.splice(..)) { return Some(Err(Term::from_heapcell( machine, @@ -589,13 +559,13 @@ 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; } /// Runs a query. pub fn run_query(&mut self, query: impl Into) -> QueryState { - let mut parser = Parser::new( + let mut parser = LexerParser::new( Stream::from_owned_string(query.into(), &mut self.machine_st.arena), &mut self.machine_st, ); diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index f62e01f6..9ac56972 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -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::*; @@ -434,19 +433,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: FocusedHeap, - preprocessor: &mut Preprocessor, - ) -> Result { - 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..) { diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 40800f97..18a4c973 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -20,6 +20,25 @@ use std::convert::TryFrom; use std::fmt; use std::ops::{Deref, DerefMut}; +impl TermWriteResult { + pub(super) fn from(heap: &mut Heap, value: HeapCellValue) -> Result { + let focus = heap.index_of(value)?; + let mut stack = Stack::uninitialized(); + + heap[0] = value; + + let inverse_var_locs = inverse_var_locs_from_iter( + stackful_preorder_iter::( + heap, + &mut stack, + 0, + ), + ); + + Ok(Self { focus, inverse_var_locs }) + } +} + /* * The loader compiles Prolog terms read from a TermStream instance, * which may be incremental or monolithic. The monolithic term stream @@ -176,18 +195,18 @@ impl CompilationTarget { } pub struct PredicateQueue { - pub(super) predicates: Vec, - pub(super) compilation_target: CompilationTarget, + pub predicates: Vec, + pub compilation_target: CompilationTarget, } impl PredicateQueue { #[inline] - pub(super) fn push(&mut self, clause: FocusedHeap) { - self.predicates.push(clause); + pub(super) fn push(&mut self, term_write_result: TermWriteResult) { + self.predicates.push(term_write_result); } #[inline] - pub(crate) fn first(&self) -> Option<&FocusedHeap> { + pub(crate) fn first(&self) -> Option<&TermWriteResult> { self.predicates.first() } @@ -381,7 +400,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) @@ -399,7 +417,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> { #[inline(always)] fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { - loader.term_stream.parser.lexer.machine_st + loader.term_stream.lexer_parser.machine_st } #[inline(always)] @@ -491,23 +509,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } } - pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap { - use crate::iterators::fact_iterator; - - let mut term = FocusedHeap::empty(); - let mut stack = Stack::uninitialized(); - let machine_st = LS::machine_st(&mut self.payload); - - term.copy_term_from_machine_heap(machine_st, cell); - term.inverse_var_locs = inverse_var_locs_from_iter( - fact_iterator::( - &mut term.heap, - &mut stack, - 0, - ), - ); - - term + #[inline] + pub(super) fn machine_heap(&mut self) -> &mut Heap { + &mut LS::machine_st(&mut self.payload).heap } pub(crate) fn load(mut self) -> Result { @@ -525,14 +529,26 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target); let mut term = load_state.term_stream.next(&composite_op_dir)?; + let predicate_focus_opt = load_state.predicates.first().map(|term_write_result| { + term_write_result.focus + }); - if !term.is_consistent(&load_state.predicates) { - self.compile_and_submit()?; + let machine_st = LS::machine_st(&mut self.payload); + let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus); + + if let Some(predicate_focus) = predicate_focus_opt { + let predicate_key_opt = clause_predicate_key(&machine_st.heap, predicate_focus); + + debug_assert!(predicate_key_opt.is_some()); + + if term_key_opt != predicate_key_opt { + self.compile_and_submit()?; + } } - if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 { - let new_focus = term.nth_arg(term.focus, 1).unwrap(); - let term = term.as_ref_mut(new_focus); + if Some((atom!(":-"), 1)) == term_key_opt { + let machine_st = LS::machine_st(&mut self.payload); + term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap(); return Ok(Some(setup_declaration(self, term)?)); } @@ -1055,48 +1071,55 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { let machine_st = LS::machine_st(&mut self.payload); let cell = machine_st[r]; - let export_list = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell); + let focus = machine_st.heap.cell_len(); + machine_st.heap.push_cell(cell) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + + let export_list = FocusedHeapRefMut { heap: &mut machine_st.heap, focus }; let export_list = setup_module_export_list(export_list)?; Ok(export_list.into_iter().collect()) } - fn clause_clause(&mut self, cell: HeapCellValue) -> Result { + fn clause_clause(&mut self, cell: HeapCellValue) -> Result { let machine_st = LS::machine_st(&mut self.payload); - let mut term = FocusedHeap::empty(); + let focus = machine_st.heap.cell_len(); read_heap_cell!(cell, (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) .get_name_and_arity(); - term.copy_term_from_machine_heap(machine_st, cell); - let focus = term.heap.len(); + let mut writer = machine_st.heap.reserve(4) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; - term.heap.push(str_loc_as_cell!(focus+1)); - term.heap.push(atom_as_cell!(atom!("clause"), 2)); + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(focus+1)); + section.push_cell(atom_as_cell!(atom!("clause"), 2)); - match (name, arity) { - (atom!(":-"), 2) => { - term.heap.push(heap_loc_as_cell!(2)); - term.heap.push(heap_loc_as_cell!(3)); - } - _ => { - term.heap.push(heap_loc_as_cell!(0)); - term.heap.push(atom_as_cell!(atom!("true"))); + match (name, arity) { + (atom!(":-"), 2) => { + section.push_cell(heap_loc_as_cell!(s+1)); + section.push_cell(heap_loc_as_cell!(s+2)); + } + _ => { + section.push_cell(str_loc_as_cell!(s)); + section.push_cell(atom_as_cell!(atom!("true"))); + } } - } - - term.focus = focus; + }); } (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { - term.heap.push(str_loc_as_cell!(1)); - term.heap.push(atom_as_cell!(atom!("clause"), 2)); - term.heap.push(atom_as_cell!(name)); - term.heap.push(atom_as_cell!(atom!("true"))); - - term.focus = 0; + let mut writer = machine_st.heap.reserve(4) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + + writer.write_with(|section| { + section.push_cell(str_loc_as_cell!(focus+1)); + section.push_cell(atom_as_cell!(atom!("clause"), 2)); + section.push_cell(atom_as_cell!(name)); + section.push_cell(atom_as_cell!(atom!("true"))); + }); } else { return Err(CompilationError::InadmissibleFact); } @@ -1106,11 +1129,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { } ); - let value = term.heap[term.focus]; - term.inverse_var_locs = inverse_var_locs_from_iter( - eager_stackful_preorder_iter(&mut term.heap, value), - ); - Ok(term) + Ok(TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus)) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?) } fn add_extensible_predicate_declaration( @@ -1330,18 +1350,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> { fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> { let machine_st = LS::machine_st(&mut self.payload); - let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value); - - let name_opt = ClauseInfo::name(&term); + let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value); - if let Some(predicate_name) = name_opt { - let arity = ClauseInfo::arity(&term); + if let Some((predicate_name, predicate_arity)) = key_opt { 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); @@ -1574,11 +1594,14 @@ impl Machine { pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { let value = self.machine_st.registers[1]; + let term = resource_error_call_result!( + self.machine_st, + TermWriteResult::from(&mut self.machine_st.heap, value) + ); + let mut loader = self.loader_from_heap_evacuable(temp_v!(2)); let add_clause = || { - let term = loader.copy_term_from_heap(value); - loader.incremental_compile_clause( (atom!("term_expansion"), 2), term, @@ -1599,31 +1622,40 @@ impl Machine { .machine_st .store(self.machine_st.deref(self.machine_st.registers[1]))); - let value = self.machine_st.registers[2]; - let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); - let compilation_target = match target_module_name { atom!("user") => CompilationTarget::User, _ => CompilationTarget::Module(target_module_name), }; - let add_clause = || { - let term = loader.copy_term_from_heap(value); + let value = self.machine_st.registers[2]; + let term = resource_error_call_result!( + self.machine_st, + TermWriteResult::from(&mut self.machine_st.heap, value) + ); - let indexing_arg = match term.name(term.focus) { - Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)), - Some(_) => term.nth_arg(term.focus, 1), + let add_clause = || { + let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) { + Some((atom!(":-"), _)) => { + term_nth_arg(&self.machine_st.heap, term.focus, 1).and_then(|h| { + term_nth_arg(&self.machine_st.heap, h, 1) + }) + } + Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1), None => None, }; - if let Some(indexing_term_loc) = indexing_arg { - if let Some(indexing_name) = term.name(indexing_term_loc) { - loader - .wam_prelude - .indices - .goal_expansion_indices - .insert((indexing_name, term.arity(indexing_term_loc))); - } + let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| { + term_predicate_key(&self.machine_st.heap, indexing_term_loc) + }); + + let mut loader = self.loader_from_heap_evacuable(temp_v!(3)); + + if let Some((name, arity)) = key_opt { + loader + .wam_prelude + .indices + .goal_expansion_indices + .insert((name, arity)); } loader.incremental_compile_clause( @@ -1929,19 +1961,16 @@ impl Machine { let stub_gen = || functor_stub(key.0, key.1); let assert_clause = self.machine_st.registers[2]; - let (name, arity) = { - let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause); - (ClauseInfo::name(&term), ClauseInfo::arity(&term)) - }; + let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause); - let mut compile_assert = |assert_clause, name, arity| { + let mut compile_assert = |assert_clause, key_opt| { let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = Loader::new(self, LiveTermStream::new(ListingSource::User)); loader.payload.compilation_target = compilation_target; - let name = if let Some(name) = name { - name + let (name, arity) = if let Some(key) = key_opt { + key } else { return Err(SessionError::from(CompilationError::InvalidRuleHead)); }; @@ -1979,11 +2008,16 @@ impl Machine { // if a new predicate was just created, make it dynamic. loader.add_dynamic_predicate(compilation_target, name, arity)?; - let asserted_clause = loader.copy_term_from_heap(assert_clause); + + let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); + // let asserted_clause = loader.copy_term_from_heap(assert_clause); + + let term = TermWriteResult::from(&mut machine_st.heap, assert_clause) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; loader.incremental_compile_clause( (name, arity), - asserted_clause, + term, compilation_target, false, append_or_prepend, @@ -2004,7 +2038,7 @@ impl Machine { LiveLoadAndMachineState::evacuate(loader) }; - match compile_assert(assert_clause, name, arity) { + match compile_assert(assert_clause, key_opt) { Ok(_) => Ok(()), Err(SessionError::CompilationError( CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact, @@ -2206,11 +2240,21 @@ impl Machine { }; let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); + let predicate_focus_opt = loader.payload.predicates.first().map(|term_write_result| { + term_write_result.focus + }); + + let is_consistent = if let Some(predicate_focus) = predicate_focus_opt { + let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload); + clause_predicate_key(&machine_st.heap, predicate_focus) == Some(key) + } else { + true + }; LiveLoadAndMachineState::machine_st(&mut loader.payload).fail = (!loader.payload.predicates.is_empty() - && loader.payload.predicates.compilation_target != compilation_target) - || !key.is_consistent(&loader.payload.predicates); + && loader.payload.predicates.compilation_target != compilation_target) + || !is_consistent; let result = LiveLoadAndMachineState::evacuate(loader); self.restore_load_state_payload(result) @@ -2278,29 +2322,36 @@ 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 { - 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)) - } - })); + 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; + } + }; - let heap_loc = self.machine_st.heap.len(); + 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)) + } + }); + } - self.machine_st - .heap - .push(atom_as_cell!(atom!("meta_predicate"), 1)); - self.machine_st.heap.push(str_loc_as_cell!(term_loc)); + section.push_cell(atom_as_cell!(atom!("meta_predicate"), 1)); + section.push_cell(str_loc_as_cell!(term_loc)); + }); + + let heap_loc = self.machine_st.heap.cell_len() - 2; unify!( self.machine_st, @@ -2411,13 +2462,16 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> { } let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); - let value = machine_st[term_reg]; + let value = machine_st.store(MachineState::deref(&machine_st, machine_st[term_reg])); self.add_clause_clause_if_dynamic(value)?; - let term = self.copy_term_from_heap(value); - self.payload.term_stream.term_queue.push_back(term); + let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); + let term = TermWriteResult::from(&mut machine_st.heap, value) + .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?; + + self.payload.term_stream.term_queue.push_back(term); self.load() } } diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index ea8db552..5017cb78 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -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; +pub type MachineStub = Vec; pub type MachineStubGen = Box 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, - from: ErrorProvenance, } // from 7.12.2 b) of 13211-1:1995 @@ -91,45 +85,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 { - 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, - } - } -} - -impl TypeError for FunctorStub { - 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, } } } @@ -139,15 +114,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 +145,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 +187,12 @@ 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 +200,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,60 +226,46 @@ 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)]); + let stub = functor!(atom!("domain_error"), [atom_as_cell((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 { +impl DomainError for Number { + fn domain_error(self, machine_st: &mut MachineState, error: 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())), number(self, (&mut machine_st.arena))] ); MachineError { stub, location: None, - from: ErrorProvenance::Constructed, } } } -impl DomainError for Number { - fn domain_error(self, machine_st: &mut MachineState, error: DomainErrorType) -> MachineError { +impl DomainError for MachineStub { + 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())), functor(self)] ); MachineError { stub, location: None, - from: ErrorProvenance::Received, } } } -pub(super) type FunctorStub = [HeapCellValue; 3]; - #[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,17 +276,15 @@ 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, } } @@ -339,18 +293,17 @@ impl MachineState { 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 +320,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 +333,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,43 +364,75 @@ 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, } } } } + 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) + } + } + } + pub(super) fn permission_error( &mut self, err: Permission, @@ -471,7 +449,6 @@ impl MachineState { fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { match err { - ArithmeticError::UninstantiatedVar => self.instantiation_error(), ArithmeticError::NonEvaluableFunctor(cell, arity) => { let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]); @@ -495,7 +472,6 @@ impl MachineState { MachineError { stub, location: None, - from: ErrorProvenance::Received, } } @@ -505,15 +481,11 @@ impl MachineState { Permission::Modify, atom!("static_procedure"), functor_stub(key.0, key.1) - .into_iter() - .collect::(), ), SessionError::CannotOverwriteStaticProcedure(key) => self.permission_error( Permission::Modify, atom!("static_procedure"), functor_stub(key.0, key.1) - .into_iter() - .collect::(), ), SessionError::CannotOverwriteBuiltInModule(module) => { self.permission_error(Permission::Modify, atom!("static_module"), module) @@ -524,8 +496,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 +507,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 +526,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 +555,27 @@ 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, } } - 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, - 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 +584,44 @@ 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]. - } 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)); + pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub { + if let Some(ParserErrorSrc { line_num, .. }) = err.location { + functor!(atom!("error"), [functor((err.stub)), + functor((atom!(":")), [functor(src), + number(line_num, (&mut self.arena))])]) } else { - stub[1] = err.stub[0]; - } - - if let Some(ParserErrorSrc { 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 - ))); + functor!(atom!("error"), [functor((err.stub)), + functor(src)]) } + } - 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 +629,6 @@ impl MachineState { } } -impl MachineError { - fn into_iter(self, offset: usize) -> Box> { - 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), @@ -715,12 +647,12 @@ pub enum CompilationError { #[derive(Debug)] pub enum DirectiveError { - ExpectedDirective(Term), + ExpectedDirective(HeapCellValue), InvalidDirective(Atom, usize /* arity */), - InvalidOpDeclNameType(Term), - InvalidOpDeclSpecDomain(Term), + InvalidOpDeclNameType(HeapCellValue), + InvalidOpDeclSpecDomain(HeapCellValue), InvalidOpDeclSpecValue(Atom), - InvalidOpDeclPrecType(Term), + InvalidOpDeclPrecType(HeapCellValue), InvalidOpDeclPrecDomain(Fixnum), ShallNotCreate(Atom), ShallNotModify(Atom), @@ -757,11 +689,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 +706,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, _). @@ -896,14 +826,13 @@ 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 +844,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 +856,7 @@ 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 +868,7 @@ 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 +930,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())) } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 56c03e7e..e0142b77 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -169,6 +169,13 @@ impl From> for CodeIndex { } } +impl From for HeapCellValue { + #[inline(always)] + fn from(idx: CodeIndex) -> HeapCellValue { + untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)) + } +} + impl CodeIndex { #[inline] pub(crate) fn new(ptr: IndexPtr, arena: &mut Arena) -> Self { @@ -208,10 +215,12 @@ impl CodeIndex { std::mem::replace(self.0.deref_mut(), value) } + /* #[inline(always)] pub(crate) fn as_ptr(&self) -> *const IndexPtr { self.0.as_ptr() } + */ } pub(crate) type GlobalVarDir = IndexMap), FxBuildHasher>; diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 1c18f16a..b5fdc1c0 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -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::*; @@ -12,7 +13,6 @@ use crate::machine::stack::*; use crate::machine::streams::*; use crate::machine::Machine; use crate::parser::ast::*; -use crate::read::TermWriteResult; use crate::types::*; use crate::parser::dashu::Integer; @@ -21,7 +21,7 @@ use indexmap::IndexMap; use std::convert::TryFrom; use std::fmt; -use std::ops::{Index, IndexMut}; +use std::ops::{Index, IndexMut, Range}; use std::rc::Rc; use std::sync::Arc; @@ -36,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 { @@ -184,8 +184,9 @@ impl IndexMut for MachineState { } } -pub type CallResult = Result<(), Vec>; +pub type CallResult = Result<(), Vec>; +/* #[inline(always)] pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixnum) { read_heap_cell!(heap[index], @@ -200,30 +201,44 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn } ) } +*/ fn push_var_eq_functors( heap: &mut Heap, + size: usize, iter: impl Iterator, atom_tbl: &AtomTable, -) -> Vec { - let mut list_of_var_eqs = vec![]; +) -> Result { + let src_h = heap.cell_len(); - for (var_loc, var) in iter { // (var, binding) in iter { - let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); - let h = heap.len(); - let binding = heap[var_loc]; + if size > 0 { + let mut writer = heap.reserve(1 + 5 * size)?; - heap.push(atom_as_cell!(atom!("="), 2)); - heap.push(atom_as_cell!(var_atom)); - heap.push(binding); + writer.write_with(|section| { + for (var_loc, var) in iter { // (var, binding) in iter { + let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); + let binding = heap_loc_as_cell!(var_loc); - list_of_var_eqs.push(str_loc_as_cell!(h)); - } + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(var_atom)); + section.push_cell(binding); + } - 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)); + } + section.push_cell(empty_list_as_cell!()); + }); + + Ok(heap_loc_as_cell!(src_h + 3 * size)) + } else { + Ok(empty_list_as_cell!()) + } +} +/* pub(crate) fn copy_and_align_iter>( iter: Iter, boundary: i64, @@ -232,6 +247,7 @@ pub(crate) fn copy_and_align_iter>( let diff = boundary - h; iter.map(move |heap_value| heap_value - diff) } +*/ #[derive(Debug)] pub struct Ball { @@ -252,8 +268,17 @@ impl Ball { self.stub.clear(); } - pub(super) fn copy_and_align(&self, h: usize) -> Heap { - copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect() + pub(super) fn copy_and_align_to(&self, dest: &mut Heap) -> Result { + let h = dest.cell_len(); + let diff = self.boundary as i64 - h as i64; + + dest.append(self.stub.splice(..))?; + + for cell in &mut dest.splice_mut(h ..) { + *cell = *cell - diff; + } + + Ok(h) } } @@ -286,13 +311,13 @@ impl<'a> IndexMut for CopyTerm<'a> { impl<'a> CopierTarget for CopyTerm<'a> { #[inline(always)] - fn threshold(&self) -> usize { - self.state.heap.len() + fn store(&self, value: HeapCellValue) -> HeapCellValue { + self.state.store(value) } #[inline(always)] - fn push(&mut self, hcv: HeapCellValue) { - self.state.heap.push(hcv); + fn deref(&self, value: HeapCellValue) -> HeapCellValue { + self.state.deref(value) } #[inline(always)] @@ -301,18 +326,49 @@ impl<'a> CopierTarget for CopyTerm<'a> { } #[inline(always)] - fn store(&self, value: HeapCellValue) -> HeapCellValue { - self.state.store(value) + fn stack(&mut self) -> &mut Stack { + &mut self.state.stack } #[inline(always)] - fn deref(&self, value: HeapCellValue) -> HeapCellValue { - self.state.deref(value) + fn threshold(&self) -> usize { + self.state.heap.cell_len() } #[inline(always)] - fn stack(&mut self) -> &mut Stack { - &mut self.state.stack + fn copy_pstr_to_threshold(&mut self, pstr_loc: usize) -> Result { + self.state.heap.copy_pstr_within(pstr_loc) + } + + #[inline(always)] + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { + self.state.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } + + #[inline(always)] + fn pstr_at(&self, loc: usize) -> bool { + self.state.heap.pstr_vec()[loc] + } + + #[inline(always)] + fn next_non_pstr_cell_index(&self, loc: usize) -> usize { + // unwrap is safe here because a partial string is always + // followed by a tail cell, i.e. a non-pstr cell, supposing + // self.state.heap[loc] is a pstr cell + self.state.heap.pstr_vec()[loc ..].first_zero().unwrap() + } + + #[inline(always)] + fn reserve(&mut self, num_cells: usize) -> Result { + self.state.heap.reserve(num_cells) + } + + #[inline(always)] + fn copy_slice_to_end(&mut self, bounds: Range) -> Result<(), usize> { + self.state.heap.copy_slice_to_end(bounds) } } @@ -321,7 +377,6 @@ pub(crate) struct CopyBallTerm<'a> { attr_var_queue: &'a mut Vec, stack: &'a mut Stack, heap: &'a mut Heap, - heap_boundary: usize, stub: &'a mut Heap, } @@ -332,13 +387,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, } } @@ -348,10 +400,10 @@ impl<'a> Index 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] } } @@ -359,10 +411,10 @@ impl<'a> Index for CopyBallTerm<'a> { impl<'a> IndexMut 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] } } @@ -370,11 +422,7 @@ impl<'a> IndexMut 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)] @@ -385,10 +433,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] } } @@ -417,6 +465,67 @@ 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 { + debug_assert!(pstr_loc < self.heap.byte_len()); + + let (string, tail_loc) = self.heap.scan_slice_to_str(pstr_loc); + self.stub.allocate_pstr(string)?; + Ok(tail_loc) + } + + #[inline] + fn reserve(&mut self, num_cells: usize) -> Result { + self.stub.reserve(num_cells) + } + + #[inline] + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { + if pstr_loc >= self.heap.byte_len() { + self.stub.pstr_vec()[0 .. cell_index!(pstr_loc - self.heap.byte_len())] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } else { + self.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } + } + + #[inline] + fn pstr_at(&self, loc: usize) -> bool { + if loc >= self.heap.cell_len() { + self.stub.pstr_vec()[loc - self.heap.cell_len()] + } else { + self.heap.pstr_vec()[loc] + } + } + + #[inline] + fn next_non_pstr_cell_index(&self, loc: usize) -> usize { + let zero_from_loc = if loc >= self.heap.cell_len() { + self.stub.pstr_vec()[loc - self.heap.cell_len() ..].first_zero().unwrap() + } else { + self.heap.pstr_vec()[loc ..].first_zero().unwrap() + }; + + zero_from_loc + loc + } + + fn copy_slice_to_end(&mut self, bounds: Range) -> 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 { @@ -467,10 +576,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() { @@ -543,35 +648,37 @@ impl MachineState { pub fn write_read_term_options( &mut self, mut var_list: Vec<(Var, HeapCellValue, usize)>, - singleton_var_list: Vec, + singletons_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().map(|(var_name, var, _)| { (var.get_value() as usize, var_name.clone()) }), + num_vars, &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, singletons_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( - &mut self.heap, - var_list.into_iter().map(|(_, cell, _)| cell) - )); + let vars_offset = resource_error_call_result!( + self, + sized_iter_to_heap_list( + &mut self.heap, + var_list.len(), + var_list.iter().map(|(_, cell, _)| *cell), + ) + ); unify_fn!(*self, vars_offset, vars_addr); @@ -580,23 +687,41 @@ impl MachineState { } let var_names_addr = self.registers[5]; + /* let var_names_offset = heap_loc_as_cell!(iter_to_heap_list( &mut self.heap, list_of_var_eqs.into_iter() )); + */ + + let var_names_offset = resource_error_call_result!( + self, + push_var_eq_functors( + &mut self.heap, + var_list.len(), + var_list.iter().map(|(var_name, var, _)| { + (var.get_value() as usize, var_name.clone()) + }), + &self.atom_tbl, + ) + ); Ok(unify_fn!(*self, var_names_offset, var_names_addr)) } pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult { - let heap_loc = read_heap_cell!(self.heap[term.heap_loc], - (HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => { + let heap_loc = self.heap[term.focus]; + + /* + read_heap_cell!(self.heap[term.heap_loc], + (HeapCellValueTag::PStr) => { // | HeapCellValueTag::PStrOffset) => { pstr_loc_as_cell!(term.heap_loc) } _ => { heap_loc_as_cell!(term.heap_loc) } ); + */ unify_fn!(*self, heap_loc, self.registers[2]); @@ -612,7 +737,7 @@ impl MachineState { let mut singleton_var_set: IndexMap = IndexMap::new(); - for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) { + for cell in stackful_preorder_iter::(&mut self.heap, &mut self.stack, term.focus) { let cell = unmark_cell_bits!(cell); if let Some(var) = cell.as_var() { @@ -624,29 +749,33 @@ impl MachineState { } } - let singleton_var_list = push_var_eq_functors( - &mut self.heap, - term.inverse_var_locs - .iter() - .filter_map(|(var_loc, var_name)| { - // add h to offset the term variable into its heap location. - let r = Ref::heap_cell(*var_loc); - - if singleton_var_set.get(&r).cloned().unwrap_or(false) { - Some((*var_loc, var_name.clone())) - } else { - None - } - }), - &self.atom_tbl, + let singleton_var_list = resource_error_call_result!( + self, + push_var_eq_functors( + &mut self.heap, + singleton_var_set + .iter() + .filter(|(var, is_singleton)| { + **is_singleton && term.inverse_var_locs.contains_key( + &(var.get_value() as usize) + ) + }) + .count(), + term.inverse_var_locs + .iter() + .filter_map(|(var_loc, var_name)| { + let r = Ref::heap_cell(*var_loc); + + if singleton_var_set.get(&r).cloned().unwrap_or(false) { + Some((*var_loc, var_name.clone())) + } else { + None + } + }), + &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_loc, var_name) in term.inverse_var_locs { @@ -744,7 +873,7 @@ 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, } @@ -793,9 +922,6 @@ impl MachineState { } read_heap_cell!(atom, - (HeapCellValueTag::Char, c) => { - var_names.insert(var, Rc::new(c.to_string())); - } (HeapCellValueTag::Atom, (name, _arity)) => { debug_assert_eq!(_arity, 0); var_names.insert(var, Rc::new(name.as_str().to_owned())); @@ -884,16 +1010,20 @@ impl MachineState { } ); - let h = self.heap.len(); - self.heap.push(term_to_be_printed); + let term_loc = self.heap.cell_len(); + + step_or_resource_error!( + self, + self.heap.push_cell(term_to_be_printed), + { return Ok(None); } + ); let mut printer = HCPrinter::new( &mut self.heap, - Arc::clone(&self.atom_tbl), &mut self.stack, op_dir, PrinterOutputter::new(), - h, + term_loc, ); printer.ignore_ops = ignore_ops; @@ -984,42 +1114,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)] diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index e93356fd..34fbe5ca 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -22,6 +22,12 @@ use std::convert::TryFrom; impl MachineState { pub(crate) fn new() -> Self { + let mut heap = Heap::with_cell_capacity(256 * 256).unwrap(); + + // this is an interstitial cell reserved for use by the runtime. + heap.push_cell(empty_list_as_cell!()).unwrap(); + heap.store_resource_error(); + MachineState { arena: Arena::new(), atom_tbl: AtomTable::new(), @@ -38,7 +44,7 @@ impl MachineState { cp: 0, attr_var_init: AttrVarInitializer::new(0), fail: false, - heap: Heap::with_capacity(256 * 256), + heap, mode: MachineMode::Write, stack: Stack::new(), registers: [heap_loc_as_cell!(0); MAX_ARITY + 1], // self.registers[0] is never used. @@ -261,9 +267,14 @@ impl MachineState { unifier.unify_atom(atom, value); } - pub fn unify_complete_string(&mut self, atom: Atom, value: HeapCellValue) { + pub fn unify_list(&mut self, l1: usize, value: HeapCellValue) { let mut unifier = DefaultUnifier::from(self); - unifier.unify_complete_string(atom, value); + unifier.unify_list(l1, value); + } + + pub fn unify_partial_string(&mut self, pstr_loc: usize, value: HeapCellValue) { + let mut unifier = DefaultUnifier::from(self); + unifier.unify_partial_string(pstr_loc, value); } pub fn unify_char(&mut self, c: char, value: HeapCellValue) { @@ -316,18 +327,23 @@ impl MachineState { self.ball.reset(); let addr = self.registers[1]; - self.ball.boundary = self.heap.len(); - - copy_term( - CopyBallTerm::new( - &mut self.attr_var_init.attr_var_queue, - &mut self.stack, - &mut self.heap, - &mut self.ball.stub, - ), - addr, - AttrVarPolicy::DeepCopy, + let ball_boundary = self.heap.cell_len(); + + step_or_resource_error!( + self, + copy_term( + CopyBallTerm::new( + &mut self.attr_var_init.attr_var_queue, + &mut self.stack, + &mut self.heap, + &mut self.ball.stub, + ), + addr, + AttrVarPolicy::DeepCopy, + ) ); + + self.ball.boundary = ball_boundary; } #[inline(always)] @@ -336,84 +352,34 @@ impl MachineState { self.fail = true; } + // return the read value and the succeeding HeapPtr pub(crate) fn read_s(&mut self) -> HeapCellValue { - match &mut self.s { - &mut HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), - &mut HeapPtr::PStrChar(h, n) if self.s_offset == 0 => { - read_heap_cell!(self.heap[h], - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - - if let Some(c) = pstr.as_str_from(n).chars().next() { - char_as_cell!(c) - } else { - self.deref(self.heap[h+1]) - } - } - (HeapCellValueTag::CStr, cstr_atom) => { - let pstr = PartialString::from(cstr_atom); - - if let Some(c) = pstr.as_str_from(n).chars().next() { - char_as_cell!(c) - } else { - empty_list_as_cell!() - } - } - _ => { - unreachable!() - } - ) - } - &mut HeapPtr::PStrChar(h, ref mut n) | &mut HeapPtr::PStrLocation(h, ref mut n) => { - read_heap_cell!(self.heap[h], - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - let n_offset: usize = pstr.as_str_from(*n) - .chars() - .take(self.s_offset) - .map(|c| c.len_utf8()) - .sum(); - - self.s_offset = 0; - *n += n_offset; - - if *n < pstr_atom.len() { - let h_len = self.heap.len(); - - self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64))); - - pstr_loc_as_cell!(h_len) - } else { - self.deref(self.heap[h+1]) - } - } - (HeapCellValueTag::CStr, cstr_atom) => { - let pstr = PartialString::from(cstr_atom); - let n_offset: usize = pstr.as_str_from(*n) - .chars() - .take(self.s_offset) - .map(|c| c.len_utf8()) - .sum(); - - self.s_offset = 0; - *n += n_offset; - - if *n < cstr_atom.len() { - let h_len = self.heap.len(); - - self.heap.push(pstr_offset_as_cell!(h)); - self.heap.push(fixnum_as_cell!(Fixnum::build_with(*n as i64))); - - pstr_loc_as_cell!(h_len) - } else { - empty_list_as_cell!() - } - } - _ => { - unreachable!() + match self.s { + HeapPtr::HeapCell(h) => self.deref(self.heap[h + self.s_offset]), + HeapPtr::PStr(h) => { + let mut char_iter = self.heap.char_iter(h); + + if self.s_offset == 0 { // read the car of the list + let c = char_iter.next().unwrap(); + char_as_cell!(c) + } else { // read the (self.s_offset)^{th} cdr of the list + let byte_offset: usize = char_iter + .take(self.s_offset) + .map(|c| c.len_utf8()) + .sum(); + let new_h = h + byte_offset; + + self.s_offset = 0; + + if self.heap.char_iter(new_h).next().is_some() { + self.s = HeapPtr::PStr(new_h); + pstr_loc_as_cell!(new_h) + } else { + let h = Heap::neighboring_cell_offset(new_h); + self.s = HeapPtr::HeapCell(h); + self.deref(heap_loc_as_cell!(h)) } - ) + } } } } @@ -482,6 +448,7 @@ impl MachineState { return Some(n1.cmp(&n2)); } } + /* (HeapCellValueTag::Char, c2) => { if let Some(c1) = n1.as_char() { if c1 != c2 { @@ -496,6 +463,7 @@ impl MachineState { ); } } + */ (HeapCellValueTag::Str, s) => { let n2 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -510,6 +478,7 @@ impl MachineState { } ) } + /* (HeapCellValueTag::Char, c1) => { read_heap_cell!(v2, (HeapCellValueTag::Atom, (n2, _a2)) => { @@ -554,6 +523,7 @@ impl MachineState { } ) } + */ (HeapCellValueTag::Str, s) => { let n1 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -565,6 +535,7 @@ impl MachineState { return Some(n1.cmp(&n2)); } } + /* (HeapCellValueTag::Char, c2) => { if let Some(c1) = n1.as_char() { if c1 != c2 { @@ -579,6 +550,7 @@ impl MachineState { ); } } + */ (HeapCellValueTag::Str, s) => { let n2 = cell_as_atom_cell!(self.heap[s]) .get_name(); @@ -599,121 +571,22 @@ impl MachineState { ) } Some(TermOrderCategory::Compound) => { - fn stalled_pstr_iter_comparator( - iteratee: PStrIteratee, - iter2: HeapPStrIter, - pdl: &mut Vec, - ) -> Option { - let compound = Some(TermOrderCategory::Compound); - - if iter2.focus.order_category(iter2.heap) != compound { - Some(compound.cmp(&iter2.focus.order_category(iter2.heap))) - } else { - let c1 = match iteratee { - PStrIteratee::Char(_, c) => c, - PStrIteratee::PStrSegment(focus, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - - match pstr.as_str_from(n).chars().next() { - Some(c) => c, - None => { - pdl.push(iter2.focus); - // iter2 is continuable, so it - // has a tail in the heap at - // focus+1. - pdl.push(iter2.heap[focus + 1]); - - return None; - } - } - } - }; - - read_heap_cell!(iter2.focus, - (HeapCellValueTag::Lis, l) => { - pdl.push(iter2.heap[l]); - pdl.push(char_as_cell!(c1)); - - None - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(iter2.heap[s]) - .get_name_and_arity(); - - if name == atom!(".") && arity == 2 { - pdl.push(iter2.heap[s+1]); - pdl.push(char_as_cell!(c1)); - - None - } else { - Some((2, atom!(".")).cmp(&(arity, name))) - } - } - _ => { - unreachable!() - } - ) - } - } - - fn pstr_comparator( - heap: &[HeapCellValue], - pdl: &mut Vec, - s1: usize, - s2: usize, - ) -> Option { - let mut iter1 = HeapPStrIter::new(heap, s1); - let mut iter2 = HeapPStrIter::new(heap, s2); - - match compare_pstr_prefixes(&mut iter1, &mut iter2) { - PStrCmpResult::Ordered(ordering) => Some(ordering), - PStrCmpResult::FirstIterContinuable(iteratee) => { - stalled_pstr_iter_comparator(iteratee, iter2, pdl) - } - PStrCmpResult::SecondIterContinuable(iteratee) => { - let result = stalled_pstr_iter_comparator(iteratee, iter1, pdl); - - if let Some(ordering) = result { - Some(ordering.reverse()) - } else { - let pdl_len = pdl.len(); - pdl.swap(pdl_len - 2, pdl_len - 1); - result - } - } - PStrCmpResult::Unordered => { - pdl.push(iter2.focus); - pdl.push(iter1.focus); - - None - } - } - } - read_heap_cell!(v1, (HeapCellValueTag::Lis, l1) => { read_heap_cell!(v2, - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - let h = self.heap.len(); - - self.heap.push(v1); - self.heap.push(v2); - - if let Some(ordering) = pstr_comparator( - &self.heap, &mut self.pdl, h, h+1 - ) { - if ordering != Ordering::Equal { - self.heap.pop(); - self.heap.pop(); - - self.pdl.clear(); - - return Some(ordering); - } - } - - self.heap.pop(); - self.heap.pop(); + (HeapCellValueTag::PStrLoc, l2) => { + // like the action of + // partial_string_to_pdl here but + // the ordering of PDL pushes is + // (crucially for comparison + // correctness) different. + let (c, succ_cell) = self.heap.last_str_char_and_tail(l2); + + self.pdl.push(succ_cell); + self.pdl.push(heap_loc_as_cell!(l1 + 1)); + + self.pdl.push(char_as_cell!(c)); + self.pdl.push(heap_loc_as_cell!(l1)); } (HeapCellValueTag::Lis, l2) => { if tabu_list.contains(&(l1, l2)) { @@ -757,27 +630,44 @@ impl MachineState { } ) } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - let h = self.heap.len(); - - self.heap.push(v1); - self.heap.push(v2); + (HeapCellValueTag::PStrLoc, l1) => { + read_heap_cell!(v2, + (HeapCellValueTag::PStrLoc, l2) => { + let cmp_result = self.heap.compare_pstr_segments(l1, l2); - if let Some(ordering) = pstr_comparator( - &self.heap, &mut self.pdl, h, h+1, - ) { - if ordering != Ordering::Equal { - self.heap.pop(); - self.heap.pop(); + if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) { + return Some(ordering); + } + } + (HeapCellValueTag::Lis, l2) => { + let (c, succ_cell) = self.heap.last_str_char_and_tail(l1); - self.pdl.clear(); + self.pdl.push(succ_cell); + self.pdl.push(heap_loc_as_cell!(l2 + 1)); - return Some(ordering); + self.pdl.push(char_as_cell!(c)); + self.pdl.push(heap_loc_as_cell!(l2)); } - } + (HeapCellValueTag::Str, s) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s]) + .get_name_and_arity(); + + if name == atom!(".") && arity == 2 { + let (c, succ_cell) = self.heap.last_str_char_and_tail(l1); + + self.pdl.push(heap_loc_as_cell!(s+2)); + self.pdl.push(succ_cell); - self.heap.pop(); - self.heap.pop(); + self.pdl.push(heap_loc_as_cell!(s+1)); + self.pdl.push(char_as_cell!(c)); + } else { + self.fail = true; + } + } + _ => { + unreachable!() + } + ); } (HeapCellValueTag::Str, s1) => { read_heap_cell!(v2, @@ -831,27 +721,21 @@ impl MachineState { } } } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - let h = self.heap.len(); - - self.heap.push(v1); - self.heap.push(v2); + (HeapCellValueTag::PStrLoc, l2) => { + let (name, arity) = cell_as_atom_cell!(self.heap[s1]) + .get_name_and_arity(); - if let Some(ordering) = pstr_comparator( - &self.heap, &mut self.pdl, h, h+1, - ) { - if ordering != Ordering::Equal { - self.heap.pop(); - self.heap.pop(); + if name == atom!(".") && arity == 2 { + let (c, succ_cell) = self.heap.last_str_char_and_tail(l2); - self.pdl.clear(); + self.pdl.push(succ_cell); + self.pdl.push(heap_loc_as_cell!(s1+2)); - return Some(ordering); - } + self.pdl.push(char_as_cell!(c)); + self.pdl.push(heap_loc_as_cell!(s1+1)); + } else { + self.fail = true; } - - self.heap.pop(); - self.heap.pop(); } _ => { unreachable!() @@ -875,185 +759,37 @@ impl MachineState { Some(Ordering::Equal) } - pub fn match_partial_string(&mut self, value: HeapCellValue, string: Atom, has_tail: bool) { - let h = self.heap.len(); - self.heap.push(value); - - let prefix_len; - let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); - - let s = string.as_str(); - - match heap_pstr_iter.compare_pstr_to_string(&s) { - Some(PStrPrefixCmpResult { - focus, - offset, - prefix_len, - }) if prefix_len == s.len() => { - let focus_addr = self.heap[focus]; - - read_heap_cell!(focus_addr, - (HeapCellValueTag::PStr | HeapCellValueTag::CStr, pstr_atom) => { - if has_tail { - self.s = HeapPtr::PStrLocation(focus, offset); - self.s_offset = 0; - self.mode = MachineMode::Read; - } else if offset == pstr_atom.len() { - let focus = heap_pstr_iter.focus; - unify!(self, focus, empty_list_as_cell!()); - } else { - self.fail = true; - } - } - (HeapCellValueTag::PStrLoc | HeapCellValueTag::PStrOffset, h) => { - let (focus, _) = pstr_loc_and_offset(&self.heap, h); - let pstr_atom = cell_as_atom!(self.heap[focus]); - - if has_tail { - self.s = HeapPtr::PStrLocation(focus, offset); - self.s_offset = 0; - self.mode = MachineMode::Read; - } else if offset == pstr_atom.len() { - let focus = heap_pstr_iter.focus; - unify!(self, focus, empty_list_as_cell!()); - } else { - self.fail = true; - } - } - _ => { - let focus = heap_pstr_iter.focus(); - - if has_tail { - self.s = HeapPtr::HeapCell(focus); - self.s_offset = 0; - self.mode = MachineMode::Read; - } else { - let focus = heap_pstr_iter.focus; - unify!(self, focus, empty_list_as_cell!()); - } - } - ); + /* TODO: new, inlined match_partial_string. now inlined into GetPartialString, + * the only place it is called from. Therefore, it has been inlined. - return; + pub fn match_partial_string( + &mut self, + value: HeapCellValue, + string: &str, + ) -> Result<(), usize> { + debug_assert!(value.is_ref()); + + self.heap[0] = value; + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0); + + match heap_pstr_iter.compare_pstr_to_string(string) { + Some(PStrCmpResult::CompleteMatch { bytes_matched, pstr_loc }) => { + self.s_offset = bytes_matched; + self.s = HeapPtr::PStr(pstr_loc); + self.mode = MachineMode::Read; } - Some(PStrPrefixCmpResult { - prefix_len: inner_prefix_len, - .. - }) => { - prefix_len = inner_prefix_len; + Some(PStrCmpResult::PartialMatch { string, var_loc }) => { + let cell = self.heap.allocate_pstr(string)?; + unify!(self, cell, heap_loc_as_loc!(var_loc)); } None => { - read_heap_cell!(value, - (HeapCellValueTag::Str, s) => { - let cell = heap_loc_as_cell!(s + 1); - let is_list = self.heap[s] == atom_as_cell!(atom!("."), 2); - - if !(is_list && self.store(self.deref(cell)).is_var()) { - self.fail = true; - return; - } - } - (HeapCellValueTag::Lis, l) => { - let cell = heap_loc_as_cell!(l); - - if !self.store(self.deref(cell)).is_var() { - self.fail = true; - return; - } - } - (HeapCellValueTag::AttrVar | - HeapCellValueTag::StackVar | - HeapCellValueTag::Var) => { - } - _ => { - self.fail = true; - return; - } - ); - - prefix_len = 0; + self.fail = true; } } - let focus = heap_pstr_iter.focus(); - let tail_addr = self.heap[focus]; - let target_cell = self.push_str_to_heap(&string.as_str()[prefix_len..], has_tail); - - unify!(self, tail_addr, target_cell); - } - - #[inline(always)] - pub(super) fn push_str_to_heap(&mut self, pstr: &str, has_tail: bool) -> HeapCellValue { - let h = self.heap.len(); - - if has_tail { - self.s = HeapPtr::HeapCell(h + 1); - self.s_offset = 0; - self.mode = MachineMode::Read; - - put_partial_string(&mut self.heap, pstr, &self.atom_tbl) - } else { - put_complete_string(&mut self.heap, pstr, &self.atom_tbl) - } - } - - pub(super) fn write_literal_to_var(&mut self, deref_v: HeapCellValue, lit: HeapCellValue) { - let store_v = self.store(deref_v); - - read_heap_cell!(lit, - (HeapCellValueTag::Atom, (atom, arity)) => { - if arity == 0 { - self.unify_atom(atom, store_v); - } else { - self.fail = true; - } - } - (HeapCellValueTag::Char, c) => { - self.unify_char(c, store_v); - } - (HeapCellValueTag::Fixnum, n) => { - self.unify_fixnum(n, store_v); - } - (HeapCellValueTag::F64, f64_ptr) => { - self.unify_f64(f64_ptr, store_v); - } - (HeapCellValueTag::Cons, ptr) => { - match_untyped_arena_ptr!(ptr, - (ArenaHeaderTag::Integer, n) => { - self.unify_big_int(n, store_v); - } - (ArenaHeaderTag::Rational, r) => { - self.unify_rational(r, store_v); - } - _ => { - self.fail = true; - } - ) - } - (HeapCellValueTag::CStr, cstr_atom) => { - read_heap_cell!(store_v, - (HeapCellValueTag::PStrLoc | - HeapCellValueTag::Lis | - HeapCellValueTag::Str) => { - self.match_partial_string(store_v, cstr_atom, false); - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var) => { - let r = store_v.as_var().unwrap(); - self.bind(r, lit); - } - (HeapCellValueTag::CStr, cstr2_atom) => { - self.fail = cstr_atom != cstr2_atom; - } - _ => { - self.fail = true; - } - ); - } - _ => { - unreachable!() - } - ) + Ok(()) } + */ pub(crate) fn setup_call_n_init_goal_info( &mut self, @@ -1084,9 +820,11 @@ impl MachineState { (name, 0, 0) } + /* (HeapCellValueTag::Char, c) => { (AtomTable::build_with(&self.atom_tbl, &c.to_string()), 0, 0) } + */ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let stub = functor_stub(atom!("call"), arity + 1); let err = self.instantiation_error(); @@ -1118,24 +856,14 @@ impl MachineState { } #[inline] - pub fn is_cyclic_term(&mut self, value: HeapCellValue) -> bool { - let value = self.store(self.deref(value)); - - if value.is_stack_var() || value.is_constant() { + pub fn is_cyclic_term(&mut self, term_loc: usize) -> bool { + if self.heap[term_loc].is_stack_var() { return false; } - let h = self.heap.len(); - self.heap.push(value); - - let cycle_found = { - let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, h); - for _ in iter.by_ref() {} - iter.cycle_found() - }; - - self.heap.pop(); - cycle_found + let mut iter = cycle_detecting_stackless_preorder_iter(&mut self.heap, term_loc); + for _ in iter.by_ref() {} + iter.cycle_found() } // arg(+N, +Term, ?Arg) @@ -1202,19 +930,27 @@ impl MachineState { (HeapCellValueTag::PStrLoc, pstr_loc) => { if n == 1 || n == 2 { let a3 = self.registers[3]; - let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); + // let (h, offset) = pstr_loc_and_offset(&self.heap, pstr_loc); + let mut char_iter = self.heap.char_iter(pstr_loc); - let pstr = cell_as_string!(self.heap[h]); - let offset = offset.get_num() as usize; + // let pstr = cell_as_string!(self.heap[h]); + // let offset = offset.get_num() as usize; - if let Some(c) = pstr.as_str_from(offset).chars().next() { + if let Some(c) = char_iter.next() { // pstr.as_str_from(offset).chars().next() { if n == 1 { self.unify_char(c, a3); } else { - let offset = (offset + c.len_utf8()) as i64; - let h_len = self.heap.len(); - let pstr_atom: Atom = pstr.into(); + // let offset = (offset + c.len_utf8()) as i64; + // let h_len = self.heap.len(); + // let pstr_atom: Atom = pstr.into(); + if char_iter.next().is_some() { + unify_fn!(*self, pstr_loc_as_cell!(pstr_loc + c.len_utf8()), a3); + } else { + let tail_idx = Heap::neighboring_cell_offset(pstr_loc); + unify_fn!(*self, self.heap[tail_idx]); + } + /* if pstr_atom.len() > offset as usize { self.heap.push(pstr_offset_as_cell!(h)); self.heap.push(fixnum_as_cell!(Fixnum::build_with(offset))); @@ -1233,6 +969,7 @@ impl MachineState { } } } + */ } } else { unreachable!() @@ -1241,6 +978,7 @@ impl MachineState { self.fail = true; } } + /* (HeapCellValueTag::CStr, cstr_atom) => { let cstr = PartialString::from(cstr_atom); @@ -1267,6 +1005,7 @@ impl MachineState { unreachable!() } } + */ _ => { // 8.5.2.3 d) let err = self.type_error(ValidType::Compound, term); @@ -1297,7 +1036,7 @@ impl MachineState { fn try_functor_unify_components(&mut self, name: HeapCellValue, arity: usize) { let a2 = self.deref(self.registers[2]); - self.write_literal_to_var(a2, name); + unify!(self, a2, name); if !self.fail { let a3 = self.store(self.deref(self.registers[3])); @@ -1305,20 +1044,25 @@ impl MachineState { } } - fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) { - let h = self.heap.len(); + fn try_functor_fabricate_struct(&mut self, name: Atom, arity: usize, r: Ref) -> Result<(), usize> { + let h = self.heap.cell_len(); + let mut writer = self.heap.reserve(arity + 1)?; let f_a = if name == atom!(".") && arity == 2 { - self.heap.push(heap_loc_as_cell!(h)); - self.heap.push(heap_loc_as_cell!(h + 1)); + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h + 1)); + }); list_loc_as_cell!(h) } else { - self.heap.push(atom_as_cell!(name, arity)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(name, arity)); - for i in 0..arity { - self.heap.push(heap_loc_as_cell!(h + i + 1)); - } + for i in 0..arity { + section.push_cell(heap_loc_as_cell!(h + i + 1)); + } + }); if arity == 0 { heap_loc_as_cell!(h) @@ -1328,6 +1072,7 @@ impl MachineState { }; (self.bind_fn)(self, r, f_a); + Ok(()) } pub fn try_functor(&mut self) -> CallResult { @@ -1335,7 +1080,7 @@ impl MachineState { let a1 = self.store(self.deref(self.registers[1])); read_heap_cell!(a1, - (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // | HeapCellValueTag::Char HeapCellValueTag::F64) => { self.try_functor_unify_components(a1, 0); } @@ -1347,7 +1092,7 @@ impl MachineState { let (name, arity) = cell_as_atom_cell!(self.heap[s]).get_name_and_arity(); self.try_functor_compound_case(name, arity); } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => { + (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { // | HeapCellValueTag::CStr) => { self.try_functor_compound_case(atom!("."), 2); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { @@ -1399,16 +1144,19 @@ impl MachineState { }; read_heap_cell!(store_name, - (HeapCellValueTag::Cons | HeapCellValueTag::Char | HeapCellValueTag::Fixnum | + (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | // HeapCellValueTag::Char | HeapCellValueTag::F64) if arity == 0 => { self.bind(a1.as_var().unwrap(), deref_name); } (HeapCellValueTag::Atom, (name, atom_arity)) => { debug_assert_eq!(atom_arity, 0); - self.try_functor_fabricate_struct( - name, - arity as usize, - a1.as_var().unwrap(), + resource_error_call_result!( + self, + self.try_functor_fabricate_struct( + name, + arity as usize, + a1.as_var().unwrap(), + ) ); } (HeapCellValueTag::Str, s) => { @@ -1416,25 +1164,33 @@ impl MachineState { .get_name_and_arity(); if atom_arity == 0 { - self.try_functor_fabricate_struct( - name, - arity as usize, - a1.as_var().unwrap(), + resource_error_call_result!( + self, + self.try_functor_fabricate_struct( + name, + arity as usize, + a1.as_var().unwrap(), + ) ); } else { let err = self.type_error(ValidType::Atomic, store_name); return Err(self.error_form(err, stub_gen())); } } + /* (HeapCellValueTag::Char, c) => { let c = AtomTable::build_with(&self.atom_tbl, &c.to_string()); - self.try_functor_fabricate_struct( - c, - arity as usize, - a1.as_var().unwrap(), + resource_error_call_result!( + self, + self.try_functor_fabricate_struct( + c, + arity as usize, + a1.as_var().unwrap(), + ) ); } + */ (HeapCellValueTag::Cons | HeapCellValueTag::Fixnum | HeapCellValueTag::F64) if arity != 0 => { let err = self.type_error(ValidType::Atom, store_name); @@ -1457,7 +1213,7 @@ impl MachineState { pub fn try_from_list( &mut self, value: HeapCellValue, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> Result, MachineStub> { let value = self.store(self.deref(value)); @@ -1465,8 +1221,8 @@ impl MachineState { (HeapCellValueTag::Lis, l) => { self.try_from_inner_list(vec![], l, stub_gen, value) } - (HeapCellValueTag::PStrLoc, h) => { - self.try_from_partial_string(vec![], h, stub_gen, value) + (HeapCellValueTag::PStrLoc, pstr_loc) => { + self.try_from_partial_string(vec![], pstr_loc, stub_gen, value) } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { let err = self.instantiation_error(); @@ -1491,10 +1247,12 @@ impl MachineState { Err(self.error_form(err, stub_gen())) } } + /* (HeapCellValueTag::CStr, cstr_atom) => { let cstr = cstr_atom.as_str(); Ok(cstr.chars().map(|c| char_as_cell!(c)).collect()) } + */ _ => { let err = self.type_error(ValidType::List, value); Err(self.error_form(err, stub_gen())) @@ -1506,7 +1264,7 @@ impl MachineState { &mut self, mut result: Vec, mut l: usize, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, a1: HeapCellValue, ) -> Result, MachineStub> { result.push(self.heap[l]); @@ -1520,8 +1278,8 @@ impl MachineState { result.push(self.heap[hcp]); l = hcp + 1; } - (HeapCellValueTag::PStrLoc, l) => { - return self.try_from_partial_string(result, l, stub_gen, a1); + (HeapCellValueTag::PStrLoc, pstr_loc) => { + return self.try_from_partial_string(result, pstr_loc, stub_gen, a1); } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) @@ -1560,52 +1318,34 @@ impl MachineState { fn try_from_partial_string( &mut self, mut chars: Vec, - h: usize, - stub_gen: impl Fn() -> FunctorStub, + pstr_loc: usize, + stub_gen: impl Fn() -> MachineStub, a1: HeapCellValue, ) -> Result, MachineStub> { - let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, h); + self.heap[0] = pstr_loc_as_cell!(pstr_loc); + let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0); - for iteratee in heap_pstr_iter.by_ref() { + while let Some(iteratee) = heap_pstr_iter.next() { match iteratee { - PStrIteratee::Char(_, c) => chars.push(char_as_cell!(c)), - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - chars.extend(pstr.as_str_from(n).chars().map(|c| char_as_cell!(c))); + PStrIteratee::Char { value: c, .. } => chars.push(char_as_cell!(c)), + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { + let pstr = heap_pstr_iter.heap.slice_to_str(slice_loc, slice_len); + chars.extend(pstr.chars().map(|c| char_as_cell!(c))); } } } - match self.heap[h].get_tag() { - HeapCellValueTag::PStr => { - if heap_pstr_iter.at_string_terminator() { - Ok(chars) - } else { - read_heap_cell!(self.heap[heap_pstr_iter.focus()], - (HeapCellValueTag::Lis, l) => { - self.try_from_inner_list(chars, l, stub_gen, a1) - } - (HeapCellValueTag::Atom, (name, arity)) => { - if name == atom!(".") && arity == 2 { - let l = heap_pstr_iter.focus() + 1; - self.try_from_inner_list(chars, l, stub_gen, a1) - } else { - let err = self.type_error(ValidType::List, a1); - Err(self.error_form(err, stub_gen())) - } - } - _ => { - let err = self.type_error(ValidType::List, a1); - Err(self.error_form(err, stub_gen())) - } - ) - } - } - HeapCellValueTag::CStr => Ok(chars), - _ => { - unreachable!() - } + let end_cell = heap_pstr_iter.heap[heap_pstr_iter.focus()]; + + if heap_pstr_iter.is_cyclic() || end_cell == empty_list_as_cell!() { + let err = self.type_error(ValidType::List, a1); + return Err(self.error_form(err, stub_gen())); } + + Ok(chars) } // returns true on failure. @@ -1624,7 +1364,7 @@ impl MachineState { pub fn integers_to_bytevec( &mut self, value: HeapCellValue, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> Vec { let mut bytes: Vec = Vec::new(); diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index badd6255..e0551a60 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -4,16 +4,12 @@ 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; #[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 +27,6 @@ impl MockWAM { Self { machine_st: MachineState::new(), op_dir, - //flags: MachineFlags::default(), } } @@ -56,7 +51,7 @@ impl MockWAM { ) -> Result { 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.splice(..), term_write_result.focus); let var_names = term_write_result .inverse_var_locs @@ -68,11 +63,10 @@ impl MockWAM { let mut printer = HCPrinter::new( &mut self.machine_st.heap, - Arc::clone(&self.machine_st.atom_tbl), &mut self.machine_st.stack, &self.op_dir, PrinterOutputter::new(), - term_write_result.heap_loc, + term_write_result.focus, ); printer.var_names = var_names; @@ -154,10 +148,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 @@ -171,43 +161,123 @@ 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 { + self.wam.machine_st.heap.copy_pstr_within(pstr_loc) + } + + #[inline(always)] + fn pstr_head_cell_index(&self, pstr_loc: usize) -> usize { + self.wam.machine_st.heap.pstr_vec()[0 .. cell_index!(pstr_loc)] + .last_zero() + .map(|idx| idx + 1) + .unwrap_or(0) + } + + #[inline(always)] + fn pstr_at(&self, loc: usize) -> bool { + self.wam.machine_st.heap.pstr_vec()[loc] + } + + #[inline(always)] + fn next_non_pstr_cell_index(&self, loc: usize) -> usize { + // unwrap is safe here because a partial string is always + // followed by a tail cell, i.e. a non-pstr cell, supposing + // self.machine_st.heap[loc] is a pstr cell + self.wam.machine_st.heap.pstr_vec()[loc ..].first_zero() + .map(|idx| idx + loc) + .unwrap() + } + + #[inline(always)] + fn reserve(&mut self, num_cells: usize) -> Result { + self.wam.machine_st.heap.reserve(num_cells) + } + + #[inline(always)] + fn copy_slice_to_end(&mut self, bounds: Range) -> 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(iter: impl SizedHeap) { + let mut idx = 0; + let cell_len = iter.cell_len(); + + while idx < cell_len { + let curr_idx = idx; + let cell = if iter.pstr_at(idx) { + let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); + idx = last_cell_loc; + iter[last_cell_loc - 1] + } else { + idx += 1; + iter[curr_idx] + }; + assert!( cell.get_mark_bit(), "cell {:?} at index {} is not marked", cell, - idx + curr_idx ); assert!( !cell.get_forwarding_bit(), "cell {:?} at index {} is forwarded", cell, - idx + curr_idx ); } } #[cfg(test)] -pub fn all_cells_unmarked(heap: &Heap) { - for (idx, cell) in heap.iter().enumerate() { +pub fn unmark_all_cells(mut iter: impl SizedHeapMut) { + let mut idx = 0; + let cell_len = iter.cell_len(); + + while idx < cell_len { + if iter.pstr_at(idx) { + iter[idx].set_mark_bit(false); + + let last_cell_loc = { + let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); + last_cell_loc + }; + + iter[last_cell_loc].set_mark_bit(false); + idx = last_cell_loc; + } else { + iter[idx].set_mark_bit(false); + idx += 1; + } + } +} + +#[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; + let cell = if iter.pstr_at(idx) { + let (_s, last_cell_loc) = iter.scan_slice_to_str(heap_index!(idx)); + idx = last_cell_loc; + iter[last_cell_loc - 1] + } else { + idx += 1; + iter[curr_idx] + }; + assert!( !cell.get_mark_bit(), "cell {:?} at index {} is still marked", cell, - idx - ); - - assert!( - !cell.get_forwarding_bit(), - "cell {:?} at index {} is still forwarded", - cell, - idx + curr_idx ); } } @@ -256,6 +326,8 @@ impl Machine { mod tests { use super::*; + use crate::functor_macro::FunctorElement; + #[test] fn unify_tests() { let mut wam = MachineState::new(); @@ -276,13 +348,13 @@ mod tests { unify!( wam, str_loc_as_cell!(0), - str_loc_as_cell!(term_write_result_2.heap_loc) + str_loc_as_cell!(term_write_result_2.focus) ); assert!(wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -296,14 +368,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -317,14 +389,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -338,14 +410,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -359,14 +431,14 @@ mod tests { unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); wam.fail = false; wam.heap.clear(); @@ -378,95 +450,119 @@ mod tests { let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); unify!( wam, - heap_loc_as_cell!(term_write_result_1.heap_loc), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_1.focus), + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(!wam.fail); } - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); 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(); + + writer.write_with(|section| { + section.push_pstr("this is a string"); // 0 + + let h = section.cell_len(); + assert_eq!(h, 3); - wam.heap.push(pstr_as_cell!(atom!("this is a string"))); - wam.heap.push(pstr_loc_as_cell!(4)); + section.push_cell(heap_loc_as_cell!(h)); // 3 + section.push_pstr("this is a string"); // 4 - 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 + 1, 8); - unify!(wam, pstr_loc_as_cell!(0), pstr_loc_as_cell!(2)); + 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)); + assert_eq!(wam.heap[3], pstr_loc_as_cell!(heap_index!(8))); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); 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(); + + 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)); - 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)); + 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)); assert!(!wam.fail); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); 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)); assert!(wam.fail); wam.fail = false; - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); + 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(); + + 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)); - 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)); + 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)); assert!(!wam.fail); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); } #[test] @@ -485,12 +581,12 @@ mod tests { let term_write_result_2 = parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap(); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); unify_with_occurs_check!( wam, heap_loc_as_cell!(0), - heap_loc_as_cell!(term_write_result_2.heap_loc) + heap_loc_as_cell!(term_write_result_2.focus) ); assert!(wam.fail); @@ -503,8 +599,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]), @@ -526,11 +629,13 @@ mod tests { Some(Ordering::Equal) ); + let cstr_cell = wam.allocate_cstr("string").unwrap(); + assert_eq!( compare_term_test!( wam, atom_as_cell!(atom!("atom")), - atom_as_cstr_cell!(atom!("string")) + cstr_cell ), Some(Ordering::Less) ); @@ -564,8 +669,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)), @@ -579,21 +688,25 @@ mod tests { wam.heap.clear(); - // [1,2,3] - wam.heap.push(list_loc_as_cell!(1)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); - wam.heap.push(list_loc_as_cell!(3)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.heap.push(list_loc_as_cell!(5)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(3))); - wam.heap.push(empty_list_as_cell!()); - - // [1,2] - wam.heap.push(list_loc_as_cell!(8)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(1))); - wam.heap.push(list_loc_as_cell!(10)); - wam.heap.push(fixnum_as_cell!(Fixnum::build_with(2))); - wam.heap.push(empty_list_as_cell!()); + let mut writer = wam.heap.reserve(96).unwrap(); + + writer.write_with(|section| { + // [1,2,3] + 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] + 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)), @@ -619,11 +732,13 @@ mod tests { Some(Ordering::Greater) ); + let cstr_cell = wam.allocate_cstr("string").unwrap(); + assert_eq!( compare_term_test!( wam, empty_list_as_cell!(), - atom_as_cstr_cell!(atom!("string")) + cstr_cell ), Some(Ordering::Less) ); @@ -655,55 +770,66 @@ 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); + all_cells_unmarked(wam.heap.splice(..)); 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")))] + ), + ); + + functor_writer(&mut wam.heap).unwrap(); - assert!(!wam.is_cyclic_term(str_loc_as_cell!(0))); + let h = wam.heap.cell_len(); + wam.heap.push_cell(str_loc_as_cell!(0)).unwrap(); - all_cells_unmarked(&wam.heap); + assert!(!wam.is_cyclic_term(h)); - assert!(!wam.is_cyclic_term(heap_loc_as_cell!(1))); + all_cells_unmarked(wam.heap.splice(..)); - all_cells_unmarked(&wam.heap); + assert!(!wam.is_cyclic_term(1)); - assert!(!wam.is_cyclic_term(heap_loc_as_cell!(2))); + all_cells_unmarked(wam.heap.splice(..)); - all_cells_unmarked(&wam.heap); + assert!(!wam.is_cyclic_term(2)); + + all_cells_unmarked(wam.heap.splice(..)); wam.heap[2] = str_loc_as_cell!(0); print_heap_terms(wam.heap.iter(), 0); - assert!(wam.is_cyclic_term(str_loc_as_cell!(0))); + assert!(wam.is_cyclic_term(2)); - all_cells_unmarked(&wam.heap); + all_cells_unmarked(wam.heap.splice(..)); 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); + all_cells_unmarked(wam.heap.splice(..)); 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.allocate_cstr("a string").unwrap(); - assert!(!wam.is_cyclic_term(pstr_loc_as_cell!(0))); + assert!(!wam.is_cyclic_term(h)); } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 09d9f642..18cb7427 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -505,7 +505,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 { @@ -525,12 +528,11 @@ impl Machine { s, )) => { cell = self.deref_register(arg); - self.machine_st - .select_switch_on_term_index(cell, v, c, l, s) + self.machine_st.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) @@ -556,6 +558,7 @@ impl Machine { if cell.is_var() { offset += 1; + /* } else if lit.get_tag() == HeapCellValueTag::CStr { read_heap_cell!(cell, (HeapCellValueTag::CStr) => { @@ -582,8 +585,10 @@ impl Machine { return false; } ); + */ } else { - self.machine_st.write_literal_to_var(cell, lit); + unify!(self.machine_st, cell, lit); + // self.machine_st.write_literal_to_var(cell, lit); if self.machine_st.fail { self.machine_st.fail = false; @@ -597,7 +602,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) => { @@ -638,25 +643,32 @@ impl Machine { } &Instruction::GetPartialString( Level::Shallow, - string, + ref string, RegType::Temp(t), - has_tail, + // has_tail, ) => { + use crate::machine::partial_string::HeapPStrIter; + let cell = self.deref_register(t); read_heap_cell!(cell, - (HeapCellValueTag::CStr, cstr) => { - if !has_tail && string != cstr { + (HeapCellValueTag::PStrLoc) => { + self.machine_st.heap[0] = cell; + let iter = HeapPStrIter::new(&self.machine_st.heap, 0); + + if iter.compare_pstr_to_string(&string).is_none() { return false; } offset += 1; + } - (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; @@ -779,7 +791,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(); @@ -790,7 +802,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; @@ -811,7 +823,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(); @@ -822,7 +834,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; diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 6a6ba96d..6176e73a 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -1,78 +1,27 @@ use crate::atom_table::*; -use crate::parser::ast::*; use crate::machine::heap::*; use crate::machine::machine_errors::CycleSearchResult; use crate::machine::system_calls::BrentAlgState; use crate::types::*; -use std::cmp::Ordering; use std::ops::Deref; use std::str; -#[derive(Copy, Clone, Debug)] -pub struct PartialString(Atom); - -fn scan_for_terminator>(iter: Iter) -> usize { - let mut terminator_idx = 0; - - for c in iter { - if c == '\u{0}' && terminator_idx != 0 { - return terminator_idx; - } - - terminator_idx += c.len_utf8(); - } - - terminator_idx -} - -impl From for PartialString { - #[inline] - fn from(buf: Atom) -> PartialString { - PartialString(buf) - } -} - -impl From for Atom { - #[inline] - fn from(val: PartialString) -> Self { - val.0 - } -} - -impl PartialString { - #[inline] - pub(super) fn new<'a>(src: &'a str, atom_tbl: &AtomTable) -> Option<(Self, &'a str)> { - let terminator_idx = scan_for_terminator(src.chars()); - let pstr = PartialString(AtomTable::build_with(atom_tbl, &src[..terminator_idx])); - Some(if terminator_idx < src.as_bytes().len() { - (pstr, &src[terminator_idx + 1..]) - } else { - (pstr, "") - }) - } - - #[inline(always)] - pub(crate) fn as_str_from(&self, n: usize) -> AtomString { - self.0.as_str().map(|str| &str[n..]) - } -} - #[derive(Clone, Copy)] pub struct HeapPStrIter<'a> { - pub heap: &'a [HeapCellValue], - pub focus: HeapCellValue, + pub heap: &'a Heap, + // pub focus: HeapCellValue, orig_focus: usize, brent_st: BrentAlgState, stepper: fn(&mut HeapPStrIter<'a>) -> Option, } #[derive(Debug, Clone, Copy)] -pub struct PStrPrefixCmpResult { - pub focus: usize, - pub offset: usize, - pub prefix_len: usize, +pub enum PStrCmpResult<'a> { + ListMatch { list_loc: usize }, + CompletePStrMatch { chars_matched: usize, pstr_loc: usize }, + PartialPStrMatch { string: &'a str, var_loc: usize }, } struct PStrIterStep { @@ -80,15 +29,20 @@ struct PStrIterStep { next_hare: usize, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PStrIteratee { + Char { heap_loc: usize, value: char }, + PStrSlice { slice_loc: usize, slice_len: usize }, +} + impl<'a> HeapPStrIter<'a> { - pub fn new(heap: &'a [HeapCellValue], h: usize) -> Self { - let value = heap[h]; + pub fn new(heap: &'a Heap, orig_focus: usize) -> Self { + debug_assert!(heap[orig_focus].is_ref()); Self { heap, - focus: value, - orig_focus: h, - brent_st: BrentAlgState::new(h), + orig_focus, + brent_st: BrentAlgState::new(orig_focus), stepper: HeapPStrIter::pre_cycle_discovery_stepper, } } @@ -98,97 +52,83 @@ impl<'a> HeapPStrIter<'a> { self.brent_st.hare } - #[inline(always)] - pub fn at_string_terminator(&self) -> bool { - self.focus.is_string_terminator(self.heap) - } + pub fn compare_pstr_to_string<'b>(self, mut s: &'b str) -> Option> { + let mut curr_hare = self.brent_st.hare; - #[inline(always)] - pub fn chars(mut self) -> PStrCharsIter<'a> { - let item = self.next(); - PStrCharsIter { iter: self, item } - } + while !s.is_empty() { + read_heap_cell!(self.heap[curr_hare], + (HeapCellValueTag::PStrLoc, h) => { + let t = self.heap.slice_to_str(h, self.heap.byte_len() - h); - pub fn compare_pstr_to_string(&mut self, s: &str) -> Option { - let mut result = PStrPrefixCmpResult { - focus: self.brent_st.hare, - offset: 0, - prefix_len: 0, - }; + let mut bytes_matched = 0; + let mut chars_matched = 0; - let mut final_result = None; + for (sc, tc) in s.chars().zip(t.chars()) { + if sc != tc { + if tc != '\u{0}' { + return None; + } else { + break; + } + } - while let Some(PStrIterStep { - iteratee, - next_hare, - }) = self.step(self.brent_st.hare) - { - self.brent_st.hare = next_hare; - self.focus = self.heap[iteratee.focus()]; + bytes_matched += sc.len_utf8(); + chars_matched += 1; + } - result.focus = iteratee.focus(); - result.offset = iteratee.offset(); + s = &s[bytes_matched ..]; - match iteratee { - PStrIteratee::Char(_, c1) => { - if let Some(c2) = s[result.prefix_len..].chars().next() { - if c1 != c2 { - return None; - } else { - result.prefix_len += c1.len_utf8(); - result.offset += c1.len_utf8(); - } + if s.is_empty() { + return Some(PStrCmpResult::CompletePStrMatch { chars_matched, pstr_loc: h }); } else { - final_result = Some(result); - break; + let next_hare = Heap::neighboring_cell_offset(h + bytes_matched); + curr_hare = next_hare; } } - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - let t = pstr.as_str_from(n); - let s = &s[result.prefix_len..]; - - if s.len() >= t.len() { - if s.starts_with(&*t) { - result.prefix_len += t.len(); - result.offset += t.len(); - } else { - return None; - } - } else if t.starts_with(s) { - result.prefix_len += s.len(); - result.offset += s.len(); - - final_result = Some(result); - break; - } else { - return None; + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == curr_hare { + return Some(PStrCmpResult::PartialPStrMatch { string: s, var_loc: h }); } + + curr_hare = h; + continue; } - } + _ => { + match self.step(curr_hare).ok() { + Some(PStrIterStep { iteratee, next_hare }) => { + let value = if let PStrIteratee::Char { value, .. } = iteratee { + value + } else { + unreachable!() + }; - if s.len() == result.prefix_len { - final_result = Some(result); - break; - } - } + let c = s.chars().next().unwrap(); - if let Some(result) = &final_result { - if self.at_string_terminator() { - self.focus = empty_list_as_cell!(); - self.brent_st.hare = result.focus; - } else { - read_heap_cell!(self.heap[result.focus], - (HeapCellValueTag::Lis | HeapCellValueTag::Str | HeapCellValueTag::PStr) => { - self.focus = self.heap[self.brent_st.hare]; - } - _ => { + if c == value { + s = &s[c.len_utf8() ..]; + + if s.is_empty() { + return Some( + PStrCmpResult::ListMatch { + list_loc: next_hare, + } + ); + } + + curr_hare = next_hare; + } else { + return None; + } + } + None => { + return None; + } } - ); - } + } + ); } - Some(result) + None } fn walk_hare_to_cycle_end(&mut self) { @@ -209,21 +149,23 @@ impl<'a> HeapPStrIter<'a> { self.brent_st.hare = self.step(self.brent_st.hare).unwrap().next_hare; } - self.focus = self.heap[orig_hare]; + // self.focus = self.heap[orig_hare]; self.brent_st.hare = orig_hare; } pub fn to_string_mut(&mut self) -> String { let mut buf = String::with_capacity(32); - for iteratee in self.by_ref() { + while let Some(iteratee) = self.next() { match iteratee { - PStrIteratee::Char(_, c) => { + PStrIteratee::Char { value: c, .. } => { buf.push(c); } - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - buf += &*pstr.as_str_from(n); + PStrIteratee::PStrSlice { + slice_loc, + slice_len, + } => { + buf += self.heap.slice_to_str(slice_loc, slice_len); } } } @@ -231,97 +173,18 @@ impl<'a> HeapPStrIter<'a> { buf } - #[inline] - pub fn is_continuable(&self) -> bool { - let mut focus = self.focus; - - loop { - read_heap_cell!(focus, - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - return true; - } - (HeapCellValueTag::Atom, (name, arity)) => { // TODO: use Str here? - return name == atom!(".") && arity == 2; - } - (HeapCellValueTag::Lis, h) => { - let value = self.heap[h]; - let value = heap_bound_store( - self.heap, - heap_bound_deref(self.heap, value), - ); - - return read_heap_cell!(value, - (HeapCellValueTag::Atom, (name, arity)) => { - arity == 0 && name.as_char().is_some() - } - (HeapCellValueTag::Char) => { - true - } - _ => { - false - } - ); - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if focus == self.heap[h] { - return false; - } - - focus = self.heap[h]; - } - _ => { - return false; - } - ); - } - } - - #[inline(always)] - pub fn cycle_detected(&self) -> bool { - self.stepper as usize == HeapPStrIter::post_cycle_discovery_stepper as usize - } - - fn step(&self, mut curr_hare: usize) -> Option { + // return the next step in the iteration or the updated curr_hare + // for the sake of pointing to the pstr tail + fn step(&self, mut curr_hare: usize) -> Result { loop { read_heap_cell!(self.heap[curr_hare], - (HeapCellValueTag::CStr, cstr_atom) => { - return if self.focus == empty_list_as_cell!() { - None - } else { - Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, cstr_atom, 0), - next_hare: curr_hare, - }) - } - } (HeapCellValueTag::PStrLoc, h) => { - curr_hare = h; - } - (HeapCellValueTag::PStr, pstr_atom) => { - return Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, 0), - next_hare: curr_hare+1, - }); - } - (HeapCellValueTag::PStrOffset, pstr_offset) => { - if self.focus == empty_list_as_cell!() { - return None; - } - - let pstr_atom = cell_as_atom!(self.heap[pstr_offset]); - let n = cell_as_fixnum!(self.heap[curr_hare+1]).get_num() as usize; + let (s, tail_loc) = self.heap.scan_slice_to_str(h); - return if self.heap[pstr_offset].get_tag() == HeapCellValueTag::CStr { - Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), - next_hare: pstr_offset, - }) - } else { - Some(PStrIterStep { - iteratee: PStrIteratee::PStrSegment(curr_hare, pstr_atom, n), - next_hare: pstr_offset+1, - }) - }; + return Ok(PStrIterStep { + iteratee: PStrIteratee::PStrSlice { slice_loc: h, slice_len: s.len() }, + next_hare: tail_loc, + }); } (HeapCellValueTag::Lis, h) => { let value = heap_bound_store( @@ -330,9 +193,9 @@ impl<'a> HeapPStrIter<'a> { ); return value.as_char().map(|c| PStrIterStep { - iteratee: PStrIteratee::Char(curr_hare, c), + iteratee: PStrIteratee::Char { heap_loc: curr_hare, value: c }, next_hare: h+1, - }); + }).ok_or(curr_hare) } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(self.heap[s]) @@ -345,26 +208,26 @@ impl<'a> HeapPStrIter<'a> { ); value.as_char().map(|c| PStrIterStep { - iteratee: PStrIteratee::Char(curr_hare, c), + iteratee: PStrIteratee::Char { heap_loc: curr_hare, value: c }, next_hare: s+2, - }) + }).ok_or(curr_hare) } else { - None + Err(curr_hare) }; } (HeapCellValueTag::Atom, (_name, arity)) => { debug_assert!(arity == 0); - return None; + return Err(curr_hare); } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h == curr_hare { - return None; + return Err(curr_hare); } curr_hare = h; } _ => { - return None; + return Err(curr_hare); } ); } @@ -375,30 +238,22 @@ impl<'a> HeapPStrIter<'a> { iteratee, next_hare, } = match self.step(self.brent_st.hare) { - Some(results) => results, - None => { + Ok(results) => results, + Err(next_hare) => { + self.brent_st.hare = next_hare; return None; } }; - self.focus = self.heap[iteratee.focus()]; - - if self.at_string_terminator() { - self.focus = empty_list_as_cell!(); - self.brent_st.hare = iteratee.focus(); - - return Some(iteratee); - } - match self.brent_st.step(next_hare) { Some(cycle_result) => { - debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic(..))); + debug_assert!(matches!(cycle_result, CycleSearchResult::Cyclic { .. })); self.walk_hare_to_cycle_end(); self.stepper = HeapPStrIter::post_cycle_discovery_stepper; } None => { - self.focus = self.heap[next_hare]; + // self.focus = self.heap[next_hare]; } } @@ -414,40 +269,21 @@ impl<'a> HeapPStrIter<'a> { iteratee, next_hare, } = match self.step(self.brent_st.hare) { - Some(results) => results, - None => { + Ok(results) => results, + Err(next_hare) => { + self.brent_st.hare = next_hare; return None; } }; - self.focus = self.heap[next_hare]; + // self.focus = self.heap[next_hare]; self.brent_st.hare = next_hare; Some(iteratee) } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PStrIteratee { - Char(usize, char), - PStrSegment(usize, Atom, usize), -} - -impl PStrIteratee { - #[inline] - fn offset(&self) -> usize { - match self { - PStrIteratee::Char(_, _) => 0, - PStrIteratee::PStrSegment(_, _, n) => *n, - } - } - #[inline] - fn focus(&self) -> usize { - match self { - PStrIteratee::Char(focus, _) => *focus, - PStrIteratee::PStrSegment(focus, _, _) => *focus, - } + pub(crate) fn is_cyclic(&self) -> bool { + self.stepper as usize == Self::post_cycle_discovery_stepper as usize } } @@ -465,24 +301,6 @@ pub struct PStrCharsIter<'a> { pub item: Option, } -impl<'a> PStrCharsIter<'a> { - pub fn peek(&self) -> Option { - if let Some(iteratee) = self.item { - match iteratee { - PStrIteratee::Char(_, c) => { - return Some(c); - } - PStrIteratee::PStrSegment(_, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); - return pstr.as_str_from(n).chars().next(); - } - } - } - - None - } -} - impl<'a> Deref for PStrCharsIter<'a> { type Target = HeapPStrIter<'a>; @@ -497,18 +315,19 @@ impl<'a> Iterator for PStrCharsIter<'a> { fn next(&mut self) -> Option { while let Some(item) = self.item { match item { - PStrIteratee::Char(_, c) => { + PStrIteratee::Char { value, .. } => { self.item = self.iter.next(); - return Some(c); + return Some(value); } - PStrIteratee::PStrSegment(f1, pstr_atom, n) => { - let pstr = PartialString::from(pstr_atom); + PStrIteratee::PStrSlice { slice_loc, slice_len } => { + let s = self.iter.heap.slice_to_str(slice_loc, slice_len); - match pstr.as_str_from(n).chars().next() { + match s.chars().next() { Some(c) => { - self.item = - Some(PStrIteratee::PStrSegment(f1, pstr_atom, n + c.len_utf8())); - + self.item = Some(PStrIteratee::PStrSlice { + slice_loc: slice_loc + c.len_utf8(), + slice_len: slice_len - c.len_utf8(), + }); return Some(c); } None => { @@ -523,272 +342,6 @@ impl<'a> Iterator for PStrCharsIter<'a> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PStrCmpResult { - Ordered(Ordering), - FirstIterContinuable(PStrIteratee), - SecondIterContinuable(PStrIteratee), - Unordered, -} - -impl PStrCmpResult { - #[inline] - pub fn is_second_iter(&self) -> bool { - matches!(self, PStrCmpResult::SecondIterContinuable(_)) - } -} - -#[inline] -pub fn compare_pstr_prefixes<'a>( - i1: &mut HeapPStrIter<'a>, - i2: &mut HeapPStrIter<'a>, -) -> PStrCmpResult { - #[inline(always)] - fn step(iter: &mut HeapPStrIter, hare: usize) -> Option { - let result = iter.step(hare); - iter.focus = iter.heap[hare]; - - if iter.focus.is_string_terminator(iter.heap) { - iter.focus = empty_list_as_cell!(); - } - - result - } - - #[inline(always)] - fn cycle_detection_step(i1: &mut HeapPStrIter, i2: &HeapPStrIter, step: &PStrIterStep) -> bool { - if i1.cycle_detected() { - i1.brent_st.hare = step.next_hare; - i2.cycle_detected() - } else if i1.brent_st.step(step.next_hare).is_some() { - i1.stepper = HeapPStrIter::post_cycle_discovery_stepper; - i2.cycle_detected() - } else { - false - } - } - - let mut r1 = step(i1, i1.brent_st.hare); - let mut r2 = step(i2, i2.brent_st.hare); - - loop { - if let Some(step_1) = r1.as_mut() { - if let Some(step_2) = r2.as_mut() { - match (step_1.iteratee, step_2.iteratee) { - (PStrIteratee::Char(_, c1), PStrIteratee::Char(_, c2)) => { - if c1 != c2 { - return PStrCmpResult::Ordered(c1.cmp(&c2)); - } - - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - (PStrIteratee::Char(_, c1), PStrIteratee::PStrSegment(f2, pstr_atom, n)) => { - let pstr = PartialString::from(pstr_atom); - - if let Some(c2) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return PStrCmpResult::Ordered(c1.cmp(&c2)); - } - - let n1 = n + c2.len_utf8(); - - if n1 < pstr_atom.len() { - step_2.iteratee = PStrIteratee::PStrSegment(f2, pstr_atom, n1); - - let c1_result = cycle_detection_step(i1, i2, step_1); - r1 = step(i1, i1.brent_st.hare); - - if !c1_result { - continue; - } - } else { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - } else { - let c2_result = cycle_detection_step(i2, i1, step_2); - r2 = step(i2, i2.brent_st.hare); - - if !c2_result { - continue; - } - } - } - (PStrIteratee::PStrSegment(f1, pstr_atom, n), PStrIteratee::Char(_, c2)) => { - let pstr = PartialString::from(pstr_atom); - - if let Some(c1) = pstr.as_str_from(n).chars().next() { - if c1 != c2 { - return PStrCmpResult::Ordered(c1.cmp(&c2)); - } - - let n1 = n + c1.len_utf8(); - - if n1 < pstr_atom.len() { - step_1.iteratee = PStrIteratee::PStrSegment(f1, pstr_atom, n1); - - let c2_result = cycle_detection_step(i2, i1, step_2); - r2 = step(i2, step_2.next_hare); - - if !c2_result { - continue; - } - } else { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - } else { - let c1_result = cycle_detection_step(i1, i2, step_1); - r1 = step(i1, i1.brent_st.hare); - - if !c1_result { - continue; - } - } - } - ( - PStrIteratee::PStrSegment(f1, pstr1_atom, n1), - PStrIteratee::PStrSegment(f2, pstr2_atom, n2), - ) => { - if pstr1_atom == pstr2_atom && n1 == n2 { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - - break; - } - - let pstr1 = PartialString::from(pstr1_atom); - let pstr2 = PartialString::from(pstr2_atom); - - let str1 = pstr1.as_str_from(n1); - let str2 = pstr2.as_str_from(n2); - - match str1.len().cmp(&str2.len()) { - Ordering::Equal if *str1 == *str2 => { - cycle_detection_step(i1, i2, step_1); - let both_cyclic = cycle_detection_step(i2, i1, step_2); - - r1 = step(i1, i1.brent_st.hare); - r2 = step(i2, i2.brent_st.hare); - - if !both_cyclic { - continue; - } - } - Ordering::Less if str2.starts_with(&*str1) => { - step_2.iteratee = - PStrIteratee::PStrSegment(f2, pstr2_atom, n2 + str1.len()); - let c1_result = cycle_detection_step(i1, i2, step_1); - r1 = step(i1, i1.brent_st.hare); - - if !c1_result { - continue; - } - } - Ordering::Greater if str1.starts_with(&*str2) => { - step_1.iteratee = - PStrIteratee::PStrSegment(f1, pstr1_atom, n1 + str2.len()); - let c2_result = cycle_detection_step(i2, i1, step_2); - r2 = step(i2, i2.brent_st.hare); - - if !c2_result { - continue; - } - } - _ => { - return PStrCmpResult::Ordered(str1.cmp(&*str2)); - } - } - } - } - } - } - - break; - } - - // to have a cyclic term, the cell at i1.focus must be: - // - // 1) 'continuable' as a cell in a string traversal, and, - // 2) matchable by compare_pstr_prefixes to the cell at i2.focus. - // - // If both cells are continuable they must have been encountered - // and thus matched by the compare_pstr_prefixes loop previously, - // so here it suffices to check if they are both continuable. - - let r1_at_end = r1.is_none(); - let r2_at_end = r2.is_none(); - - if r1_at_end && r2_at_end { - if i1.focus == i2.focus { - PStrCmpResult::Ordered(Ordering::Equal) - } else { - PStrCmpResult::Unordered - } - } else if r1_at_end { - if i1.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Less) - } else { - let r2_step = r2.unwrap(); - - // advance i2 to the next character so the same character - // isn't repeated - if matches!(r2_step.iteratee, PStrIteratee::Char(..)) { - cycle_detection_step(i2, i1, &r2_step); - } - - PStrCmpResult::SecondIterContinuable(r2_step.iteratee) - } - } else if r2_at_end { - if i2.focus == empty_list_as_cell!() { - PStrCmpResult::Ordered(Ordering::Greater) - } else { - let r1_step = r1.unwrap(); - - // advance i1 to the next character so the same character - // isn't repeated - if matches!(r1_step.iteratee, PStrIteratee::Char(..)) { - cycle_detection_step(i1, i2, &r1_step); - } - - PStrCmpResult::FirstIterContinuable(r1_step.iteratee) - } - } else if i1.is_continuable() && i2.is_continuable() { - PStrCmpResult::Ordered(Ordering::Equal) - } else { - PStrCmpResult::Unordered - } -} - #[cfg(test)] mod test { use super::*; @@ -799,233 +352,158 @@ mod test { fn pstr_iter_tests() { let mut wam = MockWAM::new(); - let pstr_var_cell = - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap(); + wam.machine_st.heap.push_cell(empty_list_as_cell!()).unwrap(); - let pstr_cell = wam.machine_st.heap[pstr_var_cell.get_value() as usize]; + // not overwriting anything! 0 is an interstitial cell + // reserved for use by the runtime + wam.machine_st.heap[0] = pstr_cell; { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }), ); assert_eq!(iter.next(), None); - - assert!(!iter.at_string_terminator()); + assert!(!iter.is_cyclic()); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); + assert_eq!(wam.machine_st.heap[2], empty_list_as_cell!()); + + wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3)); - let pstr_second_var_cell = - put_partial_string(&mut wam.machine_st.heap, "def", &wam.machine_st.atom_tbl); + wam.machine_st.allocate_pstr("def").unwrap(); + let h = wam.machine_st.heap.cell_len(); - let pstr_second_cell = wam.machine_st.heap[pstr_second_var_cell.get_value() as usize]; + wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap(); { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }) ); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment( - 2, - cell_as_atom!(pstr_second_cell), - 0 - )) + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(3), + slice_len: "def".len(), + }) ); assert_eq!(iter.next(), None); - assert!(!iter.at_string_terminator()); + assert!(!iter.is_cyclic()); } - wam.machine_st.heap.pop(); - wam.machine_st.heap.push(empty_list_as_cell!()); + assert_eq!(wam.machine_st.heap[h], heap_loc_as_cell!(h)); + + wam.machine_st.heap[h] = empty_list_as_cell!(); { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(0, cell_as_atom!(pstr_cell), 0)) + Some(PStrIteratee::PStrSlice { slice_loc: heap_index!(1), slice_len: "abc ".len() }) ); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment( - 2, - cell_as_atom!(pstr_second_cell), - 0 - )) + Some(PStrIteratee::PStrSlice { + slice_loc: heap_index!(3), + slice_len: "def".len(), + }) ); assert_eq!(iter.next(), None); - assert!(iter.at_string_terminator()); + assert!(!iter.is_cyclic()); } - 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(0))); + wam.machine_st.heap[h] = pstr_loc_as_cell!(heap_index!(3)); { let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 0); - for _ in iter.by_ref() {} - - assert!(!iter.at_string_terminator()); - } - - { - let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); - let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 0); - - assert_eq!( - compare_pstr_prefixes(&mut iter1, &mut iter2), - PStrCmpResult::Ordered(Ordering::Equal) - ); - } - - { - let second_h = wam.machine_st.heap.len(); - - // construct a structurally similar but different cyclic partial string - // matching the one beginning at wam.machine_st.heap[0]. - - put_partial_string(&mut wam.machine_st.heap, "ab", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.pop(); - - wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 2)); - - put_partial_string(&mut wam.machine_st.heap, "c ", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.pop(); - - wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 4)); - - wam.machine_st.heap.push(pstr_second_cell); - wam.machine_st.heap.push(pstr_loc_as_cell!(second_h + 6)); - - wam.machine_st.heap.push(pstr_offset_as_cell!(second_h)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(0))); - - let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); - let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, second_h); - - assert_eq!( - compare_pstr_prefixes(&mut iter1, &mut iter2), - PStrCmpResult::Ordered(Ordering::Equal) - ); - } - - wam.machine_st.heap.clear(); - - put_partial_string(&mut wam.machine_st.heap, "abc ", &wam.machine_st.atom_tbl); - - let pstr_cell = wam.machine_st.heap[0]; - - wam.machine_st.heap[1] = list_loc_as_cell!(2); - - wam.machine_st.heap.push(char_as_cell!('a')); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(char_as_cell!('b')); - wam.machine_st.heap.push(empty_list_as_cell!()); - - wam.machine_st.heap.push(pstr_cell); - wam.machine_st.heap.push(heap_loc_as_cell!(7)); - - { - let mut iter1 = HeapPStrIter::new(&wam.machine_st.heap, 0); - let mut iter2 = HeapPStrIter::new(&wam.machine_st.heap, 6); - - assert_eq!( - compare_pstr_prefixes(&mut iter1, &mut iter2), - PStrCmpResult::FirstIterContinuable(PStrIteratee::Char(1, 'a')), - ); - - assert_eq!(iter2.focus, heap_loc_as_cell!(7)); + assert!(iter.is_cyclic()); } // test "abc" = [X,Y,Z]. wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(heap_loc_as_cell!(4)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(heap_loc_as_cell!(1 + start)); - wam.machine_st.heap.push(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(3 + start)); + section.push_cell(heap_loc_as_cell!(3 + start)); - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(5 + start)); + section.push_cell(heap_loc_as_cell!(5 + start)); - assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),); + section.push_cell(empty_list_as_cell!()); + }); - assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),); + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(2)); - assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),); + assert_eq!(wam.machine_st.heap[1 + start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[3 + start], char_as_cell!('b')); + assert_eq!(wam.machine_st.heap[5 + start], char_as_cell!('c')); // test "abc" = [X,Y,Z|D]. wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); - - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); // X - - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(heap_loc_as_cell!(4)); // Y + let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); // Z + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(heap_loc_as_cell!(7)); // D + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(heap_loc_as_cell!(1 + start)); // X - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + section.push_cell(list_loc_as_cell!(3 + start)); + section.push_cell(heap_loc_as_cell!(3 + start)); // Y - assert!(!wam.machine_st.fail); + section.push_cell(list_loc_as_cell!(5 + start)); + section.push_cell(heap_loc_as_cell!(5 + start)); // Z - assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),); + section.push_cell(heap_loc_as_cell!(6 + start)); // D + }); - assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),); + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(2)); - assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),); + assert!(!wam.machine_st.fail); - assert_eq!(wam.machine_st.heap[7], empty_list_as_cell!(),); + assert_eq!(wam.machine_st.heap[3], char_as_cell!('a'),); + assert_eq!(wam.machine_st.heap[5], char_as_cell!('b'),); + assert_eq!(wam.machine_st.heap[7], char_as_cell!('c'),); + assert_eq!(wam.machine_st.heap[8], empty_list_as_cell!(),); // test "d" = [d]. wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "d", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("d").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(char_as_cell!('d')); - wam.machine_st.heap.push(empty_list_as_cell!()); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(char_as_cell!('d')); + section.push_cell(empty_list_as_cell!()); + }); - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(start)); assert!(!wam.machine_st.fail); @@ -1033,71 +511,83 @@ mod test { wam.machine_st.heap.clear(); - let cstr_var_cell = - put_complete_string(&mut wam.machine_st.heap, "abc", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(list_loc_as_cell!(2)); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - wam.machine_st.heap.push(list_loc_as_cell!(4)); - wam.machine_st.heap.push(char_as_cell!('b')); + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(1 + start)); + section.push_cell(heap_loc_as_cell!(1 + start)); - wam.machine_st.heap.push(list_loc_as_cell!(6)); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); + section.push_cell(list_loc_as_cell!(3 + start)); + section.push_cell(char_as_cell!('b')); - wam.machine_st.heap.push(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(5 + start)); + section.push_cell(heap_loc_as_cell!(5 + start)); - unify!(wam.machine_st, cstr_var_cell, heap_loc_as_cell!(1)); - - assert!(!wam.machine_st.fail); + section.push_cell(empty_list_as_cell!()); + }); - assert_eq!(wam.machine_st.heap[2], char_as_cell!('a'),); + unify!(wam.machine_st, pstr_cell, heap_loc_as_cell!(start)); - assert_eq!(wam.machine_st.heap[4], char_as_cell!('b'),); + assert!(!wam.machine_st.fail); - assert_eq!(wam.machine_st.heap[6], char_as_cell!('c'),); + assert_eq!(wam.machine_st.heap[1 + start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[3 + start], char_as_cell!('b')); + assert_eq!(wam.machine_st.heap[5 + start], char_as_cell!('c')); // test "abcdef" = [a,b,c|X]. wam.machine_st.heap.clear(); - put_complete_string(&mut wam.machine_st.heap, "abcdef", &wam.machine_st.atom_tbl); + let pstr_cell = wam.machine_st.allocate_cstr("abcdef").unwrap(); + let start = wam.machine_st.heap.cell_len(); - wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); - wam.machine_st.heap.push(heap_loc_as_cell!(2)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - unify!(wam.machine_st, heap_loc_as_cell!(0), pstr_loc_as_cell!(1)); + writer.write_with(|section| { + section.push_pstr("abc"); + let h = section.cell_len(); // h == 3 + section.push_cell(heap_loc_as_cell!(h)); + }); - print_heap_terms(wam.machine_st.heap.iter(), 0); + unify!(wam.machine_st, pstr_cell, pstr_loc_as_cell!(heap_index!(start))); assert!(!wam.machine_st.fail); - assert_eq!(wam.machine_st.heap[2], pstr_loc_as_cell!(5)); - assert_eq!(wam.machine_st.heap[3], pstr_loc_as_cell!(1)); - assert_eq!(wam.machine_st.heap[4], atom_as_cstr_cell!(atom!("abcdef"))); - assert_eq!(wam.machine_st.heap[5], pstr_offset_as_cell!(4)); assert_eq!( - wam.machine_st.heap[6], - fixnum_as_cell!(Fixnum::build_with("abc".len() as i64)) + wam.machine_st.heap.slice_to_str(0, "abcdef".len()), + "abcdef" + ); + assert_eq!( + wam.machine_st.heap.slice_to_str(heap_index!(start), "abc".len()), + "abc" + ); + assert_eq!( + wam.machine_st.heap[3], + pstr_loc_as_cell!(heap_index!(0) + 3) ); // test iteration on X = [b,c,b,c,b,c,b,c|...] as an offset. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(pstr_as_cell!(atom!("abc"))); - wam.machine_st.heap.push(pstr_loc_as_cell!(2)); - wam.machine_st.heap.push(pstr_offset_as_cell!(0)); - wam.machine_st - .heap - .push(fixnum_as_cell!(Fixnum::build_with(1))); + wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(pstr_loc_as_cell!('a'.len_utf8())); + }); { - let mut iter = HeapPStrIter::new(&wam.machine_st.heap, 2); + let mut iter = HeapPStrIter::new(&wam.machine_st.heap, start); assert_eq!( iter.next(), - Some(PStrIteratee::PStrSegment(2, atom!("abc"), 1)) + Some(PStrIteratee::PStrSlice { slice_loc: 'a'.len_utf8(), slice_len: "bc".len() }) ); for _ in iter {} @@ -1107,13 +597,19 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a "))); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr("a ").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(start)); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(empty_list_as_cell!()); + }); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); assert!(!wam.machine_st.fail); @@ -1121,98 +617,143 @@ mod test { wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a"))); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr(" a").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); assert!(!wam.machine_st.fail); // #2293, test3. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("a b"))); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr("a b").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(start)); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(heap_loc_as_cell!(4 + start)); + section.push_cell(empty_list_as_cell!()); + }); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + assert_eq!(wam.machine_st.heap[start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('b')); assert!(!wam.machine_st.fail); // #2293, test4. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a "))); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr(" a ").unwrap(); + let start = wam.machine_st.heap.cell_len(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + writer.write_with(|section| { + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); assert!(!wam.machine_st.fail); // #2293, test5. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!(" a bc"))); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(char_as_cell!(' ')); - wam.machine_st.heap.push(heap_loc_as_cell!(6)); + wam.machine_st.allocate_cstr(" a bc").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(char_as_cell!(' ')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(char_as_cell!(' ')); + section.push_cell(heap_loc_as_cell!(5 + start)); + }); + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[5 + start], pstr_loc_as_cell!(heap_index!(0) + 3)); assert!(!wam.machine_st.fail); // #2293, test6. wam.machine_st.heap.clear(); - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abc"))); - wam.machine_st.heap.push(heap_loc_as_cell!(1)); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(char_as_cell!('b')); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(heap_loc_as_cell!(5)); - wam.machine_st.heap.push(empty_list_as_cell!()); + wam.machine_st.allocate_cstr("abc").unwrap(); + let start = wam.machine_st.heap.cell_len(); + + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(start)); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(char_as_cell!('b')); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(heap_loc_as_cell!(4 + start)); + section.push_cell(empty_list_as_cell!()); + }); + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[start], char_as_cell!('a')); + assert_eq!(wam.machine_st.heap[4 + start], char_as_cell!('c')); assert!(!wam.machine_st.fail); // #2293, test7. wam.machine_st.heap.clear(); - - wam.machine_st.heap.push(atom_as_cstr_cell!(atom!("abcde"))); - wam.machine_st.heap.push(char_as_cell!('a')); - wam.machine_st.heap.push(list_loc_as_cell!(3)); - wam.machine_st.heap.push(heap_loc_as_cell!(3)); - wam.machine_st.heap.push(list_loc_as_cell!(5)); - wam.machine_st.heap.push(char_as_cell!('c')); - wam.machine_st.heap.push(list_loc_as_cell!(7)); - wam.machine_st.heap.push(heap_loc_as_cell!(7)); - wam.machine_st.heap.push(list_loc_as_cell!(9)); - wam.machine_st.heap.push(char_as_cell!('e')); - wam.machine_st.heap.push(empty_list_as_cell!()); - - unify!(wam.machine_st, list_loc_as_cell!(1), heap_loc_as_cell!(0)); - + wam.machine_st.allocate_cstr("abcde").unwrap(); + + let start = wam.machine_st.heap.cell_len(); + let mut writer = wam.machine_st.heap.reserve(16).unwrap(); + + writer.write_with(|section| { + section.push_cell(char_as_cell!('a')); + section.push_cell(list_loc_as_cell!(2 + start)); + section.push_cell(heap_loc_as_cell!(2 + start)); + section.push_cell(list_loc_as_cell!(4 + start)); + section.push_cell(char_as_cell!('c')); + section.push_cell(list_loc_as_cell!(6 + start)); + section.push_cell(heap_loc_as_cell!(6 + start)); + section.push_cell(list_loc_as_cell!(8 + start)); + section.push_cell(char_as_cell!('e')); + section.push_cell(empty_list_as_cell!()); + }); + + unify!(wam.machine_st, list_loc_as_cell!(start), pstr_loc_as_cell!(0)); + + assert_eq!(wam.machine_st.heap[2 + start], char_as_cell!('b')); + assert_eq!(wam.machine_st.heap[6 + start], char_as_cell!('d')); assert!(!wam.machine_st.fail); } } diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index 0173285e..751b55b6 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -3,6 +3,7 @@ use crate::codegen::CodeGenSettings; use crate::forms::*; use crate::instructions::*; use crate::machine::disjuncts::*; +use crate::machine::heap::*; use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::CodeIndex; @@ -27,25 +28,42 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result Result { let (focus, _cell) = subterm_index(term.heap, term.focus); - let name = match term.name(focus+3) { - Some(name) => name, - None => return Err(CompilationError::InconsistentEntry), + let name = match term_predicate_key(term.heap, focus+3) { + Some((name, 0)) => name, + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclNameType(term.heap[focus+3]), + )); + } }; - let spec = match term.name(focus+2) { - Some(name) => name, - None => return Err(CompilationError::InconsistentEntry), + let spec = match term_predicate_key(term.heap, focus+2) { + Some((name, _)) => name, + None => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus+2]), + )); + } }; - let prec = read_heap_cell!(term.deref_loc(focus+1), + let spec = to_op_decl_spec(spec)?; + let prec = term.deref_loc(focus+1); + + let prec = read_heap_cell!(prec, (HeapCellValueTag::Fixnum, n) => { match u16::try_from(n.get_num()) { Ok(n) if n <= 1200 => n, - _ => return Err(CompilationError::InconsistentEntry), + _ => { + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclPrecDomain(n), + )); + } } } _ => { - return Err(CompilationError::InconsistentEntry); + return Err(CompilationError::InvalidDirective( + DirectiveError::InvalidOpDeclPrecType(prec), + )); } ); @@ -71,10 +89,9 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result { } fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result { - let name_opt = term.name(term.focus); - let arity = term.arity(term.focus); + let key_opt = term_predicate_key(term.heap, term.focus); - if let (Some(atom!("/") | atom!("//")), 2) = (name_opt, arity) { + if let Some((atom!("/") | atom!("//"), 2)) = key_opt { let arity_loc = term.nth_arg(term.focus, 2).unwrap(); let arity = match Number::try_from(term.deref_loc(arity_loc)) { @@ -85,11 +102,11 @@ fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result Result { - if h == focus { - break; - } else { - focus = h; - } - } - (HeapCellValueTag::Lis, l) => { - let term = FocusedHeapRefMut { - heap: term.heap, - focus: l, - }; - exports.push(setup_module_export(&term)?); - - focus = l + 1; - } - (HeapCellValueTag::Atom, (name, _arity)) => { - if name == atom!("[]") { - return Ok(exports); - } else { - break; - } - } - _ => { - break; - } - ); + read_heap_cell!(term.heap[focus], + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { + if h == focus { + break; + } else { + focus = h; + } + } + (HeapCellValueTag::Lis, l) => { + let term = FocusedHeapRefMut { + heap: term.heap, + focus: l, + }; + + exports.push(setup_module_export(&term)?); + focus = l + 1; + } + (HeapCellValueTag::Atom, (name, _arity)) => { + if name == atom!("[]") { + return Ok(exports); + } else { + break; + } + } + _ => { + break; + } + ); } Err(CompilationError::InvalidModuleDecl) } -fn setup_module_decl(term: FocusedHeapRefMut) -> Result { - let name = term - .name(term.focus + 1) +fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result { + let name = term_predicate_key(term.heap, term.focus + 1) + .map(|(name, _)| name) .ok_or(CompilationError::InvalidModuleDecl)?; - let export_list = FocusedHeapRefMut { - heap: term.heap, - focus: term.focus + 2, - }; - let exports = setup_module_export_list(export_list)?; + + term.focus = term.focus + 2; + let exports = setup_module_export_list(term)?; Ok(ModuleDecl { name, exports }) } @@ -224,8 +238,8 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result Result>( - term: FocusedHeapRefMut, + term: TermWriteResult, loader: &mut Loader<'a, LS>, ) -> Result<(Atom, Atom, Vec), CompilationError> { fn get_meta_specs( @@ -319,24 +333,27 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( Ok(meta_specs) } - read_heap_cell!(term.deref_loc(term.focus+1), + let heap = loader.machine_heap(); + let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus+1])); + + read_heap_cell!(cell, (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity(); + let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); match (name, arity) { (atom!(":"), 2) => { - let module_name = term.heap[s+1]; - let spec = term.heap[s+2]; + let module_name = heap[s+1]; + let spec = heap[s+2]; read_heap_cell!(module_name, (HeapCellValueTag::Atom, (module_name, arity)) => { if arity == 0 { read_heap_cell!(spec, (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(term.heap[s]) + let (name, arity) = cell_as_atom_cell!(heap[s]) .get_name_and_arity(); - let term = FocusedHeapRefMut { heap: term.heap, focus: s }; + let term = FocusedHeapRefMut { heap, focus: s }; return Ok((module_name, name, get_meta_specs(term, arity)?)); } _ => { @@ -351,9 +368,11 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( ); } _ => { - let term = FocusedHeapRefMut { heap: term.heap, focus: s }; + let term = FocusedHeapRefMut { heap, focus: s }; + let specs = get_meta_specs(term, arity)?; let module_name = loader.payload.compilation_target.module_name(); - return Ok((module_name, name, get_meta_specs(term, arity)?)); + + return Ok((module_name, name, specs)); } } @@ -367,38 +386,41 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>( pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, - term: FocusedHeapRefMut, + mut term: TermWriteResult, ) -> Result { let mut focus = term.focus; + let machine_st = LS::machine_st(&mut loader.payload); loop { - read_heap_cell!(term.heap[focus], + let decl = machine_st.heap[focus]; + + read_heap_cell!(decl, (HeapCellValueTag::Atom, (name, arity)) => { - let term = FocusedHeapRefMut { heap: term.heap, focus }; + let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus); return match (name, arity) { (atom!("dynamic"), 1) => { - let (name, arity) = setup_predicate_indicator(&term)?; + let (name, arity) = setup_predicate_indicator(&focused)?; Ok(Declaration::Dynamic(name, arity)) } (atom!("module"), 2) => { - Ok(Declaration::Module(setup_module_decl(term)?)) + Ok(Declaration::Module(setup_module_decl(focused)?)) } (atom!("op"), 3) => { - Ok(Declaration::Op(setup_op_decl(&term)?)) + Ok(Declaration::Op(setup_op_decl(&focused)?)) } (atom!("non_counted_backtracking"), 1) => { - let focus = term.nth_arg(term.focus, 1).unwrap(); - let (name, arity) = setup_predicate_indicator(&FocusedHeapRefMut { heap: term.heap, focus })?; + focused.focus = focused.nth_arg(focused.focus, 1).unwrap(); + let (name, arity) = setup_predicate_indicator(&focused)?; Ok(Declaration::NonCountedBacktracking(name, arity)) } - (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&term)?)), + (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)), (atom!("use_module"), 2) => { - let (name, exports) = setup_qualified_import(term)?; - + let (name, exports) = setup_qualified_import(focused)?; Ok(Declaration::UseQualifiedModule(name, exports)) } (atom!("meta_predicate"), 1) => { + term.focus = focus; let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?; Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) } @@ -415,13 +437,13 @@ pub(super) fn setup_declaration<'a, LS: LoadState<'a>>( focus = h; } else { return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(heap_loc_as_cell!(h)), + DirectiveError::ExpectedDirective(decl), )); } } _ => { return Err(CompilationError::InvalidDirective( - DirectiveError::ExpectedDirective(term.heap[focus]) + DirectiveError::ExpectedDirective(decl), )); } ); @@ -432,41 +454,44 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, module_name: Atom, arity: usize, - term: &FocusedHeapRefMut, + term: &TermWriteResult, meta_specs: Vec, ) -> IndexMap { + use crate::machine::heap::Heap; let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default()); for (subterm_loc, meta_spec) in (term.focus + 1..term.focus + arity + 1).zip(meta_specs) { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { - if let Some(name) = term.name(subterm_loc) { + let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); + + if let Some((name, arity)) = predicate_key_opt { if name == atom!("$call") { continue; } - let arity = term.arity(subterm_loc); - struct QualifiedNameInfo { module_name: Atom, name: Atom, + arity: usize, qualified_term_loc: usize, } fn get_qualified_name( - term: &FocusedHeapRefMut, + heap: &Heap, module_term_loc: usize, qualified_term_loc: usize, ) -> Option { - let (module_term_loc, _) = subterm_index(term.heap, module_term_loc); - let (qualified_term_loc, _) = subterm_index(term.heap, qualified_term_loc); + let (module_term_loc, _) = subterm_index(heap, module_term_loc); + let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc); - read_heap_cell!(term.heap[module_term_loc], + read_heap_cell!(heap[module_term_loc], (HeapCellValueTag::Atom, (module_name, arity)) => { if arity == 0 { - if let Some(name) = term.name(qualified_term_loc) { + if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) { return Some(QualifiedNameInfo { module_name, name, + arity, qualified_term_loc, }); } @@ -478,23 +503,20 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( None } - let (subterm_loc, _) = subterm_index(term.heap, subterm_loc); - - let subterm_arity = term.arity(subterm_loc); - let subterm_name_opt = term.name(subterm_loc); + let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc); + let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); let (module_name, key, term_loc) = - if subterm_name_opt == Some(atom!(":")) && subterm_arity == 2 { - debug_assert_eq!(term.heap[subterm_loc].get_tag(), HeapCellValueTag::Atom); - - match get_qualified_name(term, subterm_loc + 1, subterm_loc + 2) { + if subterm_key_opt == Some((atom!(":"), 2)) { + match get_qualified_name(loader.machine_heap(), subterm_loc + 1, subterm_loc + 2) { Some(QualifiedNameInfo { module_name, name, + arity, qualified_term_loc, }) => ( module_name, - (name, term.arity(qualified_term_loc) + supp_args), + (name, arity + supp_args), qualified_term_loc, ), None => { @@ -505,7 +527,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( (module_name, (name, arity + supp_args), subterm_loc) }; - if let Some(index_ptr) = fetch_index_ptr(term.heap, key.1, term_loc) { + if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), key.1, term_loc) { index_ptrs.insert(term_loc, index_ptr); continue; } @@ -525,13 +547,13 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, key: PredicateKey, - terms: FocusedHeapRefMut, + terms: &TermWriteResult, term: HeapCellValue, call_policy: CallPolicy, ) -> QueryClause { // supplementary code vector indices are unnecessary for // root-level clauses. - blunt_index_ptr(terms.heap, key, terms.focus); + blunt_index_ptr(loader.machine_heap(), key, terms.focus); let mut ct = loader.get_clause_type(key.0, key.1); @@ -539,11 +561,10 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { let module_name = loader.payload.compilation_target.module_name(); let code_indices = - build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs); + build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs); return QueryClause { ct: ClauseType::Named(key.1, key.0, idx), - arity, term, code_indices, call_policy, @@ -555,7 +576,6 @@ pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( QueryClause { ct, - arity: key.1, term, code_indices: IndexMap::with_hasher(FxBuildHasher::default()), call_policy, @@ -567,13 +587,13 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( loader: &mut Loader<'a, LS>, key: PredicateKey, module_name: Atom, - terms: FocusedHeapRefMut, + terms: &TermWriteResult, term: HeapCellValue, call_policy: CallPolicy, ) -> QueryClause { // supplementary code vector indices are unnecessary for // root-level clauses. - blunt_index_ptr(terms.heap, key, terms.focus); + blunt_index_ptr(loader.machine_heap(), key, terms.focus); let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1); @@ -584,7 +604,6 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( return QueryClause { ct: ClauseType::Named(key.1, key.0, idx), - arity, term, code_indices, call_policy, @@ -596,7 +615,6 @@ pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( QueryClause { ct, - arity: key.1, term, code_indices: IndexMap::with_hasher(FxBuildHasher::default()), call_policy, @@ -613,15 +631,18 @@ impl Preprocessor { Preprocessor { settings } } - pub fn setup_fact( + pub fn setup_fact<'a, LS: LoadState<'a>>( &mut self, - mut term: FocusedHeap, + loader: &mut Loader<'a, LS>, + term: TermWriteResult, ) -> Result<(Fact, VarData), CompilationError> { - if term.name(term.focus).is_some() { + let heap = loader.machine_heap(); + + if term_predicate_key(heap, term.focus).is_some() { let classifier = VariableClassifier::new(self.settings.default_call_policy()); - let var_data = classifier.classify_fact(&mut term)?; + let var_data = classifier.classify_fact(loader, &term)?; - Ok((Fact { term }, var_data)) + Ok((Fact { term_loc: term.focus }, var_data)) } else { Err(CompilationError::InadmissibleFact) } @@ -630,14 +651,16 @@ impl Preprocessor { fn setup_rule<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - mut term: FocusedHeap, + term: TermWriteResult, ) -> Result<(Rule, VarData), CompilationError> { let classifier = VariableClassifier::new(self.settings.default_call_policy()); - let (clauses, var_data) = classifier.classify_rule(loader, &mut term)?; - let head_loc = term.nth_arg(term.focus, 1).unwrap(); + let (clauses, var_data) = classifier.classify_rule(loader, &term)?; + + let heap = loader.machine_heap(); + let head_loc = term_nth_arg(heap, term.focus, 1).unwrap(); - if term.name(head_loc).is_some() { - Ok((Rule { term, clauses }, var_data)) + if term_predicate_key(heap, head_loc).is_some() { + Ok((Rule { term_loc: term.focus, clauses }, var_data)) } else { Err(CompilationError::InvalidRuleHead) } @@ -646,19 +669,18 @@ impl Preprocessor { pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( &mut self, loader: &mut Loader<'a, LS>, - term: FocusedHeap, - ) -> Result { - let name = term.name(term.focus); - let arity = term.arity(term.focus); + term: TermWriteResult, + ) -> Result { + let heap = &LS::machine_st(&mut loader.payload).heap; - match (name, arity) { - (Some(atom!(":-")), 2) => { + match term_predicate_key(heap, term.focus) { + Some((atom!(":-"), 2)) => { let (rule, var_data) = self.setup_rule(loader, term)?; - Ok(TopLevel::Rule(rule, var_data)) + Ok(PredicateClause::Rule(rule, var_data)) } _ => { - let (fact, var_data) = self.setup_fact(term)?; - Ok(TopLevel::Fact(fact, var_data)) + let (fact, var_data) = self.setup_fact(loader, term)?; + Ok(PredicateClause::Fact(fact, var_data)) } } } diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 4b02dae7..9635e1ad 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -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::*; @@ -476,7 +476,7 @@ impl StreamOptions { #[inline] pub fn get_alias(self) -> Option { if self.has_alias() { - Some(Atom::from(self.alias() << 3)) + Some(Atom::from(self.alias())) } else { None } @@ -487,7 +487,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); } } } @@ -1937,7 +1937,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) @@ -1945,7 +1945,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) diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index 12bde5f6..2dccc87d 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,4 +1,5 @@ use crate::parser::ast::*; +use crate::parser::lexer::LexerParser; use crate::parser::parser::*; use base64::Engine; @@ -11,6 +12,7 @@ use crate::atom_table::*; #[cfg(feature = "ffi")] use crate::ffi::*; use crate::forms::*; +use crate::functor_macro::*; use crate::heap_iter::*; use crate::heap_print::*; #[cfg(feature = "http")] @@ -39,7 +41,6 @@ use ordered_float::OrderedFloat; use fxhash::{FxBuildHasher, FxHasher}; use indexmap::IndexSet; -use std::cell::Cell; use std::cmp::Ordering; use std::convert::TryFrom; use std::env; @@ -127,15 +128,10 @@ pub(crate) enum ModuleQuantification { } impl ModuleQuantification { - fn to_functor(&self) -> (Vec, HeapCellValueTag) { + fn to_functor(&self) -> Vec { match self { - &ModuleQuantification::Specified(cell) => ( - functor!(atom!("specified"), [cell(cell)]), - HeapCellValueTag::Str, - ), - ModuleQuantification::Unspecified => { - (functor!(atom!("unspecified")), HeapCellValueTag::Var) - } + &ModuleQuantification::Specified(cell) => functor!(atom!("specified"), [cell(cell)]), + ModuleQuantification::Unspecified => functor!(atom!("unspecified")), } } @@ -170,6 +166,65 @@ pub(crate) fn get_key() -> KeyEvent { key } +fn pstr_segment_char_count_and_tail(heap: &Heap, pstr_loc: usize) -> (usize, usize) { + let char_iter = heap.char_iter(pstr_loc); + + let mut char_count = 0; + let mut byte_offset = 0; + + for c in char_iter { + if c == '\u{0}' { + break; + } + + char_count += 1; + byte_offset += c.len_utf8(); + } + + ( + char_count, + Heap::neighboring_cell_offset(pstr_loc + byte_offset), + ) +} + +fn pstr_segment_char_count_up_to( + heap: &Heap, + pstr_loc: usize, + max_chars: usize, +) -> PStrSegmentCountResult { + let mut char_iter = heap.char_iter(pstr_loc); + let mut char_count = 0; + let mut byte_offset = 0; + + if max_chars > 0 { + while let Some(c) = char_iter.next() { + if c == '\u{0}' { + break; + } + + char_count += 1; + byte_offset += c.len_utf8(); + + if char_count >= max_chars { + break; + } + } + } + + if char_iter.next().is_some() { + PStrSegmentCountResult::Mid { + char_count, + pstr_loc: pstr_loc + byte_offset, + } + } else { + let tail_loc = Heap::neighboring_cell_offset(pstr_loc + byte_offset); + PStrSegmentCountResult::End { + char_count, + tail_loc, + } + } +} + #[derive(Debug, Clone, Copy)] pub struct BrentAlgState { pub hare: usize, @@ -207,7 +262,7 @@ impl BrentAlgState { self.lam += 1; if self.tortoise == self.hare { - return Some(CycleSearchResult::Cyclic(self.lam)); + return Some(CycleSearchResult::Cyclic { lambda: self.lam }); } else { self.teleport_tortoise(); } @@ -225,28 +280,26 @@ impl BrentAlgState { self.max_steps > -1 && self.num_steps() as i64 >= self.max_steps } - pub fn to_result(mut self, heap: &[HeapCellValue]) -> CycleSearchResult { + pub fn to_result(mut self, heap: &Heap) -> CycleSearchResult { loop { read_heap_cell!(heap[self.hare], - (HeapCellValueTag::PStrOffset) => { - let (pstr_loc, offset) = pstr_loc_and_offset(heap, self.hare); - let offset = offset.get_num() as usize; - - let pstr = cell_as_string!(heap[self.hare]); - self.pstr_chars += pstr.as_str_from(offset).chars().count(); - - return CycleSearchResult::PStrLocation(self.num_steps(), pstr_loc, offset); - } - (HeapCellValueTag::PStrLoc, l) => { - let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l); - let offset = offset.get_num() as usize; - return CycleSearchResult::PStrLocation(self.num_steps(), l, offset); + (HeapCellValueTag::PStrLoc) => { + // let (_pstr_loc, offset) = pstr_loc_and_offset(heap, l); + // let offset = offset.get_num() as usize; + let num_steps = self.num_steps(); + return CycleSearchResult::PStrLocation { num_steps, pstr_loc: heap[self.hare] }; } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { - CycleSearchResult::ProperList(self.num_steps()) + CycleSearchResult::ProperList { num_steps: self.num_steps() } } else { - CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) + let heap_loc = if arity > 0 { + str_loc_as_cell!(self.hare) + } else { + heap_loc_as_cell!(self.hare) + }; + + CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc } }; } (HeapCellValueTag::Str, s) => { @@ -254,96 +307,78 @@ impl BrentAlgState { .get_name_and_arity(); return if name == atom!("[]") && arity == 0 { - CycleSearchResult::ProperList(self.num_steps()) + CycleSearchResult::ProperList { num_steps: self.num_steps() } } else { - CycleSearchResult::NotList(self.num_steps(), heap[self.hare]) + CycleSearchResult::NotList { + num_steps: self.num_steps(), + heap_loc: heap[self.hare], + } }; } (HeapCellValueTag::Lis, l) => { - return CycleSearchResult::UntouchedList(self.num_steps(), l); + return CycleSearchResult::UntouchedList { num_steps: self.num_steps(), list_loc: l }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if h == self.hare { - let var = heap[self.hare].as_var().unwrap(); - return CycleSearchResult::PartialList(self.num_steps(), var); + // let var = heap[self.hare].as_var().unwrap(); + return CycleSearchResult::PartialList { + num_steps: self.num_steps(), + heap_loc: heap[self.hare], + }; } else { self.hare = h; } } _ => { - return CycleSearchResult::NotList(self.num_steps(), heap[self.hare]); + let heap_loc = heap_loc_as_cell!(self.hare); + return CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc }; } ); } } - fn add_pstr_offset_chars( - &mut self, - heap: &[HeapCellValue], - h: usize, - offset: usize, - ) -> Option { - read_heap_cell!(heap[h], - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); - let num_chars = cstr.as_str_from(offset).chars().count(); + fn add_pstr_chars(&mut self, heap: &Heap, pstr_loc: usize) -> Option { + let next_cell_loc; - if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { - self.pstr_chars += num_chars; - Some(CycleSearchResult::ProperList(self.num_steps())) - } else { - let char_offset = self.max_steps as usize - self.num_steps(); - self.pstr_chars += char_offset; - Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, char_offset + offset)) - } - } - (HeapCellValueTag::PStr, pstr_atom) => { - let pstr = PartialString::from(pstr_atom); - let num_chars = pstr.as_str_from(offset).chars().count(); + if self.max_steps == -1 { + let num_chars; + (num_chars, next_cell_loc) = pstr_segment_char_count_and_tail(heap, pstr_loc); + self.pstr_chars += num_chars - 1; + } else { + let max_chars = self.max_steps as usize - self.num_steps(); - if self.max_steps == -1 || self.num_steps() + num_chars <= self.max_steps as usize { - self.pstr_chars += num_chars - 1; - self.step(h+1) - } else { - let char_offset = self.max_steps as usize - self.num_steps(); - self.pstr_chars += char_offset; - Some(CycleSearchResult::PStrLocation(self.max_steps as usize, h, char_offset + offset)) + match pstr_segment_char_count_up_to(heap, pstr_loc, max_chars) { + PStrSegmentCountResult::Mid { + char_count, + pstr_loc, + } => { + self.pstr_chars += char_count; + return Some(CycleSearchResult::PStrLocation { + num_steps: self.num_steps(), + pstr_loc: pstr_loc_as_cell!(pstr_loc), + }); + } + PStrSegmentCountResult::End { + char_count, + tail_loc, + } => { + self.pstr_chars += char_count.saturating_sub(1); + next_cell_loc = tail_loc; } } - _ => { - unreachable!() - } - ) - } + } - fn add_pstr_chars_and_step( - &mut self, - heap: &[HeapCellValue], - h: usize, - ) -> Option { - read_heap_cell!(heap[h], - (HeapCellValueTag::PStrOffset, l) => { - let (pstr_loc, _) = pstr_loc_and_offset(heap, l); - let offset = cell_as_fixnum!(heap[h+1]); - self.add_pstr_offset_chars(heap, pstr_loc, offset.get_num() as usize) - } - _ => { - self.add_pstr_offset_chars(heap, h, 0) - } - ) + self.step(next_cell_loc) } #[inline(always)] - fn cycle_step(&mut self, heap: &[HeapCellValue]) -> Option { + fn cycle_step(&mut self, heap: &Heap) -> Option { loop { let value = heap[self.hare]; read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { - return self.add_pstr_chars_and_step(heap, h); - } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrOffset) => { - return self.add_pstr_chars_and_step(heap, self.hare); + return self.add_pstr_chars(heap, h); } (HeapCellValueTag::Lis, h) => { return self.step(h+1); @@ -354,63 +389,49 @@ impl BrentAlgState { return if name == atom!(".") && arity == 2 { self.step(s+2) } else { - Some(CycleSearchResult::NotList(self.num_steps(), value)) + Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value }) }; } (HeapCellValueTag::Atom, (name, arity)) => { debug_assert!(arity == 0); return if name == atom!("[]") { - Some(CycleSearchResult::ProperList(self.num_steps())) + Some(CycleSearchResult::ProperList { num_steps: self.num_steps() }) } else { - Some(CycleSearchResult::NotList(self.num_steps(), value)) + Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value }) }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if self.hare == h { - let r = value.as_var().unwrap(); - return Some(CycleSearchResult::PartialList(self.num_steps(), r)); + return Some(CycleSearchResult::PartialList { num_steps: self.num_steps(), heap_loc: value }); } self.hare = h; } _ => { - return Some(CycleSearchResult::NotList(self.num_steps(), value)); + return Some(CycleSearchResult::NotList { num_steps: self.num_steps(), heap_loc: value }); } ); } } - pub fn detect_cycles(heap: &[HeapCellValue], value: HeapCellValue) -> CycleSearchResult { - let mut pstr_chars = 0; + pub fn detect_cycles(heap: &Heap, value: HeapCellValue) -> CycleSearchResult { + let mut char_count = 0; let hare = read_heap_cell!(value, (HeapCellValueTag::Lis, offset) => { offset+1 } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, n) = pstr_loc_and_offset(heap, h); - let n = n.get_num() as usize; - let pstr = cell_as_string!(heap[h_offset]); - - pstr_chars = pstr.as_str_from(n).chars().count() - 1; - - if heap[h].get_tag() == HeapCellValueTag::PStrOffset { - debug_assert!(heap[h].get_tag() == HeapCellValueTag::PStrOffset); + let tail_idx; + (char_count, tail_idx) = pstr_segment_char_count_and_tail(heap, h); - if heap[h_offset].get_tag() == HeapCellValueTag::CStr { - return CycleSearchResult::ProperList(pstr_chars + 1); - } + if heap[tail_idx] == empty_list_as_cell!() { + return CycleSearchResult::ProperList { num_steps: char_count }; } - h_offset+1 - } - (HeapCellValueTag::PStrOffset) => { - unreachable!() - } - (HeapCellValueTag::CStr, cstr_atom) => { - let cstr = PartialString::from(cstr_atom); - return CycleSearchResult::ProperList(cstr.as_str_from(0).chars().count()); + char_count = char_count.saturating_sub(1); + tail_idx } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(heap[s]) @@ -421,28 +442,29 @@ impl BrentAlgState { } else if name == atom!(".") && arity == 2 { s + 2 } else { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { CycleSearchResult::EmptyList } else { - CycleSearchResult::NotList(0, value) + debug_assert_eq!(arity, 0); + CycleSearchResult::NotList { num_steps: 0, heap_loc: value } }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - return CycleSearchResult::PartialList(0, value.as_var().unwrap()); + return CycleSearchResult::PartialList { num_steps: 0, heap_loc: value }; } _ => { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } ); let mut brent_st = BrentAlgState::new(hare); brent_st.power += 1; // advance a step. - brent_st.pstr_chars = pstr_chars; + brent_st.pstr_chars = char_count; loop { if let Some(result) = brent_st.cycle_step(heap) { @@ -452,58 +474,31 @@ impl BrentAlgState { } pub fn detect_cycles_with_max( - heap: &[HeapCellValue], + heap: &Heap, max_steps: usize, value: HeapCellValue, ) -> CycleSearchResult { - let mut pstr_chars = 0; + let mut char_count = 0; let hare = read_heap_cell!(value, (HeapCellValueTag::Lis, offset) => { if max_steps > 0 { offset+1 } else { - return CycleSearchResult::UntouchedList(0, offset); + return CycleSearchResult::UntouchedList { num_steps: 0, list_loc: offset }; } } (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, n) = pstr_loc_and_offset(heap, h); - let n = n.get_num() as usize; - let pstr = cell_as_string!(heap[h_offset]); - - pstr_chars = pstr.as_str_from(n).chars().count() - 1; - - if heap[h].get_tag() == HeapCellValueTag::PStrOffset && heap[h_offset].get_tag() == HeapCellValueTag::CStr { - return if pstr_chars < max_steps { - CycleSearchResult::ProperList(pstr_chars + 1) - } else { - let offset = max_steps + n; - CycleSearchResult::PStrLocation(max_steps, h_offset, offset) + match pstr_segment_char_count_up_to(heap, h, max_steps) { + PStrSegmentCountResult::Mid { char_count, pstr_loc } => { + let pstr_loc = pstr_loc_as_cell!(pstr_loc); + return CycleSearchResult::PStrLocation { num_steps: char_count, pstr_loc }; } - } - - if pstr_chars + 1 > max_steps { - return CycleSearchResult::PStrLocation(max_steps, h_offset, max_steps); - } - - h_offset+1 - } - (HeapCellValueTag::PStrOffset) => { - unreachable!() - } - (HeapCellValueTag::CStr, cstr_atom) => { - return if max_steps > 0 { - let cstr = PartialString::from(cstr_atom); - let pstr_chars = cstr.as_str_from(0).chars().count(); - - if pstr_chars <= max_steps { - CycleSearchResult::ProperList(pstr_chars) - } else { - CycleSearchResult::UntouchedCStr(cstr_atom, max_steps) + PStrSegmentCountResult::End { char_count: num_chars, tail_loc } => { + char_count = num_chars - 1; + tail_loc } - } else { - CycleSearchResult::UntouchedCStr(cstr_atom, 0) - }; + } } (HeapCellValueTag::Str, s) => { let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity(); @@ -514,31 +509,32 @@ impl BrentAlgState { if max_steps > 0 { s + 2 } else { - return CycleSearchResult::UntouchedList(0, s + 1); + return CycleSearchResult::UntouchedList { num_steps: 0, list_loc: s + 1 }; } } else { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } } (HeapCellValueTag::Atom, (name, arity)) => { return if name == atom!("[]") && arity == 0 { CycleSearchResult::EmptyList } else { - CycleSearchResult::NotList(0, value) + debug_assert_eq!(arity, 0); + CycleSearchResult::NotList { num_steps: 0, heap_loc: value } }; } (HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar | HeapCellValueTag::Var) => { - return CycleSearchResult::PartialList(0, value.as_var().unwrap()); + return CycleSearchResult::PartialList { num_steps: 0, heap_loc: value }; } _ => { - return CycleSearchResult::NotList(0, value); + return CycleSearchResult::NotList { num_steps: 0, heap_loc: value }; } ); let mut brent_st = BrentAlgState::new(hare); brent_st.power += 1; // advance a step. - brent_st.pstr_chars = pstr_chars; + brent_st.pstr_chars = char_count; brent_st.max_steps = max_steps as i64; loop { @@ -559,6 +555,12 @@ enum MatchSite { Match(usize), // a match } +#[derive(Debug)] +enum PStrSegmentCountResult { + Mid { char_count: usize, pstr_loc: usize }, + End { char_count: usize, tail_loc: usize }, +} + #[derive(Debug)] struct AttrListMatch { match_site: MatchSite, @@ -585,24 +587,29 @@ impl MachineState { ); } - pub(crate) fn get_attr_var_list(&mut self, attr_var: HeapCellValue) -> Option { + pub(crate) fn get_attr_var_list( + &mut self, + attr_var: HeapCellValue, + ) -> Result, usize> { read_heap_cell!(attr_var, (HeapCellValueTag::AttrVar, h) => { - Some(h + 1) + Ok(Some(h + 1)) } (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { // create an AttrVar in the heap. - let h = self.heap.len(); + let h = self.heap.cell_len(); + let mut writer = self.heap.reserve(2)?; - self.heap.push(attr_var_as_cell!(h)); - self.heap.push(heap_loc_as_cell!(h+1)); + writer.write_with(|section| { + section.push_cell(attr_var_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h+1)); + }); self.bind(Ref::attr_var(h), attr_var); - - Some(h + 1) + Ok(Some(h + 1)) } _ => { - None + Ok(None) } ) } @@ -637,12 +644,13 @@ impl MachineState { } fn skip_max_list_cycle(&mut self, lam: usize) { - fn step(heap: &[HeapCellValue], mut value: HeapCellValue) -> usize { + fn step(heap: &Heap, mut value: HeapCellValue) -> usize { loop { read_heap_cell!(value, (HeapCellValueTag::PStrLoc, h) => { - let (h_offset, _) = pstr_loc_and_offset(heap, h); - return h_offset+1; + let (_, tail) = heap.scan_slice_to_str(h); + // let (h_offset, _) = pstr_loc_and_offset(heap, h); + return tail; } (HeapCellValueTag::Lis, h) => { return h+1; @@ -660,13 +668,14 @@ impl MachineState { } } - let h = self.heap.len(); - self.heap.push(self.registers[3]); + // let h = self.heap.cell_len(); + // self.heap.push(self.registers[3]); - let mut hare = h; + let orig_hare = step(&self.heap, self.registers[3]); + let mut hare = orig_hare; let mut tortoise = hare; - for _ in 0..lam { + for _ in 1..lam { hare = step(&self.heap, self.heap[hare]); } @@ -682,7 +691,7 @@ impl MachineState { // reached in the fashion of a C do-while loop since hare // may point to the beginning of a cycle. - let mut brent_st = BrentAlgState::new(h); + let mut brent_st = BrentAlgState::new(orig_hare); brent_st.cycle_step(&self.heap); @@ -690,7 +699,7 @@ impl MachineState { brent_st.cycle_step(&self.heap); } - self.heap.pop(); + // self.heap.pop_cell(); let target_n = self.store(self.deref(self.registers[1])); self.unify_fixnum(Fixnum::build_with(brent_st.num_steps() as i64), target_n); @@ -711,72 +720,51 @@ impl MachineState { } fn skip_max_list_result(&mut self, max_steps: i64) { + let cell = self.store(self.deref(self.registers[3])); + let search_result = if max_steps == -1 { - BrentAlgState::detect_cycles(&self.heap, self.store(self.deref(self.registers[3]))) + BrentAlgState::detect_cycles(&self.heap, cell) } else { - BrentAlgState::detect_cycles_with_max( - &self.heap, - max_steps as usize, - self.store(self.deref(self.registers[3])), - ) + BrentAlgState::detect_cycles_with_max(&self.heap, max_steps as usize, cell) }; match search_result { - CycleSearchResult::PStrLocation(steps, pstr_loc, offset) => { + CycleSearchResult::PStrLocation { + num_steps, + pstr_loc, + } => { let steps = if max_steps > -1 { - std::cmp::min(max_steps, steps as i64) + std::cmp::min(max_steps, num_steps as i64) } else { - steps as i64 + max_steps as i64 }; - let cell = if offset > 0 { - let h = self.heap.len(); - let (pstr_loc, _) = pstr_loc_and_offset(&self.heap, pstr_loc); - - self.heap.push(pstr_offset_as_cell!(pstr_loc)); - self.heap - .push(fixnum_as_cell!(Fixnum::build_with(offset as i64))); - - pstr_loc_as_cell!(h) - } else { - pstr_loc_as_cell!(pstr_loc) - }; - - self.finalize_skip_max_list(steps, cell); - } - CycleSearchResult::UntouchedList(n, l) => { - self.finalize_skip_max_list(n as i64, list_loc_as_cell!(l)); + self.finalize_skip_max_list(steps, pstr_loc); // cell); } - CycleSearchResult::UntouchedCStr(cstr_atom, n) => { - let cell = if n > 0 { - let h = self.heap.len(); - - self.heap.push(string_as_cstr_cell!(cstr_atom)); - self.heap.push(pstr_offset_as_cell!(h)); - self.heap - .push(fixnum_as_cell!(Fixnum::build_with(n as i64))); - - pstr_loc_as_cell!(h + 1) - } else { - string_as_cstr_cell!(cstr_atom) - }; - - self.finalize_skip_max_list(n as i64, cell); + CycleSearchResult::UntouchedList { + num_steps, + list_loc: l, + } => { + self.finalize_skip_max_list(num_steps as i64, list_loc_as_cell!(l)); } CycleSearchResult::EmptyList => { self.finalize_skip_max_list(0, empty_list_as_cell!()); } - CycleSearchResult::PartialList(n, r) => { - self.finalize_skip_max_list(n as i64, r.as_heap_cell_value()); + CycleSearchResult::PartialList { + num_steps, + heap_loc, + } => self.finalize_skip_max_list(num_steps as i64, heap_loc), + CycleSearchResult::ProperList { num_steps } => { + self.finalize_skip_max_list(num_steps as i64, empty_list_as_cell!()) } - CycleSearchResult::ProperList(steps) => { - self.finalize_skip_max_list(steps as i64, empty_list_as_cell!()) + CycleSearchResult::NotList { + num_steps, + heap_loc, + } => { + self.finalize_skip_max_list(num_steps as i64, heap_loc); } - CycleSearchResult::NotList(n, value) => { - self.finalize_skip_max_list(n as i64, value); - } - CycleSearchResult::Cyclic(lam) => { - self.skip_max_list_cycle(lam); + CycleSearchResult::Cyclic { lambda } => { + self.skip_max_list_cycle(lambda); } }; } @@ -824,30 +812,31 @@ impl MachineState { ) { let mut seen_set = IndexSet::new(); - let outcome = if term.is_ref() { - { - let mut iter = stackful_post_order_iter::( - &mut self.heap, &mut self.stack, term.get_value() as usize, - ); + if term.is_ref() { + let mut iter = stackful_post_order_iter::( + &mut self.heap, + &mut self.stack, + term.get_value() as usize, + ); - while let Some(value) = iter.next() { - if iter.parent_stack_len() >= max_depth { - iter.pop_stack(); - continue; - } + while let Some(value) = iter.next() { + if iter.parent_stack_len() >= max_depth { + iter.pop_stack(); + continue; + } - let value = unmark_cell_bits!(value); + let value = unmark_cell_bits!(value); - if value.is_var() { - seen_set.insert(value); - } + if value.is_var() { + seen_set.insert(value); } } + } - heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter())) - } else { - empty_list_as_cell!() - }; + let outcome = step_or_resource_error!( + self, + sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter(),) + ); unify_fn!(*self, list_of_vars, outcome); } @@ -866,8 +855,8 @@ impl MachineState { &mut self, lh_offset: usize, copy_target: HeapCellValue, - ) -> usize { - let threshold = self.lifted_heap.len() - lh_offset; + ) -> Result { + let threshold = self.lifted_heap.cell_len() - lh_offset; let mut copy_ball_term = CopyBallTerm::new( &mut self.attr_var_init.attr_var_queue, @@ -876,13 +865,17 @@ impl MachineState { &mut self.lifted_heap, ); - copy_ball_term.push(list_loc_as_cell!(threshold + 1)); - copy_ball_term.push(heap_loc_as_cell!(threshold + 3)); - copy_ball_term.push(heap_loc_as_cell!(threshold + 2)); + let mut writer = copy_ball_term.reserve(3)?; + + writer.write_with(|section| { + section.push_cell(list_loc_as_cell!(threshold + 1)); + section.push_cell(heap_loc_as_cell!(threshold + 3)); + section.push_cell(heap_loc_as_cell!(threshold + 2)); + }); - copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy); + copy_term(copy_ball_term, copy_target, AttrVarPolicy::DeepCopy)?; - threshold + lh_offset + 2 + Ok(threshold + lh_offset + 2) } #[inline(always)] @@ -894,11 +887,14 @@ impl MachineState { (HeapCellValueTag::Fixnum, n) => { let lh_offset = n.get_num() as usize; - if lh_offset >= self.lifted_heap.len() { + if lh_offset >= self.lifted_heap.cell_len() { self.lifted_heap.truncate(lh_offset); } else { - let threshold = self.lifted_heap.len() - lh_offset; - self.lifted_heap.push(addr_constr(threshold)); + let threshold = self.lifted_heap.cell_len() - lh_offset; + step_or_resource_error!( + self, + self.lifted_heap.push_cell(addr_constr(threshold)) + ); } } _ => { @@ -911,7 +907,7 @@ impl MachineState { &mut self, string: &str, indices: &IndexStore, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> CallResult { use crate::parser::lexer::*; @@ -929,14 +925,14 @@ impl MachineState { std::io::Cursor::new(dot_buf) }); - let mut lexer = Lexer::new(CharReader::new(iter), self); + let mut lexer_parser = LexerParser::new(CharReader::new(iter), self); let mut tokens = vec![]; - match lexer.next_token() { - Ok(token @ Token::Literal(Literal::Atom(atom!("-")) | Literal::Char('-'))) => { + match lexer_parser.next_token() { + Ok(token @ Token::Literal(atom)) if atom == atom_as_cell!(atom!("-")) => { tokens.push(token); - if let Ok(token) = lexer.next_token() { + if let Ok(token) = lexer_parser.next_token() { tokens.push(token); } } @@ -950,23 +946,16 @@ impl MachineState { } loop { - match lexer.lookahead_char() { + match lexer_parser.lookahead_char() { Err(e) if e.is_unexpected_eof() => { - let mut parser = Parser::from_lexer(lexer); let op_dir = CompositeOpDir::new(&indices.op_dir, None); tokens.reverse(); + let byte_size = heap_index!(tokens.len()); - match parser.read_term(&op_dir, Tokens::Provided(tokens)) { + match lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) { Ok(term) => { - let mut error_gen = || { - let e = ParserError::ParseBigInt(ParserErrorSrc::default()); - let e = self.syntax_error(e); - - return Err(self.error_form(e, stub_gen())); - }; - - read_heap_cell!(term.heap[term.focus], + read_heap_cell!(lexer_parser.machine_st.heap[term.focus], (HeapCellValueTag::Cons, c) => { match_untyped_arena_ptr!(c, (ArenaHeaderTag::Rational, n) => { @@ -976,7 +965,10 @@ impl MachineState { self.unify_big_int(n, nx); } _ => { - return error_gen(); + let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); + let e = self.syntax_error(e); + + return Err(self.error_form(e, stub_gen())); } ) } @@ -987,23 +979,26 @@ impl MachineState { self.unify_fixnum(n, nx); } _ => { - return error_gen(); + let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); + let e = self.syntax_error(e); + + return Err(self.error_form(e, stub_gen())); } ); + + return Ok(()); } Err(e) => { let e = self.syntax_error(e); return Err(self.error_form(e, stub_gen())); } } - - break; } Ok('.') => { - lexer.skip_char('.'); + lexer_parser.skip_char('.'); } Ok(c) => { - let err_src = lexer.loc_to_err_src(); + let err_src = lexer_parser.loc_to_err_src(); let err = ParserError::UnexpectedChar(c, err_src); let err = self.syntax_error(err); @@ -1013,8 +1008,6 @@ impl MachineState { Err(_) => unreachable!(), } } - - Ok(()) } pub(crate) fn call_continuation_chunk( @@ -1066,6 +1059,7 @@ impl MachineState { pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option { read_heap_cell!(value, + /* (HeapCellValueTag::CStr, cstr_atom) => { // avoid allocating a String if possible: // We must be careful to preserve the string "[]" as is, @@ -1076,6 +1070,7 @@ impl MachineState { Some(AtomOrString::Atom(cstr_atom)) } } + */ (HeapCellValueTag::Atom, (atom, arity)) => { if arity == 0 { // ... likewise. @@ -1094,27 +1089,23 @@ impl MachineState { None } } - (HeapCellValueTag::Char, c) => { - Some(AtomOrString::String(c.to_string())) - } _ => { if value.is_constant() { return None; } - let h = self.heap.len(); - self.heap.push(value); + // 0 is reserved for use by the machine. See + // MachineState::new. + self.heap[0] = value; - let mut iter = HeapPStrIter::new(&self.heap, h); + let mut iter = HeapPStrIter::new(&self.heap, 0); let string = iter.to_string_mut(); - let at_terminator = iter.at_string_terminator(); - - self.heap.pop(); + let end_cell = iter.heap[iter.focus()]; // if the iteration doesn't terminate like a string // (i.e. with the [] atom or a CStr), it is not // "str_like" so return None. - if at_terminator { + if end_cell.is_string_terminator(iter.heap) { Some(AtomOrString::String(string)) } else { None @@ -1126,7 +1117,7 @@ impl MachineState { pub(crate) fn codes_to_string( &mut self, addrs: impl Iterator, - stub_gen: impl Fn() -> FunctorStub, + stub_gen: impl Fn() -> MachineStub, ) -> Result { let mut string = String::new(); @@ -1289,7 +1280,7 @@ impl Machine { boip + extract_ptr!(hm.get(&key).cloned().unwrap()) } IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => { - boip + extract_ptr!(hm.get(&Literal::Atom(key.0)).cloned().unwrap()) + boip + extract_ptr!(hm.get(&atom_as_cell!(key.0)).cloned().unwrap()) } _ => boip, }; @@ -1412,8 +1403,12 @@ impl Machine { let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) .get_name_and_arity(); - (name, arity, if self.machine_st.heap.len() > s + arity + 1 { - get_structure_index(self.machine_st.heap[s + arity + 1]) + (name, arity, if self.machine_st.heap.cell_len() > s + arity + 1 { + if !self.machine_st.heap.pstr_at(s + arity + 1) { + get_structure_index(self.machine_st.heap[s + arity + 1]) + } else { + None + } } else { None }) @@ -1474,10 +1469,9 @@ impl Machine { } }; - // println!("(fast) calling {}/{}", name.as_str(), arity); - if let Some(code_index) = index_cell { if !code_index.is_undefined() { + // println!("(fast) calling {}/{}", name.as_str(), arity); load_registers(&mut self.machine_st, goal, goal_arity); self.machine_st.neck_cut(); return call_at_index(self, name, arity, code_index.get()); @@ -1530,9 +1524,7 @@ impl Machine { // disjoint from them. if they are not, the // expanded goal is not simple. - let post_supp_args = self.machine_st.heap[s+arity-supp_vars.len()+1 .. s+arity+1] - .iter() - .cloned(); + let post_supp_args = self.machine_st.heap.splice(s+arity-supp_vars.len()+1 .. s+arity+1); post_supp_args .zip(supp_vars.iter()) @@ -1558,16 +1550,20 @@ impl Machine { }; let goal = if is_simple_goal { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); let arity = arity - supp_vars.len(); - for idx in 0 .. arity + 1 { - let value = self.machine_st.heap[s + idx]; - self.machine_st.heap.push(value); - } + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.copy_slice_to_end( + s .. s + arity + 1 + ) + ); self.machine_st.heap[h] = atom_as_cell!(name, arity); + // even if arity == 0, goal must be a Str cell, + // since an index is about to appended to it. str_loc_as_cell!(h) } else { goal @@ -1583,8 +1579,11 @@ impl Machine { (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(goal); + let h = self.machine_st.heap.cell_len(); + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.push_cell(goal) + ); GoalAnalysisResult { is_simple_goal: true, @@ -1593,11 +1592,15 @@ impl Machine { supp_vars, } } + /* (HeapCellValueTag::Char, c) => { let name = AtomTable::build_with(&self.machine_st.atom_tbl,&c.to_string()); + let h = self.machine_st.heap.cell_len(); - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(atom_as_cell!(name)); + resource_error_call_result!( + self.machine_st, + self.machine_st.heap.push_cell(atom_as_cell!(name)) + ); GoalAnalysisResult { is_simple_goal: true, @@ -1606,6 +1609,7 @@ impl Machine { supp_vars, } } + */ _ => { self.machine_st.fail = true; return Ok(()); @@ -1619,9 +1623,14 @@ impl Machine { let expanded_term = if result.is_simple_goal { let idx = self.get_or_insert_qualified_code_index(module_name, result.key); - self.machine_st - .heap - .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); + + resource_error_call_result!( + self.machine_st, + self.machine_st + .heap + .push_cell(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))) + ); + result.goal } else { let mut unexpanded_vars = IndexSet::with_hasher(FxBuildHasher::default()); @@ -1644,20 +1653,26 @@ impl Machine { Err(e) => { let err = self.machine_st.session_error(e); let stub = functor_stub(atom!("call"), result.key.1); - return Err(self.machine_st.error_form(err, stub)); } Ok(()) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); + let mut writer = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.reserve(unexpanded_vars.len() + 2) + ); - self.machine_st.heap.push(atom_as_cell!(atom!("$aux"), 0)); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("$aux"), 0)); - for value in unexpanded_vars.difference(&result.supp_vars).cloned() { - self.machine_st.heap.push(value); - } + for value in unexpanded_vars.difference(&result.supp_vars).cloned() { + section.push_cell(value); + } - let anon_str_arity = self.machine_st.heap.len() - h - 1; + section.push_cell(atom_as_cell!(atom!("[]"))); + }); + let anon_str_arity = self.machine_st.heap.cell_len() - h - 2; self.machine_st.heap[h] = atom_as_cell!(atom!("$aux"), anon_str_arity); let idx = CodeIndex::new( @@ -1665,9 +1680,9 @@ impl Machine { &mut self.machine_st.arena, ); - self.machine_st - .heap - .push(untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx))); + self.machine_st.heap.last_cell_mut().map(|cell| { + *cell = untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(idx)); + }); str_loc_as_cell!(h) } @@ -1693,7 +1708,11 @@ impl Machine { return false; } - if self.machine_st.heap.len() > s + 1 + arity { + if self.machine_st.heap.cell_len() > s + 1 + arity { + if self.machine_st.heap.pstr_at(s + 1 + arity) { + return false; + } + let idx_cell = self.machine_st.heap[s + 1 + arity]; if HeapCellValueTag::Cons == idx_cell.get_tag() { @@ -1718,18 +1737,16 @@ impl Machine { let target_module_loc = self.machine_st.registers[2]; - let (functor_stub, ref_cell_tag) = module_quantification.to_functor(); - - let h = self.machine_st.heap.len(); - let ref_cell = HeapCellValue::build_with(ref_cell_tag, h as u64); + let functor_stub = module_quantification.to_functor(); + let mut functor_writer = Heap::functor_writer(functor_stub); - self.machine_st.heap.extend(functor_stub); + let cell = functor_writer(&mut self.machine_st.heap).unwrap(); + unify_fn!(&mut self.machine_st, cell, target_module_loc); - unify_fn!(&mut self.machine_st, ref_cell, target_module_loc); - - let target_qualified_goal = self.machine_st.registers[3]; - - unify_fn!(&mut self.machine_st, qualified_goal, target_qualified_goal); + if !self.machine_st.fail { + let target_qualified_goal = self.machine_st.registers[3]; + unify_fn!(&mut self.machine_st, qualified_goal, target_qualified_goal); + } } #[inline(always)] @@ -1749,21 +1766,24 @@ impl Machine { let target_goal = if arity == 0 { qualified_goal } else { - // if narity + arity > 0 { - let h = self.machine_st.heap.len(); - self.machine_st - .heap - .push(atom_as_cell!(name, narity + arity)); + let h = self.machine_st.heap.cell_len(); - for idx in 1..narity + 1 { - self.machine_st.heap.push(self.machine_st.heap[s + idx]); - } + let mut writer = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.reserve(1 + narity + arity) + ); - for idx in 1..arity + 1 { - self.machine_st - .heap - .push(self.machine_st.registers[2 + idx]); - } + writer.write_with(|section| { + section.push_cell(atom_as_cell!(name, narity + arity)); + + for idx in 1..narity + 1 { + section.push_cell(section[s + idx]); + } + + for idx in 1..arity + 1 { + section.push_cell(self.machine_st.registers[2 + idx]); + } + }); if narity + arity > 0 { str_loc_as_cell!(h) @@ -1773,9 +1793,7 @@ impl Machine { }; let target_qualified_goal = self.machine_st.registers[1]; - unify_fn!(&mut self.machine_st, target_goal, target_qualified_goal); - Ok(()) } @@ -1799,12 +1817,17 @@ impl Machine { module_name } _ => { - let h = self.machine_st.heap.len(); - let call_form = functor!(atom!(":"), [cell(module_name), cell(self.machine_st.registers[2])]); + let goal = self.machine_st.registers[2]; + let mut functor_writer = Heap::functor_writer( + functor!(atom!(":"), [cell(module_name), cell(goal)]), + ); - self.machine_st.heap.extend(call_form); + let goal = resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ); - let err = self.machine_st.type_error(ValidType::Callable, str_loc_as_cell!(h)); + let err = self.machine_st.type_error(ValidType::Callable, goal); let stub = functor_stub(atom!("call"), narity + 1); return Err(self.machine_st.error_form(err, stub)); @@ -1981,9 +2004,12 @@ impl Machine { for entry in entries { if let Ok(entry) = entry { if let Some(name) = entry.file_name().to_str() { - let name = AtomTable::build_with(&self.machine_st.atom_tbl, name); - files.push(atom_as_cstr_cell!(name)); + let file_string_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(name) + ); + files.push(file_string_cell); continue; } } @@ -1995,12 +2021,20 @@ impl Machine { return Err(err); } - let files_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - files.into_iter() - )); + let files_list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + files.len(), + files.into_iter() + ) + ); - unify!(self.machine_st, self.machine_st.registers[2], files_list); + unify!( + self.machine_st, + self.machine_st.registers[2], + files_list_cell + ); return Ok(()); } } @@ -2087,11 +2121,14 @@ impl Machine { unreachable!() } } { - let chars_atom = self.systemtime_to_timestamp(time); + let chars_string = self.systemtime_to_timestamp(time); - self.machine_st - .unify_complete_string(chars_atom, self.machine_st.registers[3]); + let cstr_cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&chars_string) + ); + unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]); return; } } @@ -2222,10 +2259,16 @@ impl Machine { } }; - let current_atom = AtomTable::build_with(&self.machine_st.atom_tbl, current); + let current_string = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(current) + ); - let a1 = self.deref_register(1); - self.machine_st.unify_complete_string(current_atom, a1); + unify!( + self.machine_st, + current_string, + self.machine_st.registers[1] + ); if self.machine_st.fail { return Ok(()); @@ -2262,11 +2305,14 @@ impl Machine { } }; - let canonical_atom = AtomTable::build_with(&self.machine_st.atom_tbl, cs); - - let a2 = self.deref_register(2); - self.machine_st.unify_complete_string(canonical_atom, a2); + let canonical_string = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(cs)); + unify!( + self.machine_st, + canonical_string, + self.machine_st.registers[2] + ); return Ok(()); } } @@ -2278,39 +2324,38 @@ impl Machine { #[inline(always)] pub(crate) fn atom_chars(&mut self) { let a1 = self.deref_register(1); - let a2 = self.deref_register(2); read_heap_cell!(a1, + /* (HeapCellValueTag::Char) => { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(a1); - self.machine_st.heap.push(empty_list_as_cell!()); + let mut writer = resource_error_call_result!( + self.machine_st, + self.machine_st.heap.reserve(2) + ); - unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) - .get_name_and_arity(); + step_or_resource_error!( + self.machine_st, + writer.write_with(|section| { + section.push_cell(a1); + section.push_cell(empty_list_as_cell!()); + Ok::<(), usize>(()) + }) + ); - if arity == 0 { - self.machine_st.unify_complete_string( - name, - a2, - ); - } else { - self.machine_st.fail = true; - } + unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h)); } + */ (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - self.machine_st.unify_complete_string( - name, - a2, - ); - } else { - self.machine_st.fail = true; - } + debug_assert_eq!(arity, 0); + + let cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&*name.as_str()) + ); + + unify!(self.machine_st, self.machine_st.registers[2], cell); } (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let a2 = self.deref_register(2); @@ -2336,7 +2381,7 @@ impl Machine { self.machine_st.fail = true; } _ => { - unreachable!(); + self.machine_st.fail = true; } ); } @@ -2346,6 +2391,7 @@ impl Machine { let a1 = self.deref_register(1); read_heap_cell!(a1, + /* (HeapCellValueTag::Char, c) => { let h = self.machine_st.heap.len(); @@ -2354,33 +2400,50 @@ impl Machine { unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]); } + */ (HeapCellValueTag::Atom, (name, arity)) => { - if arity == 0 { - let name = name.as_str(); - let iter = name.chars() - .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + debug_assert_eq!(arity, 0); - let h = iter_to_heap_list(&mut self.machine_st.heap, iter); - unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); - } else { - self.machine_st.fail = true; - } + let name = name.as_str(); + let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + (&*name).chars().count(), + iter, + ) + ); + + unify!(self.machine_st, list_cell, self.machine_st.registers[2]); } + /* (HeapCellValueTag::Str, s) => { + /* let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s]) .get_name_and_arity(); if arity == 0 { let name = name.as_str(); - let iter = name.chars() - .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); + let iter = name.chars().map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - let h = iter_to_heap_list(&mut self.machine_st.heap, iter); - unify!(self.machine_st, heap_loc_as_cell!(h), self.machine_st.registers[2]); + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + name.as_str().chars().count(), + iter, + ) + ); + + unify!(self.machine_st, list_cell, self.machine_st.registers[2]); } else { - self.machine_st.fail = true; - } + */ + self.machine_st.fail = true; + // } } + */ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { let stub_gen = || functor_stub(atom!("atom_codes"), 2); @@ -2428,9 +2491,11 @@ impl Machine { return; } } + /* (HeapCellValueTag::Char) => { 1 } + */ _ => { unreachable!() } @@ -2484,20 +2549,25 @@ impl Machine { return; } - let pstr_h = self.machine_st.heap.len(); + let pstr_h = self.machine_st.heap.cell_len(); + + let pstr_loc_cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_pstr(&*atom.as_str()) + ); - self.machine_st.heap.push(pstr_as_cell!(atom)); - self.machine_st.heap.push(heap_loc_as_cell!(pstr_h + 1)); + let tail_loc = Heap::neighboring_cell_offset(atom.as_str().len() + heap_index!(pstr_h)); - unify!( + step_or_resource_error!( self.machine_st, - self.machine_st.registers[2], - pstr_loc_as_cell!(pstr_h) + self.machine_st.heap.push_cell(heap_loc_as_cell!(tail_loc)) ); + unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_cell); + if !self.machine_st.fail { let tail = self.machine_st.registers[3]; - unify!(self.machine_st, tail, heap_loc_as_cell!(pstr_h + 1)); + unify!(self.machine_st, tail, heap_loc_as_cell!(tail_loc)); } } @@ -2505,17 +2575,21 @@ impl Machine { pub(crate) fn is_partial_string(&mut self) { let value = self.deref_register(1); - let h = self.machine_st.heap.len(); - self.machine_st.heap.push(value); - - let mut iter = HeapPStrIter::new(&self.machine_st.heap, h); + if value.is_constant() { + self.machine_st.fail = empty_list_as_cell!() != value; + } else { + self.machine_st.heap[0] = value; + let mut iter = HeapPStrIter::new(&self.machine_st.heap, 0); - for _ in iter.by_ref() {} + for _ in iter.by_ref() {} - let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator(); - self.machine_st.fail = !at_end_of_pstr; + let focus = iter.focus(); + let end_cell = self.machine_st.heap[focus]; + let at_end_of_pstr = + end_cell.is_var() || end_cell.is_string_terminator(&self.machine_st.heap); - self.machine_st.heap.pop(); + self.machine_st.fail = !at_end_of_pstr; + } } #[inline(always)] @@ -2525,26 +2599,8 @@ impl Machine { read_heap_cell!(pstr, (HeapCellValueTag::PStrLoc, h) => { - let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h); - - if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() { - self.machine_st.unify_atom( - atom!("[]"), - a2 - ); - } else { - unify_fn!( - self.machine_st, - heap_loc_as_cell!(h+1), - a2 - ); - } - } - (HeapCellValueTag::CStr) => { - self.machine_st.unify_atom( - atom!("[]"), - a2 - ); + let (_, tail_loc) = self.machine_st.heap.scan_slice_to_str(h); + unify_fn!(self.machine_st, heap_loc_as_cell!(tail_loc), a2); } (HeapCellValueTag::Lis, h) => { unify_fn!( @@ -2686,9 +2742,11 @@ impl Machine { } let a2 = read_heap_cell!(a2, + /* (HeapCellValueTag::Char) => { a2 } + */ (HeapCellValueTag::Atom, (name, arity)) => { if arity == 0 { if let Some(c) = name.as_char() { @@ -2868,8 +2926,12 @@ impl Machine { } }; - let chars_atom = AtomTable::build_with(&self.machine_st.atom_tbl, string.trim()); - self.machine_st.unify_complete_string(chars_atom, chs); + let cstr_cell = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(string.trim()) + ); + + unify!(self.machine_st, cstr_cell, chs); } #[inline(always)] @@ -2899,8 +2961,16 @@ impl Machine { .chars() .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64))); - let h = iter_to_heap_list(&mut self.machine_st.heap, codes); - unify!(self.machine_st, heap_loc_as_cell!(h), chs); + let list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + string.trim().chars().count(), + codes, + ) + ); + + unify!(self.machine_st, list_cell, chs); } #[inline(always)] @@ -2932,7 +3002,7 @@ impl Machine { #[inline(always)] pub(crate) fn lifted_heap_length(&mut self) { let a1 = self.machine_st.registers[1]; - let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64); + let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.cell_len() as i64); self.machine_st.unify_fixnum(lh_len, a1); } @@ -2954,9 +3024,11 @@ impl Machine { debug_assert_eq!(arity, 0); name.as_char().unwrap() } + /* (HeapCellValueTag::Char, c) => { c } + */ _ => { match Number::try_from(a2) { Ok(Number::Integer(n)) => { @@ -3004,9 +3076,11 @@ impl Machine { let a2 = self.deref_register(2); let c = read_heap_cell!(a1, + /* (HeapCellValueTag::Char, c) => { c } + */ (HeapCellValueTag::Atom, (name, _arity)) => { name.as_char().unwrap() } @@ -3092,14 +3166,19 @@ impl Machine { match (name, arity) { (atom!("upper"), 1) => { let reg = self.machine_st.deref(self.machine_st.heap[s+1]); - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_uppercase().to_string()); - let upper_str = string_as_cstr_cell!(atom); + let upper_str = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&c.to_uppercase().to_string()) + ); unify!(self.machine_st, reg, upper_str); } (atom!("lower"), 1) => { let reg = self.machine_st.deref(self.machine_st.heap[s+1]); - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_lowercase().to_string()); - let lower_str = string_as_cstr_cell!(atom); + let lower_str = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&c.to_uppercase().to_string()) + ); + unify!(self.machine_st, reg, lower_str); } _ => { @@ -3147,10 +3226,10 @@ impl Machine { unify_fn!(self.machine_st, addr, *value_loc); } None if !ball.stub.is_empty() => { - let h = self.machine_st.heap.len(); - let stub = ball.copy_and_align(h); - - self.machine_st.heap.extend(stub); + let h = step_or_resource_error!( + self.machine_st, + ball.copy_and_align_to(&mut self.machine_st.heap) + ); unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h)); @@ -3248,10 +3327,12 @@ impl Machine { return Ok(()); } } + /* (HeapCellValueTag::Char, c) => { write!(&mut stream, "{}", c).unwrap(); return Ok(()); } + */ _ => { } ); @@ -3506,9 +3587,11 @@ impl Machine { (HeapCellValueTag::Atom, (atom, _arity)) => { char_as_cell!(atom.as_char().unwrap()) } + /* (HeapCellValueTag::Char) => { addr } + */ _ => { let err = self.machine_st.type_error(ValidType::InCharacter, addr); return Err(self.machine_st.error_form(err, stub_gen())); @@ -3608,9 +3691,12 @@ impl Machine { } Some(Err(e)) => { let stub = functor_stub(atom!("$get_n_chars"), 3); - let err = self.machine_st.session_error(SessionError::from( - ParserError::IO(e, ParserErrorSrc::default()), - )); + let err = + self.machine_st + .session_error(SessionError::from(ParserError::IO( + e, + ParserErrorSrc::default(), + ))); return Err(self.machine_st.error_form(err, stub)); } @@ -3622,9 +3708,10 @@ impl Machine { }; let output = self.deref_register(3); - let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &string); + let cstr_cell = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&string)); - self.machine_st.unify_complete_string(atom, output); + unify!(self.machine_st, cstr_cell, output); Ok(()) } @@ -3897,18 +3984,19 @@ impl Machine { #[inline(always)] pub(crate) fn copy_to_lifted_heap(&mut self) { let lh_offset = cell_as_fixnum!(self.deref_register(1)).get_num() as usize; - let copy_target = self.machine_st.registers[2]; + let old_threshold = step_or_resource_error!( + self.machine_st, + self.machine_st + .copy_findall_solution(lh_offset, copy_target) + ); - let old_threshold = self - .machine_st - .copy_findall_solution(lh_offset, copy_target); - let new_threshold = self.machine_st.lifted_heap.len() - lh_offset; + let new_threshold = self.machine_st.lifted_heap.cell_len() - lh_offset; self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold); - for addr in self.machine_st.lifted_heap[old_threshold + 1..].iter_mut() { - *addr -= self.machine_st.heap.len() + lh_offset; + for addr in &mut self.machine_st.lifted_heap.splice_mut(old_threshold + 1..) { + *addr -= self.machine_st.heap.cell_len() + lh_offset; } } @@ -3993,7 +4081,7 @@ impl Machine { } }; - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); let mut num_functors = 0; let code_dir = if module_name == atom!("user") { @@ -4013,51 +4101,47 @@ impl Machine { } }; - for (name, arity) in code_dir.keys() { - if self.indices.builtin_property((*name, *arity)) { + for (name, arity) in code_dir.keys().cloned() { + if self.indices.builtin_property((name, arity)) { continue; } - if name_match(pred_atom, *name) && arity_match(pred_arity, *arity) { - self.machine_st.heap.extend(functor!( - atom!("/"), - [cell(atom_as_cell!(name)), fixnum(*arity)] - )); + if name_match(pred_atom, name) && arity_match(pred_arity, arity) { + let functor = functor!(atom!("/"), [atom_as_cell(name), fixnum(arity)]); // self.machine_st.heap.extend( + + let mut functor_writer = Heap::functor_writer(functor); + + step_or_resource_error!(self.machine_st, functor_writer(&mut self.machine_st.heap)); num_functors += 1; } } - if num_functors > 0 { - let h = iter_to_heap_list( + let functor_list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( &mut self.machine_st.heap, - (0..num_functors).map(|i| str_loc_as_cell!(h + 3 * i)), - ); + num_functors, + (0..num_functors).map(|i| str_loc_as_cell!(h + 3 * i)) + ) + ); - unify!( - self.machine_st, - heap_loc_as_cell!(h), - self.machine_st.registers[4] - ); - } else { - unify!( - self.machine_st, - empty_list_as_cell!(), - self.machine_st.registers[4] - ); - } + unify!( + self.machine_st, + functor_list_cell, + self.machine_st.registers[4] + ); } #[inline(always)] pub(crate) fn get_next_op_db_ref(&mut self) { let prec = self.deref_register(1); - - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); fn write_op_functors_to_heap( heap: &mut Heap, op_descs: impl Iterator, - ) -> usize { + ) -> Result { let mut num_functors = 0; for (name, op_desc) in op_descs { @@ -4070,19 +4154,21 @@ impl Machine { let spec_atom = op_desc.get_spec().get_spec(); - heap.extend(functor!( + let functor = functor!( atom!("op"), - [ - fixnum(prec), - cell(atom_as_cell!(spec_atom)), - cell(atom_as_cell!(name)) - ] - )); + [fixnum(prec), atom_as_cell(spec_atom), atom_as_cell(name)] + ); + + let mut functor_writer = Heap::functor_writer(functor); + + if let Err(e) = functor_writer(heap) { + return Err(e); + } num_functors += 1; } - num_functors + Ok(num_functors) } if prec.is_var() { @@ -4103,9 +4189,11 @@ impl Machine { (HeapCellValueTag::Str, s) => { cell_as_atom!(self.machine_st.heap[s]) } + /* (HeapCellValueTag::Char, c) => { AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_string()) } + */ _ => { unreachable!() } @@ -4128,17 +4216,23 @@ impl Machine { if number_of_keys == 0 { self.machine_st.fail = true; } else { - let num_functors = - write_op_functors_to_heap(&mut self.machine_st.heap, op_descs); + let num_functors = step_or_resource_error!( + self.machine_st, + write_op_functors_to_heap(&mut self.machine_st.heap, op_descs,) + ); - let h = iter_to_heap_list( - &mut self.machine_st.heap, - (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), + let functor_list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + num_functors, + (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)) + ) ); unify!( self.machine_st, - heap_loc_as_cell!(h), + functor_list_cell, self.machine_st.registers[4] ); } @@ -4163,23 +4257,26 @@ impl Machine { Some((key.0, *op_desc)) }); - write_op_functors_to_heap(&mut self.machine_st.heap, op_descs) + step_or_resource_error!( + self.machine_st, + write_op_functors_to_heap(&mut self.machine_st.heap, op_descs,) + ) }; - if num_functors > 0 { - let h = iter_to_heap_list( + let functor_list_cell = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( &mut self.machine_st.heap, + num_functors, (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), - ); + ) + ); - unify!( - self.machine_st, - heap_loc_as_cell!(h), - self.machine_st.registers[4] - ); - } else { - self.machine_st.fail = true; - } + unify!( + self.machine_st, + functor_list_cell, + self.machine_st.registers[4] + ); } else { let spec = cell_as_atom!(self.deref_register(2)); let op_atom = cell_as_atom!(self.deref_register(3)); @@ -4196,21 +4293,24 @@ impl Machine { match self.indices.op_dir.get(&(op_atom, fixity)).cloned() { Some(op_desc) => { - let num_functors = write_op_functors_to_heap( - &mut self.machine_st.heap, - std::iter::once((op_atom, op_desc)), - ); - - let h = iter_to_heap_list( - &mut self.machine_st.heap, - (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), + let num_functors = step_or_resource_error!( + self.machine_st, + write_op_functors_to_heap( + &mut self.machine_st.heap, + std::iter::once((op_atom, op_desc)) + ) ); - unify!( + let functor_list = step_or_resource_error!( self.machine_st, - heap_loc_as_cell!(h), - self.machine_st.registers[4] + sized_iter_to_heap_list( + &mut self.machine_st.heap, + num_functors, + (0..num_functors).map(|i| str_loc_as_cell!(h + 4 * i)), + ) ); + + unify!(self.machine_st, functor_list, self.machine_st.registers[4]); } _ => { self.machine_st.fail = true; @@ -4325,17 +4425,18 @@ impl Machine { } }; - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - iter_to_heap_list( - &mut self.machine_st.heap, - (0..n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)), + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + n, + (0..n).map(|i| heap_loc_as_cell!(h + 2 * i + 1)), + ) ); - let tail = self.deref_register(1); - self.machine_st - .bind(tail.as_var().unwrap(), heap_loc_as_cell!(h)); - + unify!(self.machine_st, self.deref_register(1), list_cell); Ok(()) } @@ -4412,34 +4513,45 @@ impl Machine { self.machine_st .unify_fixnum(Fixnum::build_with(status as i64), address_status); // headers - let headers: Vec = resp - .headers() - .iter() - .map(|(header_name, header_value)| { - let h = self.machine_st.heap.len(); - - let header_term = functor!( - AtomTable::build_with( - &self.machine_st.atom_tbl, - header_name.as_str() - ), - [cell(string_as_cstr_cell!(AtomTable::build_with( - &self.machine_st.atom_tbl, - header_value.to_str().unwrap() - )))] - ); - - self.machine_st.heap.extend(header_term); - str_loc_as_cell!(h) - }) - .collect(); + let mut headers: Vec = vec![]; - let headers_list = - iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter()); + for (header_name, header_value) in resp.headers().iter() { + let string_cell = resource_error_call_result!( + self.machine_st, + self.machine_st + .allocate_cstr(header_value.to_str().unwrap()) + ); + + let header_term = functor!( + AtomTable::build_with( + &self.machine_st.atom_tbl, + header_name.as_str() + ), + [cell(string_cell)] + ); + + let mut functor_writer = Heap::functor_writer(header_term); + + let functor_cell = resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ); + + headers.push(functor_cell); + } + + let headers_list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + headers.len(), + headers.into_iter(), + ) + ); unify!( self.machine_st, - heap_loc_as_cell!(headers_list), + headers_list_cell, self.machine_st.registers[6] ); @@ -4467,7 +4579,9 @@ impl Machine { self.machine_st.fail = true; } } - }); + + Ok(()) + })?; } else { let err = self .machine_st @@ -4639,92 +4753,122 @@ impl Machine { (ArenaHeaderTag::HttpListener, http_listener) => { loop { match http_listener.incoming.recv_timeout(std::time::Duration::from_millis(200)) { - Ok(request) => { - let method_atom = match request.request_data.method { - Method::GET => atom!("get"), - Method::POST => atom!("post"), - Method::PUT => atom!("put"), - Method::DELETE => atom!("delete"), - Method::PATCH => atom!("patch"), - Method::HEAD => atom!("head"), - Method::OPTIONS => atom!("options"), - Method::TRACE => atom!("trace"), - Method::CONNECT => atom!("connect"), - _ => atom!("unsupported_extension"), - }; - let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); - let path_cell = atom_as_cstr_cell!(path_atom); - let headers: Vec = request.request_data.headers.iter().map(|(header_name, header_value)| { - let h = self.machine_st.heap.len(); - let header_term = functor!(AtomTable::build_with(&self.machine_st.atom_tbl, header_name.as_str()), [cell(string_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, header_value.to_str().unwrap())))]); + Ok(request) => { + let method_atom = match request.request_data.method { + Method::GET => atom!("get"), + Method::POST => atom!("post"), + Method::PUT => atom!("put"), + Method::DELETE => atom!("delete"), + Method::PATCH => atom!("patch"), + Method::HEAD => atom!("head"), + Method::OPTIONS => atom!("options"), + Method::TRACE => atom!("trace"), + Method::CONNECT => atom!("connect"), + _ => atom!("unsupported_extension"), + }; - self.machine_st.heap.extend(header_term.into_iter()); - str_loc_as_cell!(h) - }).collect(); + let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); + let path_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(&request.request_data.path) + ); - let headers_list = iter_to_heap_list(&mut self.machine_st.heap, headers.into_iter()); + let mut headers = vec![]; - let query_str = request.request_data.query; - let query_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &query_str); - let query_cell = string_as_cstr_cell!(query_atom); + for (header_name, header_value) in request.request_data.headers { + let header_value = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(header_value.to_str().unwrap()) + ); - let mut stream = Stream::from_http_stream( - path_atom, - request.request_data.body, - &mut self.machine_st.arena - ); - *stream.options_mut() = StreamOptions::default(); - stream.options_mut().set_stream_type(StreamType::Binary); + let header_term = functor!( + AtomTable::build_with(&self.machine_st.atom_tbl, header_name.unwrap().as_str()), + [cell(header_value)] + ); - self.indices.add_stream(stream, atom!("http_accept"), 7) - .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + let mut functor_writer = Heap::functor_writer(header_term); - let stream = stream_as_cell!(stream); + let functor_cell = resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ); - let handle: TypedArenaPtr = arena_alloc!(request.response, &mut self.machine_st.arena); + headers.push(functor_cell); + } + + let headers_list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + headers.len(), + headers.into_iter(), + ) + ); + + let query_str = request.request_data.query; + let query_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(&query_str) + ); + + let mut stream = Stream::from_http_stream( + path_atom, + request.request_data.body, + &mut self.machine_st.arena + ); + *stream.options_mut() = StreamOptions::default(); + stream.options_mut().set_stream_type(StreamType::Binary); + + self.indices.add_stream(stream, atom!("http_accept"), 7) + .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; + + let stream = stream_as_cell!(stream); + + let handle = arena_alloc!(request.response, &mut self.machine_st.arena) + as TypedArenaPtr; + + self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom)); + self.machine_st.bind(path.as_var().unwrap(), path_cell); + unify!(self.machine_st, headers_list_cell, self.machine_st.registers[4]); + self.machine_st.bind(query.as_var().unwrap(), query_cell); + self.machine_st.bind(stream_addr.as_var().unwrap(), stream); + self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle)); - self.machine_st.bind(method.as_var().unwrap(), atom_as_cell!(method_atom)); - self.machine_st.bind(path.as_var().unwrap(), path_cell); - unify!(self.machine_st, heap_loc_as_cell!(headers_list), self.machine_st.registers[4]); - self.machine_st.bind(query.as_var().unwrap(), query_cell); - self.machine_st.bind(stream_addr.as_var().unwrap(), stream); - self.machine_st.bind(handle_addr.as_var().unwrap(), typed_arena_ptr_as_cell!(handle)); - break - } - Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { - let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); - - match machine::INTERRUPT.compare_exchange( - interrupted, - false, - std::sync::atomic::Ordering::Relaxed, - std::sync::atomic::Ordering::Relaxed, - ) { - Ok(interruption) => { - if interruption { - self.machine_st.throw_interrupt_exception(); - self.machine_st.backtrack(); - // We have extracted controll over the Tokio runtime to the calling context for enabling library use case - // (see https://github.com/mthom/scryer-prolog/pull/1880) - // So we only have access to a runtime handle in here and can't shut it down. - // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 - // was not merged, I'm only deactivating it for now. - //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); - //old_runtime.shutdown_background(); break } + Err(std::sync::mpsc::RecvTimeoutError::Timeout) => { + let interrupted = machine::INTERRUPT.load(std::sync::atomic::Ordering::Relaxed); + + match machine::INTERRUPT.compare_exchange( + interrupted, + false, + std::sync::atomic::Ordering::Relaxed, + std::sync::atomic::Ordering::Relaxed, + ) { + Ok(interruption) => { + if interruption { + self.machine_st.throw_interrupt_exception(); + self.machine_st.backtrack(); + // We have extracted controll over the Tokio runtime to the calling context for enabling library use case + // (see https://github.com/mthom/scryer-prolog/pull/1880) + // So we only have access to a runtime handle in here and can't shut it down. + // Since I'm not aware of the consequences of deactivating this new code which came in while PR 1880 + // was not merged, I'm only deactivating it for now. + //let old_runtime = std::mem::replace(&mut self.runtime, tokio::runtime::Runtime::new().unwrap()); + //old_runtime.shutdown_background(); + break + } + } + Err(_) => unreachable!(), + } } - Err(_) => unreachable!(), - } - - } Err(_) => { - self.machine_st.fail = true; - } - } - } + self.machine_st.fail = true; + } } - _ => { + } + } + _ => { unreachable!(); } ); @@ -4924,15 +5068,20 @@ impl Machine { self.machine_st.unify_f64(n, return_value) } Value::Struct(name, args) => { - let struct_value = self.build_struct(&name, args); + let struct_value = resource_error_call_result!( + self.machine_st, + self.build_struct(&name, args) + ); + unify!(self.machine_st, return_value, struct_value); } Value::CString(cstr) => { - let cstr = AtomTable::build_with( - &self.machine_st.atom_tbl, - cstr.to_str().unwrap(), + let str_cell = resource_error_call_result!( + self.machine_st, + self.machine_st.allocate_cstr(cstr.to_str().unwrap()) ); - self.machine_st.unify_complete_string(cstr, return_value); + + unify!(self.machine_st, str_cell, return_value); } } return Ok(()); @@ -4948,30 +5097,34 @@ impl Machine { Err(e) => return Err(e), } } + self.machine_st.fail = true; Ok(()) } #[cfg(feature = "ffi")] - fn build_struct(&mut self, name: &str, mut args: Vec) -> HeapCellValue { + fn build_struct(&mut self, name: &str, mut args: Vec) -> Result { args.insert(0, Value::CString(CString::new(name).unwrap())); - let cells: Vec<_> = args - .into_iter() - .map(|val| match val { + + let mut expanded_args = Vec::with_capacity(args.len()); + + for val in args { + expanded_args.push(match val { Value::Int(n) => fixnum_as_cell!(Fixnum::build_with(n)), Value::Float(n) => HeapCellValue::from(float_alloc!(n, self.machine_st.arena)), Value::CString(cstr) => atom_as_cell!(AtomTable::build_with( &self.machine_st.atom_tbl, &cstr.into_string().unwrap() )), - Value::Struct(name, struct_args) => self.build_struct(&name, struct_args), - }) - .collect(); + Value::Struct(name, struct_args) => self.build_struct(&name, struct_args)?, + }); + } - heap_loc_as_cell!(iter_to_heap_list( + sized_iter_to_heap_list( &mut self.machine_st.heap, - cells.into_iter() - )) + expanded_args.len(), + expanded_args.into_iter(), + ) } #[cfg(feature = "ffi")] @@ -5066,29 +5219,35 @@ impl Machine { #[inline(always)] pub(crate) fn argv(&mut self) -> CallResult { let args = self.deref_register(1); - let mut args_pstrs = vec![]; + for arg in env::args() { - args_pstrs.push(put_complete_string( - &mut self.machine_st.heap, - &arg, - &self.machine_st.atom_tbl, - )); + let pstr_cell = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&arg)); + + args_pstrs.push(pstr_cell); } - let cell = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - args_pstrs.into_iter() - )); - unify!(self.machine_st, args, cell); + let list_cell = resource_error_call_result!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + args_pstrs.len(), + args_pstrs.into_iter(), + ) + ); + + unify!(self.machine_st, args, list_cell); Ok(()) } #[inline(always)] pub(crate) fn current_time(&mut self) { let timestamp = self.systemtime_to_timestamp(SystemTime::now()); - self.machine_st - .unify_complete_string(timestamp, self.machine_st.registers[1]); + let cstr_cell = + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(×tamp)); + + unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } #[inline(always)] @@ -5148,9 +5307,11 @@ impl Machine { }; let op = read_heap_cell!(self.deref_register(3), + /* (HeapCellValueTag::Char, c) => { AtomTable::build_with(&self.machine_st.atom_tbl, &c.to_string()) } + */ (HeapCellValueTag::Atom, (name, _arity)) => { name } @@ -5311,10 +5472,16 @@ impl Machine { }; if let Some(b) = b { - let iter = self.machine_st.gather_attr_vars_created_since(b); + let attr_vars = self.machine_st.gather_attr_vars_created_since(b); - let var_list_addr = - heap_loc_as_cell!(iter_to_heap_list(&mut self.machine_st.heap, iter)); + let var_list_addr = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + attr_vars.len(), + attr_vars.into_iter(), + ) + ); let list_addr = self.machine_st.registers[2]; unify!(self.machine_st, var_list_addr, list_addr); @@ -5372,7 +5539,10 @@ impl Machine { pub(crate) fn put_to_attributed_variable_list(&mut self) { let attr_var = self.deref_register(1); let attr = self.deref_register(3); - let attr_var_list = match self.machine_st.get_attr_var_list(attr_var) { + let attr_var_list_result = + step_or_resource_error!(self.machine_st, self.machine_st.get_attr_var_list(attr_var)); + + let attr_var_list = match attr_var_list_result { Some(h) => h, None => { self.machine_st.fail = true; @@ -5399,12 +5569,16 @@ impl Machine { * or str cells (> 0-arity). */ - let h = self.machine_st.heap.len(); + let module_functor = functor!(atom!(":"), [cell(module), cell(attr)]); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(str_loc_as_cell!(h + 1)); - self.machine_st - .heap - .extend(functor!(atom!(":"), [cell(module), cell(attr)])); + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(str_loc_as_cell!(h + 1)) + ); + + let mut functor_writer = Heap::functor_writer(module_functor); + step_or_resource_error!(self.machine_st, functor_writer(&mut self.machine_st.heap)); match self.match_attribute(self.machine_st.heap[attr_var_list], module, attr) { Some(AttrListMatch { match_site, .. }) => { @@ -5414,8 +5588,16 @@ impl Machine { // at the end of the (non-empty) list here. self.machine_st.heap[match_site] = list_loc_as_cell!(h + 4); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st.heap.push(heap_loc_as_cell!(h + 5)); + + let mut writer = step_or_resource_error!( + self.machine_st, + self.machine_st.heap.reserve(2) + ); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h + 5)); + }); (match_site, l) } @@ -5433,8 +5615,14 @@ impl Machine { None => { // the list is empty. self.machine_st.heap[attr_var_list] = list_loc_as_cell!(h + 4); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st.heap.push(heap_loc_as_cell!(h + 5)); + + let mut writer = + step_or_resource_error!(self.machine_st, self.machine_st.heap.reserve(2)); + + writer.write_with(|section| { + section.push_cell(heap_loc_as_cell!(h)); + section.push_cell(heap_loc_as_cell!(h + 5)); + }); self.machine_st .attr_var_init @@ -5532,10 +5720,54 @@ impl Machine { pub(crate) fn get_continuation_chunk(&mut self) { let e = self.deref_register(1); let e = cell_as_fixnum!(e).get_num() as usize; + let h = self.machine_st.heap.cell_len(); - let p_functor = self.deref_register(2); - + let p_functor_cell = self.deref_register(2); let num_cells = self.machine_st.stack.index_and_frame(e).prelude.num_cells; + + let mut writer = + step_or_resource_error!(self.machine_st, self.machine_st.heap.reserve(2 + num_cells)); + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); + section.push_cell(p_functor_cell); + + for idx in 1..=num_cells { + let mut stack_offset = stack_loc!(AndFrame, e, idx); + let mut addr = self.machine_st.stack[stack_offset]; + + while addr.get_tag() == HeapCellValueTag::StackVar { + stack_offset = addr.get_value() as usize; + + if self.machine_st.stack[stack_offset] == addr { + break; + } + + addr = self.machine_st.stack[stack_offset]; + } + + if addr.get_tag() == HeapCellValueTag::StackVar { + section.push_cell(heap_loc_as_cell!(h + 1 + idx)); + + self.machine_st.stack[stack_offset] = heap_loc_as_cell!(h + 1 + idx); + + // have to inline the TrailRef::Ref(RefTag::StackCell) case of MachineState::trail + // here to get around the borrow checker. + if stack_offset < self.machine_st.b { + self.machine_st.trail.push(TrailEntry::build_with( + TrailEntryTag::TrailedStackVar, + stack_offset as u64, + )); + + self.machine_st.tr += 1; + } + } else { + section.push_cell(addr); + } + } + }); + + /* let mut addrs = vec![]; for idx in 1..num_cells + 1 { @@ -5545,7 +5777,7 @@ impl Machine { // avoid pushing stack variables to the heap where they // must not go. if addr.is_stack_var() { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); self.machine_st.heap.push(heap_loc_as_cell!(h)); self.machine_st.bind(Ref::heap_cell(h), addr); @@ -5555,14 +5787,17 @@ impl Machine { addrs.push(addr); } } + */ - let chunk = str_loc_as_cell!(self.machine_st.heap.len()); + let chunk = str_loc_as_cell!(self.machine_st.heap.cell_len()); + /* self.machine_st .heap .push(atom_as_cell!(atom!("cont_chunk"), 1 + num_cells)); - self.machine_st.heap.push(p_functor); + self.machine_st.heap.push(p_functor_cell); self.machine_st.heap.extend(addrs); + */ unify!(self.machine_st, self.machine_st.registers[3], chunk); } @@ -5573,25 +5808,32 @@ impl Machine { let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) .get_num() as usize; - if lh_offset >= self.machine_st.lifted_heap.len() { + if lh_offset >= self.machine_st.lifted_heap.cell_len() { let solutions = self.machine_st.registers[2]; let diff = self.machine_st.registers[3]; unify_fn!(self.machine_st, solutions, diff); } else { - let h = self.machine_st.heap.len(); - let mut last_index = h; + let h = self.machine_st.heap.cell_len(); - for value in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { - last_index = self.machine_st.heap.len(); - self.machine_st.heap.push(value + h); - } + step_or_resource_error!( + self.machine_st, + self.machine_st + .heap + .append(self.machine_st.lifted_heap.splice(lh_offset..),) + ); - if last_index < self.machine_st.heap.len() { - let diff = self.machine_st.registers[3]; - unify_fn!(self.machine_st, diff, self.machine_st.heap[last_index]); + for cell in &mut self.machine_st.heap.splice_mut(h..) { + *cell = *cell + h; } + let diff = self.machine_st.registers[3]; + unify_fn!( + self.machine_st, + diff, + self.machine_st.heap.last_cell().unwrap() + ); + self.machine_st.lifted_heap.truncate(lh_offset); let solutions = self.machine_st.registers[2]; @@ -5605,14 +5847,21 @@ impl Machine { let lh_offset = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(lh_offset))) .get_num() as usize; - if lh_offset >= self.machine_st.lifted_heap.len() { + if lh_offset >= self.machine_st.lifted_heap.cell_len() { let solutions = self.machine_st.registers[2]; unify_fn!(self.machine_st, solutions, empty_list_as_cell!()); } else { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); + + step_or_resource_error!( + self.machine_st, + self.machine_st + .heap + .append(self.machine_st.lifted_heap.splice(lh_offset..),) + ); - for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() { - self.machine_st.heap.push(addr + h); + for cell in &mut self.machine_st.heap.splice_mut(h..) { + *cell = *cell + h; } self.machine_st.lifted_heap.truncate(lh_offset); @@ -5691,8 +5940,7 @@ impl Machine { // n has already been confirmed as an integer, and // internally, Rational is assumed reduced, so its // denominator must be 1. - let r = r.numerator().try_into().unwrap(); - r + r.numerator().try_into().unwrap() } _ => { unreachable!() @@ -5709,7 +5957,6 @@ impl Machine { let prev_block = self.machine_st.scc_block; self.machine_st.run_cleaners_fn = Machine::run_cleaners; - self.machine_st.scc_block = b; self.machine_st.cont_pts.push((addr, b, prev_block)); } @@ -5725,7 +5972,6 @@ impl Machine { Ok(Number::Integer(n)) => (*n).clone(), _ => { let stub = functor_stub(atom!("call_with_inference_limit"), 3); - let err = self.machine_st.type_error(ValidType::Integer, a2); return Err(self.machine_st.error_form(err, stub)); } @@ -5789,7 +6035,6 @@ impl Machine { #[inline(always)] pub(crate) fn no_such_predicate(&mut self) -> CallResult { let module_name = cell_as_atom!(self.deref_register(1)); - let head = self.deref_register(2); self.machine_st.fail = read_heap_cell!(head, @@ -6070,15 +6315,17 @@ impl Machine { #[inline(always)] pub(crate) fn get_ball(&mut self) { let addr = self.deref_register(1); - let h = self.machine_st.heap.len(); - - if !self.machine_st.ball.stub.is_empty() { - let stub = self.machine_st.ball.copy_and_align(h); - self.machine_st.heap.extend(stub); + let h = if !self.machine_st.ball.stub.is_empty() { + step_or_resource_error!( + self.machine_st, + self.machine_st + .ball + .copy_and_align_to(&mut self.machine_st.heap) + ) } else { self.machine_st.fail = true; return; - } + }; match addr.as_var() { Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]), @@ -6158,15 +6405,14 @@ impl Machine { let e = and_frame.prelude.e; let e = Fixnum::build_with(i64::try_from(e).unwrap()); - let p = str_loc_as_cell!(machine_st.heap.len()); + let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); + + let p_functor_cell = step_or_resource_error!(machine_st, writer(&mut machine_st.heap)); - machine_st - .heap - .extend(functor!(atom!("dir_entry"), [fixnum(cp)])); machine_st.unify_fixnum(e, machine_st.registers[2]); if !machine_st.fail { - unify!(machine_st, p, machine_st.registers[3]); + unify!(machine_st, p_functor_cell, machine_st.registers[3]); } }; @@ -6193,15 +6439,18 @@ impl Machine { // it later. let and_frame = self.machine_st.stack.index_and_frame(e); let cp = and_frame.prelude.cp - 1; + let mut writer = Heap::functor_writer(functor!(atom!("dir_entry"), [fixnum(cp)])); - let p = str_loc_as_cell!(self.machine_st.heap.len()); - self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)])); + let p_functor_cell = step_or_resource_error!( + self.machine_st, + writer(&mut self.machine_st.heap) + ); let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap()); self.machine_st.unify_fixnum(e, self.machine_st.registers[2]); if !self.machine_st.fail { - unify!(self.machine_st, p, self.machine_st.registers[3]); + unify!(self.machine_st, p_functor_cell, self.machine_st.registers[3]); } } _ => { @@ -6241,9 +6490,11 @@ impl Machine { None => true, }; } + /* (HeapCellValueTag::Char, c) => { self.machine_st.fail = non_quoted_token(once(c)); } + */ (HeapCellValueTag::Atom, (name, arity)) => { debug_assert_eq!(arity, 0); self.machine_st.fail = non_quoted_token(name.as_str().chars()); @@ -6311,14 +6562,14 @@ impl Machine { fn read_term_from_atom( &mut self, atom_or_string: AtomOrString, - ) -> Result, MachineStub> { + ) -> Result, MachineStub> { let string = match atom_or_string { AtomOrString::Atom(atom!("[]")) => "".to_owned(), _ => atom_or_string.into(), }; let chars = CharReader::new(ByteStream::from_string(string)); - let mut parser = Parser::new(chars, &mut self.machine_st); + let mut parser = LexerParser::new(chars, &mut self.machine_st); let op_dir = CompositeOpDir::new(&self.indices.op_dir, None); let term = parser @@ -6349,14 +6600,8 @@ impl Machine { .value_to_str_like(self.machine_st.registers[1]) .unwrap(); - if let Some(mut term) = self.read_term_from_atom(atom_or_string)? { - let heap_len = self.machine_st.heap.len(); - - self.machine_st.heap.extend( - copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64), - ); - - let result = heap_loc_as_cell!(heap_len + term.focus); + if let Some(term) = self.read_term_from_atom(atom_or_string)? { + let result = self.machine_st.heap[term.focus]; let var = self.deref_register(2).as_var().unwrap(); self.machine_st.bind(var, result); @@ -6378,8 +6623,10 @@ impl Machine { }; let chars = CharReader::new(ByteStream::from_string(string)); - let term_write_result = self.machine_st.read(chars, &self.indices.op_dir) - .map(|(term, _)| term.to_machine_heap(&mut self.machine_st)) + let term = self + .machine_st + .read(chars, &self.indices.op_dir) + .map(|(term, _)| term) .map_err(|e| { let e = self.machine_st.session_error(SessionError::from(e)); let stub = functor_stub(atom!("read_term_from_chars"), 3); @@ -6387,7 +6634,7 @@ impl Machine { self.machine_st.error_form(e, stub) })?; - self.machine_st.read_term_body(term_write_result) + self.machine_st.read_term_body(term) } #[inline(always)] @@ -6420,12 +6667,15 @@ impl Machine { #[inline(always)] pub(crate) fn reset_continuation_marker(&mut self) { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); self.machine_st.registers[3] = atom_as_cell!(atom!("none")); self.machine_st.registers[4] = heap_loc_as_cell!(h); - self.machine_st.heap.push(heap_loc_as_cell!(h)); + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(heap_loc_as_cell!(h)) + ); } #[inline(always)] @@ -6766,7 +7016,7 @@ impl Machine { .add_stream(stream, atom!("tls_client_negotiate"), 3) .map_err(|stub_gen| stub_gen(&mut self.machine_st))?; - self.machine_st.heap.push(stream_as_cell!(stream)); + // self.machine_st.heap.push(stream_as_cell!(stream)); let stream_addr = self.deref_register(3); self.machine_st .bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream)); @@ -6942,18 +7192,20 @@ impl Machine { } atom!("position") => { if let Some((position, lines_read)) = stream.position() { - let h = self.machine_st.heap.len(); - let position_term = functor!( atom!("position_and_lines_read"), [ - integer(position, &mut self.machine_st.arena), - integer(lines_read, &mut self.machine_st.arena) + number(position, (&mut self.machine_st.arena)), + number(lines_read, (&mut self.machine_st.arena)) ] ); - self.machine_st.heap.extend(position_term); - str_loc_as_cell!(h) + let mut functor_writer = Heap::functor_writer(position_term); + + resource_error_call_result!( + self.machine_st, + functor_writer(&mut self.machine_st.heap) + ) } else { self.machine_st.fail = true; return Ok(()); @@ -6990,17 +7242,20 @@ impl Machine { let value = self.machine_st.registers[2]; let mut ball = Ball::new(); - ball.boundary = self.machine_st.heap.len(); + ball.boundary = self.machine_st.heap.cell_len(); - copy_term( - CopyBallTerm::new( - &mut self.machine_st.attr_var_init.attr_var_queue, - &mut self.machine_st.stack, - &mut self.machine_st.heap, - &mut ball.stub, - ), - value, - AttrVarPolicy::DeepCopy, + step_or_resource_error!( + self.machine_st, + copy_term( + CopyBallTerm::new( + &mut self.machine_st.attr_var_init.attr_var_queue, + &mut self.machine_st.stack, + &mut self.machine_st.heap, + &mut ball.stub, + ), + value, + AttrVarPolicy::DeepCopy, + ) ); self.indices.global_variables.insert(key, (ball, None)); @@ -7044,10 +7299,15 @@ impl Machine { let seen_vars = self .machine_st .attr_vars_of_term(self.machine_st.registers[1]); - let outcome = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - seen_vars.into_iter() - )); + + let outcome = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + seen_vars.len(), + seen_vars.into_iter(), + ) + ); unify_fn!(self.machine_st, self.machine_st.registers[2], outcome); } @@ -7063,24 +7323,30 @@ impl Machine { } let stored_v = if stored_v.is_stack_var() { - let h = self.machine_st.heap.len(); + let h = self.machine_st.heap.cell_len(); - self.machine_st.heap.push(heap_loc_as_cell!(h)); - self.machine_st.bind(Ref::heap_cell(h), stored_v); + step_or_resource_error!( + self.machine_st, + self.machine_st.heap.push_cell(heap_loc_as_cell!(h)) + ); + self.machine_st.bind(Ref::heap_cell(h), stored_v); heap_loc_as_cell!(h) } else { stored_v }; let mut seen_set = IndexSet::with_hasher(FxBuildHasher::default()); - self.machine_st.variable_set(&mut seen_set, stored_v); - let outcome = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - seen_set.into_iter() - )); + let outcome = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + seen_set.len(), + seen_set.into_iter(), + ) + ); unify_fn!(self.machine_st, a2, outcome); } @@ -7135,18 +7401,18 @@ impl Machine { false } - fn walk_code_at_ptr(&mut self, index_ptr: usize) -> HeapCellValue { - let mut h = self.machine_st.heap.len(); + fn walk_code_at_ptr(&mut self, index_ptr: usize) -> Result { + let orig_h = self.machine_st.heap.cell_len(); + let mut h = orig_h; let mut functors = vec![]; let mut functor_list = vec![]; walk_code(&self.code, index_ptr, |instr| { let old_len = functors.len(); - instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors); + instr.enqueue_functors(&mut self.machine_st.arena, &mut functors); let new_len = functors.len(); - #[allow(clippy::needless_range_loop)] for index in old_len..new_len { let functor_len = functors[index].len(); @@ -7154,24 +7420,30 @@ impl Machine { 0 => {} 1 => { functor_list.push(heap_loc_as_cell!(h)); - h += functor_len; + h += cell_index!(Heap::compute_functor_byte_size(&functors[index])); } _ => { functor_list.push(str_loc_as_cell!(h)); - h += functor_len; + h += cell_index!(Heap::compute_functor_byte_size(&functors[index])); } - } + }; } }); - for functor in functors { - self.machine_st.heap.extend(functor.into_iter()); - } + let mut writer = self.machine_st.heap.reserve(h - orig_h)?; + + writer.write_with(|section| { + for functor in functors { + let mut functor_writer = ReservedHeapSection::functor_writer(functor); + functor_writer(section); + } + }); - heap_loc_as_cell!(iter_to_heap_list( + sized_iter_to_heap_list( &mut self.machine_st.heap, - functor_list.into_iter() - )) + functor_list.len(), + functor_list.into_iter(), + ) } #[inline(always)] @@ -7226,7 +7498,9 @@ impl Machine { } }; - let listing = self.walk_code_at_ptr(first_idx); + let listing = + resource_error_call_result!(self.machine_st, self.walk_code_at_ptr(first_idx)); + let listing_var = self.machine_st.registers[4]; unify!(self.machine_st, listing, listing_var); @@ -7247,7 +7521,8 @@ impl Machine { } }; - let listing = self.walk_code_at_ptr(index_ptr); + let listing = step_or_resource_error!(self.machine_st, self.walk_code_at_ptr(index_ptr)); + let listing_var = self.machine_st.registers[2]; unify!(self.machine_st, listing, listing_var); @@ -7335,19 +7610,13 @@ impl Machine { }; let result = printer.print().result(); - let chars = put_complete_string( - &mut self.machine_st.heap, - &result, - &self.machine_st.atom_tbl, - ); + let chars = + resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result)); let result_addr = self.deref_register(1); + let var = result_addr.as_var().unwrap(); - if let Some(var) = result_addr.as_var() { - self.machine_st.bind(var, chars); - } else { - unreachable!() - } + self.machine_st.bind(var, chars); Ok(()) } @@ -7357,10 +7626,10 @@ impl Machine { use git_version::git_version; let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); - let buffer_atom = AtomTable::build_with(&self.machine_st.atom_tbl, buffer); + let cstr_cell = + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)); - let a1 = self.deref_register(1); - self.machine_st.unify_complete_string(buffer_atom, a1); + unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); } #[inline(always)] @@ -7395,84 +7664,121 @@ impl Machine { let mut context = Sha3_224::new(); context.update(&bytes); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); + + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } atom!("sha3_256") => { let mut context = Sha3_256::new(); context.update(&bytes); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); + + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } atom!("sha3_384") => { let mut context = Sha3_384::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } atom!("sha3_512") => { let mut context = Sha3_512::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } atom!("blake2s256") => { let mut context = Blake2s256::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } atom!("blake2b512") => { let mut context = Blake2b512::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), + ) + ) } atom!("ripemd160") => { let mut context = Ripemd160::new(); context.update(&bytes); + let finalized_context = context.finalize(); + let context_len = finalized_context.len(); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - context - .finalize() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + context_len, + finalized_context + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } _ => { let ints = digest::digest( @@ -7488,12 +7794,16 @@ impl Machine { &bytes, ); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - ints.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + ints.as_ref().len(), + ints.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) } }; @@ -7524,12 +7834,16 @@ impl Machine { let rkey = hmac::Key::new(ralg, key.as_ref()); let tag = hmac::sign(&rkey, &data); - let ints_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - tag.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )); + let ints_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + tag.as_ref().len(), + tag.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ); unify!(self.machine_st, self.machine_st.registers[4], ints_list); } @@ -7591,12 +7905,16 @@ impl Machine { } } - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - bytes - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + bytes.len(), + bytes + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) }; unify!(self.machine_st, self.machine_st.registers[7], ints_list); @@ -7643,12 +7961,16 @@ impl Machine { &mut bytes, ); - heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - bytes - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )) + step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + bytes.len(), + bytes + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ) }; unify!(self.machine_st, self.machine_st.registers[4], ints_list); @@ -7686,14 +8008,18 @@ impl Machine { } }; - let tag_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - tag.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )); + let tag_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + tag.as_ref().len(), + tag.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ); - let complete_string = self.u8s_to_string(&in_out); + let complete_string = step_or_resource_error!(self.machine_st, self.u8s_to_string(&in_out)); unify!(self.machine_st, self.machine_st.registers[6], tag_list); unify!( @@ -7752,7 +8078,7 @@ impl Machine { if buffer.is_empty() { empty_list_as_cell!() } else { - atom_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, &buffer)) + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer)) } }; @@ -7777,7 +8103,10 @@ impl Machine { let scalar = secp256k1::Scalar::decode_reduce(&scalar_bytes); point *= scalar; - let uncompressed = self.u8s_to_string(&point.encode_uncompressed()); + let uncompressed = step_or_resource_error!( + self.machine_st, + self.u8s_to_string(&point.encode_uncompressed()) + ); unify!(self.machine_st, self.machine_st.registers[4], uncompressed); } @@ -7791,7 +8120,10 @@ impl Machine { let skey = ed25519::PrivateKey::from_seed(&seed_bytes); - let complete_string = self.u8s_to_string(skey.public_key.encoded.as_ref()); + let complete_string = step_or_resource_error!( + self.machine_st, + self.u8s_to_string(skey.public_key.encoded.as_ref()) + ); unify!( self.machine_st, @@ -7813,13 +8145,16 @@ impl Machine { let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding); let sig = skey.sign_raw(&data); - - let sig_list = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - sig.as_ref() - .iter() - .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))), - )); + let sig_list = step_or_resource_error!( + self.machine_st, + sized_iter_to_heap_list( + &mut self.machine_st.heap, + sig.as_ref().len(), + sig.as_ref() + .iter() + .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))) + ) + ); unify!(self.machine_st, self.machine_st.registers[4], sig_list); } @@ -7857,7 +8192,7 @@ impl Machine { &<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap(), ); - let string = self.u8s_to_string(&result[..]); + let string = step_or_resource_error!(self.machine_st, self.u8s_to_string(&result[..])); unify!(self.machine_st, self.machine_st.registers[3], string); } @@ -7882,29 +8217,31 @@ impl Machine { } #[inline(always)] - pub(crate) fn load_html(&mut self) { + pub(crate) fn load_html(&mut self) -> Result<(), usize> { if let Some(string) = self .machine_st .value_to_str_like(self.machine_st.registers[1]) { let document = scraper::Html::parse_document(&string.as_str()); - let result = self.html_node_to_term(document.tree.root().first_child().unwrap()); + let result = self.html_node_to_term(document.tree.root().first_child().unwrap())?; unify!(self.machine_st, self.machine_st.registers[2], result); } else { self.machine_st.fail = true; } + + Ok(()) } #[inline(always)] - pub(crate) fn load_xml(&mut self) { + pub(crate) fn load_xml(&mut self) -> Result<(), usize> { if let Some(string) = self .machine_st .value_to_str_like(self.machine_st.registers[1]) { match roxmltree::Document::parse(&string.as_str()) { Ok(doc) => { - let result = self.xml_node_to_term(doc.root_element()); + let result = self.xml_node_to_term(doc.root_element())?; unify!(self.machine_st, self.machine_st.registers[2], result); } _ => { @@ -7914,6 +8251,8 @@ impl Machine { } else { self.machine_st.fail = true; } + + Ok(()) } #[inline(always)] @@ -7924,10 +8263,9 @@ impl Machine { { match env::var(&*key.as_str()) { Ok(value) => { - let cstr = put_complete_string( - &mut self.machine_st.heap, - &value, - &self.machine_st.atom_tbl, + let cstr = step_or_resource_error!( + self.machine_st, + self.machine_st.allocate_cstr(&value) ); unify!(self.machine_st, self.machine_st.registers[2], cstr); @@ -8058,7 +8396,8 @@ impl Machine { match bytes { Ok(bs) => { - let string = self.u8s_to_string(&bs); + let string = + resource_error_call_result!(self.machine_st, self.u8s_to_string(&bs)); unify!(self.machine_st, self.machine_st.registers[1], string); } @@ -8080,7 +8419,8 @@ impl Machine { } let b64 = b64_engine.encode(bytes); - let string = self.u8s_to_string(b64.as_bytes()); + let string = + resource_error_call_result!(self.machine_st, self.u8s_to_string(b64.as_bytes())); unify!(self.machine_st, self.machine_st.registers[2], string); } @@ -8138,12 +8478,12 @@ impl Machine { 1, )?; - let mut parser = Parser::new(stream, &mut self.machine_st); + let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st); - match devour_whitespace(&mut parser) { + match devour_whitespace(&mut lexer_parser) { Ok(false) => { // not at EOF ... - stream.add_lines_read(parser.lines_read()); + stream.add_lines_read(lexer_parser.line_num()); // ... unless we are. if stream.at_end_of_stream() { @@ -8151,7 +8491,7 @@ impl Machine { } } Ok(true) => { - stream.add_lines_read(parser.lines_read()); + stream.add_lines_read(lexer_parser.line_num()); self.machine_st.fail = true; } Err(err) => { @@ -8212,7 +8552,7 @@ impl Machine { if path.is_dir() { if let Some(path) = path.to_str() { let path_string = - put_complete_string(&mut self.machine_st.heap, path, &self.machine_st.atom_tbl); + step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path)); unify!(self.machine_st, self.machine_st.registers[1], path_string); return; @@ -8247,7 +8587,7 @@ impl Machine { unify!(self.machine_st, self.machine_st.registers[2], pop_count); } - pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom { + pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> String { let datetime: DateTime = system_time.into(); let mut fstr = "[".to_string(); @@ -8261,9 +8601,7 @@ impl Machine { } fstr.push_str("finis]."); - let s = datetime.format(&fstr).to_string(); - - AtomTable::build_with(&self.machine_st.atom_tbl, &s) + datetime.format(&fstr).to_string() } pub(super) fn string_encoding_bytes( @@ -8282,128 +8620,124 @@ impl Machine { } } - pub(super) fn xml_node_to_term(&mut self, node: roxmltree::Node) -> HeapCellValue { + pub(super) fn xml_node_to_term( + &mut self, + node: roxmltree::Node, + ) -> Result { if node.is_text() { - put_complete_string( - &mut self.machine_st.heap, - node.text().unwrap(), - &self.machine_st.atom_tbl, - ) + self.machine_st.allocate_cstr(node.text().unwrap()) } else { let mut avec = Vec::new(); for attr in node.attributes() { let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.name()); - let value = put_complete_string( - &mut self.machine_st.heap, - attr.value(), - &self.machine_st.atom_tbl, - ); + let value = self.machine_st.allocate_cstr(attr.value())?; + + avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len())); - avec.push(str_loc_as_cell!(self.machine_st.heap.len())); + let mut writer = self.machine_st.heap.reserve(3)?; - self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - self.machine_st.heap.push(atom_as_cell!(name)); - self.machine_st.heap.push(value); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(name)); + section.push_cell(value); + }); } - let attrs = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - avec.into_iter() - )); + let attrs = + sized_iter_to_heap_list(&mut self.machine_st.heap, avec.len(), avec.into_iter())?; let mut cvec = Vec::new(); for child in node.children() { - cvec.push(self.xml_node_to_term(child)); + cvec.push(self.xml_node_to_term(child)?); } - let children = heap_loc_as_cell!(iter_to_heap_list( - &mut self.machine_st.heap, - cvec.into_iter() - )); + let children = + sized_iter_to_heap_list(&mut self.machine_st.heap, cvec.len(), cvec.into_iter())?; let tag = AtomTable::build_with(&self.machine_st.atom_tbl, node.tag_name().name()); + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(4)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("element"), 3)); + section.push_cell(atom_as_cell!(tag)); + section.push_cell(attrs); + section.push_cell(children); + }); - let result = str_loc_as_cell!(self.machine_st.heap.len()); - - self.machine_st - .heap - .push(atom_as_cell!(atom!("element"), 3)); - self.machine_st.heap.push(atom_as_cell!(tag)); - self.machine_st.heap.push(attrs); - self.machine_st.heap.push(children); - - result + Ok(result) } } pub(super) fn html_node_to_term( &mut self, node: ego_tree::NodeRef<'_, scraper::Node>, - ) -> HeapCellValue { + ) -> Result { match node.value().as_element() { - None => put_complete_string( - &mut self.machine_st.heap, - &node.value().as_text().unwrap().text, - &self.machine_st.atom_tbl, - ), + None => self + .machine_st + .allocate_cstr(&node.value().as_text().unwrap().text), Some(element) => { let mut avec = Vec::new(); for attr in element.attrs() { let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.0); - let value = put_complete_string( - &mut self.machine_st.heap, - attr.1, - &self.machine_st.atom_tbl, - ); + let value = self.machine_st.allocate_cstr(attr.1)?; + + avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len())); - avec.push(str_loc_as_cell!(self.machine_st.heap.len())); + let mut writer = self.machine_st.heap.reserve(3)?; - self.machine_st.heap.push(atom_as_cell!(atom!("="), 2)); - self.machine_st.heap.push(atom_as_cell!(name)); - self.machine_st.heap.push(value); + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("="), 2)); + section.push_cell(atom_as_cell!(name)); + section.push_cell(value); + }); } - let attrs = heap_loc_as_cell!(iter_to_heap_list( + let attrs = sized_iter_to_heap_list( &mut self.machine_st.heap, - avec.into_iter() - )); + avec.len(), + avec.into_iter(), + )?; let mut cvec = Vec::new(); for child in node.children() { - cvec.push(self.html_node_to_term(child)); + cvec.push(self.html_node_to_term(child)?); } - let children = heap_loc_as_cell!(iter_to_heap_list( + let children = sized_iter_to_heap_list( &mut self.machine_st.heap, - cvec.into_iter() - )); + cvec.len(), + cvec.into_iter(), + )?; let tag = AtomTable::build_with(&self.machine_st.atom_tbl, element.name()); - let result = str_loc_as_cell!(self.machine_st.heap.len()); - - self.machine_st - .heap - .push(atom_as_cell!(atom!("element"), 3)); - self.machine_st.heap.push(atom_as_cell!(tag)); - self.machine_st.heap.push(attrs); - self.machine_st.heap.push(children); + let result = str_loc_as_cell!(self.machine_st.heap.cell_len()); + let mut writer = self.machine_st.heap.reserve(4)?; + + writer.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("element"), 3)); + section.push_cell(atom_as_cell!(tag)); + section.push_cell(attrs); + section.push_cell(children); + }); - result + Ok(result) } } } - pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> HeapCellValue { + pub(super) fn u8s_to_string(&mut self, data: &[u8]) -> Result { let buffer = String::from_iter(data.iter().map(|b| *b as char)); if buffer.is_empty() { - empty_list_as_cell!() + Ok(empty_list_as_cell!()) } else { - atom_as_cstr_cell!(AtomTable::build_with(&self.machine_st.atom_tbl, &buffer)) + self.machine_st.allocate_cstr(&buffer) } } } diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs index 58c6e2c8..9a1f9fa6 100644 --- a/src/machine/term_stream.rs +++ b/src/machine/term_stream.rs @@ -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; @@ -20,11 +21,11 @@ pub struct LoadStatePayload { pub(super) module_op_exports: ModuleOpExports, pub(super) non_counted_bt_preds: IndexSet, pub(super) predicates: PredicateQueue, - pub(super) clause_clauses: Vec, + pub(super) clause_clauses: Vec, } pub trait TermStream: Sized { - fn next(&mut self, op_dir: &CompositeOpDir) -> Result; + fn next(&mut self, op_dir: &CompositeOpDir) -> Result; fn eof(&mut self) -> Result; fn listing_src(&self) -> &ListingSource; } @@ -32,7 +33,7 @@ pub trait TermStream: Sized { #[derive(Debug)] pub struct BootstrappingTermStream<'a> { listing_src: ListingSource, - pub(super) parser: Parser<'a, Stream>, + pub(super) lexer_parser: LexerParser<'a, Stream>, } impl<'a> BootstrappingTermStream<'a> { @@ -42,26 +43,23 @@ impl<'a> BootstrappingTermStream<'a> { machine_st: &'a mut MachineState, listing_src: ListingSource, ) -> Self { - let parser = Parser::new(stream, machine_st); - Self { - parser, - listing_src, - } + let lexer_parser = LexerParser::new(stream, machine_st); + Self { lexer_parser, listing_src } } } impl<'a> TermStream for BootstrappingTermStream<'a> { #[inline] - fn next(&mut self, op_dir: &CompositeOpDir) -> Result { - self.parser.reset(); - self.parser - .read_term(op_dir, Tokens::Default) - .map_err(CompilationError::from) + fn next(&mut self, op_dir: &CompositeOpDir) -> Result { + let result = self.lexer_parser.read_term(op_dir, Tokens::Default) + .map_err(CompilationError::from); + + result } #[inline] fn eof(&mut self) -> Result { - devour_whitespace(&mut self.parser) // eliminate dangling comments before checking for EOF. + devour_whitespace(&mut self.lexer_parser) // eliminate dangling comments before checking for EOF. .map_err(CompilationError::from) } @@ -72,7 +70,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> { } pub struct LiveTermStream { - pub(super) term_queue: VecDeque, + pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } @@ -108,7 +106,7 @@ impl LoadStatePayload { impl TermStream for LiveTermStream { #[inline] - fn next(&mut self, _: &CompositeOpDir) -> Result { + fn next(&mut self, _: &CompositeOpDir) -> Result { Ok(self.term_queue.pop_front().unwrap()) } @@ -126,7 +124,7 @@ impl TermStream for LiveTermStream { pub struct InlineTermStream {} impl TermStream for InlineTermStream { - fn next(&mut self, _: &CompositeOpDir) -> Result { + fn next(&mut self, _: &CompositeOpDir) -> Result { Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default()))) } diff --git a/src/machine/unify.rs b/src/machine/unify.rs index 05ba4749..5b7c23e8 100644 --- a/src/machine/unify.rs +++ b/src/machine/unify.rs @@ -2,11 +2,9 @@ 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::types::*; -use std::cmp::Ordering; use std::ops::{Deref, DerefMut}; use derive_more::*; @@ -14,6 +12,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 { fn unify_structure(&mut self, s1: usize, value: HeapCellValue) { // s1 is the value of a STR cell. @@ -82,8 +92,8 @@ pub(crate) trait Unifier: DerefMut { 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,263 +110,42 @@ pub(crate) trait Unifier: DerefMut { ); } - 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)); - } - + Self::bind(self, r, pstr_loc_as_cell!(pstr_loc)); return; } + let machine_st = self.deref_mut(); + 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]) + let (name, arity) = cell_as_atom_cell!(machine_st.heap[s]) .get_name_and_arity(); - if arity == 0 { - self.fail = atom == atom!("") && name != atom!("[]"); + if name == atom!(".") && arity == 2 { + machine_st.partial_string_to_pdl(pstr_loc, s+1); } 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); - } + machine_st.fail = true; } } - (HeapCellValueTag::CStr, cstr_atom) => { - self.fail = atom != cstr_atom; + (HeapCellValueTag::Lis, l) => { + machine_st.partial_string_to_pdl(pstr_loc, l); } - (HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc) => { - Self::unify_partial_string(self, atom_as_cstr_cell!(atom), value); + (HeapCellValueTag::PStrLoc, other_pstr_loc) => { + let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc); - if !self.pdl.is_empty() { - Self::unify_internal(self); + if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() { + debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. })); + machine_st.fail = true; } } _ => { - self.fail = true; + machine_st.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); - 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]; - } - (HeapCellValueTag::Str, s) => { - let (name, arity) = cell_as_atom_cell!(pstr_iter2.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]; - } else { - machine_st.fail = true; - break 'outer; - } - } - (HeapCellValueTag::CStr | HeapCellValueTag::PStrLoc) => { - unify_sequence(machine_st, chars_iter.item.unwrap(), focus); - return; - } - (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) { read_heap_cell!(value, (HeapCellValueTag::Atom, (name, arity)) => { @@ -368,6 +157,7 @@ pub(crate) trait Unifier: DerefMut { self.fail = !(arity == 0 && name == atom); } + /* (HeapCellValueTag::CStr, cstr_atom) if atom == atom!("[]") => { self.fail = cstr_atom != atom!(""); } @@ -378,6 +168,7 @@ pub(crate) trait Unifier: DerefMut { self.fail = true; } } + */ (HeapCellValueTag::AttrVar, h) => { Self::bind(self, Ref::attr_var(h), atom_as_cell!(atom)); } @@ -412,11 +203,13 @@ pub(crate) trait Unifier: DerefMut { 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)); } @@ -610,7 +403,7 @@ pub(crate) trait Unifier: DerefMut { tabu_list.insert((d1, d2)); } } - (HeapCellValueTag::PStrLoc) => { + (HeapCellValueTag::PStrLoc, l) => { read_heap_cell!(d2, (HeapCellValueTag::PStrLoc | HeapCellValueTag::Lis | @@ -619,8 +412,7 @@ pub(crate) trait Unifier: DerefMut { continue; } } - (HeapCellValueTag::CStr | - HeapCellValueTag::AttrVar | + (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => { } @@ -630,13 +422,14 @@ pub(crate) trait Unifier: DerefMut { } ); - 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) => { @@ -667,15 +460,18 @@ pub(crate) trait Unifier: DerefMut { Self::unify_partial_string(self, d2, d1); } + */ (HeapCellValueTag::F64, 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); } @@ -709,12 +505,12 @@ fn bind_with_occurs_check(unifier: &mut U, r: Ref, value: HeapCellVa let value = machine_st.store(MachineState::deref(machine_st, value)); if value.is_ref() && !value.is_stack_var() { - let root_loc = value.get_value() as usize; + machine_st.heap[0] = value; for cell in stackful_preorder_iter::( &mut machine_st.heap, &mut machine_st.stack, - root_loc, // value, + 0, ) { let cell = unmark_cell_bits!(cell); diff --git a/src/macros.rs b/src/macros.rs index b01df829..5463c0c8 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -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()) }; } @@ -46,32 +41,23 @@ 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(), + 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) + AtomCell::build_with($atom.index, $arity as u8) .into_bytes(), ) }; } -macro_rules! cell_as_string { +macro_rules! cell_as_atom { ($cell:expr) => { - PartialString::from(cell_as_atom!($cell)) + AtomCell::from_bytes($cell.into_bytes()).get_name() }; } -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) - }}; -} - macro_rules! cell_as_atom_cell { ($cell:expr) => { AtomCell::from_bytes($cell.into_bytes()) @@ -91,26 +77,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) @@ -185,38 +157,6 @@ 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()) @@ -356,6 +296,7 @@ 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)] @@ -376,6 +317,7 @@ macro_rules! read_heap_cell_pat_body { #[allow(unused_braces)] $code }}; + */ ($cell:ident, Fixnum, $value:ident, $code:expr) => {{ let $value = Fixnum::from_bytes($cell.into_bytes()); #[allow(unused_braces)] @@ -442,119 +384,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); @@ -639,3 +468,40 @@ 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![]); // TODO: return Ok(()); + }) + }; +} + +macro_rules! heap_index { + ($idx:expr) => {($idx) * std::mem::size_of::()}; +} + +macro_rules! cell_index { + ($idx:expr) => {(($idx) / std::mem::size_of::())}; +} diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 477e9382..45335c88 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -3,10 +3,8 @@ use crate::arena::*; use crate::atom_table::*; use crate::forms::PredicateKey; -use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::machine_indices::*; -use crate::machine::machine_state::*; use crate::types::*; use std::fmt; @@ -14,11 +12,8 @@ use std::hash::Hash; use std::io::{Error as IOError, ErrorKind}; use std::ops::Neg; use std::rc::Rc; -use std::sync::Arc; use std::vec::Vec; -use crate::parser::dashu::{Integer, Rational}; - use fxhash::FxBuildHasher; use indexmap::IndexMap; use scryer_modular_bitfield::error::OutOfBounds; @@ -26,7 +21,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)] @@ -143,7 +138,12 @@ pub const BTERM: u32 = 0x11000; pub const NEGATIVE_SIGN: u32 = 0x0200; macro_rules! fixnum { - ($wrapper:tt, $n:expr, $arena:expr) => { + ($n:expr, $arena:expr) => { + Fixnum::build_with_checked($n) + .map(|n| fixnum_as_cell!(n)) + .unwrap_or_else(|_| typed_arena_ptr_as_cell!(arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr)) + }; + ($wrapper:ty, $n:expr, $arena:expr) => { Fixnum::build_with_checked($n) .map(<$wrapper>::Fixnum) .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena))) @@ -272,50 +272,12 @@ impl fmt::Display for RegType { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub enum VarReg { - ArgAndNorm(RegType, usize), - Norm(RegType), -} - -impl VarReg { - pub fn norm(self) -> RegType { - match self { - VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, - } - } -} - -impl fmt::Display for VarReg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), - VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), - VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), - VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), - } - } -} - -impl Default for VarReg { - fn default() -> Self { - VarReg::Norm(RegType::default()) - } -} - macro_rules! temp_v { ($x:expr) => { $crate::parser::ast::RegType::Temp($x) }; } -#[macro_export] -macro_rules! perm_v { - ($x:expr) => { - $crate::parser::ast::RegType::Perm($x) - }; -} - #[bitfield] #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct OpDesc { @@ -410,7 +372,6 @@ pub fn default_op_dir() -> OpDir { #[derive(Debug, Clone)] pub enum ArithmeticError { NonEvaluableFunctor(HeapCellValue, usize), - UninstantiatedVar, } #[derive(Debug, Copy, Clone, Default)] @@ -424,11 +385,12 @@ pub enum ParserError { BackQuotedString(ParserErrorSrc), IO(IOError, ParserErrorSrc), IncompleteReduction(ParserErrorSrc), - InvalidSingleQuotedCharacter(char, ParserErrorSrc), - LexicalError(lexical::Error, ParserErrorSrc), + InvalidSingleQuotedCharacter(ParserErrorSrc), + LexicalError(ParserErrorSrc), MissingQuote(ParserErrorSrc), NonPrologChar(ParserErrorSrc), ParseBigInt(ParserErrorSrc), + ResourceError(ParserErrorSrc), UnexpectedChar(char, ParserErrorSrc), // UnexpectedEOF, Utf8Error(ParserErrorSrc), @@ -440,11 +402,12 @@ impl ParserError { &ParserError::BackQuotedString(err_src) | &ParserError::IO(_, err_src) | &ParserError::IncompleteReduction(err_src) - | &ParserError::InvalidSingleQuotedCharacter(_, err_src) - | &ParserError::LexicalError(_, err_src) + | &ParserError::InvalidSingleQuotedCharacter(err_src) + | &ParserError::LexicalError(err_src) | &ParserError::MissingQuote(err_src) | &ParserError::NonPrologChar(err_src) | &ParserError::ParseBigInt(err_src) + | &ParserError::ResourceError(err_src) | &ParserError::UnexpectedChar(_, err_src) | &ParserError::Utf8Error(err_src) => err_src, } @@ -470,6 +433,7 @@ impl ParserError { ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), ParserError::UnexpectedChar(..) => atom!("unexpected_char"), ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), + ParserError::ResourceError(..) => atom!("resource_error"), } } @@ -487,29 +451,13 @@ impl ParserError { } } } -/* -impl From for ParserError { - fn from((e, err_src): (lexical::Error, ParserErrorSrc)) -> ParserError { - ParserError::LexicalError(e, err_src) - } -} -impl From for ParserError { - fn from(e: IOError) -> ParserError { - ParserError::IO(e) +impl From for ParserError { + fn from(err_src: ParserErrorSrc) -> ParserError { + ParserError::LexicalError(err_src) } } -impl From<&IOError> for ParserError { - fn from(error: &IOError) -> ParserError { - if error.get_ref().filter(|e| e.is::()).is_some() { - ParserError::Utf8Error(0, 0) - } else { - ParserError::IO(error.kind().into()) - } - } -} -*/ #[derive(Debug, Clone, Copy)] pub struct CompositeOpDir<'a, 'b> { pub primary_op_dir: Option<&'b OpDir>, @@ -618,16 +566,16 @@ impl Neg for Fixnum { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +/* +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Literal { Atom(Atom), - Char(char), CodeIndex(CodeIndex), Fixnum(Fixnum), Integer(TypedArenaPtr), Rational(TypedArenaPtr), Float(F64Offset), - String(Atom), + String(Rc), } impl From for Literal { @@ -643,7 +591,7 @@ impl fmt::Display for Literal { Literal::Atom(ref atom) => { write!(f, "{}", atom.flat_index()) } - Literal::Char(c) => write!(f, "'{}'", *c as u32), + // Literal::Char(c) => write!(f, "'{}'", *c as u32), Literal::CodeIndex(i) => write!(f, "{:x}", i.as_ptr() as u64), Literal::Fixnum(n) => write!(f, "{}", n.get_num()), Literal::Integer(ref n) => write!(f, "{}", n), @@ -662,10 +610,14 @@ impl Literal { } } } +*/ pub type Var = Rc; -pub(crate) fn subterm_index(heap: &[HeapCellValue], subterm_loc: usize) -> (usize, HeapCellValue) { +pub(crate) fn subterm_index( + heap: &impl SizedHeap, + subterm_loc: usize, +) -> (usize, HeapCellValue) { let subterm = heap[subterm_loc]; if subterm.is_ref() { @@ -691,11 +643,12 @@ pub enum Term { AnonVar, Clause(Cell, Atom, Vec), Cons(Cell, Box, Box), - Literal(Cell, Literal), + Literal(Cell, HeapCellValue), + // Literal(Cell, Literal), // PartialString wraps a String in anticipation of it absorbing // other PartialString variants in as_partial_string. - PartialString(Cell, String, Box), - CompleteString(Cell, Atom), + PartialString(Cell, Rc, Box), + CompleteString(Cell, Rc), Var(Cell, VarPtr), } @@ -709,8 +662,11 @@ impl Term { pub fn name(&self) -> Option { match self { - &Term::Literal(_, Literal::Atom(ref atom)) | &Term::Clause(_, ref atom, ..) => { - Some(*atom) + Term::Literal(_, cell) => { + cell.to_atom() + } + &Term::Clause(_, atom, ..) => { + Some(atom) } _ => None, } @@ -755,11 +711,11 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec { */ pub(crate) fn fetch_index_ptr( - heap: &[HeapCellValue], + heap: &impl SizedHeap, arity: usize, term_loc: usize, ) -> Option { - if term_loc + arity + 1 >= heap.len() { + if term_loc + arity + 1 >= heap.cell_len() || heap.pstr_at(term_loc + arity + 1) { return None; } @@ -779,7 +735,7 @@ pub(crate) fn fetch_index_ptr( } pub(crate) fn blunt_index_ptr( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, key: PredicateKey, term_loc: usize, ) -> bool { @@ -792,7 +748,7 @@ pub(crate) fn blunt_index_ptr( } pub(crate) fn unfold_by_str_once( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, start_term: HeapCellValue, atom: Atom, ) -> Option { @@ -816,7 +772,7 @@ pub(crate) fn unfold_by_str_once( } pub fn unfold_by_str( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, mut start_term: HeapCellValue, atom: Atom, ) -> Vec { @@ -857,7 +813,7 @@ pub fn unfold_by_str_locs( */ pub fn unfold_by_str_locs( - heap: &mut [HeapCellValue], + heap: &mut impl SizedHeapMut, mut term_loc: usize, atom: Atom, ) -> Vec<(HeapCellValue, usize)> { @@ -875,11 +831,14 @@ pub fn unfold_by_str_locs( terms } -pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option { +pub fn term_predicate_key( + heap: &impl SizedHeap, + mut term_loc: usize, +) -> Option { loop { read_heap_cell!(heap[term_loc], - (HeapCellValueTag::Atom, (name, _arity)) => { - return Some(name); + (HeapCellValueTag::Atom, (name, arity)) => { + return Some((name, arity)); } (HeapCellValueTag::Str, s) => { term_loc = s; @@ -898,32 +857,6 @@ pub fn term_name(heap: &[HeapCellValue], mut term_loc: usize) -> Option { } } -pub fn term_arity(heap: &[HeapCellValue], mut term_loc: usize) -> usize { - loop { - read_heap_cell!(heap[term_loc], - (HeapCellValueTag::Atom, (_name, arity)) => { - return arity; - } - (HeapCellValueTag::Str, s) => { - term_loc = s; - } - (HeapCellValueTag::Lis) => { - return 2; - } - (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { - if h != term_loc { - term_loc = h; - } else { - return 0; - } - } - _ => { - return 0; - } - ); - } -} - pub fn inverse_var_locs_from_iter>(iter: I) -> InverseVarLocs { let mut occurrence_set: IndexMap = IndexMap::with_hasher(FxBuildHasher::default()); @@ -970,7 +903,7 @@ pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue } */ -pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Option { +pub fn term_nth_arg(heap: &impl SizedHeap, mut term_loc: usize, n: usize) -> Option { loop { read_heap_cell!(heap[term_loc], (HeapCellValueTag::Str, s) => { @@ -1010,108 +943,55 @@ pub fn term_nth_arg(heap: &[HeapCellValue], mut term_loc: usize, n: usize) -> Op } } -pub type VarLocs = IndexMap; -pub type InverseVarLocs = IndexMap; - #[derive(Debug)] -pub struct FocusedHeap { - pub heap: Vec, +pub struct TermWriteResult { pub focus: usize, pub inverse_var_locs: InverseVarLocs, } -impl FocusedHeap { - pub fn empty() -> Self { - Self { - heap: vec![], - focus: 0, - inverse_var_locs: InverseVarLocs::default(), - } - } - - pub fn copy_term_from_machine_heap( - &mut self, - machine_st: &mut MachineState, - cell: HeapCellValue, - ) { - let hb = machine_st.heap.len(); - - copy_term( - CopyBallTerm::new( - &mut machine_st.attr_var_init.attr_var_queue, - &mut machine_st.stack, - &mut machine_st.heap, - &mut self.heap, - ), - cell, - AttrVarPolicy::DeepCopy, - ); - - for cell in self.heap.iter_mut() { - *cell = *cell - hb; - } - } - - pub fn as_ref_mut(&mut self, focus: usize) -> FocusedHeapRefMut { - FocusedHeapRefMut { - heap: &mut self.heap, - focus, - } - } - - pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { - use crate::machine::heap::*; - - let cell = self.heap[term_loc]; - heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell)) - } - - pub fn name(&self, term_loc: usize) -> Option { - term_name(&self.heap, term_loc) - } - - pub fn arity(&self, term_loc: usize) -> usize { - term_arity(&self.heap, term_loc) - } - - pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option { - term_nth_arg(&self.heap, term_loc, n) - } -} +pub type VarLocs = IndexMap; +pub type InverseVarLocs = IndexMap; +#[derive(Debug)] pub struct FocusedHeapRefMut<'a> { - pub heap: &'a mut Vec, + pub heap: &'a mut Heap, pub focus: usize, } impl<'a> FocusedHeapRefMut<'a> { - pub fn name(&self, term_loc: usize) -> Option { - term_name(&self.heap, term_loc) + #[inline] + pub fn from(heap: &'a mut Heap, focus: usize) -> Self { + Self { heap, focus } + } + + pub fn predicate_key(&self, term_loc: usize) -> Option { + term_predicate_key(self.heap, term_loc) } pub fn arity(&self, term_loc: usize) -> usize { - term_arity(&self.heap, term_loc) + self.predicate_key(term_loc) + .map(|(_, arity)| arity) + .unwrap_or(0) } pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue { - use crate::machine::heap::*; - let cell = self.heap[term_loc]; - heap_bound_store(&self.heap, heap_bound_deref(&self.heap, cell)) + heap_bound_store(self.heap, heap_bound_deref(self.heap, cell)) } pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option { term_nth_arg(self.heap, term_loc, n) } - pub fn from_cell(heap: &'a mut Vec, cell: HeapCellValue) -> Self { + /* + pub fn from_cell(heap: &'a mut Heap, cell: HeapCellValue) -> Self { let focus = read_heap_cell!(cell, (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { h } _ => { let h = heap.len(); - heap.push(cell); + heap.push_cell(cell).unwrap(); h } @@ -1119,4 +999,5 @@ impl<'a> FocusedHeapRefMut<'a> { Self { heap, focus } } + */ } diff --git a/src/parser/lexer.rs b/src/parser/lexer.rs index 05868fbf..800e5f44 100644 --- a/src/parser/lexer.rs +++ b/src/parser/lexer.rs @@ -1,11 +1,13 @@ -use lexical::{FromLexicalLossy, parse_lossy}; +use lexical::{FromLexical, parse}; -use crate::arena::ArenaAllocated; +use crate::arena::*; use crate::atom_table::*; +use crate::machine::heap::*; pub use crate::machine::machine_state::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::dashu::Integer; +use crate::types::*; use std::convert::TryFrom; use std::fmt; @@ -31,8 +33,9 @@ struct LayoutInfo { #[derive(Debug, PartialEq)] pub enum Token { - Literal(Literal), + Literal(HeapCellValue), Var(String), + String(String), Open, // '(' OpenCT, // '(' Close, // ')' @@ -46,22 +49,46 @@ pub enum Token { } impl Token { + pub(super) fn byte_size(&self, flags: MachineFlags) -> usize { + match self { + Token::String(string) if flags.double_quotes.is_codes() => { + 2 * string.chars().count() + 1 + } + Token::String(string) => { + Heap::compute_pstr_size(&string) + } + Token::Literal(_) | + Token::Comma | + Token::HeadTailSeparator | + Token::Open | + Token::OpenCT | + Token::OpenCurly | + Token::OpenList | + Token::Var(_) => { + heap_index!(1) + } + _ => { + 0 + } + } + } + #[inline] pub(super) fn is_end(&self) -> bool { matches!(self, Token::End) } } -pub struct Lexer<'a, R> { +pub(crate) struct LexerParser<'a, R> { pub(crate) reader: R, pub(crate) machine_st: &'a mut MachineState, pub(crate) line_num: usize, pub(crate) col_num: usize, } -impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { +impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'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) @@ -69,9 +96,9 @@ impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> { } } -impl<'a, R: CharRead> Lexer<'a, R> { +impl<'a, R: CharRead> LexerParser<'a, R> { pub fn new(src: R, machine_st: &'a mut MachineState) -> Self { - Lexer { + LexerParser { reader: src, machine_st, line_num: 0, @@ -93,11 +120,6 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - #[inline] - pub fn loc_to_err_src(&self) -> ParserErrorSrc { - ParserErrorSrc { line_num: self.line_num, col_num: self.col_num } - } - #[inline(always)] fn return_char(&mut self, c: char) { self.reader.put_back_char(c); @@ -460,14 +482,16 @@ impl<'a, R: CharRead> Lexer<'a, R> { } i64::from_str_radix(&token, 16) - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { Integer::from_str_radix(&token, 16) .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -495,14 +519,16 @@ impl<'a, R: CharRead> Lexer<'a, R> { } i64::from_str_radix(&token, 8) - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { Integer::from_str_radix(&token, 8) .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -530,14 +556,16 @@ impl<'a, R: CharRead> Lexer<'a, R> { } i64::from_str_radix(&token, 2) - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { Integer::from_str_radix(&token, 2) .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -610,11 +638,11 @@ 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(char_as_cell!(c))); } } } else { - return Err(ParserError::InvalidSingleQuotedCharacter(c, self.loc_to_err_src())); + return Err(ParserError::InvalidSingleQuotedCharacter(self.loc_to_err_src())); } } else { match self.get_back_quoted_string() { @@ -624,26 +652,29 @@ impl<'a, R: CharRead> Lexer<'a, R> { } if token.as_str() == "[]" { - Ok(Token::Literal(Literal::Atom(atom!("[]")))) + Ok(Token::Literal(empty_list_as_cell!())) } else { - Ok(Token::Literal(Literal::Atom(AtomTable::build_with( + Ok(Token::Literal(atom_as_cell!(AtomTable::build_with( &self.machine_st.atom_tbl, &token, )))) } } - fn parse_lossy_wrapper(&self, token: String) -> Result { - match parse_lossy::(token.as_bytes()) { + fn parse_lossy_wrapper(&self, token: &str) -> Result { + match parse::(token.as_bytes()) { Ok(n) => Ok(n), - Err(e) => return Err(ParserError::LexicalError(e, self.loc_to_err_src())), + Err(_) => return Err(ParserError::LexicalError(self.loc_to_err_src())), } } fn vacate_with_float(&mut self, mut token: String) -> Result { self.return_char(token.pop().unwrap()); - let n = self.parse_lossy_wrapper::(token)?; - Ok(Token::Literal(Literal::from(float_alloc!(n, self.machine_st.arena)))) + let n = self.parse_lossy_wrapper::(&token)?; + Ok(Token::Literal(HeapCellValue::from(float_alloc!( + n, + self.machine_st.arena + )))) } fn skip_underscore_in_number(&mut self) -> Result { @@ -685,15 +716,17 @@ impl<'a, R: CharRead> Lexer<'a, R> { token .parse::() - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -757,9 +790,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } - let n = self.parse_lossy_wrapper::(token)?; - - Ok(Token::Literal(Literal::from(float_alloc!( + let n = self.parse_lossy_wrapper::(&token)?; + Ok(Token::Literal(HeapCellValue::from(float_alloc!( n, self.machine_st.arena )))) @@ -767,8 +799,8 @@ impl<'a, R: CharRead> Lexer<'a, R> { return self.vacate_with_float(token); } } else { - let n = self.parse_lossy_wrapper::(token)?; - Ok(Token::Literal(Literal::from(float_alloc!( + let n = self.parse_lossy_wrapper::(&token)?; + Ok(Token::Literal(HeapCellValue::from(float_alloc!( n, self.machine_st.arena )))) @@ -778,15 +810,17 @@ impl<'a, R: CharRead> Lexer<'a, R> { token .parse::() - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -798,16 +832,18 @@ impl<'a, R: CharRead> Lexer<'a, R> { token .parse::() .map(|n| { - Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)) + Token::Literal(fixnum!(n, &mut self.machine_st.arena)) }) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| { ParserError::ParseBigInt(self.loc_to_err_src()) @@ -823,16 +859,18 @@ impl<'a, R: CharRead> Lexer<'a, R> { token .parse::() .map(|n| { - Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)) + Token::Literal(fixnum!(n, &mut self.machine_st.arena)) }) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| { ParserError::ParseBigInt(self.loc_to_err_src()) @@ -848,16 +886,18 @@ impl<'a, R: CharRead> Lexer<'a, R> { token .parse::() .map(|n| { - Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)) + Token::Literal(fixnum!(n, &mut self.machine_st.arena)) }) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| { ParserError::ParseBigInt(self.loc_to_err_src()) @@ -879,14 +919,14 @@ impl<'a, R: CharRead> Lexer<'a, R> { self.skip_char(c); self.return_char('\''); - return Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(0)))); + return Ok(Token::Literal(fixnum_as_cell!(Fixnum::build_with(0)))); } else { self.return_char('\\'); } } self.get_single_quoted_char() - .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64)))) + .map(|c| Token::Literal(fixnum_as_cell!(Fixnum::build_with(c as i64)))) .or_else(|err| { match err { ParserError::UnexpectedChar('\'', ..) => {} @@ -898,16 +938,18 @@ impl<'a, R: CharRead> Lexer<'a, R> { token .parse::() .map(|n| { - Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)) + Token::Literal(fixnum!(n, &mut self.machine_st.arena)) }) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| { ParserError::ParseBigInt(self.loc_to_err_src()) @@ -917,15 +959,17 @@ impl<'a, R: CharRead> Lexer<'a, R> { } else { token .parse::() - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -933,15 +977,17 @@ impl<'a, R: CharRead> Lexer<'a, R> { } else { token .parse::() - .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))) + .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena))) .or_else(|_| { token .parse::() .map(|n| { - Token::Literal(Literal::Integer(arena_alloc!( - n, - &mut self.machine_st.arena - ))) + Token::Literal(typed_arena_ptr_as_cell!( + arena_alloc!( + n, + &mut self.machine_st.arena + ) as TypedArenaPtr + )) }) .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src())) }) @@ -1085,12 +1131,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 { - Ok(Token::Literal(Literal::Atom(atom))) + let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s); + Ok(Token::Literal(atom_as_cell!(atom))) } else { - Ok(Token::Literal(Literal::String(atom))) + Ok(Token::String(s)) }; } @@ -1104,13 +1150,3 @@ impl<'a, R: CharRead> Lexer<'a, R> { } } } - -fn parse_float_lossy(token: &str) -> Result { - const FORMAT: u128 = lexical::format::STANDARD; - let options = lexical::ParseFloatOptions::builder() - .lossy(true) - .build() - .unwrap(); - let n = lexical::parse_with_options::(token.as_bytes(), &options)?; - Ok(n) -} diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 5271b4a0..b67b1a4d 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -3,14 +3,13 @@ use dashu::Rational; use crate::arena::*; use crate::atom_table::*; -use crate::machine::heap::{heap_bound_deref, heap_bound_store}; -use crate::machine::partial_string::*; +use crate::forms::Number; +use crate::machine::heap::*; use crate::parser::ast::*; use crate::parser::char_reader::*; use crate::parser::lexer::*; use crate::types::*; -use std::mem; use std::ops::Neg; use std::rc::Rc; @@ -53,7 +52,7 @@ provided via the Provided variant. #[derive(Debug)] pub enum Tokens { Default, - Provided(Vec), + Provided(Vec, usize), } impl TokenType { @@ -176,22 +175,27 @@ pub struct CompositeOpDesc { } #[derive(Debug)] -pub struct Parser<'a, R> { - pub lexer: Lexer<'a, R>, +struct Parser<'a> { tokens: Vec, stack: Vec, - terms: Vec, + terms: HeapWriter<'a>, + arena: &'a mut Arena, + flags: MachineFlags, + line_num: &'a mut usize, + col_num: &'a mut usize, var_locs: VarLocs, inverse_var_locs: InverseVarLocs, } -fn read_tokens(lexer: &mut Lexer) -> Result, ParserError> { +pub fn read_tokens(lexer: &mut LexerParser) -> Result<(Vec, usize), ParserError> { let mut tokens = vec![]; + let mut term_size = 0; loop { match lexer.next_token() { Ok(token) => { let at_end = token.is_end(); + term_size += token.byte_size(lexer.machine_st.flags); tokens.push(token); if at_end { @@ -209,19 +213,11 @@ fn read_tokens(lexer: &mut Lexer) -> Result, ParserEr tokens.reverse(); - Ok(tokens) -} - -fn atomize_literal(atom_tbl: &AtomTable, c: Literal) -> Option { - match c { - Literal::Atom(ref name) => Some(*name), - Literal::Char(c) => Some(AtomTable::build_with(atom_tbl, &c.to_string())), - _ => None, - } + Ok((tokens, term_size)) } pub(crate) fn as_partial_string( - heap: &[HeapCellValue], + heap: &impl SizedHeap, head: HeapCellValue, tail: HeapCellValue, ) -> Option<(String, Option)> { @@ -240,9 +236,6 @@ pub(crate) fn as_partial_string( return None; } } - (HeapCellValueTag::Char, c) => { - c.to_string() - } _ => { return None; } @@ -263,9 +256,6 @@ pub(crate) fn as_partial_string( break; } } - (HeapCellValueTag::Char, c) => { - string.push(c); - } _ => { return None; } @@ -274,16 +264,9 @@ pub(crate) fn as_partial_string( tail = heap[l+1]; } (HeapCellValueTag::PStrLoc, l) => { - let (index, n) = pstr_loc_and_offset(&heap, l); - let n = n.get_num() as usize; - - string += &*cell_as_string!(heap[index]).as_str_from(n); - tail = heap[l+1]; - } - (HeapCellValueTag::CStr, cstr_atom) => { - string += &*cstr_atom.as_str(); - tail = empty_list_as_cell!(); - break; + let (pstr, tail_loc) = heap.scan_slice_to_str(l); + string += pstr; + tail = heap[tail_loc]; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { if heap[h] != tail { @@ -316,36 +299,15 @@ pub(crate) fn as_partial_string( ) } -impl<'a, R: CharRead> Parser<'a, R> { - pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self { - Parser { - lexer: Lexer::new(stream, machine_st), - tokens: vec![], - stack: vec![], - terms: vec![], - var_locs: VarLocs::default(), - inverse_var_locs: InverseVarLocs::default(), - } - } - - pub fn from_lexer(lexer: Lexer<'a, R>) -> Self { - Parser { - lexer, - tokens: vec![], - stack: vec![], - terms: vec![], - var_locs: VarLocs::default(), - inverse_var_locs: InverseVarLocs::default(), - } - } - +impl<'a> Parser<'a> { fn get_term_name(&self, td: TokenDesc) -> Option { match td.tt { TokenType::HeadTailSeparator => Some(atom!("|")), TokenType::Comma => Some(atom!(",")), TokenType::Term { heap_loc } => { if heap_loc.is_ref() { - term_name(&self.terms, heap_loc.get_value() as usize) + term_predicate_key(&self.terms, heap_loc.get_value() as usize) + .map(|key| key.0) } else { None } @@ -354,16 +316,6 @@ impl<'a, R: CharRead> Parser<'a, R> { } } - #[inline] - pub fn line_num(&self) -> usize { - self.lexer.line_num - } - - #[inline] - pub fn col_num(&self) -> usize { - self.lexer.col_num - } - fn push_binary_op( &mut self, op: TokenDesc, @@ -382,13 +334,15 @@ impl<'a, R: CharRead> Parser<'a, R> { } = operand_1 { if let Some(name) = self.get_term_name(op) { - let str_loc = self.terms.len(); + let str_loc = self.terms.cell_len(); - self.terms.push(atom_as_cell!(name, 2)); - self.terms.push(arg1); - self.terms.push(arg2); + self.terms.write_with(|section| { + section.push_cell(atom_as_cell!(name, 2)); + section.push_cell(arg1); + section.push_cell(arg2); - self.terms.push(str_loc_as_cell!(str_loc)); + section.push_cell(str_loc_as_cell!(str_loc)); + }); self.stack.push(TokenDesc { tt: TokenType::Term { @@ -404,10 +358,6 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) { - // if is_postfix!(assoc) { - // mem::swap(&mut op, &mut operand); - // } - if let TokenDesc { tt: TokenType::Term { heap_loc: arg1 }, .. @@ -419,11 +369,13 @@ impl<'a, R: CharRead> Parser<'a, R> { } = op { if let Some(name) = self.get_term_name(op) { - let str_loc = self.terms.len(); + let str_loc = self.terms.cell_len(); - self.terms.push(atom_as_cell!(name, 1)); - self.terms.push(arg1); - self.terms.push(str_loc_as_cell!(str_loc)); + self.terms.write_with(|section| { + section.push_cell(atom_as_cell!(name, 1)); + section.push_cell(arg1); + section.push_cell(str_loc_as_cell!(str_loc)); + }); self.stack.push(TokenDesc { tt: TokenType::Term { @@ -439,8 +391,8 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) { - let h = self.terms.len(); - self.terms.push(atom_as_cell!(atom)); + let h = self.terms.cell_len(); + self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom))); self.stack.push(TokenDesc { tt: TokenType::Term { heap_loc: heap_loc_as_cell!(h), @@ -452,51 +404,61 @@ impl<'a, R: CharRead> Parser<'a, R> { } fn shift(&mut self, token: Token, priority: usize, spec: Specifier) { - let heap_loc = heap_loc_as_cell!(self.terms.len()); + let heap_loc = heap_loc_as_cell!(self.terms.cell_len()); let tt = match token { - Token::Literal(Literal::String(s)) - if self.lexer.machine_st.flags.double_quotes.is_codes() => - { + Token::String(s) if self.flags.double_quotes.is_codes() => { let mut list = empty_list_as_cell!(); - for c in s.as_str().chars().rev() { - let h = self.terms.len(); + self.terms.write_with(|section| { + for c in s.as_str().chars().rev() { + let h = section.cell_len(); - self.terms - .push(fixnum_as_cell!(Fixnum::build_with(c as i64))); - self.terms.push(list); + section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64))); + section.push_cell(list); - list = list_loc_as_cell!(h); - } + list = list_loc_as_cell!(h); + } - self.terms.push(list); + section.push_cell(list); + }); TokenType::Term { heap_loc: list } } - Token::Literal(Literal::String(s)) - if self.lexer.machine_st.flags.double_quotes.is_chars() => - { - if s.is_empty() { - self.terms.push(empty_list_as_cell!()); - } else { - self.terms.push(string_as_cstr_cell!(s)); - } + Token::String(s) => { + debug_assert!(self.flags.double_quotes.is_chars()); + let mut pstr_cell = heap_loc; - TokenType::Term { heap_loc } - } - Token::Literal(Literal::Char(c)) => { - // soon this will be gone due to chars being folded - // into atoms - self.terms.push(atom_as_cell!(atomize_literal( - &self.lexer.machine_st.atom_tbl, - Literal::Char(c), - ).unwrap())); + if s == "\u{0}" { + let h = self.terms.cell_len(); - TokenType::Term { heap_loc } + self.terms.write_with(|section| { + section.push_cell(char_as_cell!('\u{0}')); + section.push_cell(empty_list_as_cell!()); + section.push_cell(list_loc_as_cell!(h)); + }); + + TokenType::Term { heap_loc: heap_loc_as_cell!(h + 2) } + } else { + self.terms.write_with(|section| { + match section.push_pstr(&s) { + Some(pstr_loc_cell) => { + section.push_cell(empty_list_as_cell!()); + let h = section.cell_len(); + section.push_cell(pstr_loc_cell); + pstr_cell = heap_loc_as_cell!(h); + } + None => { + section.push_cell(empty_list_as_cell!()); + } + } + }); + + TokenType::Term { heap_loc: pstr_cell } + } } Token::Literal(c) => { - self.terms.push(HeapCellValue::from(c)); + self.terms.write_with(|section| section.push_cell(c)); TokenType::Term { heap_loc } } Token::Var(var_string) => { @@ -504,11 +466,11 @@ impl<'a, R: CharRead> Parser<'a, R> { match self.var_locs.get(&var).cloned() { Some(heap_loc) => { - self.terms.push(heap_loc); + self.terms.write_with(|section| section.push_cell(heap_loc)); TokenType::Term { heap_loc } } None => { - self.terms.push(heap_loc); + self.terms.write_with(|section| section.push_cell(heap_loc)); // if var_string == "_", it not being present // as a key of self.var_locs means it is @@ -649,23 +611,23 @@ impl<'a, R: CharRead> Parser<'a, R> { return false; } - if self.terms.len() < arity { + if self.terms.cell_len() < arity { return false; } let stack_len = self.stack.len() - 2 * arity - 1; - let term_idx = self.terms.len(); + let term_idx = self.terms.cell_len(); let push_structure = |parser: &mut Self, name: Atom| -> TokenType { - parser.terms.push(atom_as_cell!(name, arity)); + parser.terms.write_with(|section| section.push_cell(atom_as_cell!(name, arity))); for idx in (stack_len + 2..parser.stack.len()).step_by(2) { let subterm = parser.term_from_stack(idx).unwrap(); - parser.terms.push(subterm); + parser.terms.write_with(|section| section.push_cell(subterm)); } - let str_loc_idx = parser.terms.len(); - parser.terms.push(str_loc_as_cell!(term_idx)); + let str_loc_idx = parser.terms.cell_len(); + parser.terms.write_with(|section| section.push_cell(str_loc_as_cell!(term_idx))); TokenType::Term { heap_loc: heap_loc_as_cell!(str_loc_idx), @@ -679,39 +641,38 @@ impl<'a, R: CharRead> Parser<'a, R> { { let idx = heap_loc.get_value() as usize; - if let Some(name) = term_name(&self.terms, idx) { + if let Some((name, arity)) = term_predicate_key(&self.terms, idx) { // reduce the '.' functor to a cons cell if it applies. let new_tt = if name == atom!(".") && arity == 2 { let head = self.term_from_stack(stack_len + 2).unwrap(); let tail = self.term_from_stack(stack_len + 4).unwrap(); + let cell_len = self.terms.cell_len(); match as_partial_string(&self.terms, head, tail) { - Some((string_buf, Some(tail))) => { - let atom = - AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); + Some((string_buf, tail_opt)) => { + let bytes_written = self.terms.write_with(|section| { + let pstr_cell = section.push_pstr(&string_buf).unwrap(); + section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); + section.push_cell(pstr_cell); + }); - self.terms.push(string_as_pstr_cell!(atom)); - self.terms.push(tail); - self.terms.push(pstr_loc_as_cell!(term_idx)); + let heap_loc = cell_index!(bytes_written) - 1 + cell_len; TokenType::Term { - heap_loc: heap_loc_as_cell!(term_idx + 2), - } - } - Some((string_buf, None)) => { - let atom = - AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - TokenType::Term { - heap_loc: string_as_cstr_cell!(atom), + heap_loc: heap_loc_as_cell!(heap_loc), } } None => { - self.terms.push(head); - self.terms.push(tail); - self.terms.push(list_loc_as_cell!(term_idx)); + let bytes_written = self.terms.write_with(|section| { + section.push_cell(head); + section.push_cell(tail); + section.push_cell(list_loc_as_cell!(term_idx)); + }); TokenType::Term { - heap_loc: heap_loc_as_cell!(term_idx + 2), + heap_loc: heap_loc_as_cell!( + cell_len + cell_index!(bytes_written) - 1 + ), } } } @@ -747,9 +708,8 @@ impl<'a, R: CharRead> Parser<'a, R> { false } - pub fn reset(&mut self) { - self.stack.clear(); - self.var_locs.clear(); + fn loc_to_err_src(&self) -> ParserErrorSrc { + ParserErrorSrc { line_num: *self.line_num, col_num: *self.col_num } } fn expand_comma_compacted_terms(&mut self, index: usize) -> usize { @@ -764,17 +724,17 @@ impl<'a, R: CharRead> Parser<'a, R> { ); if term.is_ref() && - 0 < op_desc.priority && op_desc.priority < self.stack[index].priority + 0 < op_desc.priority && + op_desc.priority < self.stack[index].priority { /* '|' is a head-tail separator here, not * an operator, so expand the * terms it compacted out again. */ let focus = term.get_value() as usize; - let name_opt = term_name(&self.terms, focus); - let arity = term_arity(&self.terms, focus); + let key_opt = term_predicate_key(&self.terms, focus); - if name_opt == Some(atom!(",")) && arity == 2 { + if key_opt == Some((atom!(","), 2)) { let terms = if op_desc.unfold_bounds == 0 { unfold_by_str(&mut self.terms, term, atom!(",")) } else { @@ -855,8 +815,8 @@ impl<'a, R: CharRead> Parser<'a, R> { if let Some(ref mut td) = self.stack.last_mut() { // parsed an empty list token if td.tt == TokenType::OpenList { - let h = self.terms.len(); - self.terms.push(empty_list_as_cell!()); + let h = self.terms.cell_len(); + self.terms.write_with(|section| section.push_cell(empty_list_as_cell!())); td.spec = TERM; td.tt = TokenType::Term { @@ -886,7 +846,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Some(term) => term, None => { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } }; @@ -902,13 +862,13 @@ impl<'a, R: CharRead> Parser<'a, R> { tail_term }; - if arity > self.terms.len() { + if arity > self.terms.cell_len() { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } - let pre_terms_len = self.terms.len(); + let pre_terms_len = self.terms.cell_len(); while let Some(token_desc) = self.stack.pop() { let subterm = match token_desc.tt { @@ -922,11 +882,13 @@ impl<'a, R: CharRead> Parser<'a, R> { arity -= 1; - let link_cell = list_loc_as_cell!(self.terms.len() + 1); + let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1); - self.terms.push(link_cell); - self.terms.push(subterm); - self.terms.push(tail_term); + self.terms.write_with(|section| { + section.push_cell(link_cell); + section.push_cell(subterm); + section.push_cell(tail_term); + }); tail_term = link_cell; @@ -939,29 +901,22 @@ impl<'a, R: CharRead> Parser<'a, R> { self.stack.truncate(list_start_idx); - let list_loc = self.terms.len() - 3; + let list_loc = self.terms.cell_len() - 3; let head_term = self.terms[list_loc + 1]; let tail_term = self.terms[list_loc + 2]; let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) { - Some((string_buf, Some(tail))) => { + Some((string_buf, tail_opt)) => { self.terms.truncate(pre_terms_len); - let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - - self.terms.push(string_as_pstr_cell!(atom)); - self.terms.push(tail); - self.terms.push(pstr_loc_as_cell!(pre_terms_len)); - - heap_loc_as_cell!(pre_terms_len + 2) - } - Some((string_buf, None)) => { - self.terms.truncate(pre_terms_len); - let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - self.terms.push(string_as_cstr_cell!(atom)); + let bytes_written = self.terms.write_with(|section| { + let pstr_cell = section.push_pstr(&string_buf).unwrap(); + section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!())); + section.push_cell(pstr_cell); + }); - heap_loc_as_cell!(pre_terms_len) + heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1) } None => { heap_loc_as_cell!(list_loc) // head_term @@ -975,22 +930,6 @@ impl<'a, R: CharRead> Parser<'a, R> { unfold_bounds: 0, }); - /* - 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) - } - Ok((string_buf, None)) => { - let atom = AtomTable::build_with(&self.lexer.machine_st.atom_tbl, &string_buf); - Term::CompleteString(Cell::default(), atom) - } - Err(term) => term, - }, - term => term, - }); - */ - Ok(true) } @@ -1001,8 +940,9 @@ impl<'a, R: CharRead> Parser<'a, R> { if let Some(ref mut td) = self.stack.last_mut() { if td.tt == TokenType::OpenCurly { - let h = self.terms.len(); - self.terms.push(atom_as_cell!(atom!("{}"))); + let h = self.terms.cell_len(); + + self.terms.write_with(|section| section.push_cell(atom_as_cell!(atom!("{}")))); td.tt = TokenType::Term { heap_loc: heap_loc_as_cell!(h), @@ -1025,7 +965,7 @@ impl<'a, R: CharRead> Parser<'a, R> { if oc.tt == TokenType::OpenCurly { if let TokenType::Term { heap_loc } = td.tt { - let curly_idx = self.terms.len(); + let curly_idx = self.terms.cell_len(); oc.tt = TokenType::Term { heap_loc: heap_loc_as_cell!(curly_idx + 2), @@ -1033,9 +973,11 @@ impl<'a, R: CharRead> Parser<'a, R> { oc.priority = 0; oc.spec = TERM; - self.terms.push(atom_as_cell!(atom!("{}"), 1)); - self.terms.push(heap_loc); - self.terms.push(str_loc_as_cell!(curly_idx)); + self.terms.write_with(|section| { + section.push_cell(atom_as_cell!(atom!("{}"), 1)); + section.push_cell(heap_loc); + section.push_cell(str_loc_as_cell!(curly_idx)); + }); /* let term = match self.terms.pop() { @@ -1089,8 +1031,6 @@ impl<'a, R: CharRead> Parser<'a, R> { let term = if self.stack[idx].tt.sep_to_atom().is_some() { atom_as_cell!(atom!("|")) - // self.terms - // .push(Term::Literal(Cell::default(), Literal::Atom(atom))); } else { self.term_from_stack(idx).unwrap() }; @@ -1117,7 +1057,7 @@ impl<'a, R: CharRead> Parser<'a, R> { match self .tokens .last() - .ok_or(ParserError::unexpected_eof(self.lexer.loc_to_err_src()))? + .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))? { // do this when layout hasn't been inserted, // ie. why we don't match on Token::Open. @@ -1173,7 +1113,7 @@ impl<'a, R: CharRead> Parser<'a, R> { fn negate_number(&mut self, n: N, negator: Negator, constr: ToLiteral) where Negator: Fn(N, &mut Arena) -> N, - ToLiteral: Fn(N, &mut Arena) -> Literal, + ToLiteral: Fn(N, &mut Arena) -> HeapCellValue, { match self.stack.last().cloned() { Some( @@ -1187,7 +1127,7 @@ impl<'a, R: CharRead> Parser<'a, R> { if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) { self.stack.pop(); - let arena = &mut self.lexer.machine_st.arena; + let arena = &mut self.arena; let literal = constr(negator(n, arena), arena); self.shift(Token::Literal(literal), 0, TERM); @@ -1199,7 +1139,7 @@ impl<'a, R: CharRead> Parser<'a, R> { _ => {} } - let literal = constr(n, &mut self.lexer.machine_st.arena); + let literal = constr(n, &mut self.arena); self.shift(Token::Literal(literal), 0, TERM); } @@ -1217,29 +1157,38 @@ 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)) - } - Token::Literal(Literal::Rational(n)) => { - self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r)) - } - 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_literal(&self.lexer.machine_st.atom_tbl, c); - - if let Some(name) = atomized { - if !self.shift_op(name, op_dir)? { - self.shift(Token::Literal(c), 0, TERM); + match Number::try_from(c) { + Ok(Number::Integer(n)) => { + self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n)) + } + Ok(Number::Rational(n)) => { + self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r)) + } + Ok(Number::Float(n)) => { + use ordered_float::OrderedFloat; + + self.negate_number( + n, + |n, _| -n, + |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)), + ) + } + Ok(Number::Fixnum(n)) => { + self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n)) + } + Err(_) => { + if let Some(name) = c.to_atom() { + if !self.shift_op(name, op_dir)? { + self.shift(Token::Literal(c), 0, TERM); + } + } else { + self.shift(Token::Literal(c), 0, TERM); + } } - } else { - self.shift(Token::Literal(c), 0, TERM); } } Token::Var(v) => self.shift(Token::Var(v), 0, TERM), @@ -1248,7 +1197,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::Close => { if !self.reduce_term() && !self.reduce_brackets() { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } } @@ -1256,7 +1205,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::CloseList => { if !self.reduce_list()? { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } } @@ -1264,7 +1213,7 @@ impl<'a, R: CharRead> Parser<'a, R> { Token::CloseCurly => { if !self.reduce_curly()? { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )); } } @@ -1300,7 +1249,7 @@ impl<'a, R: CharRead> Parser<'a, R> { | Some(TokenType::HeadTailSeparator) | Some(TokenType::Comma) => { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + self.loc_to_err_src(), )) } _ => {} @@ -1309,10 +1258,16 @@ impl<'a, R: CharRead> Parser<'a, R> { Ok(()) } +} +impl<'a, R: CharRead> LexerParser<'a, R> { #[inline] - pub fn lines_read(&self) -> usize { - self.lexer.line_num + pub fn line_num(&self) -> usize { + self.line_num + } + + pub fn loc_to_err_src(&self) -> ParserErrorSrc { + ParserErrorSrc { line_num: self.line_num, col_num: self.col_num } } // on success, returns the parsed term and the number of lines read. @@ -1320,35 +1275,62 @@ impl<'a, R: CharRead> Parser<'a, R> { &mut self, op_dir: &CompositeOpDir, tokens: Tokens, - ) -> Result { - self.tokens = match tokens { - Tokens::Default => read_tokens(&mut self.lexer)?, - Tokens::Provided(tokens) => tokens, + ) -> Result { + let (tokens, term_byte_size) = match tokens { + Tokens::Default => read_tokens(self)?, + Tokens::Provided(tokens, size) => (tokens, size), + }; + + // the parser uses conditional indirection in many places so + // the reserved size should be at least 3 * term_byte_size + // so all cells are accounted for. + let writer = match self.machine_st.heap.reserve(cell_index!(3 * term_byte_size)) { + Ok(term) => term, + Err(_err_loc) => { + return Err(ParserError::ResourceError(self.loc_to_err_src())); + } }; - while let Some(token) = self.tokens.pop() { - self.shift_token(token, op_dir)?; + let before_len = writer.cell_len(); + + let mut parser_impl = Parser { + tokens, + stack: vec![], + terms: writer, + arena: &mut self.machine_st.arena, + flags: self.machine_st.flags, + line_num: &mut self.line_num, + col_num: &mut self.col_num, + var_locs: VarLocs::default(), + inverse_var_locs: InverseVarLocs::default(), + }; + + while let Some(token) = parser_impl.tokens.pop() { + parser_impl.shift_token(token, op_dir)?; } - self.reduce_op(1400); + parser_impl.reduce_op(1400); + + let after_len = parser_impl.terms.cell_len(); + + debug_assert!(after_len - before_len <= cell_index!(4 * term_byte_size)); - if self.stack.len() > 1 || self.terms.is_empty() { + if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() { return Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + parser_impl.loc_to_err_src(), )); } - match self.stack.pop() { + match parser_impl.stack.pop() { Some(TokenDesc { tt: TokenType::Term { heap_loc }, .. - }) => Ok(FocusedHeap { - heap: mem::replace(&mut self.terms, vec![]), + }) => Ok(TermWriteResult { focus: heap_loc.get_value() as usize, - inverse_var_locs: mem::replace(&mut self.inverse_var_locs, InverseVarLocs::default()), + inverse_var_locs: parser_impl.inverse_var_locs, }), _ => Err(ParserError::IncompleteReduction( - self.lexer.loc_to_err_src(), + parser_impl.loc_to_err_src(), )), } } diff --git a/src/read.rs b/src/read.rs index e2fcfa0c..e0b5d7d9 100644 --- a/src/read.rs +++ b/src/read.rs @@ -3,9 +3,10 @@ use crate::parser::parser::*; use crate::atom_table::*; use crate::machine::machine_errors::*; -use crate::machine::machine_state::{MachineState, copy_and_align_iter}; +use crate::machine::machine_state::MachineState; use crate::machine::streams::*; use crate::parser::char_reader::*; +use crate::parser::lexer::LexerParser; #[cfg(feature = "repl")] use crate::repl_helper::Helper; @@ -22,9 +23,9 @@ use std::io::{Error, ErrorKind}; use std::sync::Arc; pub(crate) fn devour_whitespace( - parser: &mut Parser<'_, R>, + lexer: &mut LexerParser<'_, R>, ) -> Result { - 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), @@ -47,35 +48,17 @@ pub(crate) fn error_after_read_term( CompilationError::from(err) } -impl FocusedHeap { - pub fn to_machine_heap(mut self, machine_st: &mut MachineState) -> TermWriteResult { - let heap_len = machine_st.heap.len(); - machine_st.heap.extend(copy_and_align_iter(self.heap.drain(..), 0, heap_len as i64)); - - let mut inverse_var_locs = InverseVarLocs::default(); - - for (var_loc, var_name) in self.inverse_var_locs.drain(..) { - inverse_var_locs.insert(var_loc + heap_len, var_name); - } - - TermWriteResult { - heap_loc: self.focus + heap_len, - inverse_var_locs, - } - } -} - impl MachineState { pub(crate) fn read( &mut self, inner: R, op_dir: &OpDir, - ) -> Result<(FocusedHeap, usize), ParserError> { - let mut parser = Parser::new(inner, self); + ) -> Result<(TermWriteResult, usize), ParserError> { + let mut lexer_parser = LexerParser::new(inner, self); let op_dir = CompositeOpDir::new(op_dir, None); - let term_result = parser.read_term(&op_dir, Tokens::Default); - let lines_read = parser.lines_read(); + let term_result = lexer_parser.read_term(&op_dir, Tokens::Default); + let lines_read = lexer_parser.line_num(); term_result.map(|term| (term, lines_read)) } @@ -96,7 +79,7 @@ impl MachineState { } }; - Ok(term.to_machine_heap(self)) + Ok(term) } } @@ -305,9 +288,3 @@ impl CharRead for ReadlineStream { self.pending_input.put_back_char(c); } } - -#[derive(Debug)] -pub struct TermWriteResult { - pub heap_loc: usize, - pub inverse_var_locs: InverseVarLocs, -} diff --git a/src/repl_helper.rs b/src/repl_helper.rs index afec4fd2..26199c22 100644 --- a/src/repl_helper.rs +++ b/src/repl_helper.rs @@ -6,7 +6,7 @@ use rustyline::{Context, Helper as RlHelper, Result}; use std::sync::Weak; -use crate::atom_table::{AtomString, AtomTable, STATIC_ATOMS_MAP}; +use crate::atom_table::{AtomString, AtomTable}; //, STATIC_ATOMS_MAP}; // TODO: Maybe add validation to the helper pub struct Helper { @@ -74,7 +74,7 @@ impl Completer for Helper { let mut matching = index_set .iter() - .chain(STATIC_ATOMS_MAP.values()) + // .chain(STATIC_ATOMS_MAP.values()) .map(|a| a.as_str()) .filter(|a| a.starts_with(sub_str)) .collect::>(); diff --git a/src/targets.rs b/src/targets.rs index c2d7cde9..bea12f5c 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -5,22 +5,24 @@ use crate::forms::*; use crate::instructions::*; use crate::types::*; +use std::rc::Rc; + pub(crate) struct FactInstruction; pub(crate) struct QueryInstruction; pub(crate) trait CompilationTarget<'a> { - fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction; + fn to_constant(lvl: Level, cell: HeapCellValue, 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, r: RegType) -> Instruction; fn incr_void_instr(instr: &mut Instruction); - fn constant_subterm(literal: Literal) -> Instruction; + fn constant_subterm(literal: HeapCellValue) -> Instruction; fn argument_to_variable(r: RegType, r: usize) -> Instruction; fn argument_to_value(r: RegType, val: usize) -> Instruction; @@ -36,8 +38,8 @@ pub(crate) trait CompilationTarget<'a> { } impl<'a> CompilationTarget<'a> for FactInstruction { - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { - Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg) + fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction { + Instruction::GetConstant(lvl, cell, reg) } fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction { @@ -56,8 +58,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, r: RegType) -> Instruction { + Instruction::GetPartialString(lvl, string, r) } fn incr_void_instr(instr: &mut Instruction) { @@ -66,8 +68,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } } - fn constant_subterm(constant: Literal) -> Instruction { - Instruction::UnifyConstant(HeapCellValue::from(constant)) + fn constant_subterm(constant: HeapCellValue) -> Instruction { + Instruction::UnifyConstant(constant) } fn argument_to_variable(arg: RegType, val: usize) -> Instruction { @@ -104,20 +106,20 @@ impl<'a> CompilationTarget<'a> for FactInstruction { } impl<'a> CompilationTarget<'a> for QueryInstruction { - fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { - Instruction::PutStructure(name, arity, r) + fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction { + Instruction::PutConstant(lvl, constant, reg) } - fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction { - Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg) + fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { + Instruction::PutStructure(name, arity, r) } 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, r: RegType) -> Instruction { + Instruction::PutPartialString(lvl, string, r) } fn to_void(subterms: usize) -> Instruction { @@ -134,8 +136,8 @@ impl<'a> CompilationTarget<'a> for QueryInstruction { } } - fn constant_subterm(constant: Literal) -> Instruction { - Instruction::SetConstant(HeapCellValue::from(constant)) + fn constant_subterm(constant: HeapCellValue) -> Instruction { + Instruction::SetConstant(constant) } fn argument_to_variable(arg: RegType, val: usize) -> Instruction { diff --git a/src/tests/call_with_inference_limit.pl b/src/tests/call_with_inference_limit.pl index 84b78a75..7a093019 100644 --- a/src/tests/call_with_inference_limit.pl +++ b/src/tests/call_with_inference_limit.pl @@ -14,7 +14,7 @@ test_queries_on_call_with_inference_limit :- error, true), \+ call_with_inference_limit(g(X), 5, R), - maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), % TODO this line fails! + maplist(assertz, [g(1), g(2), g(3), g(4), g(5)]), findall([R,X], call_with_inference_limit(g(X), 11, R), [[true, 1], diff --git a/src/types.rs b/src/types.rs index 49ff0a6e..e9caa4a7 100644 --- a/src/types.rs +++ b/src/types.rs @@ -3,8 +3,8 @@ 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::parser::ast::Fixnum; @@ -15,59 +15,64 @@ use std::mem; use std::ops::{Add, Sub, SubAssign}; #[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, + F64 = 0b010101, + Fixnum = 0b011001, + // Char = 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, + F64 = 0b010101, + Fixnum = 0b011001, + Char = 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] @@ -105,9 +110,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,6 +250,7 @@ pub struct HeapCellValue { val: B56, f: bool, m: bool, + #[allow(dead_code)] tag: HeapCellValueTag, } @@ -279,6 +285,7 @@ impl fmt::Debug for HeapCellValue { .field("f", &self.f()) .finish() } + /* HeapCellValueTag::PStr => { let (name, _) = cell_as_atom_cell!(self).get_name_and_arity(); @@ -289,6 +296,7 @@ impl fmt::Debug for HeapCellValue { .field("f", &self.f()) .finish() } + */ tag => f .debug_struct("HeapCellValue") .field("tag", &tag) @@ -354,19 +362,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 (_s, tail_loc) = heap.scan_slice_to_str(h); + self = heap[tail_loc]; continue; } (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => { @@ -379,9 +383,6 @@ impl HeapCellValue { self = cell; continue; } - (HeapCellValueTag::PStrOffset, pstr_offset) => { - heap[pstr_offset].get_tag() == HeapCellValueTag::CStr - } _ => { false } @@ -399,16 +400,13 @@ impl HeapCellValue { | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar | HeapCellValueTag::PStrLoc - | HeapCellValueTag::PStrOffset + // | HeapCellValueTag::PStrOffset ) } #[inline] pub fn as_char(self) -> Option { read_heap_cell!(self, - (HeapCellValueTag::Char, c) => { - Some(c) - } (HeapCellValueTag::Atom, (name, arity)) => { if arity > 0 { return None; @@ -428,9 +426,7 @@ impl HeapCellValue { HeapCellValueTag::Cons | HeapCellValueTag::F64 | 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 +438,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 +494,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 +502,10 @@ impl HeapCellValue { #[inline] pub fn to_atom(self) -> Option { - match self.tag() { - HeapCellValueTag::Atom => Some(Atom::from(self.val() << 3)), - _ => None, - } - } - - #[inline] - pub fn to_pstr(self) -> Option { - 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, } } @@ -593,7 +580,7 @@ impl HeapCellValue { } } - pub fn order_category(self, heap: &[HeapCellValue]) -> Option { + pub fn order_category(self, heap: &Heap) -> Option { match Number::try_from(self).ok() { Some(Number::Integer(_)) | Some(Number::Fixnum(_)) | Some(Number::Rational(_)) => { Some(TermOrderCategory::Integer) @@ -603,13 +590,14 @@ impl HeapCellValue { HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar => { Some(TermOrderCategory::Variable) } - HeapCellValueTag::Char => Some(TermOrderCategory::Atom), + // HeapCellValueTag::Char => Some(TermOrderCategory::Atom), HeapCellValueTag::Atom => Some(if cell_as_atom_cell!(self).get_arity() > 0 { TermOrderCategory::Compound } else { TermOrderCategory::Atom }), - HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr => { + HeapCellValueTag::Lis | HeapCellValueTag::PStrLoc => { + // | HeapCellValueTag::CStr => { Some(TermOrderCategory::Compound) } HeapCellValueTag::Str => { @@ -732,12 +720,14 @@ impl Add 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, } } @@ -750,12 +740,14 @@ impl Sub 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, } } @@ -776,12 +768,14 @@ impl Sub 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 { diff --git a/tests-pl/invalid_decl11.pl b/tests-pl/invalid_decl11.pl index 9d4c6193..d099faff 100644 --- a/tests-pl/invalid_decl11.pl +++ b/tests-pl/invalid_decl11.pl @@ -1 +1 @@ -:- op(10, xf, [example, Var]). \ No newline at end of file +:- op(10, xf, [example, Var]). diff --git a/tests-pl/issue2588.pl b/tests-pl/issue2588.pl index 4e87a39a..dbea342e 100644 --- a/tests-pl/issue2588.pl +++ b/tests-pl/issue2588.pl @@ -2,4 +2,4 @@ test :- load_html("Hello!", Es, []), write(Es). -:- initialization(test). \ No newline at end of file +:- initialization(test).