]> Repositorios git - scryer-prolog.git/commitdiff
flatten the instruction dispatch loop
authorMark Thom <[email protected]>
Mon, 20 Dec 2021 01:57:57 +0000 (18:57 -0700)
committerMark Thom <[email protected]>
Fri, 7 Jan 2022 05:09:36 +0000 (22:09 -0700)
52 files changed:
Cargo.lock
Cargo.toml
build.rs
crates/instructions-template/Cargo.lock [new file with mode: 0644]
crates/instructions-template/Cargo.toml [new file with mode: 0644]
crates/instructions-template/src/lib.rs [new file with mode: 0644]
crates/prolog_parser/Cargo.toml [deleted file]
crates/static-string-indexing/Cargo.toml
crates/to-syn-value/Cargo.toml [new file with mode: 0644]
crates/to-syn-value/src/lib.rs [new file with mode: 0644]
crates/to-syn-value_derive/Cargo.toml [new file with mode: 0644]
crates/to-syn-value_derive/src/lib.rs [new file with mode: 0644]
src/allocator.rs
src/arithmetic.rs
src/clause_types.rs [deleted file]
src/codegen.rs
src/debray_allocator.rs
src/fixtures.rs
src/forms.rs
src/heap_print.rs
src/instructions.rs [deleted file]
src/iterators.rs
src/lib.rs
src/lib/between.pl
src/lib/builtins.pl
src/lib/lists.pl
src/loader.pl
src/machine/arithmetic_ops.rs
src/machine/attributed_variables.rs
src/machine/code_repo.rs [deleted file]
src/machine/code_walker.rs
src/machine/compile.rs
src/machine/dispatch.rs
src/machine/gc.rs
src/machine/heap.rs
src/machine/load_state.rs
src/machine/loader.rs
src/machine/machine_errors.rs
src/machine/machine_indices.rs
src/machine/machine_state.rs
src/machine/machine_state_impl.rs
src/machine/mock_wam.rs
src/machine/mod.rs
src/machine/preprocessor.rs
src/machine/stack.rs
src/machine/system_calls.rs
src/macros.rs
src/parser/ast.rs
src/read.rs
src/targets.rs
src/toplevel.pl
src/write.rs

index 7818a0a4f75ac07de5d3a5c7dc6ef2a59fc4dca0..4d699f115f6e257af98290249ec772d5455eb12f 100644 (file)
@@ -378,6 +378,15 @@ dependencies = [
  "new_debug_unreachable",
 ]
 
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
 [[package]]
 name = "generic-array"
 version = "0.12.4"
@@ -436,6 +445,15 @@ version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
 [[package]]
 name = "hostname"
 version = "0.3.1"
@@ -471,6 +489,20 @@ dependencies = [
  "hashbrown",
 ]
 
+[[package]]
+name = "instructions-template"
+version = "0.1.0"
+dependencies = [
+ "indexmap",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "strum",
+ "strum_macros",
+ "syn 1.0.81",
+ "to-syn-value",
+ "to-syn-value_derive",
+]
+
 [[package]]
 name = "iovec"
 version = "0.1.4"
@@ -1325,6 +1357,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "rustversion"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+
 [[package]]
 name = "rustyline"
 version = "9.0.0"
@@ -1392,9 +1430,11 @@ dependencies = [
  "crossterm",
  "dirs-next",
  "divrem",
+ "fxhash",
  "git-version",
  "hostname",
  "indexmap",
+ "instructions-template",
  "lazy_static",
  "lexical",
  "libc",
@@ -1655,6 +1695,25 @@ version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
 
+[[package]]
+name = "strum"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
+
+[[package]]
+name = "strum_macros"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
+dependencies = [
+ "heck",
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "rustversion",
+ "syn 1.0.81",
+]
+
 [[package]]
 name = "subtle"
 version = "1.0.0"
@@ -1724,6 +1783,23 @@ dependencies = [
  "winapi 0.3.9",
 ]
 
+[[package]]
+name = "to-syn-value"
+version = "0.1.0"
+dependencies = [
+ "syn 1.0.81",
+ "to-syn-value_derive",
+]
+
+[[package]]
+name = "to-syn-value_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2 1.0.32",
+ "quote 1.0.10",
+ "syn 1.0.81",
+]
+
 [[package]]
 name = "typenum"
 version = "1.14.0"
index d0a332fba319806d9e243a120db39e4a1e4b6e8f..8e81a947f99d13054d8023ffe7f534e775416aa9 100644 (file)
@@ -12,7 +12,11 @@ categories = ["command-line-utilities"]
 build = "build.rs"
 
 [workspace]
-members = ["crates/num-rug-adapter", "crates/static-string-indexing"]
+members = ["crates/num-rug-adapter",
+           "crates/static-string-indexing",
+           "crates/instructions-template",
+           "crates/to-syn-value",
+           "crates/to-syn-value_derive"]
 
 [features]
 num = ["num-rug-adapter"]
@@ -24,6 +28,7 @@ default = ["rug"]
 [build-dependencies]
 indexmap = "1.0.2"
 static-string-indexing = { path = "./crates/static-string-indexing" }
+instructions-template = { path = "./crates/instructions-template" }
 proc-macro2 = "*"
 
 [dependencies]
@@ -31,13 +36,13 @@ cpu-time = "1.0.0"
 crossterm = "0.16.0"
 dirs-next = "2.0.0"
 divrem = "0.1.0"
+fxhash = "0.2.1"
 git-version = "0.3.4"
 hostname = "0.3.1"
 indexmap = "1.0.2"
 lazy_static = "1.4.0"
 lexical = "5.2.2"
 libc = "0.2.62"
-# temporary to remove unnecessary braces warnings.
 modular-bitfield = { git = "https://github.com/mthom/modular-bitfield" } # modular-bitfield = "0.11.2"
 nix = "0.15.0"
 num-rug-adapter = { optional = true, path = "./crates/num-rug-adapter" }
index 88267cdc5b7d99e1dd39cad486eef7831c95ddf1..6c31576926ad19176e53d0e26e7cff4216618479 100644 (file)
--- a/build.rs
+++ b/build.rs
@@ -1,4 +1,5 @@
 use static_string_indexing::index_static_strings;
+use instructions_template::generate_instructions_rs;
 
 use std::env;
 use std::fs;
@@ -55,6 +56,20 @@ fn main() {
     find_prolog_files(&mut libraries, "", &lib_path);
     libraries.write_all(b"\n        m\n    };\n}\n").unwrap();
 
+    let instructions_path = Path::new("src/instructions.rs");
+    let mut instructions_file = File::create(&instructions_path).unwrap();
+
+    let quoted_output = generate_instructions_rs();
+
+    instructions_file
+        .write_all(quoted_output.to_string().as_bytes())
+        .unwrap();
+
+    Command::new("rustfmt")
+        .arg(instructions_path.as_os_str())
+        .spawn().unwrap()
+        .wait().unwrap();
+
     let static_atoms_path = Path::new("src/static_atoms.rs");
     let mut static_atoms_file = File::create(&static_atoms_path).unwrap();
 
diff --git a/crates/instructions-template/Cargo.lock b/crates/instructions-template/Cargo.lock
new file mode 100644 (file)
index 0000000..08be8ba
--- /dev/null
@@ -0,0 +1,129 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "instructions-template"
+version = "0.1.0"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "strum",
+ "strum_macros",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "392a54546fda6b7cc663379d0e6ce8b324cf88aecc5a499838e1be9781bdce2e"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
+
+[[package]]
+name = "strum"
+version = "0.23.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
+
+[[package]]
+name = "strum_macros"
+version = "0.23.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.84"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "to-syn-value"
+version = "0.1.0"
+dependencies = [
+ "syn",
+ "to-syn-value_derive",
+]
+
+[[package]]
+name = "to-syn-value_derive"
+version = "0.1.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
diff --git a/crates/instructions-template/Cargo.toml b/crates/instructions-template/Cargo.toml
new file mode 100644 (file)
index 0000000..92f130e
--- /dev/null
@@ -0,0 +1,14 @@
+[package]
+name = "instructions-template"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+indexmap = "*"
+proc-macro2 = "*"
+quote = "*"
+strum = "0.23"
+strum_macros = "0.23"
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+to-syn-value = { path = "../to-syn-value" }
+to-syn-value_derive = { path = "../to-syn-value_derive" }
\ No newline at end of file
diff --git a/crates/instructions-template/src/lib.rs b/crates/instructions-template/src/lib.rs
new file mode 100644 (file)
index 0000000..386bafd
--- /dev/null
@@ -0,0 +1,3286 @@
+// use crate::atom_table::*;
+// use crate::machine::machine_indices::*;
+// use crate::types::*;
+//
+
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens, TokenStreamExt};
+use strum_macros::{EnumDiscriminants, EnumProperty, EnumString};
+use syn::*;
+use to_syn_value_derive::ToDeriveInput;
+
+/*
+ * This crate exists to generate the Instruction enum in
+ * src/instructions.rs and its adjoining impl functions. The types
+ * defined in it are empty and serve only as schema for the generation
+ * of Instruction. They mimick most of the structure of the previous
+ * Line instruction type. The strum crate is used to provide reflection
+ * on each of the node types to the tree walker.
+ */
+
+use std::any::*;
+use std::str::FromStr;
+
+struct ArithmeticTerm;
+struct Atom;
+struct CodeIndex;
+struct Death;
+struct HeapCellValue;
+struct IndexingLine;
+struct Level;
+struct NextOrFail;
+struct RegType;
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum CompareNumber {
+    #[strum_discriminants(strum(props(Arity = "2", Name = ">")))]
+    NumberGreaterThan(ArithmeticTerm, ArithmeticTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "<")))]
+    NumberLessThan(ArithmeticTerm, ArithmeticTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = ">=")))]
+    NumberGreaterThanOrEqual(ArithmeticTerm, ArithmeticTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "=<")))]
+    NumberLessThanOrEqual(ArithmeticTerm, ArithmeticTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "=\\=")))]
+    NumberNotEqual(ArithmeticTerm, ArithmeticTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "=:=")))]
+    NumberEqual(ArithmeticTerm, ArithmeticTerm),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum CompareTerm {
+    #[strum_discriminants(strum(props(Arity = "2", Name = "@<")))]
+    TermLessThan,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "@=<")))]
+    TermLessThanOrEqual,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "@>=")))]
+    TermGreaterThanOrEqual,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "@>")))]
+    TermGreaterThan,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "==")))]
+    TermEqual,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "\\==")))]
+    TermNotEqual,
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum ClauseType {
+    BuiltIn(BuiltInClauseType),
+    #[strum_discriminants(strum(props(Arity = "arity", Name = "$call")))]
+    CallN(usize),
+    Inlined(InlinedClauseType),
+    #[strum_discriminants(strum(props(Arity = "arity", Name = "call_named")))]
+    Named(usize, Atom, CodeIndex), // name, arity, index.
+    System(SystemClauseType),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum BuiltInClauseType {
+    #[strum_discriminants(strum(props(Arity = "1", Name = "acyclic_term")))]
+    AcyclicTerm,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "arg")))]
+    Arg,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "compare")))]
+    Compare,
+    CompareTerm(CompareTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "copy_term")))]
+    CopyTerm,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "functor")))]
+    Functor,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "ground")))]
+    Ground,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "is")))]
+    Is(RegType, ArithmeticTerm),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "keysort")))]
+    KeySort,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "read")))]
+    Read,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "sort")))]
+    Sort,
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum InlinedClauseType {
+    CompareNumber(CompareNumber),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "atom")))]
+    IsAtom(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "atomic")))]
+    IsAtomic(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "compound")))]
+    IsCompound(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "integer")))]
+    IsInteger(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "number")))]
+    IsNumber(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "rational")))]
+    IsRational(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "float")))]
+    IsFloat(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "nonvar")))]
+    IsNonVar(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "var")))]
+    IsVar(RegType),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum REPLCodePtr {
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$add_discontiguous_predicate")))]
+    AddDiscontiguousPredicate,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$add_dynamic_predicate")))]
+    AddDynamicPredicate,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$add_multifile_predicate")))]
+    AddMultifilePredicate,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$add_goal_expansion_clause")))]
+    AddGoalExpansionClause,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$add_term_expansion_clause")))]
+    AddTermExpansionClause,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$add_in_situ_filename_module")))]
+    AddInSituFilenameModule,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$clause_to_evacuable")))]
+    ClauseToEvacuable,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$scoped_clause_to_evacuable")))]
+    ScopedClauseToEvacuable,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$conclude_load")))]
+    ConcludeLoad,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$declare_module")))]
+    DeclareModule,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$load_compiled_library")))]
+    LoadCompiledLibrary,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_source")))]
+    LoadContextSource,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_file")))]
+    LoadContextFile,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_dir")))]
+    LoadContextDirectory,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_module")))]
+    LoadContextModule,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$prolog_lc_stream")))]
+    LoadContextStream,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$pop_load_context")))]
+    PopLoadContext,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$pop_load_state_payload")))]
+    PopLoadStatePayload,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$push_load_state_payload")))]
+    PushLoadStatePayload,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$push_load_context")))]
+    PushLoadContext,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$use_module")))]
+    UseModule,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$built_in_property")))]
+    BuiltInProperty,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$meta_predicate_property")))]
+    MetaPredicateProperty,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$multifile_property")))]
+    MultifileProperty,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$discontiguous_property")))]
+    DiscontiguousProperty,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$dynamic_property")))]
+    DynamicProperty,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
+    AbolishClause,
+    #[strum_discriminants(strum(props(Arity = "5", Name = "$asserta")))]
+    Asserta,
+    #[strum_discriminants(strum(props(Arity = "5", Name = "$assertz")))]
+    Assertz,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
+    Retract,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$is_consistent_with_term_queue")))]
+    IsConsistentWithTermQueue,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$flush_term_queue")))]
+    FlushTermQueue,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$remove_module_exports")))]
+    RemoveModuleExports,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$add_non_counted_backtracking")))]
+    AddNonCountedBacktracking,
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum SystemClauseType {
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_chars")))]
+    AtomChars,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_codes")))]
+    AtomCodes,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$atom_length")))]
+    AtomLength,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$bind_from_register")))]
+    BindFromRegister,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$call_continuation")))]
+    CallContinuation,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$char_code")))]
+    CharCode,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$char_type")))]
+    CharType,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$chars_to_number")))]
+    CharsToNumber,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$codes_to_number")))]
+    CodesToNumber,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_term_without_attr_vars")))]
+    CopyTermWithoutAttrVars,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$check_cp")))]
+    CheckCutPoint,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$close")))]
+    Close,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$copy_to_lh")))]
+    CopyToLiftedHeap,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$create_partial_string")))]
+    CreatePartialString,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$current_hostname")))]
+    CurrentHostname,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$current_input")))]
+    CurrentInput,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$current_output")))]
+    CurrentOutput,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$directory_files")))]
+    DirectoryFiles,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$file_size")))]
+    FileSize,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$file_exists")))]
+    FileExists,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$directory_exists")))]
+    DirectoryExists,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$directory_separator")))]
+    DirectorySeparator,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$make_directory")))]
+    MakeDirectory,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$make_directory_path")))]
+    MakeDirectoryPath,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_file")))]
+    DeleteFile,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$rename_file")))]
+    RenameFile,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "working_directory")))]
+    WorkingDirectory,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_directory")))]
+    DeleteDirectory,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$path_canonical")))]
+    PathCanonical,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$file_time")))]
+    FileTime,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_non_head")))]
+    DeleteAttribute,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$del_attr_head")))]
+    DeleteHeadAttribute,
+    #[strum_discriminants(strum(props(Arity = "arity", Name = "$module_call")))]
+    DynamicModuleResolution(usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$enqueue_attr_var")))]
+    EnqueueAttributedVar,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$fetch_global_var")))]
+    FetchGlobalVar,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$first_stream")))]
+    FirstStream,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$flush_output")))]
+    FlushOutput,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_byte")))]
+    GetByte,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_char")))]
+    GetChar,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$get_n_chars")))]
+    GetNChars,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_code")))]
+    GetCode,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_single_char")))]
+    GetSingleChar,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$reset_attr_var_state")))]
+    ResetAttrVarState,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$truncate_if_no_lh_growth_diff")))]
+    TruncateIfNoLiftedHeapGrowthDiff,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$truncate_if_no_lh_growth")))]
+    TruncateIfNoLiftedHeapGrowth,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_attr_list")))]
+    GetAttributedVariableList,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_attr_var_queue_delim")))]
+    GetAttrVarQueueDelimiter,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_attr_var_queue_beyond")))]
+    GetAttrVarQueueBeyond,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_b_value")))]
+    GetBValue,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$get_cont_chunk")))]
+    GetContinuationChunk,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$get_next_db_ref")))]
+    GetNextDBRef,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$get_next_op_db_ref")))]
+    GetNextOpDBRef,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$is_partial_string")))]
+    IsPartialString,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$halt")))]
+    Halt,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$get_lh_from_offset")))]
+    GetLiftedHeapFromOffset,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$get_lh_from_offset_diff")))]
+    GetLiftedHeapFromOffsetDiff,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_scc_cleaner")))]
+    GetSCCCleaner,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$head_is_dynamic")))]
+    HeadIsDynamic,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$install_scc_cleaner")))]
+    InstallSCCCleaner,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$install_inference_counter")))]
+    InstallInferenceCounter,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$lh_length")))]
+    LiftedHeapLength,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$load_library_as_stream")))]
+    LoadLibraryAsStream,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$module_exists")))]
+    ModuleExists,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$nextEP")))]
+    NextEP,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$no_such_predicate")))]
+    NoSuchPredicate,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$number_to_chars")))]
+    NumberToChars,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$number_to_codes")))]
+    NumberToCodes,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$op")))]
+    OpDeclaration,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$open")))]
+    Open,
+    #[strum_discriminants(strum(props(Arity = "5", Name = "$set_stream_options")))]
+    SetStreamOptions,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$next_stream")))]
+    NextStream,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$partial_string_tail")))]
+    PartialStringTail,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_byte")))]
+    PeekByte,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_char")))]
+    PeekChar,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$peek_code")))]
+    PeekCode,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$points_to_cont_reset_marker")))]
+    PointsToContinuationResetMarker,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$put_byte")))]
+    PutByte,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$put_char")))]
+    PutChar,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$put_chars")))]
+    PutChars,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$put_code")))]
+    PutCode,
+    #[strum_discriminants(strum(props(Arity = "5", Name = "$read_query_term")))]
+    ReadQueryTerm,
+    #[strum_discriminants(strum(props(Arity = "5", Name = "$read_term")))]
+    ReadTerm,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$redo_attr_var_binding")))]
+    RedoAttrVarBinding,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$remove_call_policy_check")))]
+    RemoveCallPolicyCheck,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$remove_inference_counter")))]
+    RemoveInferenceCounter,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$reset_cont_marker")))]
+    ResetContinuationMarker,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$restore_cut_policy")))]
+    RestoreCutPolicy,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp")))]
+    SetCutPoint(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_input")))]
+    SetInput,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_output")))]
+    SetOutput,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$store_backtrackable_global_var")))]
+    StoreBacktrackableGlobalVar,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$store_global_var")))]
+    StoreGlobalVar,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$stream_property")))]
+    StreamProperty,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$set_stream_position")))]
+    SetStreamPosition,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$inference_level")))]
+    InferenceLevel,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$clean_up_block")))]
+    CleanUpBlock,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$erase_ball")))]
+    EraseBall,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$fail")))]
+    Fail,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_ball")))]
+    GetBall,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_current_block")))]
+    GetCurrentBlock,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_cp")))]
+    GetCutPoint,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_staggered_cp")))]
+    GetStaggeredCutPoint,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$get_double_quotes")))]
+    GetDoubleQuotes,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$install_new_block")))]
+    InstallNewBlock,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$maybe")))]
+    Maybe,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$current_time")))]
+    CurrentTime,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$quoted_token")))]
+    QuotedToken,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$read_term_from_chars")))]
+    ReadTermFromChars,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$reset_block")))]
+    ResetBlock,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$return_from_verify_attr")))]
+    ReturnFromVerifyAttr,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_ball")))]
+    SetBall,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_cp_by_default")))]
+    SetCutPointByDefault(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_double_quotes")))]
+    SetDoubleQuotes,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$set_seed")))]
+    SetSeed,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$skip_max_list")))]
+    SkipMaxList,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$sleep")))]
+    Sleep,
+    #[strum_discriminants(strum(props(Arity = "8", Name = "$socket_client_open")))]
+    SocketClientOpen,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$socket_server_open")))]
+    SocketServerOpen,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$socket_server_accept")))]
+    SocketServerAccept,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$socket_server_close")))]
+    SocketServerClose,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$tls_accept_client")))]
+    TLSAcceptClient,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$tls_client_connect")))]
+    TLSClientConnect,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$succeed")))]
+    Succeed,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$term_attributed_variables")))]
+    TermAttributedVariables,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$term_variables")))]
+    TermVariables,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$term_variables_under_max_depth")))]
+    TermVariablesUnderMaxDepth,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$truncate_lh_to")))]
+    TruncateLiftedHeapTo,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$unify_with_occurs_check")))]
+    UnifyWithOccursCheck,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$unwind_environments")))]
+    UnwindEnvironments,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$unwind_stack")))]
+    UnwindStack,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$wam_instructions")))]
+    WAMInstructions,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$write_term")))]
+    WriteTerm,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$write_term_to_chars")))]
+    WriteTermToChars,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$scryer_prolog_version")))]
+    ScryerPrologVersion,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$crypto_random_byte")))]
+    CryptoRandomByte,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_data_hash")))]
+    CryptoDataHash,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_hkdf")))]
+    CryptoDataHKDF,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$crypto_password_hash")))]
+    CryptoPasswordHash,
+    #[strum_discriminants(strum(props(Arity = "7", Name = "$crypto_data_encrypt")))]
+    CryptoDataEncrypt,
+    #[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
+    CryptoDataDecrypt,
+    #[strum_discriminants(strum(props(Arity = "5", Name = "$crypto_curve_scalar_mult")))]
+    CryptoCurveScalarMult,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
+    Ed25519Sign,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
+    Ed25519Verify,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
+    Ed25519NewKeyPair,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
+    Ed25519KeyPairPublicKey,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$curve25519_scalar_mult")))]
+    Curve25519ScalarMult,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
+    FirstNonOctet,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
+    LoadHTML,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "$load_xml")))]
+    LoadXML,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$getenv")))]
+    GetEnv,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$setenv")))]
+    SetEnv,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$unsetenv")))]
+    UnsetEnv,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$shell")))]
+    Shell,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$pid")))]
+    PID,
+    #[strum_discriminants(strum(props(Arity = "4", Name = "$chars_base64")))]
+    CharsBase64,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$devour_whitespace")))]
+    DevourWhitespace,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$is_sto_enabled")))]
+    IsSTOEnabled,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$set_sto_as_unify")))]
+    SetSTOAsUnify,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$set_nsto_as_unify")))]
+    SetNSTOAsUnify,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$set_sto_with_error_as_unify")))]
+    SetSTOWithErrorAsUnify,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$home_directory")))]
+    HomeDirectory,
+    #[strum_discriminants(strum(props(Arity = "0", Name = "$debug_hook")))]
+    DebugHook,
+    #[strum_discriminants(strum(props(Arity = "2", Name = "$popcount")))]
+    PopCount,
+    #[strum_discriminants(strum(props(Arity = "1", Name = "$cpu_now")))]
+    CpuNow,
+    REPL(REPLCodePtr),
+}
+
+#[allow(dead_code)]
+#[derive(ToDeriveInput, EnumDiscriminants)]
+#[strum_discriminants(derive(EnumProperty, EnumString))]
+enum InstructionTemplate {
+    #[strum_discriminants(strum(props(Arity = "3", Name = "get_constant")))]
+    GetConstant(Level, HeapCellValue, RegType),
+    #[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),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "get_structure")))]
+    GetStructure(Atom, usize, RegType),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "get_variable")))]
+    GetVariable(RegType, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "get_value")))]
+    GetValue(RegType, usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "unify_constant")))]
+    UnifyConstant(HeapCellValue),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "unify_local_value")))]
+    UnifyLocalValue(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "unify_variable")))]
+    UnifyVariable(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "unify_value")))]
+    UnifyValue(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "unify_void")))]
+    UnifyVoid(usize),
+    // query instruction
+    #[strum_discriminants(strum(props(Arity = "3", Name = "put_constant")))]
+    PutConstant(Level, HeapCellValue, RegType),
+    #[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),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "put_structure")))]
+    PutStructure(Atom, usize, RegType),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "put_unsafe_value")))]
+    PutUnsafeValue(usize, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "put_value")))]
+    PutValue(RegType, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "put_variable")))]
+    PutVariable(RegType, usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "set_constant")))]
+    SetConstant(HeapCellValue),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "set_local_value")))]
+    SetLocalValue(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "set_variable")))]
+    SetVariable(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "set_value")))]
+    SetValue(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "set_void")))]
+    SetVoid(usize),
+    // cut instruction
+    #[strum_discriminants(strum(props(Arity = "1", Name = "cut")))]
+    Cut(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "get_level")))]
+    GetLevel(RegType),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "get_level_and_unify")))]
+    GetLevelAndUnify(RegType),
+    #[strum_discriminants(strum(props(Arity = "0", Name = "neck_cut")))]
+    NeckCut,
+    // choice instruction
+    #[strum_discriminants(strum(props(Arity = "3", Name = "dynamic_else")))]
+    DynamicElse(usize, Death, NextOrFail),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "dynamic_internal_else")))]
+    DynamicInternalElse(usize, Death, NextOrFail),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "default_retry_me_else")))]
+    DefaultRetryMeElse(usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))]
+    DefaultTrustMe(usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "retry_me_else")))]
+    RetryMeElse(usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "trust_me")))]
+    TrustMe(usize),
+    #[strum_discriminants(strum(props(Arity = "1", Name = "default_trust_me")))]
+    TryMeElse(usize),
+    // arithmetic instruction
+    #[strum_discriminants(strum(props(Arity = "3", Name = "add")))]
+    Add(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "sub")))]
+    Sub(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "mul")))]
+    Mul(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "pow")))]
+    Pow(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "int_pow")))]
+    IntPow(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "i_div")))]
+    IDiv(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "max")))]
+    Max(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "min")))]
+    Min(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "int_floor_div")))]
+    IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "r_div")))]
+    RDiv(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "div")))]
+    Div(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "shl")))]
+    Shl(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "shr")))]
+    Shr(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "xor")))]
+    Xor(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "and")))]
+    And(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "or")))]
+    Or(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "mod")))]
+    Mod(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "rem")))]
+    Rem(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "gcd")))]
+    Gcd(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "sign")))]
+    Sign(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "cos")))]
+    Cos(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "sin")))]
+    Sin(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "tan")))]
+    Tan(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "log")))]
+    Log(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "exp")))]
+    Exp(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "acos")))]
+    ACos(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "asin")))]
+    ASin(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "atan")))]
+    ATan(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "3", Name = "atan2")))]
+    ATan2(ArithmeticTerm, ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "sqrt")))]
+    Sqrt(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "abs")))]
+    Abs(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "float")))]
+    Float(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "truncate")))]
+    Truncate(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "round")))]
+    Round(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "ceiling")))]
+    Ceiling(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "floor")))]
+    Floor(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "neg")))]
+    Neg(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "plus")))]
+    Plus(ArithmeticTerm, usize),
+    #[strum_discriminants(strum(props(Arity = "2", Name = "bitwise_complement")))]
+    BitwiseComplement(ArithmeticTerm, usize),
+    // control instructions
+    #[strum_discriminants(strum(props(Arity = "1", Name = "allocate")))]
+    Allocate(usize), // num_frames.
+    #[strum_discriminants(strum(props(Arity = "0", Name = "deallocate")))]
+    Deallocate,
+    #[strum_discriminants(strum(props(Arity = "3", Name = "jmp_by_call")))]
+    JmpByCall(usize, usize), // arity, relative offset.
+    #[strum_discriminants(strum(props(Arity = "3", Name = "jmp_by_execute")))]
+    JmpByExecute(usize, usize), // arity, relative offset.
+    #[strum_discriminants(strum(props(Arity = "1", Name = "rev_jmp_by")))]
+    RevJmpBy(usize),
+    #[strum_discriminants(strum(props(Arity = "0", Name = "proceed")))]
+    Proceed,
+    // indexing.
+    #[strum_discriminants(strum(props(Arity = "1", Name = "indexing_code")))]
+    IndexingCode(Vec<IndexingLine>),
+    // break from loop instruction.
+    #[strum_discriminants(strum(props(Arity = "0", Name = "break_from_dispatch")))]
+    BreakFromDispatchLoop,
+    // swap the verify attr interrupt instruction with the next control instruction.
+    #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))]
+    InstallVerifyAttr,
+    // call verify_attrs.
+    #[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))]
+    VerifyAttrInterrupt,
+    // procedures
+    CallClause(ClauseType, usize, usize, bool, bool), // ClauseType,
+                                                      // arity,
+                                                      // perm_vars,
+                                                      // last_call,
+                                                      // use_default_call_policy.
+}
+
+fn derive_input(ty: &Type) -> Option<DeriveInput> {
+    let clause_type: Type = parse_quote!{ ClauseType };
+    let built_in_clause_type: Type = parse_quote! { BuiltInClauseType };
+    let inlined_clause_type: Type = parse_quote! { InlinedClauseType };
+    let system_clause_type: Type = parse_quote! { SystemClauseType };
+    let compare_term_type: Type = parse_quote! { CompareTerm };
+    let compare_number_type: Type = parse_quote! { CompareNumber };
+    let repl_code_ptr_type: Type = parse_quote! { REPLCodePtr };
+
+    if ty == &clause_type {
+        Some(ClauseType::to_derive_input())
+    } else if ty == &built_in_clause_type {
+        Some(BuiltInClauseType::to_derive_input())
+    } else if ty == &inlined_clause_type {
+        Some(InlinedClauseType::to_derive_input())
+    } else if ty == &system_clause_type {
+        Some(SystemClauseType::to_derive_input())
+    } else if ty == &compare_number_type {
+        Some(CompareNumber::to_derive_input())
+    } else if ty == &compare_term_type {
+        Some(CompareTerm::to_derive_input())
+    } else if ty == &repl_code_ptr_type {
+        Some(REPLCodePtr::to_derive_input())
+    } else {
+        None
+    }
+}
+
+impl ToTokens for Arity {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        match self {
+            Arity::Static(arity) => {
+                arity.to_tokens(tokens);
+            }
+            Arity::Ident(arity) => {
+                let ident = format_ident!("{}", arity);
+                tokens.append(ident);
+            }
+        }
+    }
+}
+
+fn add_discriminant_data<DiscriminantT>(
+    variant: &Variant,
+    prefix: &'static str,
+    variant_data: &mut Vec<(&'static str, Arity, Variant)>,
+) -> (&'static str, Arity)
+    where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug
+{
+    let name = prop_from_ident::<DiscriminantT>(&variant.ident, "Name");
+    let arity = Arity::from(prop_from_ident::<DiscriminantT>(&variant.ident, "Arity"));
+
+    if prefix == "Call" {
+        let mut variant = variant.clone();
+        variant.attrs.clear();
+
+        variant_data.push((name, arity, variant));
+    }
+
+    (name, arity)
+}
+
+fn generate_instruction_preface() -> TokenStream {
+    quote! {
+        use crate::arena::*;
+        use crate::arithmetic::*;
+        use crate::atom_table::*;
+        use crate::forms::*;
+        use crate::machine::heap::*;
+        use crate::machine::machine_errors::MachineStub;
+        use crate::machine::machine_indices::CodeIndex;
+        use crate::parser::ast::*;
+        use crate::types::*;
+
+        use indexmap::IndexMap;
+        use slice_deque::SliceDeque;
+
+        fn reg_type_into_functor(r: RegType) -> MachineStub {
+            match r {
+                RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]),
+                RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]),
+            }
+        }
+
+        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"))]),
+                }
+            }
+        }
+
+        impl ArithmeticTerm {
+            fn into_functor(&self, arena: &mut Arena) -> MachineStub {
+                match self {
+                    &ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
+                    &ArithmeticTerm::Interm(i) => {
+                        functor!(atom!("intermediate"), [fixnum(i)])
+                    }
+                    &ArithmeticTerm::Number(n) => {
+                        vec![HeapCellValue::from((n, arena))]
+                    }
+                }
+            }
+        }
+
+        #[derive(Debug, Clone, Copy)]
+        pub enum NextOrFail {
+            Next(usize),
+            Fail(usize),
+        }
+
+        impl Default for NextOrFail {
+            fn default() -> Self {
+                NextOrFail::Fail(0)
+            }
+        }
+
+        impl NextOrFail {
+            #[inline]
+            pub fn is_next(&self) -> bool {
+                if let NextOrFail::Next(_) = self {
+                    true
+                } else {
+                    false
+                }
+            }
+        }
+
+        #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+        pub enum Death {
+            Finite(usize),
+            Infinity,
+        }
+
+        impl Default for Death {
+            fn default() -> Self {
+                Death::Infinity
+            }
+        }
+
+        #[derive(Clone, Copy, Debug)]
+        pub enum IndexedChoiceInstruction {
+            Retry(usize),
+            Trust(usize),
+            Try(usize),
+        }
+
+        impl IndexedChoiceInstruction {
+            pub(crate) fn offset(&self) -> usize {
+                match self {
+                    &IndexedChoiceInstruction::Retry(offset) => offset,
+                    &IndexedChoiceInstruction::Trust(offset) => offset,
+                    &IndexedChoiceInstruction::Try(offset) => offset,
+                }
+            }
+
+            pub(crate) fn to_functor(&self) -> MachineStub {
+                match self {
+                    &IndexedChoiceInstruction::Try(offset) => {
+                        functor!(atom!("try"), [fixnum(offset)])
+                    }
+                    &IndexedChoiceInstruction::Trust(offset) => {
+                        functor!(atom!("trust"), [fixnum(offset)])
+                    }
+                    &IndexedChoiceInstruction::Retry(offset) => {
+                        functor!(atom!("retry"), [fixnum(offset)])
+                    }
+                }
+            }
+        }
+
+        /// `IndexingInstruction` cf. page 110 of wambook.
+        #[derive(Clone, Debug)]
+        pub enum IndexingInstruction {
+            // The first index is the optimal argument being indexed.
+            SwitchOnTerm(
+                usize,
+                IndexingCodePtr,
+                IndexingCodePtr,
+                IndexingCodePtr,
+                IndexingCodePtr,
+            ),
+            SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>),
+            SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>),
+        }
+
+        #[derive(Debug, Clone, Copy)]
+        pub enum IndexingCodePtr {
+            External(usize),        // the index points past the indexing instruction prelude.
+            DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
+            Fail,
+            Internal(usize), // the index points into the indexing instruction prelude.
+        }
+
+        impl IndexingCodePtr {
+            #[allow(dead_code)]
+            pub fn to_functor(self) -> MachineStub {
+                match self {
+                    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"))]
+                    },
+                }
+            }
+        }
+
+        impl IndexingInstruction {
+            pub fn to_functor(&self, mut h: usize) -> 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)
+                            ]
+                        )
+                    }
+                    &IndexingInstruction::SwitchOnConstant(ref constants) => {
+                        let mut key_value_list_stub = vec![];
+                        let orig_h = h;
+
+                        h += 2; // skip the 2-cell "switch_on_constant" functor.
+
+                        for (c, ptr) in constants.iter() {
+                            let key_value_pair = functor!(
+                                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]
+                        )
+                    }
+                    &IndexingInstruction::SwitchOnStructure(ref structures) => {
+                        let mut key_value_list_stub = vec![];
+                        let orig_h = h;
+
+                        h += 2; // skip the 2-cell "switch_on_constant" functor.
+
+                        for ((name, arity), ptr) in structures.iter() {
+                            let predicate_indicator_stub = functor!(
+                                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!(
+                            atom!("switch_on_structure"),
+                            [str(orig_h, 0)],
+                            [key_value_list_stub]
+                        )
+                    }
+                }
+            }
+        }
+
+        /// A `Line` is an instruction (cf. page 98 of wambook).
+        #[derive(Clone, Debug)]
+        pub enum IndexingLine {
+            Indexing(IndexingInstruction),
+            IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
+            DynamicIndexedChoice(SliceDeque<usize>),
+        }
+
+        impl From<IndexingInstruction> for IndexingLine {
+            #[inline]
+            fn from(instr: IndexingInstruction) -> Self {
+                IndexingLine::Indexing(instr)
+            }
+        }
+
+        impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
+            #[inline]
+            fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
+                IndexingLine::IndexedChoice(instrs)
+            }
+        }
+
+        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])
+        }
+
+        fn arith_instr_bin_functor(
+            h: usize,
+            name: Atom,
+            arena: &mut Arena,
+            at_1: &ArithmeticTerm,
+            at_2: &ArithmeticTerm,
+            t: usize,
+        ) -> MachineStub {
+            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]
+            )
+        }
+
+        pub type Code = Vec<Instruction>;
+
+        impl Instruction {
+            #[inline]
+            pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec<IndexingLine>> {
+                match self {
+                    Instruction::IndexingCode(ref mut indexing_code) => Some(indexing_code),
+                    _ => None,
+                }
+            }
+
+            #[inline]
+            pub fn to_indexing_line(&self) -> Option<&Vec<IndexingLine>> {
+                match self {
+                    Instruction::IndexingCode(ref indexing_code) => Some(indexing_code),
+                    _ => None,
+                }
+            }
+
+            #[inline]
+            pub fn is_head_instr(&self) -> bool {
+                match self {
+                    Instruction::GetConstant(..) |
+                    Instruction::GetList(..) |
+                    Instruction::GetPartialString(..) |
+                    Instruction::GetStructure(..) |
+                    Instruction::GetValue(..) |
+                    Instruction::UnifyConstant(..) |
+                    Instruction::UnifyLocalValue(..) |
+                    Instruction::UnifyVariable(..) |
+                    Instruction::UnifyValue(..) |
+                    Instruction::UnifyVoid(..) |
+                    Instruction::GetVariable(..) |
+                    Instruction::PutConstant(..) |
+                    Instruction::PutList(..) |
+                    Instruction::PutPartialString(..) |
+                    Instruction::PutStructure(..) |
+                    Instruction::PutUnsafeValue(..) |
+                    Instruction::PutValue(..) |
+                    Instruction::PutVariable(..) |
+                    Instruction::SetConstant(..) |
+                    Instruction::SetLocalValue(..) |
+                    Instruction::SetVariable(..) |
+                    Instruction::SetValue(..) |
+                    Instruction::SetVoid(..) => true,
+                    _ => false,
+                }
+            }
+
+            pub fn enqueue_functors(
+                &self,
+                mut h: usize,
+                arena: &mut Arena,
+                functors: &mut Vec<MachineStub>,
+            ) {
+                match self {
+                    &Instruction::IndexingCode(ref indexing_instrs) => {
+                        for indexing_instr in indexing_instrs {
+                            match indexing_instr {
+                                IndexingLine::Indexing(indexing_instr) => {
+                                    let section = indexing_instr.to_functor(h);
+                                    h += section.len();
+                                    functors.push(section);
+                                }
+                                IndexingLine::IndexedChoice(indexed_choice_instrs) => {
+                                    for indexed_choice_instr in indexed_choice_instrs {
+                                        let section = indexed_choice_instr.to_functor();
+                                        h += section.len();
+                                        functors.push(section);
+                                    }
+                                }
+                                IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
+                                    for indexed_choice_instr in indexed_choice_instrs {
+                                        let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]);
+
+                                        h += section.len();
+                                        functors.push(section);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    instr => functors.push(instr.to_functor(h, arena)),
+                }
+            }
+
+            fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub {
+                match self {
+                    &Instruction::InstallVerifyAttr => {
+                        functor!(atom!("install_verify_attr"))
+                    }
+                    &Instruction::VerifyAttrInterrupt => {
+                        functor!(atom!("verify_attr_interrupt"))
+                    }
+                    &Instruction::DynamicElse(birth, death, next_or_fail) => {
+                        match (death, next_or_fail) {
+                            (Death::Infinity, NextOrFail::Next(i)) => {
+                                functor!(
+                                    atom!("dynamic_else"),
+                                    [fixnum(birth), atom(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]
+                                )
+                            }
+                            (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]
+                                )
+                            }
+                            (Death::Finite(d), NextOrFail::Next(i)) => {
+                                functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)])
+                            }
+                        }
+                    }
+                    &Instruction::DynamicInternalElse(birth, death, next_or_fail) => {
+                        match (death, next_or_fail) {
+                            (Death::Infinity, NextOrFail::Next(i)) => {
+                                functor!(
+                                    atom!("dynamic_internal_else"),
+                                    [fixnum(birth), atom(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]
+                                )
+                            }
+                            (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]
+                                )
+                            }
+                            (Death::Finite(d), NextOrFail::Next(i)) => {
+                                functor!(
+                                    atom!("dynamic_internal_else"),
+                                    [fixnum(birth), fixnum(d), fixnum(i)]
+                                )
+                            }
+                        }
+                    }
+                    &Instruction::TryMeElse(offset) => {
+                        functor!(atom!("try_me_else"), [fixnum(offset)])
+                    }
+                    &Instruction::RetryMeElse(offset) => {
+                        functor!(atom!("retry_me_else"), [fixnum(offset)])
+                    }
+                    &Instruction::TrustMe(offset) => {
+                        functor!(atom!("trust_me"), [fixnum(offset)])
+                    }
+                    &Instruction::DefaultRetryMeElse(offset) => {
+                        functor!(atom!("default_retry_me_else"), [fixnum(offset)])
+                    }
+                    &Instruction::DefaultTrustMe(offset) => {
+                        functor!(atom!("default_trust_me"), [fixnum(offset)])
+                    }
+                    &Instruction::Cut(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("cut"), [str(h, 0)], [rt_stub])
+                    }
+                    &Instruction::GetLevel(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
+                    }
+                    &Instruction::GetLevelAndUnify(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("get_level_and_unify"), [str(h, 0)], [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)
+                    }
+                    &Instruction::Sub(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::IntPow(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::IDiv(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::Min(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::RDiv(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::Shl(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::Xor(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::Or(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::Rem(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, 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)
+                    }
+                    &Instruction::Gcd(ref at_1, ref at_2, t) => {
+                        arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t)
+                    }
+                    &Instruction::Sign(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
+                    }
+                    &Instruction::Cos(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("cos"), arena, at, t)
+                    }
+                    &Instruction::Sin(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
+                    }
+                    &Instruction::Tan(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("tan"), arena, at, t)
+                    }
+                    &Instruction::Log(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("log"), arena, at, t)
+                    }
+                    &Instruction::Exp(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("exp"), arena, at, t)
+                    }
+                    &Instruction::ACos(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
+                    }
+                    &Instruction::ASin(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("asin"), arena, at, t)
+                    }
+                    &Instruction::ATan(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
+                    }
+                    &Instruction::Sqrt(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
+                    }
+                    &Instruction::Abs(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
+                    }
+                    &Instruction::Float(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("float"), arena, at, t)
+                    }
+                    &Instruction::Truncate(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
+                    }
+                    &Instruction::Round(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("round"), arena, at, t)
+                    }
+                    &Instruction::Ceiling(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t)
+                    }
+                    &Instruction::Floor(ref at, t) => {
+                        arith_instr_unary_functor(h, atom!("floor"), 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,
+                        t,
+                    ),
+                    &Instruction::IndexingCode(_) => {
+                        // this case is covered in enqueue_functors, which
+                        // should be called instead (to_functor is a private
+                        // function for this reason).
+                        vec![]
+                    }
+                    &Instruction::Allocate(num_frames) => {
+                        functor!(atom!("allocate"), [fixnum(num_frames)])
+                    }
+                    &Instruction::CallNamed(arity, name, ..) => {
+                        functor!(atom!("call"), [atom(name), fixnum(arity)])
+                    }
+                    &Instruction::ExecuteNamed(arity, name, ..) => {
+                        functor!(atom!("execute"), [atom(name), fixnum(arity)])
+                    }
+                    &Instruction::DefaultCallNamed(arity, name, ..) => {
+                        functor!(atom!("call_default"), [atom(name), fixnum(arity)])
+                    }
+                    &Instruction::DefaultExecuteNamed(arity, name, ..) => {
+                        functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
+                    }
+                    &Instruction::CallN(arity, _) => {
+                        functor!(atom!("call_n"), [fixnum(arity)])
+                    }
+                    &Instruction::ExecuteN(arity, _) => {
+                        functor!(atom!("execute_n"), [fixnum(arity)])
+                    }
+                    &Instruction::DefaultCallN(arity, _) => {
+                        functor!(atom!("call_default_n"), [fixnum(arity)])
+                    }
+                    &Instruction::DefaultExecuteN(arity, _) => {
+                        functor!(atom!("execute_default_n"), [fixnum(arity)])
+                    }
+                    &Instruction::CallTermGreaterThan(_) |
+                    &Instruction::CallTermLessThan(_) |
+                    &Instruction::CallTermGreaterThanOrEqual(_) |
+                    &Instruction::CallTermLessThanOrEqual(_) |
+                    &Instruction::CallTermEqual(_) |
+                    &Instruction::CallTermNotEqual(_) |
+                    &Instruction::CallNumberGreaterThan(..) |
+                    &Instruction::CallNumberLessThan(..) |
+                    &Instruction::CallNumberGreaterThanOrEqual(..) |
+                    &Instruction::CallNumberLessThanOrEqual(..) |
+                    &Instruction::CallNumberEqual(..) |
+                    &Instruction::CallNumberNotEqual(..) |
+                    &Instruction::CallIs(..) |
+                    &Instruction::CallAcyclicTerm(_) |
+                    &Instruction::CallArg(_) |
+                    &Instruction::CallCompare(_) |
+                    &Instruction::CallCopyTerm(_) |
+                    &Instruction::CallFunctor(_) |
+                    &Instruction::CallGround(_) |
+                    &Instruction::CallKeySort(_) |
+                    &Instruction::CallRead(_) |
+                    &Instruction::CallSort(_) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("call"), [atom(name), fixnum(arity)])
+                    }
+                    //
+                    &Instruction::ExecuteTermGreaterThan(_) |
+                    &Instruction::ExecuteTermLessThan(_) |
+                    &Instruction::ExecuteTermGreaterThanOrEqual(_) |
+                    &Instruction::ExecuteTermLessThanOrEqual(_) |
+                    &Instruction::ExecuteTermEqual(_) |
+                    &Instruction::ExecuteTermNotEqual(_) |
+                    &Instruction::ExecuteNumberGreaterThan(..) |
+                    &Instruction::ExecuteNumberLessThan(..) |
+                    &Instruction::ExecuteNumberGreaterThanOrEqual(..) |
+                    &Instruction::ExecuteNumberLessThanOrEqual(..) |
+                    &Instruction::ExecuteNumberEqual(..) |
+                    &Instruction::ExecuteNumberNotEqual(..) |
+                    &Instruction::ExecuteAcyclicTerm(_) |
+                    &Instruction::ExecuteArg(_) |
+                    &Instruction::ExecuteCompare(_) |
+                    &Instruction::ExecuteCopyTerm(_) |
+                    &Instruction::ExecuteFunctor(_) |
+                    &Instruction::ExecuteGround(_) |
+                    &Instruction::ExecuteIs(..) |
+                    &Instruction::ExecuteKeySort(_) |
+                    &Instruction::ExecuteRead(_) |
+                    &Instruction::ExecuteSort(_) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("execute"), [atom(name), fixnum(arity)])
+                    }
+                    //
+                    &Instruction::DefaultCallTermGreaterThan(_) |
+                    &Instruction::DefaultCallTermLessThan(_) |
+                    &Instruction::DefaultCallTermGreaterThanOrEqual(_) |
+                    &Instruction::DefaultCallTermLessThanOrEqual(_) |
+                    &Instruction::DefaultCallTermEqual(_) |
+                    &Instruction::DefaultCallTermNotEqual(_) |
+                    &Instruction::DefaultCallNumberGreaterThan(..) |
+                    &Instruction::DefaultCallNumberLessThan(..) |
+                    &Instruction::DefaultCallNumberGreaterThanOrEqual(..) |
+                    &Instruction::DefaultCallNumberLessThanOrEqual(..) |
+                    &Instruction::DefaultCallNumberEqual(..) |
+                    &Instruction::DefaultCallNumberNotEqual(..) |
+                    &Instruction::DefaultCallAcyclicTerm(_) |
+                    &Instruction::DefaultCallArg(_) |
+                    &Instruction::DefaultCallCompare(_) |
+                    &Instruction::DefaultCallCopyTerm(_) |
+                    &Instruction::DefaultCallFunctor(_) |
+                    &Instruction::DefaultCallGround(_) |
+                    &Instruction::DefaultCallIs(..) |
+                    &Instruction::DefaultCallKeySort(_) |
+                    &Instruction::DefaultCallRead(_) |
+                    &Instruction::DefaultCallSort(_) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("call_default"), [atom(name), fixnum(arity)])
+                    }
+                    //
+                    &Instruction::DefaultExecuteTermGreaterThan(_) |
+                    &Instruction::DefaultExecuteTermLessThan(_) |
+                    &Instruction::DefaultExecuteTermGreaterThanOrEqual(_) |
+                    &Instruction::DefaultExecuteTermLessThanOrEqual(_) |
+                    &Instruction::DefaultExecuteTermEqual(_) |
+                    &Instruction::DefaultExecuteTermNotEqual(_) |
+                    &Instruction::DefaultExecuteNumberGreaterThan(..) |
+                    &Instruction::DefaultExecuteNumberLessThan(..) |
+                    &Instruction::DefaultExecuteNumberGreaterThanOrEqual(..) |
+                    &Instruction::DefaultExecuteNumberLessThanOrEqual(..) |
+                    &Instruction::DefaultExecuteNumberEqual(..) |
+                    &Instruction::DefaultExecuteNumberNotEqual(..) |
+                    &Instruction::DefaultExecuteAcyclicTerm(_) |
+                    &Instruction::DefaultExecuteArg(_) |
+                    &Instruction::DefaultExecuteCompare(_) |
+                    &Instruction::DefaultExecuteCopyTerm(_) |
+                    &Instruction::DefaultExecuteFunctor(_) |
+                    &Instruction::DefaultExecuteGround(_) |
+                    &Instruction::DefaultExecuteIs(..) |
+                    &Instruction::DefaultExecuteKeySort(_) |
+                    &Instruction::DefaultExecuteRead(_) |
+                    &Instruction::DefaultExecuteSort(_) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("execute_default"), [atom(name), fixnum(arity)])
+                    }
+                    &Instruction::CallIsAtom(_, _) |
+                    &Instruction::CallIsAtomic(_, _) |
+                    &Instruction::CallIsCompound(_, _) |
+                    &Instruction::CallIsInteger(_, _) |
+                    &Instruction::CallIsNumber(_, _) |
+                    &Instruction::CallIsRational(_, _) |
+                    &Instruction::CallIsFloat(_, _) |
+                    &Instruction::CallIsNonVar(_, _) |
+                    &Instruction::CallIsVar(_, _) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("call"), [atom(name), fixnum(arity)])
+                    }
+                    &Instruction::ExecuteIsAtom(_, _) |
+                    &Instruction::ExecuteIsAtomic(_, _) |
+                    &Instruction::ExecuteIsCompound(_, _) |
+                    &Instruction::ExecuteIsInteger(_, _) |
+                    &Instruction::ExecuteIsNumber(_, _) |
+                    &Instruction::ExecuteIsRational(_, _) |
+                    &Instruction::ExecuteIsFloat(_, _) |
+                    &Instruction::ExecuteIsNonVar(_, _) |
+                    &Instruction::ExecuteIsVar(_, _) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("execute"), [atom(name), fixnum(arity)])
+                    }
+                    //
+                    &Instruction::CallAtomChars(_) |
+                    &Instruction::CallAtomCodes(_) |
+                    &Instruction::CallAtomLength(_) |
+                    &Instruction::CallBindFromRegister(_) |
+                    &Instruction::CallContinuation(_) |
+                    &Instruction::CallCharCode(_) |
+                    &Instruction::CallCharType(_) |
+                    &Instruction::CallCharsToNumber(_) |
+                    &Instruction::CallCodesToNumber(_) |
+                    &Instruction::CallCopyTermWithoutAttrVars(_) |
+                    &Instruction::CallCheckCutPoint(_) |
+                    &Instruction::CallClose(_) |
+                    &Instruction::CallCopyToLiftedHeap(_) |
+                    &Instruction::CallCreatePartialString(_) |
+                    &Instruction::CallCurrentHostname(_) |
+                    &Instruction::CallCurrentInput(_) |
+                    &Instruction::CallCurrentOutput(_) |
+                    &Instruction::CallDirectoryFiles(_) |
+                    &Instruction::CallFileSize(_) |
+                    &Instruction::CallFileExists(_) |
+                    &Instruction::CallDirectoryExists(_) |
+                    &Instruction::CallDirectorySeparator(_) |
+                    &Instruction::CallMakeDirectory(_) |
+                    &Instruction::CallMakeDirectoryPath(_) |
+                    &Instruction::CallDeleteFile(_) |
+                    &Instruction::CallRenameFile(_) |
+                    &Instruction::CallWorkingDirectory(_) |
+                    &Instruction::CallDeleteDirectory(_) |
+                    &Instruction::CallPathCanonical(_) |
+                    &Instruction::CallFileTime(_) |
+                    &Instruction::CallDeleteAttribute(_) |
+                    &Instruction::CallDeleteHeadAttribute(_) |
+                    &Instruction::CallDynamicModuleResolution(..) |
+                    &Instruction::CallEnqueueAttributedVar(_) |
+                    &Instruction::CallFetchGlobalVar(_) |
+                    &Instruction::CallFirstStream(_) |
+                    &Instruction::CallFlushOutput(_) |
+                    &Instruction::CallGetByte(_) |
+                    &Instruction::CallGetChar(_) |
+                    &Instruction::CallGetNChars(_) |
+                    &Instruction::CallGetCode(_) |
+                    &Instruction::CallGetSingleChar(_) |
+                    &Instruction::CallResetAttrVarState(_) |
+                    &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff(_) |
+                    &Instruction::CallTruncateIfNoLiftedHeapGrowth(_) |
+                    &Instruction::CallGetAttributedVariableList(_) |
+                    &Instruction::CallGetAttrVarQueueDelimiter(_) |
+                    &Instruction::CallGetAttrVarQueueBeyond(_) |
+                    &Instruction::CallGetBValue(_) |
+                    &Instruction::CallGetContinuationChunk(_) |
+                    &Instruction::CallGetNextDBRef(_) |
+                    &Instruction::CallGetNextOpDBRef(_) |
+                    &Instruction::CallIsPartialString(_) |
+                    &Instruction::CallHalt(_) |
+                    &Instruction::CallGetLiftedHeapFromOffset(_) |
+                    &Instruction::CallGetLiftedHeapFromOffsetDiff(_) |
+                    &Instruction::CallGetSCCCleaner(_) |
+                    &Instruction::CallHeadIsDynamic(_) |
+                    &Instruction::CallInstallSCCCleaner(_) |
+                    &Instruction::CallInstallInferenceCounter(_) |
+                    &Instruction::CallLiftedHeapLength(_) |
+                    &Instruction::CallLoadLibraryAsStream(_) |
+                    &Instruction::CallModuleExists(_) |
+                    &Instruction::CallNextEP(_) |
+                    &Instruction::CallNoSuchPredicate(_) |
+                    &Instruction::CallNumberToChars(_) |
+                    &Instruction::CallNumberToCodes(_) |
+                    &Instruction::CallOpDeclaration(_) |
+                    &Instruction::CallOpen(_) |
+                    &Instruction::CallSetStreamOptions(_) |
+                    &Instruction::CallNextStream(_) |
+                    &Instruction::CallPartialStringTail(_) |
+                    &Instruction::CallPeekByte(_) |
+                    &Instruction::CallPeekChar(_) |
+                    &Instruction::CallPeekCode(_) |
+                    &Instruction::CallPointsToContinuationResetMarker(_) |
+                    &Instruction::CallPutByte(_) |
+                    &Instruction::CallPutChar(_) |
+                    &Instruction::CallPutChars(_) |
+                    &Instruction::CallPutCode(_) |
+                    &Instruction::CallReadQueryTerm(_) |
+                    &Instruction::CallReadTerm(_) |
+                    &Instruction::CallRedoAttrVarBinding(_) |
+                    &Instruction::CallRemoveCallPolicyCheck(_) |
+                    &Instruction::CallRemoveInferenceCounter(_) |
+                    &Instruction::CallResetContinuationMarker(_) |
+                    &Instruction::CallRestoreCutPolicy(_) |
+                    &Instruction::CallSetCutPoint(..) |
+                    &Instruction::CallSetInput(_) |
+                    &Instruction::CallSetOutput(_) |
+                    &Instruction::CallStoreBacktrackableGlobalVar(_) |
+                    &Instruction::CallStoreGlobalVar(_) |
+                    &Instruction::CallStreamProperty(_) |
+                    &Instruction::CallSetStreamPosition(_) |
+                    &Instruction::CallInferenceLevel(_) |
+                    &Instruction::CallCleanUpBlock(_) |
+                    &Instruction::CallEraseBall(_) |
+                    &Instruction::CallFail(_) |
+                    &Instruction::CallGetBall(_) |
+                    &Instruction::CallGetCurrentBlock(_) |
+                    &Instruction::CallGetCutPoint(_) |
+                    &Instruction::CallGetStaggeredCutPoint(_) |
+                    &Instruction::CallGetDoubleQuotes(_) |
+                    &Instruction::CallInstallNewBlock(_) |
+                    &Instruction::CallMaybe(_) |
+                    &Instruction::CallCpuNow(_) |
+                    &Instruction::CallCurrentTime(_) |
+                    &Instruction::CallQuotedToken(_) |
+                    &Instruction::CallReadTermFromChars(_) |
+                    &Instruction::CallResetBlock(_) |
+                    &Instruction::CallReturnFromVerifyAttr(_) |
+                    &Instruction::CallSetBall(_) |
+                    &Instruction::CallSetCutPointByDefault(..) |
+                    &Instruction::CallSetDoubleQuotes(_) |
+                    &Instruction::CallSetSeed(_) |
+                    &Instruction::CallSkipMaxList(_) |
+                    &Instruction::CallSleep(_) |
+                    &Instruction::CallSocketClientOpen(_) |
+                    &Instruction::CallSocketServerOpen(_) |
+                    &Instruction::CallSocketServerAccept(_) |
+                    &Instruction::CallSocketServerClose(_) |
+                    &Instruction::CallTLSAcceptClient(_) |
+                    &Instruction::CallTLSClientConnect(_) |
+                    &Instruction::CallSucceed(_) |
+                    &Instruction::CallTermAttributedVariables(_) |
+                    &Instruction::CallTermVariables(_) |
+                    &Instruction::CallTermVariablesUnderMaxDepth(_) |
+                    &Instruction::CallTruncateLiftedHeapTo(_) |
+                    &Instruction::CallUnifyWithOccursCheck(_) |
+                    &Instruction::CallUnwindEnvironments(_) |
+                    &Instruction::CallUnwindStack(_) |
+                    &Instruction::CallWAMInstructions(_) |
+                    &Instruction::CallWriteTerm(_) |
+                    &Instruction::CallWriteTermToChars(_) |
+                    &Instruction::CallScryerPrologVersion(_) |
+                    &Instruction::CallCryptoRandomByte(_) |
+                    &Instruction::CallCryptoDataHash(_) |
+                    &Instruction::CallCryptoDataHKDF(_) |
+                    &Instruction::CallCryptoPasswordHash(_) |
+                    &Instruction::CallCryptoDataEncrypt(_) |
+                    &Instruction::CallCryptoDataDecrypt(_) |
+                    &Instruction::CallCryptoCurveScalarMult(_) |
+                    &Instruction::CallEd25519Sign(_) |
+                    &Instruction::CallEd25519Verify(_) |
+                    &Instruction::CallEd25519NewKeyPair(_) |
+                    &Instruction::CallEd25519KeyPairPublicKey(_) |
+                    &Instruction::CallCurve25519ScalarMult(_) |
+                    &Instruction::CallFirstNonOctet(_) |
+                    &Instruction::CallLoadHTML(_) |
+                    &Instruction::CallLoadXML(_) |
+                    &Instruction::CallGetEnv(_) |
+                    &Instruction::CallSetEnv(_) |
+                    &Instruction::CallUnsetEnv(_) |
+                    &Instruction::CallShell(_) |
+                    &Instruction::CallPID(_) |
+                    &Instruction::CallCharsBase64(_) |
+                    &Instruction::CallDevourWhitespace(_) |
+                    &Instruction::CallIsSTOEnabled(_) |
+                    &Instruction::CallSetSTOAsUnify(_) |
+                    &Instruction::CallSetNSTOAsUnify(_) |
+                    &Instruction::CallSetSTOWithErrorAsUnify(_) |
+                    &Instruction::CallHomeDirectory(_) |
+                    &Instruction::CallDebugHook(_) |
+                    &Instruction::CallAddDiscontiguousPredicate(_) |
+                    &Instruction::CallAddDynamicPredicate(_) |
+                    &Instruction::CallAddMultifilePredicate(_) |
+                    &Instruction::CallAddGoalExpansionClause(_) |
+                    &Instruction::CallAddTermExpansionClause(_) |
+                    &Instruction::CallAddInSituFilenameModule(_) |
+                    &Instruction::CallClauseToEvacuable(_) |
+                    &Instruction::CallScopedClauseToEvacuable(_) |
+                    &Instruction::CallConcludeLoad(_) |
+                    &Instruction::CallDeclareModule(_) |
+                    &Instruction::CallLoadCompiledLibrary(_) |
+                    &Instruction::CallLoadContextSource(_) |
+                    &Instruction::CallLoadContextFile(_) |
+                    &Instruction::CallLoadContextDirectory(_) |
+                    &Instruction::CallLoadContextModule(_) |
+                    &Instruction::CallLoadContextStream(_) |
+                    &Instruction::CallPopLoadContext(_) |
+                    &Instruction::CallPopLoadStatePayload(_) |
+                    &Instruction::CallPushLoadContext(_) |
+                    &Instruction::CallPushLoadStatePayload(_) |
+                    &Instruction::CallUseModule(_) |
+                    &Instruction::CallBuiltInProperty(_) |
+                    &Instruction::CallMetaPredicateProperty(_) |
+                    &Instruction::CallMultifileProperty(_) |
+                    &Instruction::CallDiscontiguousProperty(_) |
+                    &Instruction::CallDynamicProperty(_) |
+                    &Instruction::CallAbolishClause(_) |
+                    &Instruction::CallAsserta(_) |
+                    &Instruction::CallAssertz(_) |
+                    &Instruction::CallRetract(_) |
+                    &Instruction::CallIsConsistentWithTermQueue(_) |
+                    &Instruction::CallFlushTermQueue(_) |
+                    &Instruction::CallRemoveModuleExports(_) |
+                    &Instruction::CallAddNonCountedBacktracking(_) |
+                    &Instruction::CallPopCount(_) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("call"), [atom(name), fixnum(arity)])
+                    }
+                    //
+                    &Instruction::ExecuteAtomChars(_) |
+                    &Instruction::ExecuteAtomCodes(_) |
+                    &Instruction::ExecuteAtomLength(_) |
+                    &Instruction::ExecuteBindFromRegister(_) |
+                    &Instruction::ExecuteContinuation(_) |
+                    &Instruction::ExecuteCharCode(_) |
+                    &Instruction::ExecuteCharType(_) |
+                    &Instruction::ExecuteCharsToNumber(_) |
+                    &Instruction::ExecuteCodesToNumber(_) |
+                    &Instruction::ExecuteCopyTermWithoutAttrVars(_) |
+                    &Instruction::ExecuteCheckCutPoint(_) |
+                    &Instruction::ExecuteClose(_) |
+                    &Instruction::ExecuteCopyToLiftedHeap(_) |
+                    &Instruction::ExecuteCreatePartialString(_) |
+                    &Instruction::ExecuteCurrentHostname(_) |
+                    &Instruction::ExecuteCurrentInput(_) |
+                    &Instruction::ExecuteCurrentOutput(_) |
+                    &Instruction::ExecuteDirectoryFiles(_) |
+                    &Instruction::ExecuteFileSize(_) |
+                    &Instruction::ExecuteFileExists(_) |
+                    &Instruction::ExecuteDirectoryExists(_) |
+                    &Instruction::ExecuteDirectorySeparator(_) |
+                    &Instruction::ExecuteMakeDirectory(_) |
+                    &Instruction::ExecuteMakeDirectoryPath(_) |
+                    &Instruction::ExecuteDeleteFile(_) |
+                    &Instruction::ExecuteRenameFile(_) |
+                    &Instruction::ExecuteWorkingDirectory(_) |
+                    &Instruction::ExecuteDeleteDirectory(_) |
+                    &Instruction::ExecutePathCanonical(_) |
+                    &Instruction::ExecuteFileTime(_) |
+                    &Instruction::ExecuteDeleteAttribute(_) |
+                    &Instruction::ExecuteDeleteHeadAttribute(_) |
+                    &Instruction::ExecuteDynamicModuleResolution(_, _) |
+                    &Instruction::ExecuteEnqueueAttributedVar(_) |
+                    &Instruction::ExecuteFetchGlobalVar(_) |
+                    &Instruction::ExecuteFirstStream(_) |
+                    &Instruction::ExecuteFlushOutput(_) |
+                    &Instruction::ExecuteGetByte(_) |
+                    &Instruction::ExecuteGetChar(_) |
+                    &Instruction::ExecuteGetNChars(_) |
+                    &Instruction::ExecuteGetCode(_) |
+                    &Instruction::ExecuteGetSingleChar(_) |
+                    &Instruction::ExecuteResetAttrVarState(_) |
+                    &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff(_) |
+                    &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth(_) |
+                    &Instruction::ExecuteGetAttributedVariableList(_) |
+                    &Instruction::ExecuteGetAttrVarQueueDelimiter(_) |
+                    &Instruction::ExecuteGetAttrVarQueueBeyond(_) |
+                    &Instruction::ExecuteGetBValue(_) |
+                    &Instruction::ExecuteGetContinuationChunk(_) |
+                    &Instruction::ExecuteGetNextDBRef(_) |
+                    &Instruction::ExecuteGetNextOpDBRef(_) |
+                    &Instruction::ExecuteIsPartialString(_) |
+                    &Instruction::ExecuteHalt(_) |
+                    &Instruction::ExecuteGetLiftedHeapFromOffset(_) |
+                    &Instruction::ExecuteGetLiftedHeapFromOffsetDiff(_) |
+                    &Instruction::ExecuteGetSCCCleaner(_) |
+                    &Instruction::ExecuteHeadIsDynamic(_) |
+                    &Instruction::ExecuteInstallSCCCleaner(_) |
+                    &Instruction::ExecuteInstallInferenceCounter(_) |
+                    &Instruction::ExecuteLiftedHeapLength(_) |
+                    &Instruction::ExecuteLoadLibraryAsStream(_) |
+                    &Instruction::ExecuteModuleExists(_) |
+                    &Instruction::ExecuteNextEP(_) |
+                    &Instruction::ExecuteNoSuchPredicate(_) |
+                    &Instruction::ExecuteNumberToChars(_) |
+                    &Instruction::ExecuteNumberToCodes(_) |
+                    &Instruction::ExecuteOpDeclaration(_) |
+                    &Instruction::ExecuteOpen(_) |
+                    &Instruction::ExecuteSetStreamOptions(_) |
+                    &Instruction::ExecuteNextStream(_) |
+                    &Instruction::ExecutePartialStringTail(_) |
+                    &Instruction::ExecutePeekByte(_) |
+                    &Instruction::ExecutePeekChar(_) |
+                    &Instruction::ExecutePeekCode(_) |
+                    &Instruction::ExecutePointsToContinuationResetMarker(_) |
+                    &Instruction::ExecutePutByte(_) |
+                    &Instruction::ExecutePutChar(_) |
+                    &Instruction::ExecutePutChars(_) |
+                    &Instruction::ExecutePutCode(_) |
+                    &Instruction::ExecuteReadQueryTerm(_) |
+                    &Instruction::ExecuteReadTerm(_) |
+                    &Instruction::ExecuteRedoAttrVarBinding(_) |
+                    &Instruction::ExecuteRemoveCallPolicyCheck(_) |
+                    &Instruction::ExecuteRemoveInferenceCounter(_) |
+                    &Instruction::ExecuteResetContinuationMarker(_) |
+                    &Instruction::ExecuteRestoreCutPolicy(_) |
+                    &Instruction::ExecuteSetCutPoint(_, _) |
+                    &Instruction::ExecuteSetInput(_) |
+                    &Instruction::ExecuteSetOutput(_) |
+                    &Instruction::ExecuteStoreBacktrackableGlobalVar(_) |
+                    &Instruction::ExecuteStoreGlobalVar(_) |
+                    &Instruction::ExecuteStreamProperty(_) |
+                    &Instruction::ExecuteSetStreamPosition(_) |
+                    &Instruction::ExecuteInferenceLevel(_) |
+                    &Instruction::ExecuteCleanUpBlock(_) |
+                    &Instruction::ExecuteEraseBall(_) |
+                    &Instruction::ExecuteFail(_) |
+                    &Instruction::ExecuteGetBall(_) |
+                    &Instruction::ExecuteGetCurrentBlock(_) |
+                    &Instruction::ExecuteGetCutPoint(_) |
+                    &Instruction::ExecuteGetStaggeredCutPoint(_) |
+                    &Instruction::ExecuteGetDoubleQuotes(_) |
+                    &Instruction::ExecuteInstallNewBlock(_) |
+                    &Instruction::ExecuteMaybe(_) |
+                    &Instruction::ExecuteCpuNow(_) |
+                    &Instruction::ExecuteCurrentTime(_) |
+                    &Instruction::ExecuteQuotedToken(_) |
+                    &Instruction::ExecuteReadTermFromChars(_) |
+                    &Instruction::ExecuteResetBlock(_) |
+                    &Instruction::ExecuteReturnFromVerifyAttr(_) |
+                    &Instruction::ExecuteSetBall(_) |
+                    &Instruction::ExecuteSetCutPointByDefault(_, _) |
+                    &Instruction::ExecuteSetDoubleQuotes(_) |
+                    &Instruction::ExecuteSetSeed(_) |
+                    &Instruction::ExecuteSkipMaxList(_) |
+                    &Instruction::ExecuteSleep(_) |
+                    &Instruction::ExecuteSocketClientOpen(_) |
+                    &Instruction::ExecuteSocketServerOpen(_) |
+                    &Instruction::ExecuteSocketServerAccept(_) |
+                    &Instruction::ExecuteSocketServerClose(_) |
+                    &Instruction::ExecuteTLSAcceptClient(_) |
+                    &Instruction::ExecuteTLSClientConnect(_) |
+                    &Instruction::ExecuteSucceed(_) |
+                    &Instruction::ExecuteTermAttributedVariables(_) |
+                    &Instruction::ExecuteTermVariables(_) |
+                    &Instruction::ExecuteTermVariablesUnderMaxDepth(_) |
+                    &Instruction::ExecuteTruncateLiftedHeapTo(_) |
+                    &Instruction::ExecuteUnifyWithOccursCheck(_) |
+                    &Instruction::ExecuteUnwindEnvironments(_) |
+                    &Instruction::ExecuteUnwindStack(_) |
+                    &Instruction::ExecuteWAMInstructions(_) |
+                    &Instruction::ExecuteWriteTerm(_) |
+                    &Instruction::ExecuteWriteTermToChars(_) |
+                    &Instruction::ExecuteScryerPrologVersion(_) |
+                    &Instruction::ExecuteCryptoRandomByte(_) |
+                    &Instruction::ExecuteCryptoDataHash(_) |
+                    &Instruction::ExecuteCryptoDataHKDF(_) |
+                    &Instruction::ExecuteCryptoPasswordHash(_) |
+                    &Instruction::ExecuteCryptoDataEncrypt(_) |
+                    &Instruction::ExecuteCryptoDataDecrypt(_) |
+                    &Instruction::ExecuteCryptoCurveScalarMult(_) |
+                    &Instruction::ExecuteEd25519Sign(_) |
+                    &Instruction::ExecuteEd25519Verify(_) |
+                    &Instruction::ExecuteEd25519NewKeyPair(_) |
+                    &Instruction::ExecuteEd25519KeyPairPublicKey(_) |
+                    &Instruction::ExecuteCurve25519ScalarMult(_) |
+                    &Instruction::ExecuteFirstNonOctet(_) |
+                    &Instruction::ExecuteLoadHTML(_) |
+                    &Instruction::ExecuteLoadXML(_) |
+                    &Instruction::ExecuteGetEnv(_) |
+                    &Instruction::ExecuteSetEnv(_) |
+                    &Instruction::ExecuteUnsetEnv(_) |
+                    &Instruction::ExecuteShell(_) |
+                    &Instruction::ExecutePID(_) |
+                    &Instruction::ExecuteCharsBase64(_) |
+                    &Instruction::ExecuteDevourWhitespace(_) |
+                    &Instruction::ExecuteIsSTOEnabled(_) |
+                    &Instruction::ExecuteSetSTOAsUnify(_) |
+                    &Instruction::ExecuteSetNSTOAsUnify(_) |
+                    &Instruction::ExecuteSetSTOWithErrorAsUnify(_) |
+                    &Instruction::ExecuteHomeDirectory(_) |
+                    &Instruction::ExecuteDebugHook(_) |
+                    &Instruction::ExecuteAddDiscontiguousPredicate(_) |
+                    &Instruction::ExecuteAddDynamicPredicate(_) |
+                    &Instruction::ExecuteAddMultifilePredicate(_) |
+                    &Instruction::ExecuteAddGoalExpansionClause(_) |
+                    &Instruction::ExecuteAddTermExpansionClause(_) |
+                    &Instruction::ExecuteAddInSituFilenameModule(_) |
+                    &Instruction::ExecuteClauseToEvacuable(_) |
+                    &Instruction::ExecuteScopedClauseToEvacuable(_) |
+                    &Instruction::ExecuteConcludeLoad(_) |
+                    &Instruction::ExecuteDeclareModule(_) |
+                    &Instruction::ExecuteLoadCompiledLibrary(_) |
+                    &Instruction::ExecuteLoadContextSource(_) |
+                    &Instruction::ExecuteLoadContextFile(_) |
+                    &Instruction::ExecuteLoadContextDirectory(_) |
+                    &Instruction::ExecuteLoadContextModule(_) |
+                    &Instruction::ExecuteLoadContextStream(_) |
+                    &Instruction::ExecutePopLoadContext(_) |
+                    &Instruction::ExecutePopLoadStatePayload(_) |
+                    &Instruction::ExecutePushLoadContext(_) |
+                    &Instruction::ExecutePushLoadStatePayload(_) |
+                    &Instruction::ExecuteUseModule(_) |
+                    &Instruction::ExecuteBuiltInProperty(_) |
+                    &Instruction::ExecuteMetaPredicateProperty(_) |
+                    &Instruction::ExecuteMultifileProperty(_) |
+                    &Instruction::ExecuteDiscontiguousProperty(_) |
+                    &Instruction::ExecuteDynamicProperty(_) |
+                    &Instruction::ExecuteAbolishClause(_) |
+                    &Instruction::ExecuteAsserta(_) |
+                    &Instruction::ExecuteAssertz(_) |
+                    &Instruction::ExecuteRetract(_) |
+                    &Instruction::ExecuteIsConsistentWithTermQueue(_) |
+                    &Instruction::ExecuteFlushTermQueue(_) |
+                    &Instruction::ExecuteRemoveModuleExports(_) |
+                    &Instruction::ExecuteAddNonCountedBacktracking(_) |
+                    &Instruction::ExecutePopCount(_) => {
+                        let (name, arity) = self.to_name_and_arity();
+                        functor!(atom!("execute"), [atom(name), fixnum(arity)])
+                    }
+                    //
+                    &Instruction::Deallocate => {
+                        functor!(atom!("deallocate"))
+                    }
+                    &Instruction::JmpByCall(_, offset, ..) => {
+                        functor!(atom!("jmp_by_call"), [fixnum(offset)])
+                    }
+                    &Instruction::JmpByExecute(_, offset, ..) => {
+                        functor!(atom!("jmp_by_execute"), [fixnum(offset)])
+                    }
+                    &Instruction::RevJmpBy(offset) => {
+                        functor!(atom!("rev_jmp_by"), [fixnum(offset)])
+                    }
+                    &Instruction::Proceed => {
+                        functor!(atom!("proceed"))
+                    }
+                    &Instruction::GetConstant(lvl, c, 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]
+                        )
+                    }
+                    &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]
+                        )
+                    }
+                    &Instruction::GetPartialString(lvl, s, r, has_tail) => {
+                        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]
+                        )
+                    }
+                    &Instruction::GetStructure(name, arity, r) => {
+                        let rt_stub = reg_type_into_functor(r);
+
+                        functor!(
+                            atom!("get_structure"),
+                            [atom(name), fixnum(arity), str(h, 0)],
+                            [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])
+                    }
+                    &Instruction::GetVariable(r, arg) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
+                    }
+                    &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])
+                    }
+                    &Instruction::UnifyVariable(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
+                    }
+                    &Instruction::UnifyValue(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
+                    }
+                    &Instruction::UnifyVoid(vars) => {
+                        functor!(atom!("unify_void"), [fixnum(vars)])
+                    }
+                    &Instruction::PutUnsafeValue(norm, arg) => {
+                        functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)])
+                    }
+                    &Instruction::PutConstant(lvl, c, r) => {
+                        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]
+                        )
+                    }
+                    &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]
+                        )
+                    }
+                    &Instruction::PutPartialString(lvl, s, r, has_tail) => {
+                        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]
+                        )
+                    }
+                    &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]
+                        )
+                    }
+                    &Instruction::PutValue(r, arg) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
+                    }
+                    &Instruction::PutVariable(r, arg) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
+                    }
+                    &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])
+                    }
+                    &Instruction::SetVariable(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
+                    }
+                    &Instruction::SetValue(r) => {
+                        let rt_stub = reg_type_into_functor(r);
+                        functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
+                    }
+                    &Instruction::SetVoid(vars) => {
+                        functor!(atom!("set_void"), [fixnum(vars)])
+                    }
+                    &Instruction::BreakFromDispatchLoop => {
+                        functor!(atom!("$break_from_dispatch_loop"))
+                    }
+                }
+            }
+        }
+    }
+}
+
+pub fn generate_instructions_rs() -> TokenStream {
+    let input = InstructionTemplate::to_derive_input();
+    let mut instr_data = InstructionData::new();
+
+    instr_data.generate_instruction_enum_loop(input);
+
+    let instr_variants: Vec<_> = instr_data.instr_variants
+        .iter()
+        .cloned()
+        .map(|(_, _, _, variant)| variant)
+        .collect();
+
+    fn attributeless_enum<T: ToDeriveInput>() -> Vec<Variant> {
+        if let Data::Enum(DataEnum { mut variants, .. }) = T::to_derive_input().data {
+            for variant in &mut variants {
+                variant.attrs.clear();
+            }
+
+            variants.into_iter().collect()
+        } else {
+            unreachable!()
+        }
+    }
+
+    let clause_type_variants = attributeless_enum::<ClauseType>();
+    let builtin_type_variants = attributeless_enum::<BuiltInClauseType>();
+    let inlined_type_variants = attributeless_enum::<InlinedClauseType>();
+    let system_clause_type_variants = attributeless_enum::<SystemClauseType>();
+    let repl_code_ptr_variants = attributeless_enum::<REPLCodePtr>();
+    let compare_number_variants = attributeless_enum::<CompareNumber>();
+    let compare_term_variants = attributeless_enum::<CompareTerm>();
+
+    let mut clause_type_from_name_and_arity_arms = vec![];
+    let mut clause_type_to_instr_arms = vec![];
+    let mut clause_type_name_arms = vec![];
+
+    for (name, arity, variant) in instr_data.compare_number_variants {
+        let ident = variant.ident.clone();
+
+        let variant_fields: Vec<_> = variant.fields
+            .into_iter()
+            .map(|field| {
+                let ty = field.ty;
+                quote! { #ty::default() }
+            })
+            .collect();
+
+        clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::Inlined(
+                    InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#variant_fields),*))
+                )
+            }
+        } else {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::Inlined(
+                    InlinedClauseType::CompareNumber(CompareNumber::#ident)
+                )
+            }
+        });
+
+        clause_type_name_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::Inlined(
+                    InlinedClauseType::CompareNumber(CompareNumber::#ident(..))
+                ) => atom!(#name)
+            }
+        } else {
+            quote! {
+                ClauseType::Inlined(
+                    InlinedClauseType::CompareNumber(CompareNumber::#ident)
+                ) => (atom!(#name), #arity)
+            }
+        });
+
+        let ident = variant.ident;
+        let instr_ident = format_ident!("Call{}", ident);
+
+        let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+            .map(|n| format_ident!("f_{}", n))
+            .collect();
+
+        clause_type_to_instr_arms.push(
+            quote! {
+                ClauseType::Inlined(
+                    InlinedClauseType::CompareNumber(CompareNumber::#ident(#(#placeholder_ids),*))
+                ) => Instruction::#instr_ident(#(#placeholder_ids),*, 0)
+            }
+        );
+    }
+
+    for (name, arity, variant) in instr_data.compare_term_variants {
+        let ident = variant.ident.clone();
+
+        clause_type_from_name_and_arity_arms.push(quote! {
+            (atom!(#name), #arity) => ClauseType::BuiltIn(
+                BuiltInClauseType::CompareTerm(CompareTerm::#ident)
+            )
+        });
+
+        clause_type_name_arms.push(
+            quote! {
+                ClauseType::BuiltIn(
+                    BuiltInClauseType::CompareTerm(CompareTerm::#ident)
+                ) => atom!(#name)
+            }
+        );
+
+        let ident = variant.ident;
+        let instr_ident = format_ident!("Call{}", ident);
+
+        clause_type_to_instr_arms.push(
+            quote! {
+                ClauseType::BuiltIn(
+                    BuiltInClauseType::CompareTerm(CompareTerm::#ident)
+                ) => Instruction::#instr_ident(0)
+            }
+        );
+    }
+
+    for (name, arity, variant) in instr_data.builtin_type_variants {
+        let ident = variant.ident.clone();
+
+        let variant_fields: Vec<_> = variant.fields
+            .into_iter()
+            .map(|field| {
+                let ty = field.ty;
+                quote! { #ty::default() }
+            })
+            .collect();
+
+        clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::BuiltIn(
+                    BuiltInClauseType::#ident(#(#variant_fields),*)
+                )
+            }
+        } else {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::BuiltIn(
+                    BuiltInClauseType::#ident
+                )
+            }
+        });
+
+        clause_type_name_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::BuiltIn(
+                    BuiltInClauseType::#ident(..)
+                ) => atom!(#name)
+            }
+        } else {
+            quote! {
+                ClauseType::BuiltIn(
+                    BuiltInClauseType::#ident
+                ) => atom!(#name)
+            }
+        });
+
+        let ident = variant.ident;
+        let instr_ident = format_ident!("Call{}", ident);
+
+        let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+            .map(|n| format_ident!("f_{}", n))
+            .collect();
+
+        clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::BuiltIn(
+                    BuiltInClauseType::#ident(#(#placeholder_ids),*)
+                ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+            }
+        } else {
+            quote! {
+                ClauseType::BuiltIn(
+                    BuiltInClauseType::#ident
+                ) => Instruction::#instr_ident(0)
+            }
+        });
+    }
+
+    for (name, arity, variant) in instr_data.inlined_type_variants {
+        let ident = variant.ident.clone();
+
+        let variant_fields: Vec<_> = variant.fields
+            .into_iter()
+            .map(|field| {
+                if field.ty.type_id() == TypeId::of::<usize>() {
+                    quote! { #arity }
+                } else {
+                    let ty = field.ty;
+                    quote! { #ty::default() }
+                }
+            })
+            .collect();
+
+        clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::Inlined(
+                    InlinedClauseType::#ident(#(#variant_fields),*)
+                )
+            }
+        } else {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::Inlined(
+                    InlinedClauseType::#ident
+                )
+            }
+        });
+
+        clause_type_name_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::Inlined(
+                    InlinedClauseType::#ident(..)
+                ) => atom!(#name)
+            }
+        } else {
+            quote! {
+                ClauseType::Inlined(
+                    InlinedClauseType::#ident
+                ) => atom!(#name)
+            }
+        });
+
+        let ident = variant.ident;
+        let instr_ident = format_ident!("Call{}", ident);
+
+        let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+            .map(|n| format_ident!("f_{}", n))
+            .collect();
+
+        clause_type_to_instr_arms.push(
+            quote! {
+                ClauseType::Inlined(
+                    InlinedClauseType::#ident(#(#placeholder_ids),*)
+                ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+            }
+        );
+    }
+
+    for (name, arity, variant) in instr_data.system_clause_type_variants {
+        let ident = variant.ident.clone();
+
+        let variant_fields: Vec<_> = variant.fields
+            .into_iter()
+            .map(|field| {
+                if field.ty == parse_quote! { usize } {
+                    quote! { #arity }
+                } else {
+                    let ty = field.ty;
+                    quote! { #ty::default() }
+                }
+            })
+            .collect();
+
+        clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+            if ident.to_string() == "SetCutPoint" {
+                quote! {
+                    (atom!(#name), #arity) => ClauseType::System(
+                        SystemClauseType::#ident(temp_v!(1))
+                    )
+                }
+            } else if ident.to_string() == "SetCutPointByDefault" {
+                quote! {
+                    (atom!(#name), #arity) => ClauseType::System(
+                        SystemClauseType::#ident(temp_v!(1))
+                    )
+                }
+            } else {
+                quote! {
+                    (atom!(#name), #arity) => ClauseType::System(
+                        SystemClauseType::#ident(#(#variant_fields),*)
+                    )
+                }
+            }
+        } else {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::System(
+                    SystemClauseType::#ident
+                )
+            }
+        });
+
+        clause_type_name_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::System(
+                    SystemClauseType::#ident(..)
+                ) => atom!(#name)
+            }
+        } else {
+            quote! {
+                ClauseType::System(
+                    SystemClauseType::#ident
+                ) => atom!(#name)
+            }
+        });
+
+        let ident = variant.ident;
+        let instr_ident = if ident != "CallContinuation" {
+            format_ident!("Call{}", ident)
+        } else {
+            ident.clone()
+        };
+
+        let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+            .map(|n| format_ident!("f_{}", n))
+            .collect();
+
+        clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::System(
+                    SystemClauseType::#ident(#(#placeholder_ids),*)
+                ) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+            }
+        } else {
+            quote! {
+                ClauseType::System(
+                    SystemClauseType::#ident
+                ) => Instruction::#instr_ident(0)
+            }
+        });
+    }
+
+    for (name, arity, variant) in instr_data.repl_code_ptr_variants {
+        let ident = variant.ident.clone();
+
+        let variant_fields: Vec<_> = variant.fields
+            .into_iter()
+            .map(|field| {
+                if field.ty.type_id() == TypeId::of::<usize>() {
+                    quote! { #arity }
+                } else {
+                    let ty = field.ty;
+                    quote! { #ty::default() }
+                }
+            })
+            .collect();
+
+        clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL(
+                    REPLCodePtr::#ident(#(#variant_fields),*)
+                ))
+            }
+        } else {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL(
+                    REPLCodePtr::#ident
+                ))
+            }
+        });
+
+        clause_type_name_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::System(
+                    SystemClauseType::REPL(REPLCodePtr::#ident(..))
+                ) => atom!(#name)
+            }
+        } else {
+            quote! {
+                ClauseType::System(
+                    SystemClauseType::REPL(REPLCodePtr::#ident)
+                ) => atom!(#name)
+            }
+        });
+
+        let ident = variant.ident;
+        let instr_ident = format_ident!("Call{}", ident);
+
+        let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+            .map(|n| format_ident!("f_{}", n))
+            .collect();
+
+        clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::System(SystemClauseType::REPL(
+                    REPLCodePtr::#ident(#(#placeholder_ids),*)
+                )) => Instruction::#instr_ident(#(#placeholder_ids),*,0)
+            }
+        } else {
+            quote! {
+                ClauseType::System(SystemClauseType::REPL(
+                    REPLCodePtr::#ident
+                )) => Instruction::#instr_ident(0)
+            }
+        });
+    }
+
+    for (name, arity, variant) in instr_data.clause_type_variants {
+        let ident = variant.ident.clone();
+
+        if ident == "Named" {
+            clause_type_from_name_and_arity_arms.push(quote! {
+                (name, arity) => ClauseType::Named(arity, name, CodeIndex::default())
+            });
+
+            clause_type_to_instr_arms.push(quote! {
+                ClauseType::Named(arity, name, idx) => Instruction::CallNamed(arity, name, idx, 0)
+            });
+
+            clause_type_name_arms.push(quote! {
+                ClauseType::Named(_, name, _) => *name
+            });
+
+            continue;
+        }
+
+        let variant_fields: Vec<_> = variant.fields
+            .into_iter()
+            .map(|field| {
+                if field.ty == parse_quote! { usize } {
+                    quote! { #arity }
+                } else {
+                    let ty = field.ty;
+                    quote! { #ty::default() }
+                }
+            })
+            .collect();
+
+        clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::#ident(#(#variant_fields),*)
+            }
+        } else {
+            quote! {
+                (atom!(#name), #arity) => ClauseType::#ident
+            }
+        });
+
+        clause_type_name_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::#ident(..) => atom!(#name)
+            }
+        } else {
+            quote! {
+                ClauseType::#ident => atom!(#name)
+            }
+        });
+
+        let ident = variant.ident;
+
+        let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+            .map(|n| format_ident!("f_{}", n))
+            .collect();
+
+        clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+            quote! {
+                ClauseType::#ident(#(#placeholder_ids),*) =>
+                    Instruction::#ident(#(#placeholder_ids),*,0)
+            }
+        } else {
+            quote! {
+                ClauseType::#ident => Instruction::#ident(0)
+            }
+        });
+    }
+
+    let to_execute_arms: Vec<_> = instr_data.instr_variants
+        .iter()
+        .cloned()
+        .filter_map(|(_, _, _, variant)| {
+            let variant_ident = variant.ident.clone();
+            let variant_string = variant.ident.to_string();
+
+            let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+                fields.unnamed.len()
+            } else {
+                0
+            };
+
+            let placeholder_ids: Vec<_> = (0 .. enum_arity)
+                .map(|n| format_ident!("f_{}", n))
+                .collect();
+
+            if variant_string.starts_with("Call") {
+                let execute_ident = format_ident!("Execute{}", variant_string["Call".len() ..]);
+
+                Some(if enum_arity == 0 {
+                    quote! {
+                        Instruction::#variant_ident =>
+                            Instruction::#execute_ident
+                    }
+                } else {
+                    quote! {
+                        Instruction::#variant_ident(#(#placeholder_ids),*) =>
+                            Instruction::#execute_ident(#(#placeholder_ids),*)
+                    }
+                })
+            } else if variant_string.starts_with("DefaultCall") {
+                let execute_ident =
+                    format_ident!("DefaultExecute{}", variant_string["DefaultCall".len() ..]);
+
+                Some(if enum_arity == 0 {
+                    quote! {
+                        Instruction::#variant_ident =>
+                            Instruction::#execute_ident
+                    }
+                } else {
+                    quote! {
+                        Instruction::#variant_ident(#(#placeholder_ids),*) =>
+                            Instruction::#execute_ident(#(#placeholder_ids),*)
+                    }
+                })
+            } else if variant_string == "JmpByCall" {
+                Some(quote! {
+                    Instruction::JmpByCall(#(#placeholder_ids),*) =>
+                        Instruction::JmpByExecute(#(#placeholder_ids),*)
+                })
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    let is_execute_arms: Vec<_> = instr_data.instr_variants
+        .iter()
+        .cloned()
+        .filter_map(|(_, _, _, variant)| {
+            let variant_ident = variant.ident.clone();
+            let variant_string = variant.ident.to_string();
+
+            let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+                fields.unnamed.len()
+            } else {
+                0
+            };
+
+            if variant_string.starts_with("Execute") {
+                Some(if enum_arity == 0 {
+                    quote! {
+                        Instruction::#variant_ident => true
+                    }
+                } else {
+                    quote! {
+                        Instruction::#variant_ident(..) => true
+                    }
+                })
+            } else if variant_string.starts_with("DefaultExecute") {
+                Some(if enum_arity == 0 {
+                    quote! {
+                        Instruction::#variant_ident => true
+                    }
+                } else {
+                    quote! {
+                        Instruction::#variant_ident(..) => true
+                    }
+                })
+            } else if variant_string == "JmpByExecute" {
+                Some(quote! {
+                    Instruction::#variant_ident(..) => true
+                })
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    let to_default_arms: Vec<_> = instr_data.instr_variants
+        .iter()
+        .cloned()
+        .filter_map(|(_, _, countable_inference, variant)| {
+            if !is_non_default_callable(&variant.ident) {
+                return None;
+            }
+
+            if let CountableInference::HasDefault = countable_inference {
+                let variant_ident = variant.ident.clone();
+                let def_variant_ident = format_ident!("Default{}", variant.ident);
+                let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+                    fields.unnamed.len()
+                } else {
+                    unreachable!()
+                };
+
+                let placeholder_ids: Vec<_> = (0 .. enum_arity)
+                    .map(|n| format_ident!("f_{}", n))
+                    .collect();
+
+                Some(quote! {
+                    Instruction::#variant_ident(#(#placeholder_ids),*) =>
+                        Instruction::#def_variant_ident(#(#placeholder_ids),*)
+                })
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    let perm_vars_mut_arms: Vec<_> = instr_data.instr_variants
+        .iter()
+        .cloned()
+        .filter_map(|(_, _, _, variant)| {
+            if !is_callable(&variant.ident) && !is_jmp(&variant.ident) {
+                return None;
+            }
+
+            let variant_ident = variant.ident.clone();
+            let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+                fields.unnamed.len()
+            } else {
+                0
+            };
+
+            let placeholder_ids: Vec<_> = (1 .. enum_arity)
+                .map(|_| format_ident!("_"))
+                .collect();
+
+            Some(if enum_arity == 1 {
+                quote! {
+                    Instruction::#variant_ident(ref mut perm_vars) => Some(perm_vars)
+                }
+            } else {
+                quote! {
+                    Instruction::#variant_ident(#(#placeholder_ids),*, ref mut perm_vars) =>
+                        Some(perm_vars)
+                }
+            })
+        })
+        .collect();
+
+    let control_flow_arms: Vec<_> = instr_data.instr_variants
+        .iter()
+        .cloned()
+        .filter_map(|(_, _, _, variant)| {
+            if !is_callable(&variant.ident) && !is_jmp(&variant.ident) {
+                return None;
+            }
+
+            let variant_ident = variant.ident.clone();
+
+            Some(quote! {
+                Instruction::#variant_ident(..) => true
+            })
+        })
+        .collect();
+
+    let instr_macro_arms: Vec<_> = instr_data.instr_variants
+        .iter()
+        .rev() // produce default, execute & default & execute cases first.
+        .cloned()
+        .filter_map(|(name, arity, _, variant)| {
+            let variant_ident = variant.ident.clone();
+            let variant_string = variant.ident.to_string();
+            let arity = match arity {
+                Arity::Static(arity) => arity,
+                _ => 1
+            };
+
+            Some(if variant_string.starts_with("Execute") {
+                quote! {
+                    (#name, execute, $($args:expr),*) => {
+                        Instruction::#variant_ident($($args),*)
+                    }
+                }
+            } else if variant_string.starts_with("Call") {
+                quote! {
+                    (#name, $($args:expr),*) => {
+                        Instruction::#variant_ident($($args),*)
+                    }
+                }
+            } else if variant_string.starts_with("DefaultExecute") {
+                quote! {
+                    (#name, execute, default, $($args:expr),*) => {
+                        Instruction::#variant_ident($($args),*)
+                    }
+                }
+            } else if variant_string.starts_with("DefaultCall") {
+                quote! {
+                    (#name, default, $($args:expr),*) => {
+                        Instruction::#variant_ident($($args),*)
+                    }
+                }
+            } else {
+                if arity == 0 {
+                    quote! {
+                        (#name) => {
+                            Instruction::#variant_ident
+                        }
+                    }
+                } else {
+                    quote! {
+                        (#name, $($args:expr),*) => {
+                            Instruction::#variant_ident($($args),*)
+                        }
+                    }
+                }
+            })
+        })
+        .collect();
+
+    let name_and_arity_arms: Vec<_> = instr_data.instr_variants
+        .into_iter()
+        .map(|(name,arity,_,variant)| {
+            let ident = &variant.ident;
+
+            let enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+                fields.unnamed.len()
+            } else {
+                0
+            };
+
+            match arity {
+                Arity::Static(_) if enum_arity == 0 => {
+                    quote! { &Instruction::#ident => (atom!(#name), #arity) }
+                }
+                Arity::Static(_) => {
+                    quote! { &Instruction::#ident(..) => (atom!(#name), #arity) }
+                }
+                Arity::Ident(_) if enum_arity == 0 => {
+                    quote! { &Instruction::#ident(#arity) => (atom!(#name), #arity) }
+                }
+                Arity::Ident(_) => {
+                    quote! { &Instruction::#ident(#arity, ..) => (atom!(#name), #arity) }
+                }
+            }
+        })
+        .collect();
+
+    let preface_tokens = generate_instruction_preface();
+
+    quote! {
+        #preface_tokens
+
+        #[derive(Clone, Debug)]
+        pub enum CompareTerm {
+            #(
+                #compare_term_variants,
+            )*
+        }
+
+        #[derive(Clone, Copy, Debug)]
+        pub enum CompareNumber {
+            #(
+                #compare_number_variants,
+            )*
+        }
+
+        impl CompareNumber {
+            pub fn set_terms(&mut self, l_at_1: ArithmeticTerm, l_at_2: ArithmeticTerm) {
+                match self {
+                    CompareNumber::NumberGreaterThan(ref mut at_1, ref mut at_2) |
+                    CompareNumber::NumberLessThan(ref mut at_1, ref mut at_2) |
+                    CompareNumber::NumberGreaterThanOrEqual(ref mut at_1, ref mut at_2) |
+                    CompareNumber::NumberLessThanOrEqual(ref mut at_1, ref mut at_2) |
+                    CompareNumber::NumberNotEqual(ref mut at_1, ref mut at_2) |
+                    CompareNumber::NumberEqual(ref mut at_1, ref mut at_2) => {
+                        *at_1 = l_at_1;
+                        *at_2 = l_at_2;
+                    }
+                }
+            }
+        }
+
+        #[derive(Clone, Debug)]
+        pub enum BuiltInClauseType {
+            #(
+                #builtin_type_variants,
+            )*
+        }
+
+        #[derive(Clone, Debug)]
+        pub enum InlinedClauseType {
+            #(
+                #inlined_type_variants,
+            )*
+        }
+
+        #[derive(Clone, Debug)]
+        pub enum SystemClauseType {
+            #(
+                #system_clause_type_variants,
+            )*
+        }
+
+        #[derive(Clone, Debug)]
+        pub enum REPLCodePtr {
+            #(
+                #repl_code_ptr_variants,
+            )*
+        }
+
+        #[derive(Clone, Debug)]
+        pub enum ClauseType {
+            #(
+                #clause_type_variants,
+            )*
+        }
+
+        impl ClauseType {
+            pub fn from(name: Atom, arity: usize) -> ClauseType {
+                match (name, arity) {
+                    #(
+                        #clause_type_from_name_and_arity_arms,
+                    )*
+                }
+            }
+
+            pub fn to_instr(self) -> Instruction {
+                match self {
+                    #(
+                        #clause_type_to_instr_arms,
+                    )*
+                }
+            }
+
+            pub fn is_builtin(&self) -> bool {
+                if let ClauseType::BuiltIn(_) = self {
+                    true
+                } else {
+                    false
+                }
+            }
+
+            pub fn is_inlined(&self) -> bool {
+                if let ClauseType::Inlined(_) = self {
+                    true
+                } else {
+                    false
+                }
+            }
+
+            pub fn name(&self) -> Atom {
+                match self {
+                    #(
+                        #clause_type_name_arms,
+                    )*
+                }
+            }
+        }
+
+        #[derive(Clone, Debug)]
+        pub enum Instruction {
+            #(
+                #instr_variants,
+            )*
+        }
+
+        impl Instruction {
+            pub fn to_name_and_arity(&self) -> (Atom, usize) {
+                match self {
+                    #(
+                        #name_and_arity_arms,
+                    )*
+                }
+            }
+
+            pub fn to_default(self) -> Instruction {
+                match self {
+                    #(
+                        #to_default_arms,
+                    )*
+                    _ => self,
+                }
+            }
+
+            pub fn to_execute(self) -> Instruction {
+                match self {
+                    #(
+                        #to_execute_arms,
+                    )*
+                    _ => self
+                }
+            }
+
+            pub fn is_execute(&self) -> bool {
+                match self {
+                    #(
+                        #is_execute_arms,
+                    )*
+                    _ => false,
+                }
+            }
+
+            pub fn perm_vars_mut(&mut self) -> Option<&mut usize> {
+                match self {
+                    #(
+                        #perm_vars_mut_arms,
+                    )*
+                    _ => None,
+                }
+            }
+
+            pub fn is_ctrl_instr(&self) -> bool {
+                match self {
+                    &Instruction::Allocate(_) |
+                    &Instruction::Deallocate |
+                    &Instruction::Proceed |
+                    &Instruction::RevJmpBy(_) => true,
+                    #(
+                        #control_flow_arms,
+                    )*
+                    _ => false,
+                }
+            }
+
+            pub fn is_query_instr(&self) -> bool {
+                match self {
+                    &Instruction::GetVariable(..) |
+                    &Instruction::PutConstant(..) |
+                    &Instruction::PutList(..) |
+                    &Instruction::PutPartialString(..) |
+                    &Instruction::PutStructure(..) |
+                    &Instruction::PutUnsafeValue(..) |
+                    &Instruction::PutValue(..) |
+                    &Instruction::PutVariable(..) |
+                    &Instruction::SetConstant(..) |
+                    &Instruction::SetLocalValue(..) |
+                    &Instruction::SetVariable(..) |
+                    &Instruction::SetValue(..) |
+                    &Instruction::SetVoid(..) => true,
+                    _ => false,
+                }
+            }
+        }
+
+        #[macro_export]
+        macro_rules! instr {
+            #(
+                #instr_macro_arms
+            );*
+        }
+    }
+}
+
+fn is_callable(id: &Ident) -> bool {
+    let id = id.to_string();
+
+    id.starts_with("Call") || id.starts_with("Execute") || id.starts_with("DefaultCall") ||
+        id.starts_with("DefaultExecute")
+}
+
+fn is_non_default_callable(id: &Ident) -> bool {
+    let id = id.to_string();
+    id.starts_with("Call") || id.starts_with("Execute")
+}
+
+fn is_jmp(id: &Ident) -> bool {
+    let id = id.to_string();
+    id.starts_with("JmpByCall") || id.starts_with("JmpByExecute")
+}
+
+fn create_instr_variant(id: Ident, mut variant: Variant) -> Variant {
+    use proc_macro2::Span;
+    use syn::punctuated::Punctuated;
+    use syn::token::Paren;
+
+    // add the perm_vars usize field to the variant.
+
+    if is_callable(&id) || is_jmp(&id) {
+        let field = Field {
+            attrs: vec![],
+            vis: Visibility::Inherited,
+            ident: None,
+            colon_token: None,
+            ty: parse_quote! { usize },
+        };
+
+        match &mut variant.fields {
+            Fields::Unnamed(ref mut fields) => {
+                fields.unnamed.push(field);
+            }
+            Fields::Unit => {
+                variant.fields = Fields::Unnamed(FieldsUnnamed {
+                    paren_token: Paren(Span::call_site()),
+                    unnamed: {
+                        let mut fields_seq = Punctuated::new();
+                        fields_seq.push(field);
+                        fields_seq
+                    }
+                });
+            }
+            _ => {
+                unreachable!();
+            }
+        }
+    }
+
+    variant.ident = id;
+    variant.attrs.clear();
+
+    variant
+}
+
+fn prop_from_ident<DiscriminantT>(id: &Ident, key: &'static str) -> &'static str
+   where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug
+{
+    let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
+        Ok(disc) => disc,
+        Err(_) => {
+            panic!("can't generate discriminant {}", id);
+        }
+    };
+
+    match disc.get_str(key) {
+        Some(prop) => prop,
+        None => {
+            panic!("can't find property {} of discriminant {:?}", key, disc);
+        }
+    }
+}
+
+#[derive(Clone, Copy)]
+enum Arity {
+    Static(usize),
+    Ident(&'static str)
+}
+
+impl From<&'static str> for Arity {
+    fn from(arity: &'static str) -> Self {
+        usize::from_str_radix(&arity, 10)
+            .map(|n| Arity::Static(n))
+            .unwrap_or_else(|_| Arity::Ident(arity))
+    }
+}
+
+#[derive(Clone, Copy)]
+enum CountableInference {
+    HasDefault,
+    NotCounted,
+}
+
+struct InstructionData {
+    instr_variants: Vec<(&'static str, Arity, CountableInference, Variant)>,
+    clause_type_variants: Vec<(&'static str, Arity, Variant)>,
+    builtin_type_variants: Vec<(&'static str, Arity, Variant)>,
+    inlined_type_variants: Vec<(&'static str, Arity, Variant)>,
+    system_clause_type_variants: Vec<(&'static str, Arity, Variant)>,
+    compare_number_variants: Vec<(&'static str, Arity, Variant)>,
+    compare_term_variants: Vec<(&'static str, Arity, Variant)>,
+    repl_code_ptr_variants: Vec<(&'static str, Arity, Variant)>,
+}
+
+impl InstructionData {
+    fn new() -> Self {
+        Self {
+            instr_variants: vec![],
+            clause_type_variants: vec![],
+            builtin_type_variants: vec![],
+            inlined_type_variants: vec![],
+            system_clause_type_variants: vec![],
+            compare_number_variants: vec![],
+            compare_term_variants: vec![],
+            repl_code_ptr_variants: vec![],
+        }
+    }
+
+    fn label_variant(&mut self, id: &Ident, prefix: &'static str, variant: Variant) {
+        let (name, arity, countable_inference) = if id == "CompareNumber" {
+            let (name, arity) = add_discriminant_data::<CompareNumberDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.compare_number_variants,
+            );
+
+            (name, arity, CountableInference::HasDefault)
+        } else if id == "CompareTerm" {
+            let (name, arity) = add_discriminant_data::<CompareTermDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.compare_term_variants,
+            );
+
+            (name, arity, CountableInference::HasDefault)
+        } else if id == "BuiltInClauseType" {
+            let (name, arity) = add_discriminant_data::<BuiltInClauseTypeDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.builtin_type_variants,
+            );
+
+            (name, arity, CountableInference::HasDefault)
+        } else if id == "InlinedClauseType" {
+            let (name, arity) = add_discriminant_data::<InlinedClauseTypeDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.inlined_type_variants,
+            );
+
+            (name, arity, CountableInference::NotCounted)
+        } else if id == "REPLCodePtr" {
+            let (name, arity) = add_discriminant_data::<REPLCodePtrDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.repl_code_ptr_variants,
+            );
+
+            (name, arity, CountableInference::NotCounted)
+        } else if id == "SystemClauseType" {
+            let (name, arity) = add_discriminant_data::<SystemClauseTypeDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.system_clause_type_variants,
+            );
+
+            (name, arity, CountableInference::NotCounted)
+        } else if id == "InstructionTemplate" {
+            ( prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Name"),
+              Arity::from(prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Arity")),
+              CountableInference::NotCounted
+            )
+        } else if id == "ClauseType" {
+            let (name, arity) = add_discriminant_data::<ClauseTypeDiscriminants>(
+                &variant,
+                prefix,
+                &mut self.clause_type_variants,
+            );
+
+            (name, arity, CountableInference::HasDefault)
+        } else {
+            panic!("type ID is: {}", id);
+        };
+
+        let v_string = variant.ident.to_string();
+
+        let v_ident = if v_string.starts_with("Call") {
+            format_ident!("{}", v_string["Call".len() ..])
+        } else {
+            variant.ident.clone()
+        };
+
+        let generated_variant = create_instr_variant(
+            format_ident!("{}{}", prefix, v_ident),
+            variant.clone(),
+        );
+
+        self.instr_variants.push(
+            (name, arity, countable_inference, generated_variant)
+        );
+    }
+
+    fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) {
+        if let Data::Enum(DataEnum { variants, .. }) = input.data {
+            for mut variant in variants {
+                if let Some(field) = variant.fields.iter().next() {
+                    if let Some(input) = derive_input(&field.ty) {
+                        self.generate_instruction_enum_loop(input);
+                        continue;
+                    }
+                }
+
+                if input.ident == "InstructionTemplate" {
+                    variant.attrs.clear();
+                    self.label_variant(&input.ident, "", variant);
+                    continue;
+                }
+
+                self.label_variant(&input.ident, "Call", variant.clone());
+                self.label_variant(&input.ident, "Execute", variant.clone());
+
+                if input.ident == "BuiltInClauseType" ||
+                    input.ident == "CompareNumber" ||
+                    input.ident == "CompareTerm" ||
+                    input.ident == "ClauseType"
+                {
+                    self.label_variant(&input.ident, "DefaultCall", variant.clone());
+                    self.label_variant(&input.ident, "DefaultExecute", variant);
+                }
+            }
+        } else {
+            panic!("{} must be an enum!", input.ident);
+        }
+    }
+}
diff --git a/crates/prolog_parser/Cargo.toml b/crates/prolog_parser/Cargo.toml
deleted file mode 100644 (file)
index dc19afb..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-[package]
-name = "prolog_parser"
-version = "0.8.68"
-authors = ["Mark Thom <[email protected]>"]
-edition = "2021"
-repository = "https://github.com/mthom/scryer-prolog"
-description = " An operator precedence parser for the Rebis development version of Scryer Prolog, an up and coming ISO Prolog implementation."
-license = "BSD-3-Clause"
-
-[dependencies]
-indexmap = "1.0.2"
-lexical = "5.2.1"
-ordered-float = "0.5.0"
-rug = { optional = true, version = "1.4.0" }
-num-rug-adapter = { optional = true, path = "../num-rug-adapter" }
-unicode_reader = "1.0.0"
-
-[lib]
-path = "src/lib.rs"
-
-[features]
-num = ["num-rug-adapter"]
-# no default features to make num tests work
-# workaround for --no-default-features and --features not working intuitively for workspaces with a root package
-# see rust-lang/cargo#7160
-# default = ["rug"]
index a6da96b95c1c724520332ca8de4870514092fcd2..1432ae68ac4548e49270735c2ed9614c0e236ca2 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 name = "static-string-indexing"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 proc-macro2 = "*"
diff --git a/crates/to-syn-value/Cargo.toml b/crates/to-syn-value/Cargo.toml
new file mode 100644 (file)
index 0000000..3fa4953
--- /dev/null
@@ -0,0 +1,10 @@
+[package]
+name = "to-syn-value"
+version = "0.1.0"
+authors = ["Mark Thom <[email protected]>"]
+edition = "2021"
+publish = false
+
+[dependencies]
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+to-syn-value_derive = { path = "../to-syn-value_derive" }
\ No newline at end of file
diff --git a/crates/to-syn-value/src/lib.rs b/crates/to-syn-value/src/lib.rs
new file mode 100644 (file)
index 0000000..753c44a
--- /dev/null
@@ -0,0 +1,3 @@
+pub trait ToDeriveInput {
+    fn to_derive_input() -> syn::DeriveInput;
+}
diff --git a/crates/to-syn-value_derive/Cargo.toml b/crates/to-syn-value_derive/Cargo.toml
new file mode 100644 (file)
index 0000000..9dc0e8a
--- /dev/null
@@ -0,0 +1,14 @@
+[package]
+name = "to-syn-value_derive"
+version = "0.1.0"
+authors = ["Mark Thom <[email protected]>"]
+edition = "2021"
+publish = false
+
+[lib]
+proc-macro = true
+
+[dependencies]
+proc-macro2 = "*"
+syn = { version = "*", features = ['full', 'visit', 'extra-traits'] }
+quote = "*"
\ No newline at end of file
diff --git a/crates/to-syn-value_derive/src/lib.rs b/crates/to-syn-value_derive/src/lib.rs
new file mode 100644 (file)
index 0000000..13845ac
--- /dev/null
@@ -0,0 +1,20 @@
+use syn::*;
+use quote::*;
+
+#[proc_macro_derive(ToDeriveInput)]
+pub fn derive_to_derive_input(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let derive_input = parse_macro_input!(input as DeriveInput);
+    let ty_name = derive_input.ident.clone();
+
+    quote! {
+        use to_syn_value::*;
+
+        impl ToDeriveInput for #ty_name {
+            fn to_derive_input() -> syn::DeriveInput {
+                syn::parse_quote! {
+                    #derive_input
+                }
+            }
+        }
+    }.into()
+}
index c29adc9283c0b7498da74a749f591be567a44d9a..7a3b43a0c3dc2fd20e6f96afef6bdc93dd7d3b23 100644 (file)
@@ -3,6 +3,7 @@ use crate::temp_v;
 
 use crate::fixtures::*;
 use crate::forms::*;
+use crate::instructions::*;
 use crate::machine::machine_indices::*;
 
 use std::cell::Cell;
@@ -11,7 +12,7 @@ use std::rc::Rc;
 pub(crate) trait Allocator<'a> {
     fn new() -> Self;
 
-    fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Vec<Target>)
+    fn mark_anon_var<Target>(&mut self, _: Level, _: GenContext, _: &mut Code)
     where
         Target: crate::targets::CompilationTarget<'a>;
     fn mark_non_var<Target>(
@@ -19,7 +20,7 @@ pub(crate) trait Allocator<'a> {
         _: Level,
         _: GenContext,
         _: &'a Cell<RegType>,
-        _: &mut Vec<Target>,
+        _: &mut Code,
     ) where
         Target: crate::targets::CompilationTarget<'a>;
     fn mark_reserved_var<Target>(
@@ -28,7 +29,7 @@ pub(crate) trait Allocator<'a> {
         _: Level,
         _: &'a Cell<VarReg>,
         _: GenContext,
-        _: &mut Vec<Target>,
+        _: &mut Code,
         _: RegType,
         _: bool,
     ) where
@@ -39,7 +40,7 @@ pub(crate) trait Allocator<'a> {
         _: Level,
         _: &'a Cell<VarReg>,
         _: GenContext,
-        _: &mut Vec<Target>,
+        _: &mut Code,
     ) where
         Target: crate::targets::CompilationTarget<'a>;
 
index d09187f815e6013a5cd4825bc7064c39f4e34d18..6396336d481f2750dcb6bdef5d9b1780065dbd9d 100644 (file)
@@ -1,6 +1,5 @@
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::fixtures::*;
 use crate::forms::*;
 use crate::instructions::*;
@@ -25,6 +24,29 @@ use std::ops::Div;
 use std::rc::Rc;
 use std::vec::Vec;
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub enum ArithmeticTerm {
+    Reg(RegType),
+    Interm(usize),
+    Number(Number),
+}
+
+impl ArithmeticTerm {
+    pub(crate) fn interm_or(&self, interm: usize) -> usize {
+        if let &ArithmeticTerm::Interm(interm) = self {
+            interm
+        } else {
+            interm
+        }
+    }
+}
+
+impl Default for ArithmeticTerm {
+    fn default() -> Self {
+        ArithmeticTerm::Number(Number::default())
+    }
+}
+
 #[derive(Debug)]
 pub(crate) struct ArithInstructionIterator<'a> {
     state_stack: Vec<TermIterState<'a>>,
@@ -46,7 +68,7 @@ impl<'a> ArithInstructionIterator<'a> {
                     Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
                 }
                 ClauseType::Inlined(InlinedClauseType::IsFloat(_)) => {
-                    let ct = ClauseType::Named(atom!("float"), 1, CodeIndex::default());
+                    let ct = ClauseType::Named(1, atom!("float"), CodeIndex::default());
                     Ok(TermIterState::Clause(Level::Shallow, 0, cell, ct, terms))
                 }
                 _ => Err(ArithmeticError::NonEvaluableFunctor(
@@ -174,27 +196,27 @@ impl<'a> ArithmeticEvaluator<'a> {
         name: Atom,
         a1: ArithmeticTerm,
         t: usize,
-    ) -> Result<ArithmeticInstruction, ArithmeticError> {
+    ) -> Result<Instruction, ArithmeticError> {
         match name {
-            atom!("abs") => Ok(ArithmeticInstruction::Abs(a1, t)),
-            atom!("-") => Ok(ArithmeticInstruction::Neg(a1, t)),
-            atom!("+") => Ok(ArithmeticInstruction::Plus(a1, t)),
-            atom!("cos") => Ok(ArithmeticInstruction::Cos(a1, t)),
-            atom!("sin") => Ok(ArithmeticInstruction::Sin(a1, t)),
-            atom!("tan") => Ok(ArithmeticInstruction::Tan(a1, t)),
-            atom!("log") => Ok(ArithmeticInstruction::Log(a1, t)),
-            atom!("exp") => Ok(ArithmeticInstruction::Exp(a1, t)),
-            atom!("sqrt") => Ok(ArithmeticInstruction::Sqrt(a1, t)),
-            atom!("acos") => Ok(ArithmeticInstruction::ACos(a1, t)),
-            atom!("asin") => Ok(ArithmeticInstruction::ASin(a1, t)),
-            atom!("atan") => Ok(ArithmeticInstruction::ATan(a1, t)),
-            atom!("float") => Ok(ArithmeticInstruction::Float(a1, t)),
-            atom!("truncate") => Ok(ArithmeticInstruction::Truncate(a1, t)),
-            atom!("round") => Ok(ArithmeticInstruction::Round(a1, t)),
-            atom!("ceiling") => Ok(ArithmeticInstruction::Ceiling(a1, t)),
-            atom!("floor") => Ok(ArithmeticInstruction::Floor(a1, t)),
-            atom!("sign") => Ok(ArithmeticInstruction::Sign(a1, t)),
-            atom!("\\") => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
+            atom!("abs") => Ok(Instruction::Abs(a1, t)),
+            atom!("-") => Ok(Instruction::Neg(a1, t)),
+            atom!("+") => Ok(Instruction::Plus(a1, t)),
+            atom!("cos") => Ok(Instruction::Cos(a1, t)),
+            atom!("sin") => Ok(Instruction::Sin(a1, t)),
+            atom!("tan") => Ok(Instruction::Tan(a1, t)),
+            atom!("log") => Ok(Instruction::Log(a1, t)),
+            atom!("exp") => Ok(Instruction::Exp(a1, t)),
+            atom!("sqrt") => Ok(Instruction::Sqrt(a1, t)),
+            atom!("acos") => Ok(Instruction::ACos(a1, t)),
+            atom!("asin") => Ok(Instruction::ASin(a1, t)),
+            atom!("atan") => Ok(Instruction::ATan(a1, t)),
+            atom!("float") => Ok(Instruction::Float(a1, t)),
+            atom!("truncate") => Ok(Instruction::Truncate(a1, t)),
+            atom!("round") => Ok(Instruction::Round(a1, t)),
+            atom!("ceiling") => Ok(Instruction::Ceiling(a1, t)),
+            atom!("floor") => Ok(Instruction::Floor(a1, t)),
+            atom!("sign") => Ok(Instruction::Sign(a1, t)),
+            atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
             _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
         }
     }
@@ -205,28 +227,28 @@ impl<'a> ArithmeticEvaluator<'a> {
         a1: ArithmeticTerm,
         a2: ArithmeticTerm,
         t: usize,
-    ) -> Result<ArithmeticInstruction, ArithmeticError> {
+    ) -> Result<Instruction, ArithmeticError> {
         match name {
-            atom!("+") => Ok(ArithmeticInstruction::Add(a1, a2, t)),
-            atom!("-") => Ok(ArithmeticInstruction::Sub(a1, a2, t)),
-            atom!("/") => Ok(ArithmeticInstruction::Div(a1, a2, t)),
-            atom!("//") => Ok(ArithmeticInstruction::IDiv(a1, a2, t)),
-            atom!("max") => Ok(ArithmeticInstruction::Max(a1, a2, t)),
-            atom!("min") => Ok(ArithmeticInstruction::Min(a1, a2, t)),
-            atom!("div") => Ok(ArithmeticInstruction::IntFloorDiv(a1, a2, t)),
-            atom!("rdiv") => Ok(ArithmeticInstruction::RDiv(a1, a2, t)),
-            atom!("*") => Ok(ArithmeticInstruction::Mul(a1, a2, t)),
-            atom!("**") => Ok(ArithmeticInstruction::Pow(a1, a2, t)),
-            atom!("^") => Ok(ArithmeticInstruction::IntPow(a1, a2, t)),
-            atom!(">>") => Ok(ArithmeticInstruction::Shr(a1, a2, t)),
-            atom!("<<") => Ok(ArithmeticInstruction::Shl(a1, a2, t)),
-            atom!("/\\") => Ok(ArithmeticInstruction::And(a1, a2, t)),
-            atom!("\\/") => Ok(ArithmeticInstruction::Or(a1, a2, t)),
-            atom!("xor") => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
-            atom!("mod") => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
-            atom!("rem") => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
-            atom!("gcd") => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
-            atom!("atan2") => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
+            atom!("+") => Ok(Instruction::Add(a1, a2, t)),
+            atom!("-") => Ok(Instruction::Sub(a1, a2, t)),
+            atom!("/") => Ok(Instruction::Div(a1, a2, t)),
+            atom!("//") => Ok(Instruction::IDiv(a1, a2, t)),
+            atom!("max") => Ok(Instruction::Max(a1, a2, t)),
+            atom!("min") => Ok(Instruction::Min(a1, a2, t)),
+            atom!("div") => Ok(Instruction::IntFloorDiv(a1, a2, t)),
+            atom!("rdiv") => Ok(Instruction::RDiv(a1, a2, t)),
+            atom!("*") => Ok(Instruction::Mul(a1, a2, t)),
+            atom!("**") => Ok(Instruction::Pow(a1, a2, t)),
+            atom!("^") => Ok(Instruction::IntPow(a1, a2, t)),
+            atom!(">>") => Ok(Instruction::Shr(a1, a2, t)),
+            atom!("<<") => Ok(Instruction::Shl(a1, a2, t)),
+            atom!("/\\") => Ok(Instruction::And(a1, a2, t)),
+            atom!("\\/") => Ok(Instruction::Or(a1, a2, t)),
+            atom!("xor") => Ok(Instruction::Xor(a1, a2, t)),
+            atom!("mod") => Ok(Instruction::Mod(a1, a2, t)),
+            atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
+            atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
+            atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
             _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
         }
     }
@@ -244,7 +266,7 @@ impl<'a> ArithmeticEvaluator<'a> {
         &mut self,
         name: Atom,
         arity: usize,
-    ) -> Result<ArithmeticInstruction, ArithmeticError> {
+    ) -> Result<Instruction, ArithmeticError> {
         match arity {
             1 => {
                 let a1 = self.interm.pop().unwrap();
@@ -310,7 +332,7 @@ impl<'a> ArithmeticEvaluator<'a> {
                     self.interm.push(ArithmeticTerm::Reg(r));
                 }
                 ArithTermRef::Op(name, arity) => {
-                    code.push(Line::Arithmetic(self.instr_from_clause(name, arity)?));
+                    code.push(self.instr_from_clause(name, arity)?);
                 }
             }
         }
diff --git a/src/clause_types.rs b/src/clause_types.rs
deleted file mode 100644 (file)
index 8083775..0000000
+++ /dev/null
@@ -1,952 +0,0 @@
-use crate::atom_table::*;
-use crate::machine::machine_indices::*;
-use crate::parser::ast::*;
-use crate::parser::rug::rand::RandState;
-
-use crate::forms::Number;
-use crate::temp_v;
-
-use ref_thread_local::{ref_thread_local};
-
-#[derive(Debug, Clone, Copy, Eq, PartialEq)]
-pub enum CompareNumberQT {
-    GreaterThan,
-    LessThan,
-    GreaterThanOrEqual,
-    LessThanOrEqual,
-    NotEqual,
-    Equal,
-}
-
-impl CompareNumberQT {
-    fn name(self) -> Atom {
-        match self {
-            CompareNumberQT::GreaterThan => atom!(">"),
-            CompareNumberQT::LessThan => atom!("<"),
-            CompareNumberQT::GreaterThanOrEqual => atom!(">="),
-            CompareNumberQT::LessThanOrEqual => atom!("=<"),
-            CompareNumberQT::NotEqual => atom!("=\\="),
-            CompareNumberQT::Equal => atom!("=:="),
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum CompareTermQT {
-    LessThan,
-    LessThanOrEqual,
-    GreaterThanOrEqual,
-    GreaterThan,
-}
-
-impl CompareTermQT {
-    fn name(self) -> Atom {
-        match self {
-            CompareTermQT::GreaterThan => atom!("@>"),
-            CompareTermQT::LessThan => atom!("@<"),
-            CompareTermQT::GreaterThanOrEqual => atom!("@>="),
-            CompareTermQT::LessThanOrEqual => atom!("@=<"),
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-pub enum ArithmeticTerm {
-    Reg(RegType),
-    Interm(usize),
-    Number(Number),
-}
-
-impl ArithmeticTerm {
-    pub(crate) fn interm_or(&self, interm: usize) -> usize {
-        if let &ArithmeticTerm::Interm(interm) = self {
-            interm
-        } else {
-            interm
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum InlinedClauseType {
-    CompareNumber(CompareNumberQT, ArithmeticTerm, ArithmeticTerm),
-    IsAtom(RegType),
-    IsAtomic(RegType),
-    IsCompound(RegType),
-    IsInteger(RegType),
-    IsNumber(RegType),
-    IsRational(RegType),
-    IsFloat(RegType),
-    IsNonVar(RegType),
-    IsVar(RegType),
-}
-
-ref_thread_local! {
-    pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new();
-}
-
-pub fn clause_type_form(name: Atom, arity: usize) -> Option<ClauseType> {
-    match (name, arity) {
-        (atom!(">"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber(
-            CompareNumberQT::GreaterThan,
-            ar_reg!(temp_v!(1)),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!("<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber(
-            CompareNumberQT::LessThan,
-            ar_reg!(temp_v!(1)),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!(">="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber(
-            CompareNumberQT::GreaterThanOrEqual,
-            ar_reg!(temp_v!(1)),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!("=<"), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber(
-            CompareNumberQT::LessThanOrEqual,
-            ar_reg!(temp_v!(1)),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!("=:="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber(
-            CompareNumberQT::Equal,
-            ar_reg!(temp_v!(1)),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!("=\\="), 2) => Some(ClauseType::Inlined(InlinedClauseType::CompareNumber(
-            CompareNumberQT::NotEqual,
-            ar_reg!(temp_v!(1)),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!("atom"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtom(temp_v!(1)))),
-        (atom!("atomic"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsAtomic(temp_v!(1)))),
-        (atom!("compound"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsCompound(temp_v!(
-            1
-        )))),
-        (atom!("integer"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsInteger(temp_v!(
-            1
-        )))),
-        (atom!("number"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNumber(temp_v!(1)))),
-        (atom!("rational"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsRational(temp_v!(
-            1
-        )))),
-        (atom!("float"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsFloat(temp_v!(1)))),
-        (atom!("nonvar"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsNonVar(temp_v!(1)))),
-        (atom!("var"), 1) => Some(ClauseType::Inlined(InlinedClauseType::IsVar(temp_v!(1)))),
-        (atom!("acyclic_term"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::AcyclicTerm)),
-        (atom!("arg"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Arg)),
-        (atom!("compare"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Compare)),
-        (atom!("@>"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(
-            CompareTermQT::GreaterThan,
-        ))),
-        (atom!("@<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(
-            CompareTermQT::LessThan,
-        ))),
-        (atom!("@>="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(
-            CompareTermQT::GreaterThanOrEqual,
-        ))),
-        (atom!("@=<"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CompareTerm(
-            CompareTermQT::LessThanOrEqual,
-        ))),
-        (atom!("copy_term"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::CopyTerm)),
-        (atom!("=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Eq)),
-        (atom!("functor"), 3) => Some(ClauseType::BuiltIn(BuiltInClauseType::Functor)),
-        (atom!("ground"), 1) => Some(ClauseType::BuiltIn(BuiltInClauseType::Ground)),
-        (atom!("is"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Is(
-            temp_v!(1),
-            ar_reg!(temp_v!(2)),
-        ))),
-        (atom!("keysort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::KeySort)),
-        (atom!("\\=="), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::NotEq)),
-        (atom!("read"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Read)),
-        (atom!("sort"), 2) => Some(ClauseType::BuiltIn(BuiltInClauseType::Sort)),
-        _ => None,
-    }
-}
-
-impl InlinedClauseType {
-    pub(crate) fn name(&self) -> Atom {
-        match self {
-            &InlinedClauseType::CompareNumber(qt, ..) => qt.name(),
-            &InlinedClauseType::IsAtom(..) => atom!("atom"),
-            &InlinedClauseType::IsAtomic(..) => atom!("atomic"),
-            &InlinedClauseType::IsCompound(..) => atom!("compound"),
-            &InlinedClauseType::IsNumber(..) => atom!("number"),
-            &InlinedClauseType::IsInteger(..) => atom!("integer"),
-            &InlinedClauseType::IsRational(..) => atom!("rational"),
-            &InlinedClauseType::IsFloat(..) => atom!("float"),
-            &InlinedClauseType::IsNonVar(..) => atom!("nonvar"),
-            &InlinedClauseType::IsVar(..) => atom!("var"),
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum SystemClauseType {
-    AtomChars,
-    AtomCodes,
-    AtomLength,
-    BindFromRegister,
-    CallContinuation,
-    CharCode,
-    CharType,
-    CharsToNumber,
-    CodesToNumber,
-    CopyTermWithoutAttrVars,
-    CheckCutPoint,
-    Close,
-    CopyToLiftedHeap,
-    CreatePartialString,
-    CurrentHostname,
-    CurrentInput,
-    CurrentOutput,
-    DirectoryFiles,
-    FileSize,
-    FileExists,
-    DirectoryExists,
-    DirectorySeparator,
-    MakeDirectory,
-    MakeDirectoryPath,
-    DeleteFile,
-       RenameFile,
-    WorkingDirectory,
-    DeleteDirectory,
-    PathCanonical,
-    FileTime,
-    DeleteAttribute,
-    DeleteHeadAttribute,
-    DynamicModuleResolution(usize),
-    EnqueueAttributedVar,
-    FetchGlobalVar,
-    FirstStream,
-    FlushOutput,
-    GetByte,
-    GetChar,
-    GetNChars,
-    GetCode,
-    GetSingleChar,
-    ResetAttrVarState,
-    TruncateIfNoLiftedHeapGrowthDiff,
-    TruncateIfNoLiftedHeapGrowth,
-    GetAttributedVariableList,
-    GetAttrVarQueueDelimiter,
-    GetAttrVarQueueBeyond,
-    GetBValue,
-    GetContinuationChunk,
-    GetNextDBRef,
-    GetNextOpDBRef,
-    IsPartialString,
-    Halt,
-    GetLiftedHeapFromOffset,
-    GetLiftedHeapFromOffsetDiff,
-    GetSCCCleaner,
-    HeadIsDynamic,
-    InstallSCCCleaner,
-    InstallInferenceCounter,
-    LiftedHeapLength,
-    LoadLibraryAsStream,
-    ModuleExists,
-    NextEP,
-    NoSuchPredicate,
-    NumberToChars,
-    NumberToCodes,
-    OpDeclaration,
-    Open,
-    SetStreamOptions,
-    NextStream,
-    PartialStringTail,
-    PeekByte,
-    PeekChar,
-    PeekCode,
-    PointsToContinuationResetMarker,
-    PutByte,
-    PutChar,
-    PutChars,
-    PutCode,
-    REPL(REPLCodePtr),
-    ReadQueryTerm,
-    ReadTerm,
-    RedoAttrVarBinding,
-    RemoveCallPolicyCheck,
-    RemoveInferenceCounter,
-    ResetContinuationMarker,
-    RestoreCutPolicy,
-    SetCutPoint(RegType),
-    SetInput,
-    SetOutput,
-    StoreBacktrackableGlobalVar,
-    StoreGlobalVar,
-    StreamProperty,
-    SetStreamPosition,
-    InferenceLevel,
-    CleanUpBlock,
-    EraseBall,
-    Fail,
-    GetBall,
-    GetCurrentBlock,
-    GetCutPoint,
-    GetStaggeredCutPoint,
-    GetDoubleQuotes,
-    InstallNewBlock,
-    Maybe,
-    CpuNow,
-    CurrentTime,
-    QuotedToken,
-    ReadTermFromChars,
-    ResetBlock,
-    ReturnFromVerifyAttr,
-    SetBall,
-    SetCutPointByDefault(RegType),
-    SetDoubleQuotes,
-    SetSeed,
-    SkipMaxList,
-    Sleep,
-    SocketClientOpen,
-    SocketServerOpen,
-    SocketServerAccept,
-    SocketServerClose,
-    TLSAcceptClient,
-    TLSClientConnect,
-    Succeed,
-    TermAttributedVariables,
-    TermVariables,
-    TermVariablesUnderMaxDepth,
-    TruncateLiftedHeapTo,
-    UnifyWithOccursCheck,
-    UnwindEnvironments,
-    UnwindStack,
-    WAMInstructions,
-    WriteTerm,
-    WriteTermToChars,
-    ScryerPrologVersion,
-    CryptoRandomByte,
-    CryptoDataHash,
-    CryptoDataHKDF,
-    CryptoPasswordHash,
-    CryptoDataEncrypt,
-    CryptoDataDecrypt,
-    CryptoCurveScalarMult,
-    Ed25519Sign,
-    Ed25519Verify,
-    Ed25519NewKeyPair,
-    Ed25519KeyPairPublicKey,
-    Curve25519ScalarMult,
-    FirstNonOctet,
-    LoadHTML,
-    LoadXML,
-    GetEnv,
-    SetEnv,
-    UnsetEnv,
-    Shell,
-    PID,
-    CharsBase64,
-    DevourWhitespace,
-    IsSTOEnabled,
-    SetSTOAsUnify,
-    SetNSTOAsUnify,
-    SetSTOWithErrorAsUnify,
-    HomeDirectory,
-    DebugHook,
-    PopCount
-}
-
-impl SystemClauseType {
-    pub(crate) fn name(&self) -> Atom {
-        match self {
-            &SystemClauseType::AtomChars => atom!("$atom_chars"),
-            &SystemClauseType::AtomCodes => atom!("$atom_codes"),
-            &SystemClauseType::AtomLength => atom!("$atom_length"),
-            &SystemClauseType::BindFromRegister => atom!("$bind_from_register"),
-            &SystemClauseType::CallContinuation => atom!("$call_continuation"),
-            &SystemClauseType::CharCode => atom!("$char_code"),
-            &SystemClauseType::CharType => atom!("$char_type"),
-            &SystemClauseType::CharsToNumber => atom!("$chars_to_number"),
-            &SystemClauseType::CheckCutPoint => atom!("$check_cp"),
-            &SystemClauseType::CodesToNumber => atom!("$codes_to_number"),
-            &SystemClauseType::CopyTermWithoutAttrVars => {
-                atom!("$copy_term_without_attr_vars")
-            }
-            &SystemClauseType::CreatePartialString => atom!("$create_partial_string"),
-            &SystemClauseType::CurrentInput => atom!("$current_input"),
-            &SystemClauseType::CurrentHostname => atom!("$current_hostname"),
-            &SystemClauseType::CurrentOutput => atom!("$current_output"),
-            &SystemClauseType::DirectoryFiles => atom!("$directory_files"),
-            &SystemClauseType::FileSize => atom!("$file_size"),
-            &SystemClauseType::FileExists => atom!("$file_exists"),
-            &SystemClauseType::DirectoryExists => atom!("$directory_exists"),
-            &SystemClauseType::DirectorySeparator => atom!("$directory_separator"),
-            &SystemClauseType::MakeDirectory => atom!("$make_directory"),
-            &SystemClauseType::MakeDirectoryPath => atom!("$make_directory_path"),
-            &SystemClauseType::DeleteFile => atom!("$delete_file"),
-            &SystemClauseType::RenameFile => atom!("$rename_file"),
-            &SystemClauseType::DeleteDirectory => atom!("$delete_directory"),
-            &SystemClauseType::WorkingDirectory => atom!("$working_directory"),
-            &SystemClauseType::PathCanonical => atom!("$path_canonical"),
-            &SystemClauseType::FileTime => atom!("$file_time"),
-            &SystemClauseType::REPL(REPLCodePtr::AddDiscontiguousPredicate) => {
-                atom!("$add_discontiguous_predicate")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => atom!("$add_dynamic_predicate"),
-            &SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate) => {
-                atom!("$add_multifile_predicate")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => {
-                atom!("$add_goal_expansion_clause")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => {
-                atom!("$add_term_expansion_clause")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => atom!("$clause_to_evacuable"),
-            &SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable) => {
-                atom!("$scoped_clause_to_evacuable")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => atom!("$conclude_load"),
-            &SystemClauseType::REPL(REPLCodePtr::DeclareModule) => atom!("$declare_module"),
-            &SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) => atom!("$load_compiled_library"),
-            &SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) => {
-                atom!("$push_load_state_payload")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule) => {
-                atom!("$add_in_situ_filename_module")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::Asserta) => atom!("$asserta"),
-            &SystemClauseType::REPL(REPLCodePtr::Assertz) => atom!("$assertz"),
-            &SystemClauseType::REPL(REPLCodePtr::Retract) => atom!("$retract_clause"),
-            &SystemClauseType::REPL(REPLCodePtr::UseModule) => atom!("$use_module"),
-            &SystemClauseType::REPL(REPLCodePtr::PushLoadContext) => atom!("$push_load_context"),
-            &SystemClauseType::REPL(REPLCodePtr::PopLoadContext) => atom!("$pop_load_context"),
-            &SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) => atom!("$pop_load_state_payload"),
-            &SystemClauseType::REPL(REPLCodePtr::LoadContextSource) => atom!("$prolog_lc_source"),
-            &SystemClauseType::REPL(REPLCodePtr::LoadContextFile) => atom!("$prolog_lc_file"),
-            &SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) => atom!("$prolog_lc_dir"),
-            &SystemClauseType::REPL(REPLCodePtr::LoadContextModule) => atom!("$prolog_lc_module"),
-            &SystemClauseType::REPL(REPLCodePtr::LoadContextStream) => atom!("$prolog_lc_stream"),
-            &SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) => {
-                atom!("$cpp_meta_predicate_property")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::BuiltInProperty) => atom!("$cpp_built_in_property"),
-            &SystemClauseType::REPL(REPLCodePtr::DynamicProperty) => atom!("$cpp_dynamic_property"),
-            &SystemClauseType::REPL(REPLCodePtr::MultifileProperty) => atom!("$cpp_multifile_property"),
-            &SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty) => {
-                atom!("$cpp_discontiguous_property")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::AbolishClause) => atom!("$abolish_clause"),
-            &SystemClauseType::REPL(REPLCodePtr::IsConsistentWithTermQueue) => {
-                atom!("$is_consistent_with_term_queue")
-            }
-            &SystemClauseType::REPL(REPLCodePtr::FlushTermQueue) => atom!("$flush_term_queue"),
-            &SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports) => atom!("$remove_module_exports"),
-            &SystemClauseType::REPL(REPLCodePtr::AddNonCountedBacktracking) => {
-                atom!("$add_non_counted_backtracking")
-            }
-            &SystemClauseType::Close => atom!("$close"),
-            &SystemClauseType::CopyToLiftedHeap => atom!("$copy_to_lh"),
-            &SystemClauseType::DeleteAttribute => atom!("$del_attr_non_head"),
-            &SystemClauseType::DeleteHeadAttribute => atom!("$del_attr_head"),
-            &SystemClauseType::DynamicModuleResolution(_) => atom!("$module_call"),
-            &SystemClauseType::EnqueueAttributedVar => atom!("$enqueue_attr_var"),
-            &SystemClauseType::FetchGlobalVar => atom!("$fetch_global_var"),
-            &SystemClauseType::FirstStream => atom!("$first_stream"),
-            &SystemClauseType::FlushOutput => atom!("$flush_output"),
-            &SystemClauseType::GetByte => atom!("$get_byte"),
-            &SystemClauseType::GetChar => atom!("$get_char"),
-            &SystemClauseType::GetNChars => atom!("$get_n_chars"),
-            &SystemClauseType::GetCode => atom!("$get_code"),
-            &SystemClauseType::GetSingleChar => atom!("$get_single_char"),
-            &SystemClauseType::ResetAttrVarState => atom!("$reset_attr_var_state"),
-            &SystemClauseType::TruncateIfNoLiftedHeapGrowth => atom!("$truncate_if_no_lh_growth"),
-            &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => atom!("$truncate_if_no_lh_growth_diff"),
-            &SystemClauseType::GetAttributedVariableList => atom!("$get_attr_list"),
-            &SystemClauseType::GetAttrVarQueueDelimiter => atom!("$get_attr_var_queue_delim"),
-            &SystemClauseType::GetAttrVarQueueBeyond => atom!("$get_attr_var_queue_beyond"),
-            &SystemClauseType::GetContinuationChunk => atom!("$get_cont_chunk"),
-            &SystemClauseType::GetLiftedHeapFromOffset => atom!("$get_lh_from_offset"),
-            &SystemClauseType::GetLiftedHeapFromOffsetDiff => atom!("$get_lh_from_offset_diff"),
-            &SystemClauseType::GetBValue => atom!("$get_b_value"),
-            &SystemClauseType::GetNextDBRef => atom!("$get_next_db_ref"),
-            &SystemClauseType::GetNextOpDBRef => atom!("$get_next_op_db_ref"),
-            &SystemClauseType::GetDoubleQuotes => atom!("$get_double_quotes"),
-            &SystemClauseType::GetSCCCleaner => atom!("$get_scc_cleaner"),
-            &SystemClauseType::Halt => atom!("$halt"),
-            &SystemClauseType::HeadIsDynamic => atom!("$head_is_dynamic"),
-            &SystemClauseType::Open => atom!("$open"),
-            &SystemClauseType::OpDeclaration => atom!("$op"),
-            &SystemClauseType::InstallSCCCleaner => atom!("$install_scc_cleaner"),
-            &SystemClauseType::InstallInferenceCounter => atom!("$install_inference_counter"),
-            &SystemClauseType::IsPartialString => atom!("$is_partial_string"),
-            &SystemClauseType::PartialStringTail => atom!("$partial_string_tail"),
-            &SystemClauseType::PeekByte => atom!("$peek_byte"),
-            &SystemClauseType::PeekChar => atom!("$peek_char"),
-            &SystemClauseType::PeekCode => atom!("$peek_code"),
-            &SystemClauseType::LiftedHeapLength => atom!("$lh_length"),
-            &SystemClauseType::Maybe => atom!("maybe"),
-            &SystemClauseType::CpuNow => atom!("$cpu_now"),
-            &SystemClauseType::CurrentTime => atom!("$current_time"),
-            &SystemClauseType::ModuleExists => atom!("$module_exists"),
-            &SystemClauseType::NextStream => atom!("$next_stream"),
-            &SystemClauseType::NoSuchPredicate => atom!("$no_such_predicate"),
-            &SystemClauseType::NumberToChars => atom!("$number_to_chars"),
-            &SystemClauseType::NumberToCodes => atom!("$number_to_codes"),
-            &SystemClauseType::PointsToContinuationResetMarker => {
-                atom!("$points_to_cont_reset_marker")
-            }
-            &SystemClauseType::PutByte => {
-                atom!("$put_byte")
-            }
-            &SystemClauseType::PutChar => {
-                atom!("$put_char")
-            }
-            &SystemClauseType::PutChars => {
-                atom!("$put_chars")
-            }
-            &SystemClauseType::PutCode => {
-                atom!("$put_code")
-            }
-            &SystemClauseType::QuotedToken => {
-                atom!("$quoted_token")
-            }
-            &SystemClauseType::RedoAttrVarBinding => atom!("$redo_attr_var_binding"),
-            &SystemClauseType::RemoveCallPolicyCheck => atom!("$remove_call_policy_check"),
-            &SystemClauseType::RemoveInferenceCounter => atom!("$remove_inference_counter"),
-            &SystemClauseType::RestoreCutPolicy => atom!("$restore_cut_policy"),
-            &SystemClauseType::SetCutPoint(_) => atom!("$set_cp"),
-            &SystemClauseType::SetInput => atom!("$set_input"),
-            &SystemClauseType::SetOutput => atom!("$set_output"),
-            &SystemClauseType::SetSeed => atom!("$set_seed"),
-            &SystemClauseType::StreamProperty => atom!("$stream_property"),
-            &SystemClauseType::SetStreamPosition => atom!("$set_stream_position"),
-            &SystemClauseType::SetStreamOptions => atom!("$set_stream_options"),
-            &SystemClauseType::StoreBacktrackableGlobalVar => {
-                atom!("$store_back_trackable_global_var")
-            }
-            &SystemClauseType::StoreGlobalVar => atom!("$store_global_var"),
-            &SystemClauseType::InferenceLevel => atom!("$inference_level"),
-            &SystemClauseType::CleanUpBlock => atom!("$clean_up_block"),
-            &SystemClauseType::EraseBall => atom!("$erase_ball"),
-            &SystemClauseType::Fail => atom!("$fail"),
-            &SystemClauseType::GetBall => atom!("$get_ball"),
-            &SystemClauseType::GetCutPoint => atom!("$get_cp"),
-            &SystemClauseType::GetStaggeredCutPoint => atom!("$get_staggered_cp"),
-            &SystemClauseType::GetCurrentBlock => atom!("$get_current_block"),
-            &SystemClauseType::InstallNewBlock => atom!("$install_new_block"),
-            &SystemClauseType::NextEP => atom!("$nextEP"),
-            &SystemClauseType::ReadQueryTerm => atom!("$read_query_term"),
-            &SystemClauseType::ReadTerm => atom!("$read_term"),
-            &SystemClauseType::ReadTermFromChars => atom!("$read_term_from_chars"),
-            &SystemClauseType::ResetBlock => atom!("$reset_block"),
-            &SystemClauseType::ResetContinuationMarker => atom!("$reset_cont_marker"),
-            &SystemClauseType::ReturnFromVerifyAttr => atom!("$return_from_verify_attr"),
-            &SystemClauseType::SetBall => atom!("$set_ball"),
-            &SystemClauseType::SetCutPointByDefault(_) => atom!("$set_cp_by_default"),
-            &SystemClauseType::SetDoubleQuotes => atom!("$set_double_quotes"),
-            &SystemClauseType::SkipMaxList => atom!("$skip_max_list"),
-            &SystemClauseType::Sleep => atom!("$sleep"),
-            &SystemClauseType::SocketClientOpen => atom!("$socket_client_open"),
-            &SystemClauseType::SocketServerOpen => atom!("$socket_server_open"),
-            &SystemClauseType::SocketServerAccept => atom!("$socket_server_accept"),
-            &SystemClauseType::SocketServerClose => atom!("$socket_server_close"),
-            &SystemClauseType::TLSAcceptClient => atom!("$tls_accept_client"),
-            &SystemClauseType::TLSClientConnect => atom!("$tls_client_connect"),
-            &SystemClauseType::Succeed => atom!("$succeed"),
-            &SystemClauseType::TermAttributedVariables => {
-                atom!("$term_attributed_variables")
-            }
-            &SystemClauseType::TermVariables => atom!("$term_variables"),
-            &SystemClauseType::TermVariablesUnderMaxDepth => atom!("$term_variables_under_max_depth"),
-            &SystemClauseType::TruncateLiftedHeapTo => atom!("$truncate_lh_to"),
-            &SystemClauseType::UnifyWithOccursCheck => atom!("$unify_with_occurs_check"),
-            &SystemClauseType::UnwindEnvironments => atom!("$unwind_environments"),
-            &SystemClauseType::UnwindStack => atom!("$unwind_stack"),
-            &SystemClauseType::WAMInstructions => atom!("$wam_instructions"),
-            &SystemClauseType::WriteTerm => atom!("$write_term"),
-            &SystemClauseType::WriteTermToChars => atom!("$write_term_to_chars"),
-            &SystemClauseType::ScryerPrologVersion => atom!("$scryer_prolog_version"),
-            &SystemClauseType::CryptoRandomByte => atom!("$crypto_random_byte"),
-            &SystemClauseType::CryptoDataHash => atom!("$crypto_data_hash"),
-            &SystemClauseType::CryptoDataHKDF => atom!("$crypto_data_hkdf"),
-            &SystemClauseType::CryptoPasswordHash => atom!("$crypto_password_hash"),
-            &SystemClauseType::CryptoDataEncrypt => atom!("$crypto_data_encrypt"),
-            &SystemClauseType::CryptoDataDecrypt => atom!("$crypto_data_decrypt"),
-            &SystemClauseType::CryptoCurveScalarMult => atom!("$crypto_curve_scalar_mult"),
-            &SystemClauseType::Ed25519Sign => atom!("$ed25519_sign"),
-            &SystemClauseType::Ed25519Verify => atom!("$ed25519_verify"),
-            &SystemClauseType::Ed25519NewKeyPair => atom!("$ed25519_new_keypair"),
-            &SystemClauseType::Ed25519KeyPairPublicKey => {
-                atom!("$ed25519_keypair_public_key")
-            }
-            &SystemClauseType::Curve25519ScalarMult => atom!("$curve25519_scalar_mult"),
-            &SystemClauseType::FirstNonOctet => atom!("$first_non_octet"),
-            &SystemClauseType::LoadHTML => atom!("$load_html"),
-            &SystemClauseType::LoadXML => atom!("$load_xml"),
-            &SystemClauseType::GetEnv => atom!("$getenv"),
-            &SystemClauseType::SetEnv => atom!("$setenv"),
-            &SystemClauseType::UnsetEnv => atom!("$unsetenv"),
-            &SystemClauseType::Shell => atom!("$shell"),
-            &SystemClauseType::PID => atom!("$pid"),
-            &SystemClauseType::CharsBase64 => atom!("$chars_base64"),
-            &SystemClauseType::LoadLibraryAsStream => atom!("$load_library_as_stream"),
-            &SystemClauseType::DevourWhitespace => atom!("$devour_whitespace"),
-            &SystemClauseType::IsSTOEnabled => atom!("$is_sto_enabled"),
-            &SystemClauseType::SetSTOAsUnify => atom!("$set_sto_as_unify"),
-            &SystemClauseType::SetNSTOAsUnify => atom!("$set_nsto_as_unify"),
-            &SystemClauseType::HomeDirectory => atom!("$home_directory"),
-            &SystemClauseType::SetSTOWithErrorAsUnify => {
-                atom!("$set_sto_with_error_as_unify")
-            }
-            &SystemClauseType::DebugHook => atom!("$debug_hook"),
-            &SystemClauseType::PopCount => atom!("$popcount"),
-        }
-    }
-
-    pub(crate) fn from(name: Atom, arity: usize) -> Option<SystemClauseType> {
-        match (name, arity) {
-            (atom!("$abolish_clause"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::AbolishClause)),
-            (atom!("$add_dynamic_predicate"), 4) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate))
-            }
-            (atom!("$add_multifile_predicate"), 4) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::AddMultifilePredicate))
-            }
-            (atom!("$add_discontiguous_predicate"), 4) => Some(SystemClauseType::REPL(
-                REPLCodePtr::AddDiscontiguousPredicate,
-            )),
-            (atom!("$add_goal_expansion_clause"), 3) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause))
-            }
-            (atom!("$add_term_expansion_clause"), 2) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause))
-            }
-            (atom!("$atom_chars"), 2) => Some(SystemClauseType::AtomChars),
-            (atom!("$atom_codes"), 2) => Some(SystemClauseType::AtomCodes),
-            (atom!("$atom_length"), 2) => Some(SystemClauseType::AtomLength),
-            (atom!("$bind_from_register"), 2) => Some(SystemClauseType::BindFromRegister),
-            (atom!("$call_continuation"), 1) => Some(SystemClauseType::CallContinuation),
-            (atom!("$char_code"), 2) => Some(SystemClauseType::CharCode),
-            (atom!("$char_type"), 2) => Some(SystemClauseType::CharType),
-            (atom!("$chars_to_number"), 2) => Some(SystemClauseType::CharsToNumber),
-            (atom!("$codes_to_number"), 2) => Some(SystemClauseType::CodesToNumber),
-            (atom!("$copy_term_without_attr_vars"), 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
-            (atom!("$create_partial_string"), 3) => Some(SystemClauseType::CreatePartialString),
-            (atom!("$check_cp"), 1) => Some(SystemClauseType::CheckCutPoint),
-            (atom!("$copy_to_lh"), 2) => Some(SystemClauseType::CopyToLiftedHeap),
-            (atom!("$close"), 2) => Some(SystemClauseType::Close),
-            (atom!("$current_hostname"), 1) => Some(SystemClauseType::CurrentHostname),
-            (atom!("$current_input"), 1) => Some(SystemClauseType::CurrentInput),
-            (atom!("$current_output"), 1) => Some(SystemClauseType::CurrentOutput),
-            (atom!("$first_stream"), 1) => Some(SystemClauseType::FirstStream),
-            (atom!("$next_stream"), 2) => Some(SystemClauseType::NextStream),
-            (atom!("$flush_output"), 1) => Some(SystemClauseType::FlushOutput),
-            (atom!("$del_attr_non_head"), 1) => Some(SystemClauseType::DeleteAttribute),
-            (atom!("$del_attr_head"), 1) => Some(SystemClauseType::DeleteHeadAttribute),
-            (atom!("$get_next_db_ref"), 4) => Some(SystemClauseType::GetNextDBRef),
-            (atom!("$get_next_op_db_ref"), 7) => Some(SystemClauseType::GetNextOpDBRef),
-            (atom!("$module_call"), _) => Some(SystemClauseType::DynamicModuleResolution(arity - 2)),
-            (atom!("$enqueue_attr_var"), 1) => Some(SystemClauseType::EnqueueAttributedVar),
-            (atom!("$partial_string_tail"), 2) => Some(SystemClauseType::PartialStringTail),
-            (atom!("$peek_byte"), 2) => Some(SystemClauseType::PeekByte),
-            (atom!("$peek_char"), 2) => Some(SystemClauseType::PeekChar),
-            (atom!("$peek_code"), 2) => Some(SystemClauseType::PeekCode),
-            (atom!("$is_partial_string"), 1) => Some(SystemClauseType::IsPartialString),
-            (atom!("$fetch_global_var"), 2) => Some(SystemClauseType::FetchGlobalVar),
-            (atom!("$get_byte"), 2) => Some(SystemClauseType::GetByte),
-            (atom!("$get_char"), 2) => Some(SystemClauseType::GetChar),
-            (atom!("$get_n_chars"), 3) => Some(SystemClauseType::GetNChars),
-            (atom!("$get_code"), 2) => Some(SystemClauseType::GetCode),
-            (atom!("$get_single_char"), 1) => Some(SystemClauseType::GetSingleChar),
-            (atom!("$points_to_cont_reset_marker"), 1) => {
-                Some(SystemClauseType::PointsToContinuationResetMarker)
-            }
-            (atom!("$put_byte"), 2) => Some(SystemClauseType::PutByte),
-            (atom!("$put_char"), 2) => Some(SystemClauseType::PutChar),
-            (atom!("$put_chars"), 2) => Some(SystemClauseType::PutChars),
-            (atom!("$put_code"), 2) => Some(SystemClauseType::PutCode),
-            (atom!("$reset_attr_var_state"), 0) => Some(SystemClauseType::ResetAttrVarState),
-            (atom!("$truncate_if_no_lh_growth"), 1) => {
-                Some(SystemClauseType::TruncateIfNoLiftedHeapGrowth)
-            }
-            (atom!("$truncate_if_no_lh_growth_diff"), 2) => {
-                Some(SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff)
-            }
-            (atom!("$get_attr_list"), 2) => Some(SystemClauseType::GetAttributedVariableList),
-            (atom!("$get_b_value"), 1) => Some(SystemClauseType::GetBValue),
-            (atom!("$get_lh_from_offset"), 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
-            (atom!("$get_lh_from_offset_diff"), 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
-            (atom!("$get_double_quotes"), 1) => Some(SystemClauseType::GetDoubleQuotes),
-            (atom!("$get_scc_cleaner"), 1) => Some(SystemClauseType::GetSCCCleaner),
-            (atom!("$halt"), 1) => Some(SystemClauseType::Halt),
-            (atom!("$head_is_dynamic"), 2) => Some(SystemClauseType::HeadIsDynamic),
-            (atom!("$install_scc_cleaner"), 2) => Some(SystemClauseType::InstallSCCCleaner),
-            (atom!("$install_inference_counter"), 3) => Some(SystemClauseType::InstallInferenceCounter),
-            (atom!("$lh_length"), 1) => Some(SystemClauseType::LiftedHeapLength),
-            (atom!("$maybe"), 0) => Some(SystemClauseType::Maybe),
-            (atom!("$cpu_now"), 1) => Some(SystemClauseType::CpuNow),
-            (atom!("$current_time"), 1) => Some(SystemClauseType::CurrentTime),
-            (atom!("$module_exists"), 1) => Some(SystemClauseType::ModuleExists),
-            (atom!("$no_such_predicate"), 2) => Some(SystemClauseType::NoSuchPredicate),
-            (atom!("$number_to_chars"), 2) => Some(SystemClauseType::NumberToChars),
-            (atom!("$number_to_codes"), 2) => Some(SystemClauseType::NumberToCodes),
-            (atom!("$op"), 3) => Some(SystemClauseType::OpDeclaration),
-            (atom!("$open"), 7) => Some(SystemClauseType::Open),
-            (atom!("$set_stream_options"), 5) => Some(SystemClauseType::SetStreamOptions),
-            (atom!("$redo_attr_var_binding"), 2) => Some(SystemClauseType::RedoAttrVarBinding),
-            (atom!("$remove_call_policy_check"), 1) => Some(SystemClauseType::RemoveCallPolicyCheck),
-            (atom!("$remove_inference_counter"), 2) => Some(SystemClauseType::RemoveInferenceCounter),
-            (atom!("$restore_cut_policy"), 0) => Some(SystemClauseType::RestoreCutPolicy),
-            (atom!("$set_cp"), 1) => Some(SystemClauseType::SetCutPoint(temp_v!(1))),
-            (atom!("$set_input"), 1) => Some(SystemClauseType::SetInput),
-            (atom!("$set_output"), 1) => Some(SystemClauseType::SetOutput),
-            (atom!("$stream_property"), 3) => Some(SystemClauseType::StreamProperty),
-            (atom!("$set_stream_position"), 2) => Some(SystemClauseType::SetStreamPosition),
-            (atom!("$inference_level"), 2) => Some(SystemClauseType::InferenceLevel),
-            (atom!("$clean_up_block"), 1) => Some(SystemClauseType::CleanUpBlock),
-            (atom!("$erase_ball"), 0) => Some(SystemClauseType::EraseBall),
-            (atom!("$fail"), 0) => Some(SystemClauseType::Fail),
-            (atom!("$get_attr_var_queue_beyond"), 2) => Some(SystemClauseType::GetAttrVarQueueBeyond),
-            (atom!("$get_attr_var_queue_delim"), 1) => Some(SystemClauseType::GetAttrVarQueueDelimiter),
-            (atom!("$get_ball"), 1) => Some(SystemClauseType::GetBall),
-            (atom!("$get_cont_chunk"), 3) => Some(SystemClauseType::GetContinuationChunk),
-            (atom!("$get_current_block"), 1) => Some(SystemClauseType::GetCurrentBlock),
-            (atom!("$get_cp"), 1) => Some(SystemClauseType::GetCutPoint),
-            (atom!("$get_staggered_cp"), 1) => Some(SystemClauseType::GetStaggeredCutPoint),
-            (atom!("$install_new_block"), 1) => Some(SystemClauseType::InstallNewBlock),
-            (atom!("$quoted_token"), 1) => Some(SystemClauseType::QuotedToken),
-            (atom!("$nextEP"), 3) => Some(SystemClauseType::NextEP),
-            (atom!("$read_query_term"), 5) => Some(SystemClauseType::ReadQueryTerm),
-            (atom!("$read_term"), 5) => Some(SystemClauseType::ReadTerm),
-            (atom!("$read_term_from_chars"), 2) => Some(SystemClauseType::ReadTermFromChars),
-            (atom!("$reset_block"), 1) => Some(SystemClauseType::ResetBlock),
-            (atom!("$reset_cont_marker"), 0) => Some(SystemClauseType::ResetContinuationMarker),
-            (atom!("$return_from_verify_attr"), 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
-            (atom!("$set_ball"), 1) => Some(SystemClauseType::SetBall),
-            (atom!("$set_cp_by_default"), 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
-            (atom!("$set_double_quotes"), 1) => Some(SystemClauseType::SetDoubleQuotes),
-            (atom!("$set_seed"), 1) => Some(SystemClauseType::SetSeed),
-            (atom!("$skip_max_list"), 4) => Some(SystemClauseType::SkipMaxList),
-            (atom!("$sleep"), 1) => Some(SystemClauseType::Sleep),
-            (atom!("$tls_accept_client"), 4) => Some(SystemClauseType::TLSAcceptClient),
-            (atom!("$tls_client_connect"), 3) => Some(SystemClauseType::TLSClientConnect),
-            (atom!("$socket_client_open"), 8) => Some(SystemClauseType::SocketClientOpen),
-            (atom!("$socket_server_open"), 3) => Some(SystemClauseType::SocketServerOpen),
-            (atom!("$socket_server_accept"), 7) => Some(SystemClauseType::SocketServerAccept),
-            (atom!("$socket_server_close"), 1) => Some(SystemClauseType::SocketServerClose),
-            (atom!("$store_global_var"), 2) => Some(SystemClauseType::StoreGlobalVar),
-            (atom!("$store_backtrackable_global_var"), 2) => {
-                Some(SystemClauseType::StoreBacktrackableGlobalVar)
-            }
-            (atom!("$term_attributed_variables"), 2) => Some(SystemClauseType::TermAttributedVariables),
-            (atom!("$term_variables"), 2) => Some(SystemClauseType::TermVariables),
-            (atom!("$term_variables_under_max_depth"), 3) => Some(SystemClauseType::TermVariablesUnderMaxDepth),
-            (atom!("$truncate_lh_to"), 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
-            (atom!("$unwind_environments"), 0) => Some(SystemClauseType::UnwindEnvironments),
-            (atom!("$unwind_stack"), 0) => Some(SystemClauseType::UnwindStack),
-            (atom!("$unify_with_occurs_check"), 2) => Some(SystemClauseType::UnifyWithOccursCheck),
-            (atom!("$directory_files"), 2) => Some(SystemClauseType::DirectoryFiles),
-            (atom!("$file_size"), 2) => Some(SystemClauseType::FileSize),
-            (atom!("$file_exists"), 1) => Some(SystemClauseType::FileExists),
-            (atom!("$directory_exists"), 1) => Some(SystemClauseType::DirectoryExists),
-            (atom!("$directory_separator"), 1) => Some(SystemClauseType::DirectorySeparator),
-            (atom!("$make_directory"), 1) => Some(SystemClauseType::MakeDirectory),
-            (atom!("$make_directory_path"), 1) => Some(SystemClauseType::MakeDirectoryPath),
-            (atom!("$delete_file"), 1) => Some(SystemClauseType::DeleteFile),
-            (atom!("$rename_file"), 2) => Some(SystemClauseType::RenameFile),
-            (atom!("$delete_directory"), 1) => Some(SystemClauseType::DeleteDirectory),
-            (atom!("$working_directory"), 2) => Some(SystemClauseType::WorkingDirectory),
-            (atom!("$path_canonical"), 2) => Some(SystemClauseType::PathCanonical),
-            (atom!("$file_time"), 3) => Some(SystemClauseType::FileTime),
-            (atom!("$clause_to_evacuable"), 2) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable))
-            }
-            (atom!("$scoped_clause_to_evacuable"), 3) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::ScopedClauseToEvacuable))
-            }
-            (atom!("$conclude_load"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)),
-            (atom!("$use_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
-            (atom!("$declare_module"), 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)),
-            (atom!("$load_compiled_library"), 3) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary))
-            }
-            (atom!("$push_load_state_payload"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload))
-            }
-            (atom!("$add_in_situ_filename_module"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::AddInSituFilenameModule))
-            }
-            (atom!("$asserta"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Asserta)),
-            (atom!("$assertz"), 5) => Some(SystemClauseType::REPL(REPLCodePtr::Assertz)),
-            (atom!("$retract_clause"), 4) => Some(SystemClauseType::REPL(REPLCodePtr::Retract)),
-            (atom!("$is_consistent_with_term_queue"), 4) => Some(SystemClauseType::REPL(
-                REPLCodePtr::IsConsistentWithTermQueue,
-            )),
-            (atom!("$flush_term_queue"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::FlushTermQueue)),
-            (atom!("$remove_module_exports"), 2) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::RemoveModuleExports))
-            }
-            (atom!("$add_non_counted_backtracking"), 3) => Some(SystemClauseType::REPL(
-                REPLCodePtr::AddNonCountedBacktracking,
-            )),
-            (atom!("$wam_instructions"), 4) => Some(SystemClauseType::WAMInstructions),
-            (atom!("$write_term"), 7) => Some(SystemClauseType::WriteTerm),
-            (atom!("$write_term_to_chars"), 7) => Some(SystemClauseType::WriteTermToChars),
-            (atom!("$scryer_prolog_version"), 1) => Some(SystemClauseType::ScryerPrologVersion),
-            (atom!("$crypto_random_byte"), 1) => Some(SystemClauseType::CryptoRandomByte),
-            (atom!("$crypto_data_hash"), 4) => Some(SystemClauseType::CryptoDataHash),
-            (atom!("$crypto_data_hkdf"), 7) => Some(SystemClauseType::CryptoDataHKDF),
-            (atom!("$crypto_password_hash"), 4) => Some(SystemClauseType::CryptoPasswordHash),
-            (atom!("$crypto_data_encrypt"), 7) => Some(SystemClauseType::CryptoDataEncrypt),
-            (atom!("$crypto_data_decrypt"), 6) => Some(SystemClauseType::CryptoDataDecrypt),
-            (atom!("$crypto_curve_scalar_mult"), 5) => Some(SystemClauseType::CryptoCurveScalarMult),
-            (atom!("$ed25519_sign"), 4) => Some(SystemClauseType::Ed25519Sign),
-            (atom!("$ed25519_verify"), 4) => Some(SystemClauseType::Ed25519Verify),
-            (atom!("$ed25519_new_keypair"), 1) => Some(SystemClauseType::Ed25519NewKeyPair),
-            (atom!("$ed25519_keypair_public_key"), 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
-            (atom!("$curve25519_scalar_mult"), 3) => Some(SystemClauseType::Curve25519ScalarMult),
-            (atom!("$first_non_octet"), 2) => Some(SystemClauseType::FirstNonOctet),
-            (atom!("$load_html"), 3) => Some(SystemClauseType::LoadHTML),
-            (atom!("$load_xml"), 3) => Some(SystemClauseType::LoadXML),
-            (atom!("$getenv"), 2) => Some(SystemClauseType::GetEnv),
-            (atom!("$setenv"), 2) => Some(SystemClauseType::SetEnv),
-            (atom!("$unsetenv"), 1) => Some(SystemClauseType::UnsetEnv),
-            (atom!("$shell"), 2) => Some(SystemClauseType::Shell),
-            (atom!("$pid"), 1) => Some(SystemClauseType::PID),
-            (atom!("$chars_base64"), 4) => Some(SystemClauseType::CharsBase64),
-            (atom!("$load_library_as_stream"), 3) => Some(SystemClauseType::LoadLibraryAsStream),
-            (atom!("$push_load_context"), 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)),
-            (atom!("$pop_load_state_payload"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload))
-            }
-            (atom!("$pop_load_context"), 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)),
-            (atom!("$prolog_lc_source"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource))
-            }
-            (atom!("$prolog_lc_file"), 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)),
-            (atom!("$prolog_lc_dir"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory))
-            }
-            (atom!("$prolog_lc_module"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule))
-            }
-            (atom!("$prolog_lc_stream"), 1) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream))
-            }
-            (atom!("$cpp_meta_predicate_property"), 4) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty))
-            }
-            (atom!("$cpp_built_in_property"), 2) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty))
-            }
-            (atom!("$cpp_dynamic_property"), 3) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::DynamicProperty))
-            }
-            (atom!("$cpp_multifile_property"), 3) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::MultifileProperty))
-            }
-            (atom!("$cpp_discontiguous_property"), 3) => {
-                Some(SystemClauseType::REPL(REPLCodePtr::DiscontiguousProperty))
-            }
-            (atom!("$devour_whitespace"), 1) => Some(SystemClauseType::DevourWhitespace),
-            (atom!("$is_sto_enabled"), 1) => Some(SystemClauseType::IsSTOEnabled),
-            (atom!("$set_sto_as_unify"), 0) => Some(SystemClauseType::SetSTOAsUnify),
-            (atom!("$set_nsto_as_unify"), 0) => Some(SystemClauseType::SetNSTOAsUnify),
-            (atom!("$set_sto_with_error_as_unify"), 0) => Some(SystemClauseType::SetSTOWithErrorAsUnify),
-            (atom!("$home_directory"), 1) => Some(SystemClauseType::HomeDirectory),
-            (atom!("$debug_hook"), 0) => Some(SystemClauseType::DebugHook),
-            (atom!("$popcount"), 2) => Some(SystemClauseType::PopCount),
-            _ => None,
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum BuiltInClauseType {
-    AcyclicTerm,
-    Arg,
-    Compare,
-    CompareTerm(CompareTermQT),
-    CopyTerm,
-    Eq,
-    Functor,
-    Ground,
-    Is(RegType, ArithmeticTerm),
-    KeySort,
-    NotEq,
-    Read,
-    Sort,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ClauseType {
-    BuiltIn(BuiltInClauseType),
-    CallN,
-    Inlined(InlinedClauseType),
-    Named(Atom, usize, CodeIndex), // name, arity, index.
-    System(SystemClauseType),
-}
-
-impl BuiltInClauseType {
-    pub(crate) fn name(&self) -> Atom {
-        match self {
-            &BuiltInClauseType::AcyclicTerm => atom!("acyclic_term"),
-            &BuiltInClauseType::Arg => atom!("arg"),
-            &BuiltInClauseType::Compare => atom!("compare"),
-            &BuiltInClauseType::CompareTerm(qt) => qt.name(),
-            &BuiltInClauseType::CopyTerm => atom!("copy_term"),
-            &BuiltInClauseType::Eq => atom!("=="),
-            &BuiltInClauseType::Functor => atom!("functor"),
-            &BuiltInClauseType::Ground => atom!("ground"),
-            &BuiltInClauseType::Is(..) => atom!("is"),
-            &BuiltInClauseType::KeySort => atom!("keysort"),
-            &BuiltInClauseType::NotEq => atom!("\\=="),
-            &BuiltInClauseType::Read => atom!("read"),
-            &BuiltInClauseType::Sort => atom!("sort"),
-        }
-    }
-
-    pub(crate) fn arity(&self) -> usize {
-        match self {
-            &BuiltInClauseType::AcyclicTerm => 1,
-            &BuiltInClauseType::Arg => 3,
-            &BuiltInClauseType::Compare => 2,
-            &BuiltInClauseType::CompareTerm(_) => 2,
-            &BuiltInClauseType::CopyTerm => 2,
-            &BuiltInClauseType::Eq => 2,
-            &BuiltInClauseType::Functor => 3,
-            &BuiltInClauseType::Ground => 1,
-            &BuiltInClauseType::Is(..) => 2,
-            &BuiltInClauseType::KeySort => 2,
-            &BuiltInClauseType::NotEq => 2,
-            &BuiltInClauseType::Read => 1,
-            &BuiltInClauseType::Sort => 2,
-        }
-    }
-}
-
-impl ClauseType {
-    pub(crate) fn name(&self) -> Atom {
-        match self {
-            &ClauseType::BuiltIn(ref built_in) => built_in.name(),
-            &ClauseType::CallN => atom!("$call"),
-            &ClauseType::Inlined(ref inlined) => inlined.name(),
-            &ClauseType::Named(name, ..) => name,
-            &ClauseType::System(ref system) => system.name(),
-        }
-    }
-
-    pub(crate) fn from(name: Atom, arity: usize) -> Self {
-        clause_type_form(name, arity).unwrap_or_else(|| {
-            SystemClauseType::from(name, arity)
-                .map(ClauseType::System)
-                .unwrap_or_else(|| {
-                    if name == atom!("$call") {
-                        ClauseType::CallN
-                    } else {
-                        ClauseType::Named(name, arity, CodeIndex::default())
-                    }
-                })
-        })
-    }
-}
-
-impl From<InlinedClauseType> for ClauseType {
-    fn from(inlined_ct: InlinedClauseType) -> Self {
-        ClauseType::Inlined(inlined_ct)
-    }
-}
index ca344558693d7605b532151f026d6d285b562cd2..a8094841f3fed368d77872c2d8ee2f38b91597f2 100644 (file)
@@ -4,7 +4,6 @@ use crate::{perm_v, temp_v};
 
 use crate::allocator::*;
 use crate::arithmetic::*;
-use crate::clause_types::*;
 use crate::fixtures::*;
 use crate::forms::*;
 use crate::indexing::*;
@@ -13,6 +12,7 @@ use crate::iterators::*;
 use crate::targets::*;
 use crate::types::*;
 
+use crate::instr;
 use crate::machine::machine_errors::*;
 
 use indexmap::{IndexMap, IndexSet};
@@ -57,7 +57,9 @@ impl<'a> ConjunctInfo<'a> {
         let mut code_index = 0;
 
         for phase in 0.. {
-            while let Line::Query(ref query_instr) = &code[code_index] {
+            while code[code_index].is_query_instr() {
+                let query_instr = &mut code[code_index];
+
                 if !unsafe_var_marker.mark_safe_vars(query_instr) {
                     unsafe_var_marker.mark_phase(query_instr, phase);
                 }
@@ -75,7 +77,8 @@ impl<'a> ConjunctInfo<'a> {
         code_index = 0;
 
         for phase in 0.. {
-            while let Line::Query(ref mut query_instr) = &mut code[code_index] {
+            while code[code_index].is_query_instr() {
+                let query_instr = &mut code[code_index];
                 unsafe_var_marker.mark_unsafe_vars(query_instr, phase);
                 code_index += 1;
             }
@@ -103,9 +106,9 @@ impl CodeGenSettings {
     }
 
     #[inline]
-    pub(crate) fn internal_try_me_else(&self, offset: usize) -> ChoiceInstruction {
+    pub(crate) fn internal_try_me_else(&self, offset: usize) -> Instruction {
         if let Some(global_clock_time) = self.global_clock_tick {
-            ChoiceInstruction::DynamicInternalElse(
+            Instruction::DynamicInternalElse(
                 global_clock_time,
                 Death::Infinity,
                 if offset == 0 {
@@ -115,13 +118,13 @@ impl CodeGenSettings {
                 },
             )
         } else {
-            ChoiceInstruction::TryMeElse(offset)
+            Instruction::TryMeElse(offset)
         }
     }
 
-    pub(crate) fn try_me_else(&self, offset: usize) -> ChoiceInstruction {
+    pub(crate) fn try_me_else(&self, offset: usize) -> Instruction {
         if let Some(global_clock_tick) = self.global_clock_tick {
-            ChoiceInstruction::DynamicElse(
+            Instruction::DynamicElse(
                 global_clock_tick,
                 Death::Infinity,
                 if offset == 0 {
@@ -131,13 +134,13 @@ impl CodeGenSettings {
                 },
             )
         } else {
-            ChoiceInstruction::TryMeElse(offset)
+            Instruction::TryMeElse(offset)
         }
     }
 
-    pub(crate) fn internal_retry_me_else(&self, offset: usize) -> ChoiceInstruction {
+    pub(crate) fn internal_retry_me_else(&self, offset: usize) -> Instruction {
         if let Some(global_clock_tick) = self.global_clock_tick {
-            ChoiceInstruction::DynamicInternalElse(
+            Instruction::DynamicInternalElse(
                 global_clock_tick,
                 Death::Infinity,
                 if offset == 0 {
@@ -147,13 +150,13 @@ impl CodeGenSettings {
                 },
             )
         } else {
-            ChoiceInstruction::RetryMeElse(offset)
+            Instruction::RetryMeElse(offset)
         }
     }
 
-    pub(crate) fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
+    pub(crate) fn retry_me_else(&self, offset: usize) -> Instruction {
         if let Some(global_clock_tick) = self.global_clock_tick {
-            ChoiceInstruction::DynamicElse(
+            Instruction::DynamicElse(
                 global_clock_tick,
                 Death::Infinity,
                 if offset == 0 {
@@ -163,33 +166,33 @@ impl CodeGenSettings {
                 },
             )
         } else if self.non_counted_bt {
-            ChoiceInstruction::DefaultRetryMeElse(offset)
+            Instruction::DefaultRetryMeElse(offset)
         } else {
-            ChoiceInstruction::RetryMeElse(offset)
+            Instruction::RetryMeElse(offset)
         }
     }
 
-    pub(crate) fn internal_trust_me(&self) -> ChoiceInstruction {
+    pub(crate) fn internal_trust_me(&self) -> Instruction {
         if let Some(global_clock_tick) = self.global_clock_tick {
-            ChoiceInstruction::DynamicInternalElse(
+            Instruction::DynamicInternalElse(
                 global_clock_tick,
                 Death::Infinity,
                 NextOrFail::Fail(0),
             )
         } else if self.non_counted_bt {
-            ChoiceInstruction::DefaultTrustMe(0)
+            Instruction::DefaultTrustMe(0)
         } else {
-            ChoiceInstruction::TrustMe(0)
+            Instruction::TrustMe(0)
         }
     }
 
-    pub(crate) fn trust_me(&self) -> ChoiceInstruction {
+    pub(crate) fn trust_me(&self) -> Instruction {
         if let Some(global_clock_tick) = self.global_clock_tick {
-            ChoiceInstruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0))
+            Instruction::DynamicElse(global_clock_tick, Death::Infinity, NextOrFail::Fail(0))
         } else if self.non_counted_bt {
-            ChoiceInstruction::DefaultTrustMe(0)
+            Instruction::DefaultTrustMe(0)
         } else {
-            ChoiceInstruction::TrustMe(0)
+            Instruction::TrustMe(0)
         }
     }
 }
@@ -238,12 +241,11 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         vr: &'a Cell<VarReg>,
         code: &mut Code,
     ) -> RegType {
-        let mut target = Vec::new();
-        self.marker
-            .mark_var(name, Level::Shallow, vr, term_loc, &mut target);
+        let mut target = Code::new();
+        self.marker.mark_var::<QueryInstruction>(name, Level::Shallow, vr, term_loc, &mut target);
 
         if !target.is_empty() {
-            code.extend(target.into_iter().map(Line::Query));
+            code.extend(target.into_iter());
         }
 
         vr.get().norm()
@@ -271,7 +273,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         }
     }
 
-    fn add_or_increment_void_instr<Target>(target: &mut Vec<Target>)
+    fn add_or_increment_void_instr<Target>(target: &mut Code)
     where
         Target: crate::targets::CompilationTarget<'a>,
     {
@@ -291,13 +293,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         var: &'a Rc<String>,
         term_loc: GenContext,
         is_exposed: bool,
-        target: &mut Vec<Target>,
+        target: &mut Code,
     ) {
         if is_exposed || self.get_var_count(var.as_ref()) > 1 {
-            self.marker
-                .mark_var(var.clone(), Level::Deep, cell, term_loc, target);
+            self.marker.mark_var::<Target>(var.clone(), Level::Deep, cell, term_loc, target);
         } else {
-            Self::add_or_increment_void_instr(target);
+            Self::add_or_increment_void_instr::<Target>(target);
         }
     }
 
@@ -306,27 +307,26 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         subterm: &'a Term,
         term_loc: GenContext,
         is_exposed: bool,
-        target: &mut Vec<Target>,
+        target: &mut Code,
     ) {
         match subterm {
             &Term::AnonVar if is_exposed => {
-                self.marker.mark_anon_var(Level::Deep, term_loc, target);
+                self.marker.mark_anon_var::<Target>(Level::Deep, term_loc, target);
             }
             &Term::AnonVar => {
-                Self::add_or_increment_void_instr(target);
+                Self::add_or_increment_void_instr::<Target>(target);
             }
             &Term::Cons(ref cell, ..)
             | &Term::Clause(ref cell, ..)
             | Term::PartialString(ref cell, ..) => {
-                self.marker
-                    .mark_non_var(Level::Deep, term_loc, cell, target);
+                self.marker.mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
                 target.push(Target::clause_arg_to_instr(cell.get()));
             }
             &Term::Literal(_, ref constant) => {
                 target.push(Target::constant_subterm(constant.clone()));
             }
             &Term::Var(ref cell, ref var) => {
-                self.deep_var_instr(cell, var, term_loc, is_exposed, target);
+                self.deep_var_instr::<Target>(cell, var, term_loc, is_exposed, target);
             }
         };
     }
@@ -336,12 +336,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         iter: Iter,
         term_loc: GenContext,
         is_exposed: bool,
-    ) -> Vec<Target>
+    ) -> Code
     where
         Target: crate::targets::CompilationTarget<'a>,
         Iter: Iterator<Item = TermRef<'a>>,
     {
-        let mut target = Vec::new();
+        let mut target: Code = Vec::new();
 
         for term in iter {
             match term {
@@ -349,38 +349,38 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                     if let GenContext::Head = term_loc {
                         self.marker.advance_arg();
                     } else {
-                        self.marker.mark_anon_var(lvl, term_loc, &mut target);
+                        self.marker.mark_anon_var::<Target>(lvl, term_loc, &mut target);
                     }
                 }
                 TermRef::Clause(lvl, cell, ct, terms) => {
-                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
-                    target.push(Target::to_structure(ct, terms.len(), cell.get()));
+                    self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
+                    target.push(Target::to_structure(ct.name(), terms.len(), cell.get()));
 
                     for subterm in terms {
-                        self.subterm_to_instr(subterm, term_loc, is_exposed, &mut target);
+                        self.subterm_to_instr::<Target>(subterm, term_loc, is_exposed, &mut target);
                     }
                 }
                 TermRef::Cons(lvl, cell, head, tail) => {
-                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+                    self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
                     target.push(Target::to_list(lvl, cell.get()));
 
-                    self.subterm_to_instr(head, term_loc, is_exposed, &mut target);
-                    self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
+                    self.subterm_to_instr::<Target>(head, term_loc, is_exposed, &mut target);
+                    self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target);
                 }
                 TermRef::Literal(lvl @ Level::Shallow, cell, Literal::String(ref string)) => {
-                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+                    self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
                     target.push(Target::to_pstr(lvl, *string, cell.get(), false));
                 }
                 TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
-                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+                    self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
                     target.push(Target::to_constant(lvl, *constant, cell.get()));
                 }
                 TermRef::PartialString(lvl, cell, string, tail) => {
-                    self.marker.mark_non_var(lvl, term_loc, cell, &mut target);
+                    self.marker.mark_non_var::<Target>(lvl, term_loc, cell, &mut target);
 
                     if let Some(tail) = tail {
                         target.push(Target::to_pstr(lvl, string, cell.get(), true));
-                        self.subterm_to_instr(tail, term_loc, is_exposed, &mut target);
+                        self.subterm_to_instr::<Target>(tail, term_loc, is_exposed, &mut target);
                     } else {
                         target.push(Target::to_pstr(lvl, string, cell.get(), false));
                     }
@@ -388,7 +388,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                 TermRef::Var(lvl @ Level::Shallow, cell, ref var) if var.as_str() == "!" => {
                     if self.marker.is_unbound(var.clone()) {
                         if term_loc != GenContext::Head {
-                            self.marker.mark_reserved_var(
+                            self.marker.mark_reserved_var::<Target>(
                                 var.clone(),
                                 lvl,
                                 cell,
@@ -401,12 +401,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                         }
                     }
 
-                    self.marker
-                        .mark_var(var.clone(), lvl, cell, term_loc, &mut target);
+                    self.marker.mark_var::<Target>(var.clone(), lvl, cell, term_loc, &mut target);
                 }
                 TermRef::Var(lvl @ Level::Shallow, cell, var) => {
-                    self.marker
-                        .mark_var(var.clone(), lvl, cell, term_loc, &mut target);
+                    self.marker.mark_var::<Target>(var.clone(), lvl, cell, term_loc, &mut target);
                 }
                 _ => {}
             };
@@ -451,13 +449,13 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         match qt {
             &QueryTerm::Jump(ref vars) => {
                 self.jmp_by_locs.push(code.len());
-                code.push(jmp_call!(vars.len(), 0, pvs));
+                code.push(instr!("jmp_by_call", vars.len(), 0, pvs));
             }
-            &QueryTerm::Clause(_, ref ct, ref terms, true) => {
-                code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs));
+            &QueryTerm::Clause(_, ref ct, _, true) => {
+                code.push(call_clause_by_default!(ct.clone(), pvs));
             }
-            &QueryTerm::Clause(_, ref ct, ref terms, false) => {
-                code.push(call_clause!(ct.clone(), terms.len(), pvs));
+            &QueryTerm::Clause(_, ref ct, _, false) => {
+                code.push(call_clause!(ct.clone(), pvs));
             }
             _ => {}
         }
@@ -465,25 +463,29 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
 
     fn lco(code: &mut Code) -> usize {
         let mut dealloc_index = code.len() - 1;
+        let last_instr = code.pop();
 
-        match code.last_mut() {
-            Some(&mut Line::Control(ref mut ctrl)) => match ctrl {
-                &mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
-                    *last_call = true;
-                }
-                &mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => {
-                    *last_call = true;
-                }
-                &mut ControlInstruction::Proceed => {}
-                _ => {
-                    dealloc_index += 1;
-                }
-            },
-            Some(&mut Line::Cut(CutInstruction::Cut(_))) => {
+        match last_instr {
+            Some(instr @ Instruction::Proceed) => {
+                code.push(instr);
+            }
+            Some(instr @ Instruction::Cut(_)) => {
                 dealloc_index += 1;
+                code.push(instr);
             }
-            _ => {}
-        };
+            Some(mut instr) if instr.is_ctrl_instr() => {
+                code.push(if instr.perm_vars_mut().is_some() {
+                    instr.to_execute()
+                } else {
+                    dealloc_index += 1;
+                    instr
+                });
+            }
+            Some(instr) => {
+                code.push(instr);
+            }
+            None => {}
+        }
 
         dealloc_index
     }
@@ -496,7 +498,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         code: &mut Code,
     ) -> Result<(), CompilationError> {
         match ct {
-            &InlinedClauseType::CompareNumber(cmp, ..) => {
+            &InlinedClauseType::CompareNumber(mut cmp) => {
                 self.marker.reset_arg(2);
 
                 let (mut lcode, at_1) = self.call_arith_eval(&terms[0], 1)?;
@@ -523,71 +525,71 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                 &Term::Literal(_, Literal::Char(_))
                 | &Term::Literal(_, Literal::Atom(atom!("[]")))
                 | &Term::Literal(_, Literal::Atom(..)) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_atom!(r));
+                    code.push(instr!("atom", r, 0));
                 }
                 _ => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
             },
             &InlinedClauseType::IsAtomic(..) => match &terms[0] {
                 &Term::AnonVar | &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
                 &Term::Literal(_, Literal::String(_)) => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
                 &Term::Literal(..) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_atomic!(r));
+                    code.push(instr!("atomic", r, 0));
                 }
             },
             &InlinedClauseType::IsCompound(..) => match &terms[0] {
                 &Term::Clause(..) | &Term::Cons(..) | &Term::PartialString(..) |
                 &Term::Literal(_, Literal::String(..)) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_compound!(r));
+                    code.push(instr!("compound", r, 0));
                 }
                 _ => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
             },
             &InlinedClauseType::IsRational(..) => match &terms[0] {
                 &Term::Literal(_, Literal::Rational(_)) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_rational!(r));
+                    code.push(instr!("rational", r, 0));
                 }
                 _ => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
             },
             &InlinedClauseType::IsFloat(..) => match &terms[0] {
                 &Term::Literal(_, Literal::Float(_)) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_float!(r));
+                    code.push(instr!("float", r, 0));
                 }
                 _ => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
             },
             &InlinedClauseType::IsNumber(..) => match &terms[0] {
@@ -595,41 +597,41 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                 | &Term::Literal(_, Literal::Rational(_))
                 | &Term::Literal(_, Literal::Integer(_))
                 | &Term::Literal(_, Literal::Fixnum(_)) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_number!(r));
+                    code.push(instr!("number", r, 0));
                 }
                 _ => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
             },
             &InlinedClauseType::IsNonVar(..) => match &terms[0] {
                 &Term::AnonVar => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_nonvar!(r));
+                    code.push(instr!("nonvar", r, 0));
                 }
                 _ => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
             },
             &InlinedClauseType::IsInteger(..) => match &terms[0] {
                 &Term::Literal(_, Literal::Integer(_)) | &Term::Literal(_, Literal::Fixnum(_)) => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_integer!(r));
+                    code.push(instr!("integer", r, 0));
                 }
                 _ => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
             },
             &InlinedClauseType::IsVar(..) => match &terms[0] {
@@ -637,15 +639,15 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                 | &Term::Clause(..)
                 | &Term::Cons(..)
                 | &Term::PartialString(..) => {
-                    code.push(fail!());
+                    code.push(instr!("$fail", 0));
                 }
                 &Term::AnonVar => {
-                    code.push(succeed!());
+                    code.push(instr!("$succeed", 0));
                 }
                 &Term::Var(ref vr, ref name) => {
                     self.marker.reset_arg(1);
                     let r = self.mark_non_callable(name.clone(), 1, term_loc, vr, code);
-                    code.push(is_var!(r));
+                    code.push(instr!("var", r, 0));
                 }
             },
         }
@@ -678,34 +680,39 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
             &Term::Var(ref vr, ref name) => {
                 let mut target = vec![];
 
-                self.marker
-                    .mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target);
+                self.marker.mark_var::<QueryInstruction>(
+                    name.clone(),
+                    Level::Shallow,
+                    vr,
+                    term_loc,
+                    &mut target,
+                );
 
                 if !target.is_empty() {
-                    code.extend(target.into_iter().map(Line::Query));
+                    code.extend(target.into_iter());
                 }
             }
             &Term::Literal(_, c @ Literal::Integer(_))
             | &Term::Literal(_, c @ Literal::Fixnum(_)) => {
                 let v = HeapCellValue::from(c);
-                code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1))));
+                code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
 
                 self.marker.advance_arg();
             }
             &Term::Literal(_, c @ Literal::Float(_)) => {
                 let v = HeapCellValue::from(c);
-                code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1))));
+                code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
 
                 self.marker.advance_arg();
             }
             &Term::Literal(_, c @ Literal::Rational(_)) => {
                 let v = HeapCellValue::from(c);
-                code.push(Line::Query(put_constant!(Level::Shallow, v, temp_v!(1))));
+                code.push(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
 
                 self.marker.advance_arg();
             }
             _ => {
-                code.push(fail!());
+                code.push(instr!("$fail", 0));
                 return Ok(());
             }
         }
@@ -717,9 +724,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         };
 
         Ok(if use_default_call_policy {
-            code.push(is_call_by_default!(temp_v!(1), at));
+            code.push(instr!("is", default, temp_v!(1), at, 0));
         } else {
-            code.push(is_call!(temp_v!(1), at));
+            code.push(instr!("is", temp_v!(1), at, 0));
         })
     }
 
@@ -727,7 +734,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
     fn compile_unblocked_cut(&mut self, code: &mut Code, cell: &'a Cell<VarReg>) {
         let r = self.marker.get(Rc::new(String::from("!")));
         cell.set(VarReg::Norm(r));
-        code.push(set_cp!(cell.get().norm()));
+        code.push(instr!("$set_cp", cell.get().norm(), 0));
     }
 
     fn compile_get_level_and_unify(
@@ -737,21 +744,16 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         var: Rc<String>,
         term_loc: GenContext,
     ) {
-        let mut target = Vec::new();
+        let mut target = Code::new();
 
         self.marker.reset_arg(1);
-        self.marker
-            .mark_var(var, Level::Shallow, cell, term_loc, &mut target);
+        self.marker.mark_var::<QueryInstruction>(var, Level::Shallow, cell, term_loc, &mut target);
 
         if !target.is_empty() {
-            code.extend(
-                target
-                    .into_iter()
-                    .map(|query_instr| Line::Query(query_instr)),
-            );
+            code.extend(target.into_iter());
         }
 
-        code.push(get_level_and_unify!(cell.get().norm()));
+        code.push(instr!("get_level_and_unify", cell.get().norm()));
     }
 
     fn compile_seq(
@@ -775,9 +777,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                     }
                     &QueryTerm::UnblockedCut(ref cell) => self.compile_unblocked_cut(code, cell),
                     &QueryTerm::BlockedCut => code.push(if chunk_num == 0 {
-                        Line::Cut(CutInstruction::NeckCut)
+                        Instruction::NeckCut
                     } else {
-                        Line::Cut(CutInstruction::Cut(perm_v!(1)))
+                        Instruction::Cut(perm_v!(1))
                     }),
                     &QueryTerm::Clause(
                         _,
@@ -810,10 +812,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         if conjunct_info.allocates() {
             let perm_vars = conjunct_info.perm_vars();
 
-            body.push(Line::Control(ControlInstruction::Allocate(perm_vars)));
+            body.push(Instruction::Allocate(perm_vars));
 
             if conjunct_info.has_deep_cut {
-                body.push(Line::Cut(CutInstruction::GetLevel(perm_v!(1))));
+                body.push(Instruction::GetLevel(perm_v!(1)));
             }
         }
     }
@@ -826,8 +828,9 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
     ) {
         // add a proceed to bookend any trailing cuts.
         match toc {
-            &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()),
-            &QueryTerm::Clause(_, ClauseType::Inlined(..), ..) => code.push(proceed!()),
+            &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => {
+                code.push(instr!("proceed"));
+            }
             _ => {}
         };
 
@@ -843,7 +846,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                 }
             }
 
-            code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
+            code.insert(dealloc_index, instr!("deallocate"));
         }
     }
 
@@ -865,16 +868,13 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         self.compile_seq_prelude(&conjunct_info, &mut code);
 
         let iter = FactIterator::from_rule_head_clause(args);
-        let mut fact = self.compile_target(iter, GenContext::Head, false);
+        let mut fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head, false);
 
         let mut unsafe_var_marker = UnsafeVarMarker::new();
 
         if !fact.is_empty() {
             unsafe_var_marker = self.mark_unsafe_fact_vars(&mut fact);
-
-            for fact_instr in fact {
-                code.push(Line::Fact(fact_instr));
-            }
+            code.extend(fact.into_iter());
         }
 
         let iter = ChunkedIterator::from_rule_body(p1, clauses);
@@ -886,18 +886,18 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         Ok(code)
     }
 
-    fn mark_unsafe_fact_vars(&self, fact: &mut CompiledFact) -> UnsafeVarMarker {
+    fn mark_unsafe_fact_vars(&self, fact: &mut Code) -> UnsafeVarMarker {
         let mut safe_vars = IndexSet::new();
 
         for fact_instr in fact.iter_mut() {
             match fact_instr {
-                &mut FactInstruction::UnifyValue(r) => {
+                &mut Instruction::UnifyValue(r) => {
                     if !safe_vars.contains(&r) {
-                        *fact_instr = FactInstruction::UnifyLocalValue(r);
+                        *fact_instr = Instruction::UnifyLocalValue(r);
                         safe_vars.insert(r);
                     }
                 }
-                &mut FactInstruction::UnifyVariable(r) => {
+                &mut Instruction::UnifyVariable(r) => {
                     safe_vars.insert(r);
                 }
                 _ => {}
@@ -923,18 +923,20 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
             self.marker.reset_at_head(args);
 
             let iter = FactInstruction::iter(term);
-            let mut compiled_fact = self.compile_target(iter, GenContext::Head, false);
+            let mut compiled_fact = self.compile_target::<FactInstruction, _>(
+                iter,
+                GenContext::Head,
+                false,
+            );
 
             self.mark_unsafe_fact_vars(&mut compiled_fact);
 
             if !compiled_fact.is_empty() {
-                for fact_instr in compiled_fact {
-                    code.push(Line::Fact(fact_instr));
-                }
+                code.extend(compiled_fact.into_iter());
             }
         }
 
-        code.push(proceed!());
+        code.push(instr!("proceed"));
         code
     }
 
@@ -949,12 +951,10 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         self.marker.reset_arg(term.arity());
 
         let iter = query_term_post_order_iter(term);
-        let query = self.compile_target(iter, term_loc, is_exposed);
+        let query = self.compile_target::<QueryInstruction, _>(iter, term_loc, is_exposed);
 
         if !query.is_empty() {
-            for query_instr in query {
-                code.push(Line::Query(query_instr));
-            }
+            code.extend(query.into_iter());
         }
 
         self.add_conditional_call(code, term, num_perm_vars_left);
@@ -1061,12 +1061,12 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
             if clauses.len() > 1 {
                 let choice = match i {
                     0 => self.settings.internal_try_me_else(clause_code.len() + 1),
-                    //ChoiceInstruction::TryMeElse(clause_code.len() + 1),
+                    //Instruction::TryMeElse(clause_code.len() + 1),
                     _ if i == clauses.len() - 1 => self.settings.internal_trust_me(),
                     _ => self.settings.internal_retry_me_else(clause_code.len() + 1),
                 };
 
-                code.push_back(Line::Choice(choice));
+                code.push_back(choice);
             } else if self.settings.is_extensible {
                 /*
                    generate stub choice instructions for extensible
@@ -1079,9 +1079,8 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                    over them.
                 */
 
-                code.push_front(Line::Choice(self.settings.internal_try_me_else(0)));
-                //Line::Choice(ChoiceInstruction::TryMeElse(0)));
-                skip_stub_try_me_else = !self.settings.is_dynamic(); //true;
+                code.push_front(self.settings.internal_try_me_else(0));
+                skip_stub_try_me_else = !self.settings.is_dynamic();
             }
 
             let arg = match clause.args() {
@@ -1109,7 +1108,7 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
         self.global_jmp_by_locs_offset = jmp_by_locs_len;
 
         if !index_code.is_empty() {
-            code.push_front(Line::IndexingCode(index_code));
+            code.push_front(Instruction::IndexingCode(index_code));
 
             if skip_stub_try_me_else {
                 // skip the TryMeElse(0) also.
@@ -1160,13 +1159,13 @@ impl<'a, 'b: 'a, TermMarker: Allocator<'a>> CodeGenerator<'b, TermMarker> {
                     _ => self.settings.retry_me_else(code_segment.len() + 1),
                 };
 
-                code.push(Line::Choice(choice));
+                code.push(choice);
             } else if self.settings.is_extensible {
-                code.push(Line::Choice(self.settings.try_me_else(0)));
+                code.push(self.settings.try_me_else(0));
             }
 
             if self.settings.is_extensible {
-                let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some();
+                let segment_is_indexed = code_segment[0].to_indexing_line().is_some();
 
                 for clause_index_info in self.skeleton.clauses[skel_lower_bound..].iter_mut() {
                     clause_index_info.clause_start +=
index 2b67c56d830c4c959a631b953843b818b27d0d0c..9c6888582913da5ea89b0a38e6a92fd164c4a7c1 100644 (file)
@@ -3,23 +3,26 @@ use indexmap::IndexMap;
 use crate::allocator::*;
 use crate::fixtures::*;
 use crate::forms::Level;
+use crate::instructions::*;
 use crate::machine::machine_indices::*;
 use crate::parser::ast::*;
 use crate::targets::CompilationTarget;
 
 use crate::temp_v;
 
+use fxhash::FxBuildHasher;
+
 use std::cell::Cell;
 use std::collections::BTreeSet;
 use std::rc::Rc;
 
 #[derive(Debug)]
 pub(crate) struct DebrayAllocator {
-    bindings: IndexMap<Rc<String>, VarData>,
+    bindings: IndexMap<Rc<String>, VarData, FxBuildHasher>,
     arg_c: usize,
     temp_lb: usize,
     arity: usize, // 0 if not at head.
-    contents: IndexMap<usize, Rc<String>>,
+    contents: IndexMap<usize, Rc<String>, FxBuildHasher>,
     in_use: BTreeSet<usize>,
 }
 
@@ -123,7 +126,7 @@ impl DebrayAllocator {
         }
     }
 
-    fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Target>)
+    fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec<Instruction>)
     where
         Target: CompilationTarget<'a>,
     {
@@ -152,7 +155,7 @@ impl DebrayAllocator {
         var: &String,
         lvl: Level,
         term_loc: GenContext,
-        target: &mut Vec<Target>,
+        target: &mut Vec<Instruction>,
     ) -> usize
     where
         Target: CompilationTarget<'a>,
@@ -160,7 +163,7 @@ impl DebrayAllocator {
         match term_loc {
             GenContext::Head => {
                 if let Level::Shallow = lvl {
-                    self.evacuate_arg(0, target);
+                    self.evacuate_arg::<Target>(0, target);
                     self.alloc_with_cr(var)
                 } else {
                     self.alloc_with_ca(var)
@@ -169,7 +172,7 @@ impl DebrayAllocator {
             GenContext::Mid(_) => self.alloc_with_ca(var),
             GenContext::Last(chunk_num) => {
                 if let Level::Shallow = lvl {
-                    self.evacuate_arg(chunk_num, target);
+                    self.evacuate_arg::<Target>(chunk_num, target);
                     self.alloc_with_cr(var)
                 } else {
                     self.alloc_with_ca(var)
@@ -210,13 +213,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
             arity: 0,
             arg_c: 1,
             temp_lb: 1,
-            bindings: IndexMap::new(),
-            contents: IndexMap::new(),
+            bindings: IndexMap::with_hasher(FxBuildHasher::default()),
+            contents: IndexMap::with_hasher(FxBuildHasher::default()),
             in_use: BTreeSet::new(),
         }
     }
 
-    fn mark_anon_var<Target>(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec<Target>)
+    fn mark_anon_var<Target>(
+        &mut self,
+        lvl: Level,
+        term_loc: GenContext,
+        target: &mut Vec<Instruction>,
+    )
     where
         Target: CompilationTarget<'a>,
     {
@@ -228,7 +236,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
                 let k = self.arg_c;
 
                 if let GenContext::Last(chunk_num) = term_loc {
-                    self.evacuate_arg(chunk_num, target);
+                    self.evacuate_arg::<Target>(chunk_num, target);
                 }
 
                 self.arg_c += 1;
@@ -243,7 +251,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
         lvl: Level,
         term_loc: GenContext,
         cell: &Cell<RegType>,
-        target: &mut Vec<Target>,
+        target: &mut Vec<Instruction>,
     ) where
         Target: CompilationTarget<'a>,
     {
@@ -254,7 +262,7 @@ impl<'a> Allocator<'a> for DebrayAllocator {
                 let k = self.arg_c;
 
                 if let GenContext::Last(chunk_num) = term_loc {
-                    self.evacuate_arg(chunk_num, target);
+                    self.evacuate_arg::<Target>(chunk_num, target);
                 }
 
                 self.arg_c += 1;
@@ -270,20 +278,18 @@ impl<'a> Allocator<'a> for DebrayAllocator {
         cell.set(r);
     }
 
-    fn mark_var<Target>(
+    fn mark_var<Target: CompilationTarget<'a>>(
         &mut self,
         var: Rc<String>,
         lvl: Level,
         cell: &'a Cell<VarReg>,
         term_loc: GenContext,
-        target: &mut Vec<Target>,
-    ) where
-        Target: CompilationTarget<'a>,
-    {
+        target: &mut Vec<Instruction>,
+    ) {
         let (r, is_new_var) = match self.get(var.clone()) {
             RegType::Temp(0) => {
                 // here, r is temporary *and* unassigned.
-                let o = self.alloc_reg_to_var(&var, lvl, term_loc, target);
+                let o = self.alloc_reg_to_var::<Target>(&var, lvl, term_loc, target);
                 cell.set(VarReg::Norm(RegType::Temp(o)));
 
                 (RegType::Temp(o), true)
@@ -297,27 +303,25 @@ impl<'a> Allocator<'a> for DebrayAllocator {
             r => (r, false),
         };
 
-        self.mark_reserved_var(var, lvl, cell, term_loc, target, r, is_new_var);
+        self.mark_reserved_var::<Target>(var, lvl, cell, term_loc, target, r, is_new_var);
     }
 
-    fn mark_reserved_var<Target>(
+    fn mark_reserved_var<Target: CompilationTarget<'a>>(
         &mut self,
         var: Rc<String>,
         lvl: Level,
         cell: &'a Cell<VarReg>,
         term_loc: GenContext,
-        target: &mut Vec<Target>,
+        target: &mut Vec<Instruction>,
         r: RegType,
         is_new_var: bool,
-    ) where
-        Target: CompilationTarget<'a>,
-    {
+    ) {
         match lvl {
             Level::Root | Level::Shallow => {
                 let k = self.arg_c;
 
                 if self.is_curr_arg_distinct_from(&var) {
-                    self.evacuate_arg(term_loc.chunk_num(), target);
+                    self.evacuate_arg::<Target>(term_loc.chunk_num(), target);
                 }
 
                 self.arg_c += 1;
index d6a1eea9e27eed4fc1d788a42ef327e50fed2c43..43c3ace88d9e14a98d525b912cfbe41d50f60b62 100644 (file)
@@ -272,10 +272,10 @@ impl UnsafeVarMarker {
         }
     }
 
-    pub(crate) fn mark_safe_vars(&mut self, query_instr: &QueryInstruction) -> bool {
+    pub(crate) fn mark_safe_vars(&mut self, query_instr: &Instruction) -> bool {
         match query_instr {
-            &QueryInstruction::PutVariable(r @ RegType::Temp(_), _)
-            | &QueryInstruction::SetVariable(r) => {
+            &Instruction::PutVariable(r @ RegType::Temp(_), _) |
+            &Instruction::SetVariable(r) => {
                 self.safe_vars.insert(r);
                 true
             }
@@ -283,10 +283,10 @@ impl UnsafeVarMarker {
         }
     }
 
-    pub(crate) fn mark_phase(&mut self, query_instr: &QueryInstruction, phase: usize) {
+    pub(crate) fn mark_phase(&mut self, query_instr: &Instruction, phase: usize) {
         match query_instr {
-            &QueryInstruction::PutValue(r @ RegType::Perm(_), _)
-            | &QueryInstruction::SetValue(r) => {
+            &Instruction::PutValue(r @ RegType::Perm(_), _) |
+            &Instruction::SetValue(r) => {
                 let p = self.unsafe_vars.entry(r).or_insert(0);
                 *p = phase;
             }
@@ -294,21 +294,21 @@ impl UnsafeVarMarker {
         }
     }
 
-    pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut QueryInstruction, phase: usize) {
+    pub(crate) fn mark_unsafe_vars(&mut self, query_instr: &mut Instruction, phase: usize) {
         match query_instr {
-            &mut QueryInstruction::PutValue(RegType::Perm(i), arg) => {
+            &mut Instruction::PutValue(RegType::Perm(i), arg) => {
                 if let Some(p) = self.unsafe_vars.swap_remove(&RegType::Perm(i)) {
                     if p == phase {
-                        *query_instr = QueryInstruction::PutUnsafeValue(i, arg);
+                        *query_instr = Instruction::PutUnsafeValue(i, arg);
                         self.safe_vars.insert(RegType::Perm(i));
                     } else {
                         self.unsafe_vars.insert(RegType::Perm(i), p);
                     }
                 }
             }
-            &mut QueryInstruction::SetValue(r) => {
+            &mut Instruction::SetValue(r) => {
                 if !self.safe_vars.contains(&r) {
-                    *query_instr = QueryInstruction::SetLocalValue(r);
+                    *query_instr = Instruction::SetLocalValue(r);
 
                     self.safe_vars.insert(r);
                     self.unsafe_vars.remove(&r);
index b8042820afb837b5440ea9bfaada884df66d4523..ce517a5f9e9a29f80855de751f1c53e80d177094 100644 (file)
@@ -1,17 +1,17 @@
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::parser::ast::*;
-use crate::parser::parser::CompositeOpDesc;
-use crate::parser::rug::{Integer, Rational};
-use crate::{is_infix, is_postfix};
-
-use crate::clause_types::*;
+use crate::instructions::*;
 use crate::machine::heap::*;
 use crate::machine::loader::PredicateQueue;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
+use crate::parser::ast::*;
+use crate::parser::parser::CompositeOpDesc;
+use crate::parser::rug::{Integer, Rational};
 use crate::types::*;
 
+use fxhash::FxBuildHasher;
+
 use indexmap::{IndexMap, IndexSet};
 use ordered_float::OrderedFloat;
 
@@ -19,10 +19,13 @@ use slice_deque::*;
 
 use std::cell::Cell;
 use std::convert::TryFrom;
+use std::fmt;
 use std::ops::AddAssign;
 use std::path::PathBuf;
 use std::rc::Rc;
 
+use crate::{is_infix, is_postfix};
+
 pub type PredicateKey = (Atom, usize); // name, arity.
 
 pub type Predicate = Vec<PredicateClause>;
@@ -375,7 +378,6 @@ impl AtomOrString {
     }
 }
 
-//TODO: try to rid yourself and the earth of the next two functions.
 pub(crate) fn fetch_atom_op_spec(
     name: Atom,
     spec: Option<OpDesc>,
@@ -431,7 +433,7 @@ pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option<
     }
 }
 
-pub(crate) type ModuleDir = IndexMap<Atom, Module>;
+pub(crate) type ModuleDir = IndexMap<Atom, Module, FxBuildHasher>;
 
 #[derive(Debug, Clone, Eq, Hash, PartialEq)]
 pub enum ModuleExport {
@@ -464,11 +466,13 @@ impl Module {
     ) -> Self {
         Module {
             module_decl,
-            code_dir: CodeDir::new(),
+            code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
             op_dir: default_op_dir(),
-            meta_predicates: MetaPredicateDir::new(),
-            extensible_predicates: ExtensiblePredicates::new(),
-            local_extensible_predicates: LocalExtensiblePredicates::new(),
+            meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
+            extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+            local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
+                FxBuildHasher::default(),
+            ),
             listing_src,
         }
     }
@@ -476,11 +480,13 @@ impl Module {
     pub(crate) fn new_in_situ(module_decl: ModuleDecl) -> Self {
         Module {
             module_decl,
-            code_dir: CodeDir::new(),
-            op_dir: OpDir::new(),
-            meta_predicates: MetaPredicateDir::new(),
-            extensible_predicates: ExtensiblePredicates::new(),
-            local_extensible_predicates: LocalExtensiblePredicates::new(),
+            code_dir: CodeDir::with_hasher(FxBuildHasher::default()),
+            op_dir: OpDir::with_hasher(FxBuildHasher::default()),
+            meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
+            extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+            local_extensible_predicates: LocalExtensiblePredicates::with_hasher(
+                FxBuildHasher::default()
+            ),
             listing_src: ListingSource::DynamicallyGenerated,
         }
     }
@@ -495,12 +501,22 @@ pub enum Number {
 }
 
 impl Default for Number {
-    #[inline]
     fn default() -> Self {
         Number::Fixnum(Fixnum::build_with(0))
     }
 }
 
+impl fmt::Display for Number {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Number::Float(fl) => write!(f, "{}", fl),
+            Number::Integer(n) => write!(f, "{}", n),
+            Number::Rational(r) => write!(f, "{}", r),
+            Number::Fixnum(n) => write!(f, "{}", n.get_num()),
+        }
+    }
+}
+
 pub trait ArenaFrom<T> {
     fn arena_from(value: T, arena: &mut Arena) -> Self;
 }
@@ -849,12 +865,3 @@ impl PredicateSkeleton {
         }
     }
 }
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum IndexingCodePtr {
-    External(usize),        // the index points past the indexing instruction prelude.
-    DynamicExternal(usize), // an External index of a dynamic predicate, potentially invalidated by retraction.
-    Fail,
-    Internal(usize), // the index points into the indexing instruction prelude.
-}
-
index f942178895f135bd7f213f4e73a494cf2c1def33..e1c4e214efb151177157e56ac73271d72ba5c72f 100644 (file)
@@ -1,5 +1,6 @@
 use crate::arena::*;
 use crate::atom_table::*;
+use crate::instructions::*;
 use crate::parser::ast::*;
 use crate::parser::rug::{Integer, Rational};
 use crate::{
@@ -8,7 +9,6 @@ use crate::{
     sign_char, single_quote_char, small_letter_char, solo_char, variable_indicator_char,
 };
 
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
 use crate::machine::heap::*;
diff --git a/src/instructions.rs b/src/instructions.rs
deleted file mode 100644 (file)
index efaf4d5..0000000
+++ /dev/null
@@ -1,919 +0,0 @@
-use crate::arena::*;
-use crate::atom_table::*;
-use crate::parser::ast::*;
-
-use crate::clause_types::*;
-use crate::forms::*;
-use crate::types::*;
-use crate::machine::heap::*;
-use crate::machine::machine_errors::MachineStub;
-
-use indexmap::IndexMap;
-use slice_deque::SliceDeque;
-
-fn reg_type_into_functor(r: RegType) -> MachineStub {
-    match r {
-        RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]),
-        RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]),
-    }
-}
-
-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"))]),
-        }
-    }
-}
-
-impl ArithmeticTerm {
-    fn into_functor(&self, arena: &mut Arena) -> MachineStub {
-        match self {
-            &ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
-            &ArithmeticTerm::Interm(i) => {
-                functor!(atom!("intermediate"), [fixnum(i)])
-            }
-            &ArithmeticTerm::Number(n) => {
-                vec![HeapCellValue::from((n, arena))]
-            }
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub(crate) enum NextOrFail {
-    Next(usize),
-    Fail(usize),
-}
-
-impl NextOrFail {
-    #[inline]
-    pub fn is_next(&self) -> bool {
-        if let NextOrFail::Next(_) = self {
-            true
-        } else {
-            false
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub(crate) enum Death {
-    Finite(usize),
-    Infinity,
-}
-
-#[derive(Debug)]
-pub(crate) enum ChoiceInstruction {
-    DynamicElse(usize, Death, NextOrFail),
-    DynamicInternalElse(usize, Death, NextOrFail),
-    DefaultRetryMeElse(usize),
-    DefaultTrustMe(usize),
-    RetryMeElse(usize),
-    TrustMe(usize),
-    TryMeElse(usize),
-}
-
-impl ChoiceInstruction {
-    pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
-        match self {
-            &ChoiceInstruction::DynamicElse(birth, death, next_or_fail) => {
-                match (death, next_or_fail) {
-                    (Death::Infinity, NextOrFail::Next(i)) => {
-                        functor!(
-                            atom!("dynamic_else"),
-                            [fixnum(birth), atom(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]
-                        )
-                    }
-                    (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]
-                        )
-                    }
-                    (Death::Finite(d), NextOrFail::Next(i)) => {
-                        functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)])
-                    }
-                }
-            }
-            &ChoiceInstruction::DynamicInternalElse(birth, death, next_or_fail) => {
-                match (death, next_or_fail) {
-                    (Death::Infinity, NextOrFail::Next(i)) => {
-                        functor!(
-                            atom!("dynamic_internal_else"),
-                            [fixnum(birth), atom(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]
-                        )
-                    }
-                    (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]
-                        )
-                    }
-                    (Death::Finite(d), NextOrFail::Next(i)) => {
-                        functor!(
-                            atom!("dynamic_internal_else"),
-                            [fixnum(birth), fixnum(d), fixnum(i)]
-                        )
-                    }
-                }
-            }
-            &ChoiceInstruction::TryMeElse(offset) => {
-                functor!(atom!("try_me_else"), [fixnum(offset)])
-            }
-            &ChoiceInstruction::RetryMeElse(offset) => {
-                functor!(atom!("retry_me_else"), [fixnum(offset)])
-            }
-            &ChoiceInstruction::TrustMe(offset) => {
-                functor!(atom!("trust_me"), [fixnum(offset)])
-            }
-            &ChoiceInstruction::DefaultRetryMeElse(offset) => {
-                functor!(atom!("default_retry_me_else"), [fixnum(offset)])
-            }
-            &ChoiceInstruction::DefaultTrustMe(offset) => {
-                functor!(atom!("default_trust_me"), [fixnum(offset)])
-            }
-        }
-    }
-}
-
-#[derive(Debug)]
-pub(crate) enum CutInstruction {
-    Cut(RegType),
-    GetLevel(RegType),
-    GetLevelAndUnify(RegType),
-    NeckCut,
-}
-
-impl CutInstruction {
-    pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
-        match self {
-            &CutInstruction::Cut(r) => {
-                let rt_stub = reg_type_into_functor(r);
-                functor!(atom!("cut"), [str(h, 0)], [rt_stub])
-            }
-            &CutInstruction::GetLevel(r) => {
-                let rt_stub = reg_type_into_functor(r);
-                functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
-            }
-            &CutInstruction::GetLevelAndUnify(r) => {
-                let rt_stub = reg_type_into_functor(r);
-                functor!(atom!("get_level_and_unify"), [str(h, 0)], [rt_stub])
-            }
-            &CutInstruction::NeckCut => {
-                functor!(atom!("neck_cut"))
-            }
-        }
-    }
-}
-
-#[derive(Clone, Copy, Debug)]
-pub(crate) enum IndexedChoiceInstruction {
-    Retry(usize),
-    Trust(usize),
-    Try(usize),
-}
-
-impl IndexedChoiceInstruction {
-    pub(crate) fn offset(&self) -> usize {
-        match self {
-            &IndexedChoiceInstruction::Retry(offset) => offset,
-            &IndexedChoiceInstruction::Trust(offset) => offset,
-            &IndexedChoiceInstruction::Try(offset) => offset,
-        }
-    }
-
-    pub(crate) fn to_functor(&self) -> MachineStub {
-        match self {
-            &IndexedChoiceInstruction::Try(offset) => {
-                functor!(atom!("try"), [fixnum(offset)])
-            }
-            &IndexedChoiceInstruction::Trust(offset) => {
-                functor!(atom!("trust"), [fixnum(offset)])
-            }
-            &IndexedChoiceInstruction::Retry(offset) => {
-                functor!(atom!("retry"), [fixnum(offset)])
-            }
-        }
-    }
-}
-
-/// A `Line` is an instruction (cf. page 98 of wambook).
-#[derive(Debug)]
-pub(crate) enum IndexingLine {
-    Indexing(IndexingInstruction),
-    IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
-    DynamicIndexedChoice(SliceDeque<usize>),
-}
-
-impl From<IndexingInstruction> for IndexingLine {
-    #[inline]
-    fn from(instr: IndexingInstruction) -> Self {
-        IndexingLine::Indexing(instr)
-    }
-}
-
-impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
-    #[inline]
-    fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
-        IndexingLine::IndexedChoice(instrs)
-    }
-}
-
-#[derive(Debug)]
-pub(crate) enum Line {
-    Arithmetic(ArithmeticInstruction),
-    Choice(ChoiceInstruction),
-    Control(ControlInstruction),
-    Cut(CutInstruction),
-    Fact(FactInstruction),
-    IndexingCode(Vec<IndexingLine>),
-    IndexedChoice(IndexedChoiceInstruction),
-    DynamicIndexedChoice(usize),
-    Query(QueryInstruction),
-}
-
-impl Line {
-    #[inline]
-    pub(crate) fn is_head_instr(&self) -> bool {
-        match self {
-            &Line::Fact(_) => true,
-            &Line::Query(_) => true,
-            _ => false,
-        }
-    }
-
-    pub(crate) fn enqueue_functors(
-        &self,
-        mut h: usize,
-        arena: &mut Arena,
-        functors: &mut Vec<MachineStub>,
-    ) {
-        match self {
-            &Line::Arithmetic(ref arith_instr) => {
-                functors.push(arith_instr.to_functor(h, arena))
-            }
-            &Line::Choice(ref choice_instr) => functors.push(choice_instr.to_functor(h)),
-            &Line::Control(ref control_instr) => functors.push(control_instr.to_functor()),
-            &Line::Cut(ref cut_instr) => functors.push(cut_instr.to_functor(h)),
-            &Line::Fact(ref fact_instr) => functors.push(fact_instr.to_functor(h)),
-            &Line::IndexingCode(ref indexing_instrs) => {
-                for indexing_instr in indexing_instrs {
-                    match indexing_instr {
-                        IndexingLine::Indexing(indexing_instr) => {
-                            let section = indexing_instr.to_functor(h);
-                            h += section.len();
-                            functors.push(section);
-                        }
-                        IndexingLine::IndexedChoice(indexed_choice_instrs) => {
-                            for indexed_choice_instr in indexed_choice_instrs {
-                                let section = indexed_choice_instr.to_functor();
-                                h += section.len();
-                                functors.push(section);
-                            }
-                        }
-                        IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
-                            for indexed_choice_instr in indexed_choice_instrs {
-                                let section = functor!(
-                                    atom!("dynamic"),
-                                    [fixnum(*indexed_choice_instr)]
-                                );
-
-                                h += section.len();
-                                functors.push(section);
-                            }
-                        }
-                    }
-                }
-            }
-            &Line::IndexedChoice(ref indexed_choice_instr) => {
-                functors.push(indexed_choice_instr.to_functor())
-            }
-            &Line::DynamicIndexedChoice(ref indexed_choice_instr) => {
-                functors.push(functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]));
-            }
-            &Line::Query(ref query_instr) => functors.push(query_instr.to_functor(h)),
-        }
-    }
-}
-
-#[inline]
-pub(crate) fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
-    match line {
-        Line::IndexingCode(ref mut indexing_code) => Some(indexing_code),
-        _ => None,
-    }
-}
-
-#[inline]
-pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
-    match line {
-        Line::IndexingCode(ref indexing_code) => Some(indexing_code),
-        _ => None,
-    }
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum ArithmeticInstruction {
-    Add(ArithmeticTerm, ArithmeticTerm, usize),
-    Sub(ArithmeticTerm, ArithmeticTerm, usize),
-    Mul(ArithmeticTerm, ArithmeticTerm, usize),
-    Pow(ArithmeticTerm, ArithmeticTerm, usize),
-    IntPow(ArithmeticTerm, ArithmeticTerm, usize),
-    IDiv(ArithmeticTerm, ArithmeticTerm, usize),
-    Max(ArithmeticTerm, ArithmeticTerm, usize),
-    Min(ArithmeticTerm, ArithmeticTerm, usize),
-    IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
-    RDiv(ArithmeticTerm, ArithmeticTerm, usize),
-    Div(ArithmeticTerm, ArithmeticTerm, usize),
-    Shl(ArithmeticTerm, ArithmeticTerm, usize),
-    Shr(ArithmeticTerm, ArithmeticTerm, usize),
-    Xor(ArithmeticTerm, ArithmeticTerm, usize),
-    And(ArithmeticTerm, ArithmeticTerm, usize),
-    Or(ArithmeticTerm, ArithmeticTerm, usize),
-    Mod(ArithmeticTerm, ArithmeticTerm, usize),
-    Rem(ArithmeticTerm, ArithmeticTerm, usize),
-    Gcd(ArithmeticTerm, ArithmeticTerm, usize),
-    Sign(ArithmeticTerm, usize),
-    Cos(ArithmeticTerm, usize),
-    Sin(ArithmeticTerm, usize),
-    Tan(ArithmeticTerm, usize),
-    Log(ArithmeticTerm, usize),
-    Exp(ArithmeticTerm, usize),
-    ACos(ArithmeticTerm, usize),
-    ASin(ArithmeticTerm, usize),
-    ATan(ArithmeticTerm, usize),
-    ATan2(ArithmeticTerm, ArithmeticTerm, usize),
-    Sqrt(ArithmeticTerm, usize),
-    Abs(ArithmeticTerm, usize),
-    Float(ArithmeticTerm, usize),
-    Truncate(ArithmeticTerm, usize),
-    Round(ArithmeticTerm, usize),
-    Ceiling(ArithmeticTerm, usize),
-    Floor(ArithmeticTerm, usize),
-    Neg(ArithmeticTerm, usize),
-    Plus(ArithmeticTerm, usize),
-    BitwiseComplement(ArithmeticTerm, usize),
-}
-
-fn arith_instr_unary_functor(
-    h: usize,
-    name: 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])
-}
-
-fn arith_instr_bin_functor(
-    h: usize,
-    name: Atom,
-    arena: &mut Arena,
-    at_1: &ArithmeticTerm,
-    at_2: &ArithmeticTerm,
-    t: usize,
-) -> MachineStub {
-    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]
-    )
-}
-
-impl ArithmeticInstruction {
-    pub(crate) fn to_functor(
-        &self,
-        h: usize,
-        arena: &mut Arena,
-    ) -> MachineStub {
-        match self {
-            &ArithmeticInstruction::Add(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("add"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Sub(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("sub"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Mul(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("mul"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::IntPow(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("int_pow"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Pow(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("pow"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::IDiv(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("idiv"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Max(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("max"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Min(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("min"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::IntFloorDiv(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("int_floor_div"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::RDiv(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("rdiv"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Div(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("div"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Shl(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("shl"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Shr(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("shr"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Xor(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("xor"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::And(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("and"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Or(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("or"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Mod(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("mod"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Rem(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("rem"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
-                arith_instr_bin_functor(h, atom!("gcd"), arena, at_1, at_2, t)
-            }
-            &ArithmeticInstruction::Sign(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("sign"), arena, at, t)
-            }
-            &ArithmeticInstruction::Cos(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("cos"), arena, at, t)
-            }
-            &ArithmeticInstruction::Sin(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("sin"), arena, at, t)
-            }
-            &ArithmeticInstruction::Tan(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("tan"), arena, at, t)
-            }
-            &ArithmeticInstruction::Log(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("log"), arena, at, t)
-            }
-            &ArithmeticInstruction::Exp(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("exp"), arena, at, t)
-            }
-            &ArithmeticInstruction::ACos(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("acos"), arena, at, t)
-            }
-            &ArithmeticInstruction::ASin(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("asin"), arena, at, t)
-            }
-            &ArithmeticInstruction::ATan(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("atan"), arena, at, t)
-            }
-            &ArithmeticInstruction::Sqrt(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
-            }
-            &ArithmeticInstruction::Abs(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("abs"), arena, at, t)
-            }
-            &ArithmeticInstruction::Float(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("float"), arena, at, t)
-            }
-            &ArithmeticInstruction::Truncate(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("truncate"), arena, at, t)
-            }
-            &ArithmeticInstruction::Round(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("round"), arena, at, t)
-            }
-            &ArithmeticInstruction::Ceiling(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("ceiling"), arena, at, t)
-            }
-            &ArithmeticInstruction::Floor(ref at, t) => {
-                arith_instr_unary_functor(h, atom!("floor"), arena, at, t)
-            }
-            &ArithmeticInstruction::Neg(ref at, t) => arith_instr_unary_functor(
-                h,
-                atom!("-"),
-                arena,
-                at,
-                t,
-            ),
-            &ArithmeticInstruction::Plus(ref at, t) => arith_instr_unary_functor(
-                h,
-                atom!("+"),
-                arena,
-                at,
-                t,
-            ),
-            &ArithmeticInstruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
-                h,
-                atom!("\\"),
-                arena,
-                at,
-                t,
-            ),
-        }
-    }
-}
-
-#[derive(Debug)]
-pub enum ControlInstruction {
-    Allocate(usize), // num_frames.
-    // name, arity, perm_vars after threshold, last call, use default call policy.
-    CallClause(ClauseType, usize, usize, bool, bool),
-    Deallocate,
-    JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
-    RevJmpBy(usize),                  // notice the lack of context change as in
-    // JmpBy. RevJmpBy is used only to patch extensible
-    // predicates together.
-    Proceed,
-}
-
-impl ControlInstruction {
-    pub(crate) fn perm_vars(&self) -> Option<usize> {
-        match self {
-            ControlInstruction::CallClause(_, _, num_cells, ..) => Some(*num_cells),
-            ControlInstruction::JmpBy(_, _, num_cells, ..) => Some(*num_cells),
-            _ => None,
-        }
-    }
-
-    pub(crate) fn to_functor(&self) -> MachineStub {
-        match self {
-            &ControlInstruction::Allocate(num_frames) => {
-                functor!(atom!("allocate"), [fixnum(num_frames)])
-            }
-            &ControlInstruction::CallClause(ref ct, arity, _, false, _) => {
-                functor!(atom!("call"), [atom(ct.name()), fixnum(arity)])
-            }
-            &ControlInstruction::CallClause(ref ct, arity, _, true, _) => {
-                functor!(atom!("execute"), [atom(ct.name()), fixnum(arity)])
-            }
-            &ControlInstruction::Deallocate => {
-                functor!(atom!("deallocate"))
-            }
-            &ControlInstruction::JmpBy(_, offset, ..) => {
-                functor!(atom!("jmp_by"), [fixnum(offset)])
-            }
-            &ControlInstruction::RevJmpBy(offset) => {
-                functor!(atom!("rev_jmp_by"), [fixnum(offset)])
-            }
-            &ControlInstruction::Proceed => {
-                functor!(atom!("proceed"))
-            }
-        }
-    }
-}
-
-/// `IndexingInstruction` cf. page 110 of wambook.
-#[derive(Debug)]
-pub(crate) enum IndexingInstruction {
-    // The first index is the optimal argument being indexed.
-    SwitchOnTerm(
-        usize,
-        IndexingCodePtr,
-        IndexingCodePtr,
-        IndexingCodePtr,
-        IndexingCodePtr,
-    ),
-    SwitchOnConstant(IndexMap<Literal, IndexingCodePtr>),
-    SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr>),
-}
-
-impl IndexingCodePtr {
-    #[allow(dead_code)]
-    pub(crate) fn to_functor(self) -> MachineStub {
-        match self {
-            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"))]
-            },
-        }
-    }
-}
-
-impl IndexingInstruction {
-    pub(crate) fn to_functor(&self, mut h: usize) -> 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)
-                    ]
-                )
-            }
-            &IndexingInstruction::SwitchOnConstant(ref constants) => {
-                let mut key_value_list_stub = vec![];
-                let orig_h = h;
-
-                h += 2; // skip the 2-cell "switch_on_constant" functor.
-
-                for (c, ptr) in constants.iter() {
-                    let key_value_pair = functor!(
-                        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]
-                )
-            }
-            &IndexingInstruction::SwitchOnStructure(ref structures) => {
-                let mut key_value_list_stub = vec![];
-                let orig_h = h;
-
-                h += 2; // skip the 2-cell "switch_on_constant" functor.
-
-                for ((name, arity), ptr) in structures.iter() {
-                    let predicate_indicator_stub = functor!(
-                        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!(
-                    atom!("switch_on_structure"),
-                    [str(orig_h, 0)],
-                    [key_value_list_stub]
-                )
-            }
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub enum FactInstruction {
-    GetConstant(Level, HeapCellValue, RegType),
-    GetList(Level, RegType),
-    GetPartialString(Level, Atom, RegType, bool),
-    GetStructure(ClauseType, usize, RegType),
-    GetValue(RegType, usize),
-    GetVariable(RegType, usize),
-    UnifyConstant(HeapCellValue),
-    UnifyLocalValue(RegType),
-    UnifyVariable(RegType),
-    UnifyValue(RegType),
-    UnifyVoid(usize),
-}
-
-impl FactInstruction {
-    pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
-        match self {
-            &FactInstruction::GetConstant(lvl, c, 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]
-                )
-            }
-            &FactInstruction::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]
-                )
-            }
-            &FactInstruction::GetPartialString(lvl, s, r, has_tail) => {
-                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]
-                )
-            }
-            &FactInstruction::GetStructure(ref ct, arity, r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(
-                    atom!("get_structure"),
-                    [atom(ct.name()), fixnum(arity), str(h, 0)],
-                    [rt_stub]
-                )
-            }
-            &FactInstruction::GetValue(r, arg) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub])
-            }
-            &FactInstruction::GetVariable(r, arg) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
-            }
-            &FactInstruction::UnifyConstant(c) => {
-                functor!(atom!("unify_constant"), [cell(c)])
-            }
-            &FactInstruction::UnifyLocalValue(r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub])
-            }
-            &FactInstruction::UnifyVariable(r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
-            }
-            &FactInstruction::UnifyValue(r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
-            }
-            &FactInstruction::UnifyVoid(vars) => {
-                functor!(atom!("unify_void"), [fixnum(vars)])
-            }
-        }
-    }
-}
-
-#[derive(Debug, Clone)]
-pub(crate) enum QueryInstruction {
-    GetVariable(RegType, usize),
-    PutConstant(Level, HeapCellValue, RegType),
-    PutList(Level, RegType),
-    PutPartialString(Level, Atom, RegType, bool),
-    PutStructure(ClauseType, usize, RegType),
-    PutUnsafeValue(usize, usize),
-    PutValue(RegType, usize),
-    PutVariable(RegType, usize),
-    SetConstant(HeapCellValue),
-    SetLocalValue(RegType),
-    SetVariable(RegType),
-    SetValue(RegType),
-    SetVoid(usize),
-}
-
-impl QueryInstruction {
-    pub(crate) fn to_functor(&self, h: usize) -> MachineStub {
-        match self {
-            &QueryInstruction::PutUnsafeValue(norm, arg) => {
-                functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)])
-            }
-            &QueryInstruction::PutConstant(lvl, c, r) => {
-                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]
-                )
-            }
-            &QueryInstruction::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]
-                )
-            }
-            &QueryInstruction::PutPartialString(lvl, s, r, has_tail) => {
-                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]
-                )
-            }
-            &QueryInstruction::PutStructure(ref ct, arity, r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(
-                    atom!("put_structure"),
-                    [atom(ct.name()), fixnum(arity), str(h, 0)],
-                    [rt_stub]
-                )
-            }
-            &QueryInstruction::PutValue(r, arg) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
-            }
-            &QueryInstruction::GetVariable(r, arg) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
-            }
-            &QueryInstruction::PutVariable(r, arg) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
-            }
-            &QueryInstruction::SetConstant(c) => {
-                functor!(atom!("set_constant"), [cell(c)], [])
-            }
-            &QueryInstruction::SetLocalValue(r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub])
-            }
-            &QueryInstruction::SetVariable(r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
-            }
-            &QueryInstruction::SetValue(r) => {
-                let rt_stub = reg_type_into_functor(r);
-
-                functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
-            }
-            &QueryInstruction::SetVoid(vars) => {
-                functor!(atom!("set_void"), [fixnum(vars)])
-            }
-        }
-    }
-}
-
-pub(crate) type CompiledFact = Vec<FactInstruction>;
-
-pub(crate) type Code = Vec<Line>;
index 3c6e955c990ff116a0b5a9cc59d2f4da4b900119..4f255584c32ea423826ad3e80e1ebced1d1afc85 100644 (file)
@@ -1,9 +1,8 @@
 use crate::atom_table::*;
-use crate::parser::ast::*;
-
-use crate::clause_types::*;
 use crate::forms::*;
+use crate::instructions::*;
 use crate::machine::machine_indices::*;
+use crate::parser::ast::*;
 
 use std::cell::Cell;
 use std::collections::VecDeque;
@@ -52,7 +51,7 @@ impl<'a> TermIterState<'a> {
         match term {
             Term::AnonVar => TermIterState::AnonVar(lvl),
             Term::Clause(cell, name, subterms) => {
-                let ct = ClauseType::Named(name.clone(), subterms.len(), CodeIndex::default());
+                let ct = ClauseType::Named(subterms.len(), *name, CodeIndex::default());
                 TermIterState::Clause(lvl, 0, cell, ct, subterms)
             }
             Term::Cons(cell, head, tail) => {
@@ -112,8 +111,8 @@ impl<'a> QueryIterator<'a> {
 
     fn new(term: &'a QueryTerm) -> Self {
         match term {
-            &QueryTerm::Clause(ref cell, ClauseType::CallN, ref terms, _) => {
-                let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN, terms);
+            &QueryTerm::Clause(ref cell, ClauseType::CallN(arity), ref terms, _) => {
+                let state = TermIterState::Clause(Level::Root, 1, cell, ClauseType::CallN(arity), terms);
                 QueryIterator {
                     state_stack: vec![state],
                 }
@@ -164,7 +163,7 @@ impl<'a> Iterator for QueryIterator<'a> {
                 TermIterState::Clause(lvl, child_num, cell, ct, child_terms) => {
                     if child_num == child_terms.len() {
                         match ct {
-                            ClauseType::CallN => {
+                            ClauseType::CallN(_) => {
                                 self.push_subterm(Level::Shallow, &child_terms[0]);
                             }
                             ClauseType::Named(..) => {
@@ -499,7 +498,7 @@ impl<'a> ChunkedIterator<'a> {
                 }
                 ChunkedTerm::BodyTerm(&QueryTerm::Clause(
                     _,
-                    ClauseType::CallN,
+                    ClauseType::CallN(_),
                     ref subterms,
                     _,
                 )) => {
index 458ad485a24db88f3b7ff0ea818c66d1b1fbdb75..a4aff98c8bf557be6cf567b14e7c99568a1d2c11 100644 (file)
@@ -1,3 +1,5 @@
+#![recursion_limit = "4112"]
+
 #[macro_use]
 extern crate static_assertions;
 
@@ -11,7 +13,6 @@ pub mod arena;
 pub mod parser;
 mod allocator;
 mod arithmetic;
-mod clause_types;
 pub mod codegen;
 mod debray_allocator;
 mod fixtures;
@@ -19,7 +20,8 @@ mod forms;
 mod heap_iter;
 pub mod heap_print;
 mod indexing;
-mod instructions;
+#[macro_use]
+pub mod instructions;
 mod iterators;
 pub mod machine;
 mod raw_block;
index b162e0234ccfb7024dfc3f6815509388e82b9e8f..3e023c8cd16aa386dadd430166714210badfa0d5 100644 (file)
@@ -12,9 +12,7 @@ between(Lower, Upper, X) :-
     (   nonvar(X) ->
         Lower =< X,
         X =< Upper
-    ;   % compare(Ord, Lower, Upper),
-        % between_(Ord, Lower, Upper, X)
-        Lower =< Upper,
+    ;   Lower =< Upper,
         between_(Lower, Upper, X)
     ).
 
@@ -27,16 +25,6 @@ between_(Lower, Upper, Lower1) :-
        )
     ).
 
-/*
-between_(<, Lower0, Upper, X) :-
-    (   X = Lower0
-    ;   Lower1 is Lower0 + 1,
-        compare(Ord, Lower1, Upper),
-        between_(Ord, Lower1, Upper, X)
-    ).
-between_(=, Upper, Upper, Upper).
-*/
-
 enumerate_nats(I, I).
 enumerate_nats(I0, N) :-
     I1 is I0 + 1,
index f1b2f2d9e0bd3d31a583e8b4c8cc2d8622247eca..32527df963dfd940a2d0fd07ae6a0cc4a0c8e71e 100644 (file)
@@ -59,15 +59,13 @@ call(G, A, B, C, D, E, F, G) :- '$call'(G, A, B, C, D, E, F, G).
 
 call(G, A, B, C, D, E, F, G, H) :- '$call'(G, A, B, C, D, E, F, G, H).
 
+% dynamic module resolution.
 
 Module : Predicate :-
     (  atom(Module) -> '$module_call'(Module, Predicate)
     ;  throw(error(type_error(atom, Module), (:)/2))
     ).
 
-
-% dynamic module resolution.
-
 :(Module, Predicate, A1) :-
     (  atom(Module) ->
        '$module_call'(A1, Module, Predicate)
index a64c3ad365c5a73c364bcba7ad0f3e64ece3da67..752e82713537b8e95c7caf403b02e2ed959c8539 100644 (file)
@@ -56,13 +56,16 @@ length(Xs, N) :-
     !,
     '$skip_max_list'(M, -1, Xs, Xs0),
     (  Xs0 == [] -> N = M
-    ;  var(Xs0)  -> length_addendum(Xs0, N, M)).
+    ;  var(Xs0)  -> length_addendum(Xs0, N, M)
+    ).
 length(Xs, N) :-
     integer(N),
-    N >= 0, !,
+    N >= 0,
+    !,
     '$skip_max_list'(M, N, Xs, Xs0),
     (  Xs0 == [] -> N = M
-    ;  var(Xs0)  -> R is N-M, length_rundown(Xs0, R)).
+    ;  var(Xs0)  -> R is N-M, length_rundown(Xs0, R)
+    ).
 length(_, N) :-
     integer(N), !,
     domain_error(not_less_than_zero, N, length/2).
index a9e8f8d7f45197f7a2d2fa04d31113a4aa0bf00b..dd26bbb86b7d3098c260e4fff22b1ed5961811f6 100644 (file)
@@ -90,7 +90,6 @@ unload_evacuable(Evacuable) :-
 run_initialization_goals(Module) :-
     (  predicate_property(Module:'$initialization_goals'(_), dynamic) ->
        % FIXME: failing here. also, see add_module.
-       '$debug_hook',
        findall(Module:Goal, '$call'(builtins:retract(Module:'$initialization_goals'(Goal))), Goals),
        abolish(Module:'$initialization_goals'/1),
        (  maplist(Module:call, Goals) ->
@@ -543,15 +542,15 @@ use_module(Module, Exports, Evacuable) :-
 
 
 check_predicate_property(meta_predicate, Module, Name, Arity, MetaPredicateTerm) :-
-    '$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
+    '$meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm).
 check_predicate_property(built_in, _, Name, Arity, built_in) :-
-    '$cpp_built_in_property'(Name, Arity).
+    '$built_in_property'(Name, Arity).
 check_predicate_property(dynamic, Module, Name, Arity, dynamic) :-
-    '$cpp_dynamic_property'(Module, Name, Arity).
+    '$dynamic_property'(Module, Name, Arity).
 check_predicate_property(multifile, Module, Name, Arity, multifile) :-
-    '$cpp_multifile_property'(Module, Name, Arity).
+    '$multifile_property'(Module, Name, Arity).
 check_predicate_property(discontiguous, Module, Name, Arity, discontiguous) :-
-    '$cpp_discontiguous_property'(Module, Name, Arity).
+    '$discontiguous_property'(Module, Name, Arity).
 
 
 
index 85b6cbc3717497ea5ae254479611a7168d2127dd..5cc6409879425d86e6ce41dffc0a4c6f6a693fa5 100644 (file)
@@ -3,7 +3,6 @@ use divrem::*;
 use crate::arena::*;
 use crate::arithmetic::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
 use crate::machine::machine_errors::*;
@@ -1080,7 +1079,7 @@ impl MachineState {
     pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> {
         match at {
             &ArithmeticTerm::Reg(r) => {
-               let value = self.store(self.deref(self[r]));
+                       let value = self.store(self.deref(self[r]));
 
                 match Number::try_from(value) {
                     Ok(n) => Ok(n),
index 568978d8891ac07762c24bf669f5d000425dccd6..a158d3afbf76601769899914f755782ebadea07d 100644 (file)
@@ -15,8 +15,9 @@ pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
 pub(super) struct AttrVarInitializer {
     pub(super) attr_var_queue: Vec<usize>,
     pub(super) bindings: Bindings,
-    pub(super) cp: LocalCodePtr,
-    pub(super) instigating_p: LocalCodePtr,
+    pub(super) p: usize,
+    pub(super) cp: usize,
+    // pub(super) instigating_p: usize,
     pub(super) verify_attrs_loc: usize,
 }
 
@@ -25,8 +26,8 @@ impl AttrVarInitializer {
         AttrVarInitializer {
             attr_var_queue: vec![],
             bindings: vec![],
-            instigating_p: LocalCodePtr::default(),
-            cp: LocalCodePtr::default(),
+            p: 0,
+            cp: 0,
             verify_attrs_loc,
         }
     }
@@ -41,15 +42,14 @@ impl AttrVarInitializer {
 impl MachineState {
     pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: HeapCellValue) {
         if self.attr_var_init.bindings.is_empty() {
-            self.attr_var_init.instigating_p = self.p.local();
+            // save self.p and self.cp and ensure that the next
+            // instruction is InstallVerifyAttrInterrupt.
 
-            if self.last_call {
-                self.attr_var_init.cp = self.cp;
-            } else {
-                self.attr_var_init.cp = self.p.local() + 1;
-            }
+            self.attr_var_init.p = self.p;
+            self.attr_var_init.cp = self.cp;
 
-            self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
+            self.p = INSTALL_VERIFY_ATTR_INTERRUPT - 1;
+            self.cp = INSTALL_VERIFY_ATTR_INTERRUPT;
         }
 
         self.attr_var_init.bindings.push((h, addr));
@@ -109,25 +109,27 @@ impl MachineState {
     }
 
     pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
-        self.allocate(self.num_of_args + 2);
+        self.allocate(self.num_of_args + 3);
 
         let e = self.e;
-        self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
+        let and_frame = self.stack.index_and_frame_mut(e);
 
         for i in 1..self.num_of_args + 1 {
-            self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
+            and_frame[i] = self.registers[i];
         }
 
-        self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =
+        and_frame[self.num_of_args + 1] =
             fixnum_as_cell!(Fixnum::build_with(self.b0 as i64));
-        self.stack.index_and_frame_mut(e)[self.num_of_args + 2] =
+        and_frame[self.num_of_args + 2] =
             fixnum_as_cell!(Fixnum::build_with(self.num_of_args as i64));
+        and_frame[self.num_of_args + 3] =
+            fixnum_as_cell!(Fixnum::build_with(self.attr_var_init.cp as i64));
 
         self.verify_attributes();
 
-        self.num_of_args = 2;
+        self.num_of_args = 3;
         self.b0 = self.b;
-        self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+        self.p = p;
     }
 
     pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs
deleted file mode 100644 (file)
index f6fb6aa..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-use crate::clause_types::*;
-use crate::instructions::*;
-use crate::machine::{Machine, MachineState};
-use crate::machine::machine_indices::*;
-
-use std::fmt;
-
-pub(crate) enum OwnedOrIndexed {
-    Indexed(usize),
-    Owned(Line),
-}
-
-impl fmt::Debug for OwnedOrIndexed {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            &OwnedOrIndexed::Indexed(ref index) => write!(f, "Indexed({:?})", index),
-            &OwnedOrIndexed::Owned(ref owned) => write!(f, "Owned({:?})", owned),
-        }
-    }
-}
-
-impl OwnedOrIndexed {
-    #[inline(always)]
-    pub(crate) fn as_ref<'a>(&'a self, code: &'a Code) -> &'a Line {
-        match self {
-            &OwnedOrIndexed::Indexed(p) => &code[p],
-            &OwnedOrIndexed::Owned(ref r) => r,
-        }
-    }
-}
-
-
-// TODO: remove this, replace with just 'Code'.
-#[derive(Debug)]
-pub struct CodeRepo {
-    pub(super) code: Code,
-}
-
-impl CodeRepo {
-    pub(super) fn lookup_instr(&self, machine_st: &MachineState, p: &CodePtr) -> Option<OwnedOrIndexed> {
-        match p {
-            &CodePtr::Local(local) => {
-                return Some(self.lookup_local_instr(machine_st, local));
-            }
-            &CodePtr::REPL(..) => None,
-            &CodePtr::BuiltInClause(ref built_in, _) => {
-                let call_clause = call_clause!(
-                    ClauseType::BuiltIn(built_in.clone()),
-                    built_in.arity(),
-                    0,
-                    machine_st.last_call
-                );
-
-                Some(OwnedOrIndexed::Owned(call_clause))
-            }
-            &CodePtr::CallN(arity, _, last_call) => {
-                let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call);
-                Some(OwnedOrIndexed::Owned(call_clause))
-            }
-            &CodePtr::VerifyAttrInterrupt(p) => Some(OwnedOrIndexed::Indexed(p)),
-        }
-    }
-
-    #[inline]
-    pub(super) fn lookup_local_instr(&self, machine_st: &MachineState, p: LocalCodePtr) -> OwnedOrIndexed {
-        match p {
-            LocalCodePtr::Halt => {
-                // exit with the interrupt exit code.
-                std::process::exit(1);
-            }
-            LocalCodePtr::DirEntry(p) => match &self.code[p] {
-                &Line::IndexingCode(ref indexing_lines) => {
-                    match &indexing_lines[machine_st.oip as usize] {
-                        &IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
-                            OwnedOrIndexed::Owned(
-                                Line::IndexedChoice(indexed_choice_instrs[machine_st.iip as usize])
-                            )
-                        }
-                        &IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
-                            OwnedOrIndexed::Owned(
-                                Line::DynamicIndexedChoice(indexed_choice_instrs[machine_st.iip as usize])
-                            )
-                        }
-                        _ => {
-                            OwnedOrIndexed::Indexed(p)
-                        }
-                    }
-                }
-                _ => OwnedOrIndexed::Indexed(p)
-            }
-        }
-    }
-}
-
-impl Machine {
-    pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> {
-        loop {
-            match &self.code_repo.code[p] {
-                &Line::Choice(ChoiceInstruction::DynamicElse(
-                    birth,
-                    death,
-                    NextOrFail::Next(i),
-                )) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, i));
-                    } else if i > 0 {
-                        p += i;
-                    } else {
-                        return None;
-                    }
-                }
-                &Line::Choice(ChoiceInstruction::DynamicElse(
-                    birth,
-                    death,
-                    NextOrFail::Fail(_),
-                )) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, 0));
-                    } else {
-                        return None;
-                    }
-                }
-                &Line::Choice(ChoiceInstruction::DynamicInternalElse(
-                    birth,
-                    death,
-                    NextOrFail::Next(i),
-                )) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, i));
-                    } else if i > 0 {
-                        p += i;
-                    } else {
-                        return None;
-                    }
-                }
-                &Line::Choice(ChoiceInstruction::DynamicInternalElse(
-                    birth,
-                    death,
-                    NextOrFail::Fail(_),
-                )) => {
-                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                        return Some((p, 0));
-                    } else {
-                        return None;
-                    }
-                }
-                &Line::Control(ControlInstruction::RevJmpBy(i)) => {
-                    p -= i;
-                }
-                _ => {
-                    unreachable!();
-                }
-            }
-        }
-    }
-
-    pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> {
-        let p = self.machine_st.p.local().abs_loc();
-
-        let indexed_choice_instrs = match &self.code_repo.code[p] {
-            Line::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] {
-                IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
-                    indexed_choice_instrs
-                }
-                _ => unreachable!(),
-            },
-            _ => unreachable!(),
-        };
-
-        loop {
-            match &indexed_choice_instrs.get(ii as usize) {
-                Some(&offset) => match &self.code_repo.code[p + offset - 1] {
-                    &Line::Choice(ChoiceInstruction::DynamicInternalElse(
-                        birth,
-                        death,
-                        next_or_fail,
-                    )) => {
-                        if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
-                            return Some((offset, oi, ii, next_or_fail.is_next()));
-                        } else {
-                            ii += 1;
-                        }
-                    }
-                    _ => unreachable!(),
-                },
-                None => return None,
-            }
-        }
-    }
-}
-
-impl CodeRepo {
-    #[inline]
-    pub(super) fn new() -> Self {
-        CodeRepo { code: Code::new() }
-    }
-}
index fe63347f6fc27a84998f3702c8048940cf1c5318..fcda8710045e46cc205bf931e9ee964040c3478e 100644 (file)
@@ -2,45 +2,47 @@ use crate::instructions::*;
 
 use indexmap::IndexSet;
 
-fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
+fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> bool {
     match line {
-        &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
+        &Instruction::TryMeElse(offset) if offset > 0 => {
             stack.push(index + offset);
         }
-        &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset))
-        | &Line::Choice(ChoiceInstruction::RetryMeElse(offset))
+        &Instruction::DefaultRetryMeElse(offset) |
+        &Instruction::RetryMeElse(offset)
             if offset > 0 =>
         {
             stack.push(index + offset);
         }
-        &Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(offset)))
+        &Instruction::DynamicElse(_, _, NextOrFail::Next(offset))
             if offset > 0 =>
         {
             stack.push(index + offset);
         }
-        &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(offset)))
+        &Instruction::DynamicInternalElse(_, _, NextOrFail::Next(offset))
             if offset > 0 =>
         {
             stack.push(index + offset);
         }
-        &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
+        &Instruction::JmpByCall(_, offset, _) => {
             stack.push(index + offset);
         }
-        &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
+        &Instruction::JmpByExecute(_, offset, _) => {
             stack.push(index + offset);
             return true;
         }
-        &Line::Control(ControlInstruction::Proceed)
-        | &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
+        &Instruction::Proceed => {
             return true;
         }
-        &Line::Control(ControlInstruction::RevJmpBy(offset)) => {
+        &Instruction::RevJmpBy(offset) => {
             if offset > 0 {
                 stack.push(index - offset);
             } else {
                 return true;
             }
         }
+        instr if instr.is_execute() => {
+            return true;
+        }
         _ => {}
     };
 
@@ -51,7 +53,7 @@ fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
  * begin in code at the offset p. Each instruction is passed to the
  * walker function.
  */
-pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) {
+pub(crate) fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Instruction)) {
     let mut stack = vec![p];
     let mut visited_indices = IndexSet::new();
 
index 8b69ced815e5cda5b58b67dd45e303f2a5e2d0ec..fa1f7250b9ad4a9429f8380a509b5105365a41af 100644 (file)
@@ -38,7 +38,7 @@ pub(super) fn bootstrapping_compile(
     );
 
     let payload = BootstrappingLoadState(
-        LoadStatePayload::new(wam_prelude.code_repo.code.len(), term_stream)
+        LoadStatePayload::new(wam_prelude.code.len(), term_stream)
     );
 
     let loader: Loader<'_, BootstrappingLoadState> = Loader { payload, wam_prelude };
@@ -73,7 +73,8 @@ pub(super) fn compile_appendix(
         let code_len = code.len();
 
         match &mut code[jmp_by_offset] {
-            &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => {
+            &mut Instruction::JmpByCall(_, ref mut offset, ..) |
+            &mut Instruction::JmpByExecute(_, ref mut offset, ..) => {
                 *offset = code_len - jmp_by_offset;
             }
             _ => {
@@ -144,20 +145,20 @@ fn derelictize_try_me_else(
     retraction_info: &mut RetractionInfo,
 ) -> Option<usize> {
     match &mut code[index] {
-        Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(0))) => None,
-        Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o))) => {
+        Instruction::DynamicElse(_, _, NextOrFail::Next(0)) => None,
+        Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) => {
             retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
             Some(mem::replace(o, 0))
         }
-        Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(0))) => None,
-        Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o))) => {
+        Instruction::DynamicInternalElse(_, _, NextOrFail::Next(0)) => None,
+        Instruction::DynamicInternalElse(_, _, NextOrFail::Next(ref mut o)) => {
             retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(index, *o));
             Some(mem::replace(o, 0))
         }
-        Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_)))
-        | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => None,
-        Line::Choice(ChoiceInstruction::TryMeElse(0)) => None,
-        Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+        Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) |
+        Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => None,
+        Instruction::TryMeElse(0) => None,
+        Instruction::TryMeElse(ref mut o) => {
             retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(index, *o));
             Some(mem::replace(o, 0))
         }
@@ -183,7 +184,7 @@ fn merge_indices(
             let clause_loc =
                 find_inner_choice_instr(code, skeleton[clause_index].clause_start, index_loc);
 
-            let target_indexing_line = to_indexing_line_mut(&mut code[target_index_loc]).unwrap();
+            let target_indexing_line = code[target_index_loc].to_indexing_line_mut().unwrap();
 
             skeleton[clause_index]
                 .opt_arg_index_key
@@ -210,8 +211,8 @@ fn merge_indices(
 fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize {
     loop {
         match &code[index] {
-            Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(i)))
-            | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(i)))
+            Instruction::DynamicElse(_, _, NextOrFail::Next(i)) |
+            Instruction::DynamicInternalElse(_, _, NextOrFail::Next(i))
                 if *i > 0 =>
             {
                 index += i;
@@ -226,15 +227,15 @@ fn find_outer_choice_instr(code: &Code, mut index: usize) -> usize {
 fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> usize {
     loop {
         match &code[index] {
-            Line::Choice(ChoiceInstruction::TryMeElse(o))
-            | Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+            Instruction::TryMeElse(o) |
+            Instruction::RetryMeElse(o) => {
                 if *o > 0 {
                     return index;
                 } else {
                     index = index_loc;
                 }
             }
-            &Line::Choice(ChoiceInstruction::DynamicElse(_, _, next_or_fail)) => match next_or_fail
+            &Instruction::DynamicElse(_, _, next_or_fail) => match next_or_fail
             {
                 NextOrFail::Next(i) => {
                     if i == 0 {
@@ -247,7 +248,7 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u
                     index = index_loc;
                 }
             },
-            &Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, next_or_fail)) => {
+            &Instruction::DynamicInternalElse(_, _, next_or_fail) => {
                 match next_or_fail {
                     NextOrFail::Next(i) => {
                         if i == 0 {
@@ -261,20 +262,20 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u
                     }
                 }
             }
-            Line::Choice(ChoiceInstruction::TrustMe(_)) => {
+            Instruction::TrustMe(_) => {
                 return index;
             }
-            Line::IndexingCode(indexing_code) => match &indexing_code[0] {
+            Instruction::IndexingCode(indexing_code) => match &indexing_code[0] {
                 IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
                     IndexingCodePtr::External(v) => {
                         index += v;
                     }
                     IndexingCodePtr::DynamicExternal(v) => match &code[index + v] {
-                        &Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                        &Instruction::DynamicInternalElse(
                             _,
                             _,
                             NextOrFail::Next(0),
-                        )) => {
+                        ) => {
                             return index + v;
                         }
                         _ => {
@@ -287,7 +288,7 @@ fn find_inner_choice_instr(code: &Code, mut index: usize, index_loc: usize) -> u
                     unreachable!();
                 }
             },
-            Line::Control(ControlInstruction::RevJmpBy(offset)) => {
+            Instruction::RevJmpBy(offset) => {
                 index -= offset;
             }
             _ => {
@@ -310,9 +311,7 @@ fn remove_index_from_subsequence(
 ) {
     if let Some(index_loc) = opt_arg_index_key.switch_on_term_loc() {
         let clause_start = find_inner_choice_instr(code, clause_start, index_loc);
-
-        let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
-
+        let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
         let offset = clause_start - index_loc + 1;
 
         remove_index(opt_arg_index_key, target_indexing_line, offset);
@@ -351,7 +350,7 @@ fn merge_indexed_subsequences(
     );
 
     match &mut code[inner_try_me_else_loc] {
-        Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+        Instruction::TryMeElse(ref mut o) => {
             retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
                 inner_try_me_else_loc,
                 *o,
@@ -359,15 +358,15 @@ fn merge_indexed_subsequences(
 
             match *o {
                 0 => {
-                    code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
+                    code[inner_try_me_else_loc] = Instruction::TrustMe(0);
                 }
                 o => match &code[inner_try_me_else_loc + o] {
-                    Line::Control(ControlInstruction::RevJmpBy(0)) => {
-                        code[inner_try_me_else_loc] = Line::Choice(ChoiceInstruction::TrustMe(o));
+                    Instruction::RevJmpBy(0) => {
+                        code[inner_try_me_else_loc] = Instruction::TrustMe(o);
                     }
                     _ => {
                         code[inner_try_me_else_loc] =
-                            Line::Choice(ChoiceInstruction::RetryMeElse(o));
+                            Instruction::RetryMeElse(o);
                     }
                 },
             }
@@ -403,7 +402,7 @@ fn merge_indexed_subsequences(
             );
         }
         None => match &mut code[outer_threaded_choice_instr_loc] {
-            Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+            Instruction::TryMeElse(ref mut o) => {
                 retraction_info
                     .push_record(RetractionRecord::ModifiedTryMeElse(inner_trust_me_loc, *o));
 
@@ -461,60 +460,55 @@ fn blunt_leading_choice_instr(
 ) -> usize {
     loop {
         match &mut code[instr_loc] {
-            Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+            Instruction::RetryMeElse(o) => {
                 retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(instr_loc, *o));
-
-                code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(*o));
-
+                code[instr_loc] = Instruction::TryMeElse(*o);
                 return instr_loc;
             }
-            Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(_)))
-            | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(_))) => {
+            Instruction::DynamicElse(_, _, NextOrFail::Next(_)) |
+            Instruction::DynamicInternalElse(_, _, NextOrFail::Next(_)) => {
                 return instr_loc;
             }
-            &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o))) => {
+            &mut Instruction::DynamicElse(b, d, NextOrFail::Fail(o)) => {
                 retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
                     instr_loc,
                     NextOrFail::Fail(o),
                 ));
 
-                code[instr_loc] =
-                    Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(0)));
-
+                code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(0));
                 return instr_loc;
             }
-            &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(
+            &mut Instruction::DynamicInternalElse(
                 b,
                 d,
                 NextOrFail::Fail(o),
-            )) => {
+            ) => {
                 retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
                     instr_loc,
                     NextOrFail::Fail(o),
                 ));
 
-                code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                code[instr_loc] = Instruction::DynamicInternalElse(
                     b,
                     d,
                     NextOrFail::Next(0),
-                ));
+                );
 
                 return instr_loc;
             }
-            Line::Choice(ChoiceInstruction::TrustMe(o)) => {
-                retraction_info
-                    .push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false));
+            Instruction::TrustMe(o) => {
+                retraction_info.push_record(RetractionRecord::AppendedTrustMe(instr_loc, *o, false));
 
-                code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0));
+                code[instr_loc] = Instruction::TryMeElse(0);
                 return instr_loc + 1;
             }
-            Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+            Instruction::TryMeElse(0) => {
                 return instr_loc + 1;
             }
-            Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
+            Instruction::TryMeElse(o) => {
                 instr_loc += *o;
             }
-            Line::Control(ControlInstruction::RevJmpBy(o)) => {
+            Instruction::RevJmpBy(o) => {
                 instr_loc -= *o;
             }
             _ => {
@@ -530,7 +524,7 @@ fn set_switch_var_offset_to_choice_instr(
     offset: usize,
     retraction_info: &mut RetractionInfo,
 ) {
-    let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+    let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
 
     let v = match &target_indexing_line[0] {
         &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => match v {
@@ -543,9 +537,9 @@ fn set_switch_var_offset_to_choice_instr(
     };
 
     match &code[index_loc + v] {
-        Line::Choice(ChoiceInstruction::TryMeElse(_))
-        | Line::Choice(ChoiceInstruction::DynamicElse(..))
-        | Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {}
+        Instruction::TryMeElse(_) |
+        Instruction::DynamicElse(..) |
+        Instruction::DynamicInternalElse(..) => {}
         _ => {
             set_switch_var_offset(code, index_loc, offset, retraction_info);
         }
@@ -559,7 +553,7 @@ fn set_switch_var_offset(
     offset: usize,
     retraction_info: &mut RetractionInfo,
 ) {
-    let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+    let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
 
     let old_v = match &mut target_indexing_line[0] {
         IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => match *v {
@@ -585,72 +579,67 @@ fn internalize_choice_instr_at(
     retraction_info: &mut RetractionInfo,
 ) {
     match &mut code[instr_loc] {
-        Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(_)))
-        | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(_))) => {}
-        Line::Choice(ChoiceInstruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0))) => {
+        Instruction::DynamicElse(_, _, NextOrFail::Fail(_)) |
+        Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(_)) => {
+        }
+        Instruction::DynamicElse(_, _, ref mut o @ NextOrFail::Next(0)) => {
             retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
             *o = NextOrFail::Fail(0);
         }
-        &mut Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o))) => {
+        &mut Instruction::DynamicElse(b, d, NextOrFail::Next(o)) => {
             retraction_info.push_record(RetractionRecord::AppendedNextOrFail(
                 instr_loc,
                 NextOrFail::Next(o),
             ));
 
             match &mut code[instr_loc + o] {
-                Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
-                    code[instr_loc] =
-                        Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Fail(o)));
+                Instruction::RevJmpBy(p) if *p == 0 => {
+                    code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Fail(o));
                 }
                 _ => {
-                    code[instr_loc] =
-                        Line::Choice(ChoiceInstruction::DynamicElse(b, d, NextOrFail::Next(o)));
+                    code[instr_loc] = Instruction::DynamicElse(b, d, NextOrFail::Next(o));
                 }
             }
         }
-        Line::Choice(ChoiceInstruction::DynamicInternalElse(
-            _,
-            _,
-            ref mut o @ NextOrFail::Next(0),
-        )) => {
+        Instruction::DynamicInternalElse(_, _, ref mut o @ NextOrFail::Next(0)) => {
             retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, 0));
             *o = NextOrFail::Fail(0);
         }
-        &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(b, d, NextOrFail::Next(o))) => {
+        &mut Instruction::DynamicInternalElse(b, d, NextOrFail::Next(o)) => {
             retraction_info.push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, o));
 
             match &mut code[instr_loc + o] {
-                Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
-                    code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                Instruction::RevJmpBy(p) if *p == 0 => {
+                    code[instr_loc] = Instruction::DynamicInternalElse(
                         b,
                         d,
                         NextOrFail::Fail(o),
-                    ));
+                    );
                 }
                 _ => {
-                    code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                    code[instr_loc] = Instruction::DynamicInternalElse(
                         b,
                         d,
                         NextOrFail::Next(o),
-                    ));
+                    );
                 }
             }
         }
-        Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+        Instruction::TryMeElse(0) => {
             retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, 0));
-            code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
+            code[instr_loc] = Instruction::TrustMe(0);
         }
-        Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
+        Instruction::TryMeElse(o) => {
             let o = *o;
 
             retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(instr_loc, o));
 
             match &mut code[instr_loc + o] {
-                Line::Control(ControlInstruction::RevJmpBy(p)) if *p == 0 => {
-                    code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(o));
+                Instruction::RevJmpBy(p) if *p == 0 => {
+                    code[instr_loc] = Instruction::TrustMe(o);
                 }
                 _ => {
-                    code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o));
+                    code[instr_loc] = Instruction::RetryMeElse(o);
                 }
             }
         }
@@ -668,8 +657,7 @@ fn thread_choice_instr_at_to(
 ) {
     loop {
         match &mut code[instr_loc] {
-            Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
-            | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
+            Instruction::TryMeElse(ref mut o) | Instruction::RetryMeElse(ref mut o)
                 if target_loc >= instr_loc =>
             {
                 retraction_info.push_record(RetractionRecord::ReplacedChoiceOffset(instr_loc, *o));
@@ -677,82 +665,80 @@ fn thread_choice_instr_at_to(
                 *o = target_loc - instr_loc;
                 return;
             }
-            Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)))
-            | Line::Choice(ChoiceInstruction::DynamicInternalElse(
+            Instruction::DynamicElse(_, _, NextOrFail::Next(ref mut o)) |
+            Instruction::DynamicInternalElse(
                 _,
                 _,
                 NextOrFail::Next(ref mut o),
-            )) if target_loc >= instr_loc => {
+            ) if target_loc >= instr_loc => {
                 retraction_info
                     .push_record(RetractionRecord::ReplacedDynamicElseOffset(instr_loc, *o));
                 *o = target_loc - instr_loc;
                 return;
             }
-            Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Next(o)))
-            | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Next(o))) => {
+            Instruction::DynamicElse(_, _, NextOrFail::Next(o)) |
+            Instruction::DynamicInternalElse(_, _, NextOrFail::Next(o)) => {
                 instr_loc += *o;
             }
-            Line::Choice(ChoiceInstruction::TryMeElse(o))
-            | Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+            Instruction::TryMeElse(o)
+            | Instruction::RetryMeElse(o) => {
                 instr_loc += *o;
             }
-            Line::Control(ControlInstruction::RevJmpBy(ref mut o)) if instr_loc >= target_loc => {
+            Instruction::RevJmpBy(ref mut o) if instr_loc >= target_loc => {
                 retraction_info.push_record(RetractionRecord::ModifiedRevJmpBy(instr_loc, *o));
 
                 *o = instr_loc - target_loc;
                 return;
             }
-            &mut Line::Control(ControlInstruction::RevJmpBy(o)) => {
+            &mut Instruction::RevJmpBy(o) => {
                 instr_loc -= o;
             }
-            &mut Line::Choice(ChoiceInstruction::DynamicElse(birth, death, ref mut fail))
+            &mut Instruction::DynamicElse(birth, death, ref mut fail)
                 if target_loc >= instr_loc =>
             {
                 retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail));
 
-                code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicElse(
+                code[instr_loc] = instr!("dynamic_else",
                     birth,
                     death,
-                    NextOrFail::Next(target_loc - instr_loc),
-                ));
+                    NextOrFail::Next(target_loc - instr_loc)
+                );
 
                 return;
             }
-            Line::Choice(ChoiceInstruction::DynamicElse(_, _, NextOrFail::Fail(o))) if *o > 0 => {
+            Instruction::DynamicElse(_, _, NextOrFail::Fail(o)) if *o > 0 => {
                 instr_loc += *o;
             }
-            &mut Line::Choice(ChoiceInstruction::DynamicInternalElse(
+            &mut Instruction::DynamicInternalElse(
                 birth,
                 death,
                 ref mut fail,
-            )) if target_loc >= instr_loc => {
+            ) if target_loc >= instr_loc => {
                 retraction_info.push_record(RetractionRecord::AppendedNextOrFail(instr_loc, *fail));
 
-                code[instr_loc] = Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                code[instr_loc] = instr!("dynamic_internal_else",
                     birth,
                     death,
-                    NextOrFail::Next(target_loc - instr_loc),
-                ));
+                    NextOrFail::Next(target_loc - instr_loc)
+                );
 
                 return;
             }
-            Line::Choice(ChoiceInstruction::DynamicInternalElse(_, _, NextOrFail::Fail(o)))
+            Instruction::DynamicInternalElse(_, _, NextOrFail::Fail(o))
                 if *o > 0 =>
             {
                 instr_loc += *o;
             }
-            Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) if target_loc >= instr_loc => {
+            Instruction::TrustMe(ref mut o) if target_loc >= instr_loc => {
                 retraction_info.push_record(
                     RetractionRecord::AppendedTrustMe(instr_loc, *o, false),
                     //choice_instr.is_default()),
                 );
 
-                code[instr_loc] =
-                    Line::Choice(ChoiceInstruction::RetryMeElse(target_loc - instr_loc));
-
+                code[instr_loc] = instr!("retry_me_else", target_loc - instr_loc);
                 return;
             }
-            Line::Choice(ChoiceInstruction::TrustMe(o)) if *o > 0 => {
+            Instruction::TrustMe(o) if *o > 0 => {
                 instr_loc += *o;
             }
             _ => {
@@ -769,7 +755,7 @@ fn remove_non_leading_clause(
     retraction_info: &mut RetractionInfo,
 ) -> Option<IndexPtr> {
     match &mut code[non_indexed_choice_instr_loc] {
-        Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => {
+        Instruction::RetryMeElse(ref mut o) => {
             let o = *o;
 
             thread_choice_instr_at_to(
@@ -781,19 +767,19 @@ fn remove_non_leading_clause(
 
             None
         }
-        Line::Choice(ChoiceInstruction::TrustMe(_)) => {
+        Instruction::TrustMe(_) => {
             match &mut code[preceding_choice_instr_loc] {
-                Line::Choice(ChoiceInstruction::RetryMeElse(o)) => {
+                Instruction::RetryMeElse(o) => {
                     retraction_info.push_record(RetractionRecord::ModifiedRetryMeElse(
                         preceding_choice_instr_loc,
                         *o,
                     ));
 
-                    code[preceding_choice_instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0));
+                    code[preceding_choice_instr_loc] = Instruction::TrustMe(0);
 
                     None
                 }
-                Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+                Instruction::TryMeElse(ref mut o) => {
                     retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
                         preceding_choice_instr_loc,
                         *o,
@@ -850,7 +836,7 @@ fn remove_leading_unindexed_clause(
     retraction_info: &mut RetractionInfo,
 ) -> Option<IndexPtr> {
     match &mut code[non_indexed_choice_instr_loc] {
-        Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => {
+        Instruction::TryMeElse(ref mut o) => {
             if *o > 0 {
                 retraction_info.push_record(RetractionRecord::ModifiedTryMeElse(
                     non_indexed_choice_instr_loc,
@@ -878,7 +864,7 @@ fn remove_leading_unindexed_clause(
 
 fn find_dynamic_outer_choice_instr(code: &Code, index_loc: usize) -> usize {
     match &code[index_loc] {
-        Line::IndexingCode(indexing_code) => match &indexing_code[0] {
+        Instruction::IndexingCode(indexing_code) => match &indexing_code[0] {
             &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
                 _,
                 IndexingCodePtr::DynamicExternal(v),
@@ -951,22 +937,16 @@ fn prepend_compiled_clause(
                 let inner_thread_rev_offset =
                     3 + prepend_queue.len() + clause_loc - skeleton.clauses[1].clause_start;
 
-                prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
-                    inner_thread_rev_offset,
-                )));
+                prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
 
-                prepend_queue.push_front(Line::Choice(
-                    settings.internal_try_me_else(prepend_queue.len()),
-                ));
+                prepend_queue.push_front(settings.internal_try_me_else(prepend_queue.len()));
 
                 // prepend_queue is now:
                 //      | TryMeElse N_2
                 //      | (clause_code)
                 // +N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1)
 
-                prepend_queue.push_front(Line::Control(ControlInstruction::RevJmpBy(
-                    1 + clause_loc - index_loc,
-                )));
+                prepend_queue.push_front(Instruction::RevJmpBy(1 + clause_loc - index_loc));
 
                 let outer_thread_choice_offset = // outer_thread_choice_loc WAS index_loc - 1..
                     match derelictize_try_me_else(code, outer_thread_choice_loc, retraction_info) {
@@ -978,7 +958,7 @@ fn prepend_compiled_clause(
                                 next_subseq_offset;
 
                             prepend_queue.push_back(
-                                Line::Control(ControlInstruction::RevJmpBy(outer_thread_rev_offset))
+                                Instruction::RevJmpBy(outer_thread_rev_offset)
                             );
 
                             prepend_queue.len()
@@ -994,17 +974,13 @@ fn prepend_compiled_clause(
                             // awaiting the addition of unindexed
                             // clauses.
 
-                            prepend_queue.push_back(
-                                Line::Control(ControlInstruction::RevJmpBy(0)),
-                            );
+                            prepend_queue.push_back(Instruction::RevJmpBy(0));
 
                             0
                         }
                     };
 
-                prepend_queue.push_front(Line::Choice(
-                    settings.try_me_else(outer_thread_choice_offset),
-                ));
+                prepend_queue.push_front(settings.try_me_else(outer_thread_choice_offset));
 
                 // prepend_queue is now:
                 //     | TryMeElse N_3
@@ -1014,7 +990,7 @@ fn prepend_compiled_clause(
                 // N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1)
                 // N_3 | RevJmpBy (TryMeElse(N_1) at index_loc - 1 or TrustMe if N_1 == 0)
 
-                let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+                let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
 
                 merge_clause_index(
                     target_indexing_line,
@@ -1060,19 +1036,19 @@ fn prepend_compiled_clause(
 
                 // this is a stub for chaining inner-threaded choice
                 // instructions.
-                prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(0)));
+                prepend_queue.push_back(Instruction::RevJmpBy(0));
 
                 let prepend_queue_len = prepend_queue.len();
 
                 match &mut prepend_queue[1] {
-                    Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) if *o == 0 => {
+                    Instruction::TryMeElse(ref mut o) if *o == 0 => {
                         *o = prepend_queue_len - 2;
                     }
-                    Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                    Instruction::DynamicInternalElse(
                         _,
                         _,
                         ref mut o @ NextOrFail::Next(0),
-                    )) => {
+                    ) => {
                         *o = NextOrFail::Fail(prepend_queue_len - 2);
                     }
                     _ => {
@@ -1080,11 +1056,8 @@ fn prepend_compiled_clause(
                     }
                 }
 
-                prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
-                    inner_thread_rev_offset,
-                )));
-
-                prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len())));
+                prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
+                prepend_queue.push_front(settings.try_me_else(prepend_queue.len()));
 
                 // prepend_queue is now:
                 //      | TryMeElse(N_2)
@@ -1114,11 +1087,8 @@ fn prepend_compiled_clause(
                 let inner_thread_rev_offset =
                     1 + prepend_queue.len() + clause_loc - old_clause_start;
 
-                prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
-                    inner_thread_rev_offset,
-                )));
-
-                prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len())));
+                prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
+                prepend_queue.push_front(settings.try_me_else(prepend_queue.len()));
 
                 // prepend_queue is now:
                 //      | TryMeElse(N_2)
@@ -1142,11 +1112,8 @@ fn prepend_compiled_clause(
                 let inner_thread_rev_offset =
                     1 + prepend_queue.len() + clause_loc - old_clause_start;
 
-                prepend_queue.push_back(Line::Control(ControlInstruction::RevJmpBy(
-                    inner_thread_rev_offset,
-                )));
-
-                prepend_queue.push_front(Line::Choice(settings.try_me_else(prepend_queue.len())));
+                prepend_queue.push_back(Instruction::RevJmpBy(inner_thread_rev_offset));
+                prepend_queue.push_front(settings.try_me_else(prepend_queue.len()));
 
                 // prepend_queue is now:
                 //      | TryMeElse(N_2)
@@ -1205,7 +1172,7 @@ fn append_compiled_clause(
         .switch_on_term_loc()
     {
         Some(index_loc) if lower_bound_arg_num == target_arg_num => {
-            code.push(Line::Choice(settings.internal_trust_me()));
+            code.push(settings.internal_trust_me());
 
             code.extend(clause_code.drain(3..)); // skip the indexing code
 
@@ -1218,7 +1185,7 @@ fn append_compiled_clause(
                 skeleton.clauses[target_pos].clause_start,
             ));
 
-            let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap();
+            let target_indexing_line = code[index_loc].to_indexing_line_mut().unwrap();
 
             merge_clause_index(
                 target_indexing_line,
@@ -1252,7 +1219,7 @@ fn append_compiled_clause(
             target_pos_clause_start // skeleton.clauses[target_pos - 1].clause_start
         }
         _ => {
-            code.push(Line::Choice(settings.trust_me()));
+            code.push(settings.trust_me());
 
             skeleton.clauses[target_pos].opt_arg_index_key += clause_loc;
             code.extend(clause_code.drain(1..));
@@ -1331,9 +1298,9 @@ fn print_overwrite_warning(
     key: &PredicateKey,
     is_dynamic: bool,
 ) {
-    if let CompilationTarget::Module(ref module_name) = compilation_target {
-        match module_name.as_str() {
-            "builtins" | "loader" => return,
+    if let CompilationTarget::Module(module_name) = compilation_target {
+        match module_name {
+            atom!("builtins") | atom!("loader") => return,
             _ => {}
         }
     }
@@ -1405,7 +1372,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
     ) -> Result<CodeIndex, SessionError> {
         let code_index = self.get_or_insert_code_index(key, predicates.compilation_target);
 
-        let code_len = self.wam_prelude.code_repo.code.len();
+        let code_len = self.wam_prelude.code.len();
         let mut code_ptr = code_len;
 
         let mut clauses = vec![];
@@ -1443,7 +1410,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             }
 
             match &mut code[0] {
-                Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+                Instruction::TryMeElse(0) => {
                     code_ptr += 1;
                 }
                 _ => {}
@@ -1514,7 +1481,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             index_ptr,
         );
 
-        self.wam_prelude.code_repo.code.extend(code.into_iter());
+        self.wam_prelude.code.extend(code.into_iter());
         Ok(code_index)
     }
 
@@ -1690,7 +1657,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             mut standalone_skeleton,
         } = self.compile_standalone_clause(clause, settings)?;
 
-        let code_len = self.wam_prelude.code_repo.code.len();
+        let code_len = self.wam_prelude.code.len();
 
         let skeleton = match self
             .wam_prelude
@@ -1717,7 +1684,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 let global_clock = LS::machine_st(&mut self.payload).global_clock;
 
                 let result = append_compiled_clause(
-                    &mut self.wam_prelude.code_repo.code,
+                    &mut self.wam_prelude.code,
                     clause_code,
                     skeleton,
                     &mut self.payload.retraction_info,
@@ -1757,7 +1724,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 let global_clock = LS::machine_st(&mut self.payload).global_clock;
 
                 let new_code_ptr = prepend_compiled_clause(
-                    &mut self.wam_prelude.code_repo.code,
+                    &mut self.wam_prelude.code,
                     compilation_target,
                     key,
                     clause_code,
@@ -1801,16 +1768,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             .switch_on_term_loc()
         {
             Some(index_loc) => find_inner_choice_instr(
-                &self.wam_prelude.code_repo.code,
+                &self.wam_prelude.code,
                 skeleton.clauses[target_pos].clause_start,
                 index_loc,
             ),
             None => skeleton.clauses[target_pos].clause_start,
         };
 
-        match &mut self.wam_prelude.code_repo.code[clause_loc] {
-            Line::Choice(ChoiceInstruction::DynamicElse(_, ref mut d, _))
-            | Line::Choice(ChoiceInstruction::DynamicInternalElse(_, ref mut d, _)) => {
+        match &mut self.wam_prelude.code[clause_loc] {
+            Instruction::DynamicElse(_, ref mut d, _) |
+            Instruction::DynamicInternalElse(_, ref mut d, _) => {
                 *d = Death::Finite(LS::machine_st(&mut self.payload).global_clock);
             }
             _ => unreachable!(),
@@ -1840,7 +1807,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
             }
         };
 
-        let code = &mut self.wam_prelude.code_repo.code;
+        let code = &mut self.wam_prelude.code;
         let lower_bound = lower_bound_of_target_clause(skeleton, target_pos);
         let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some();
 
@@ -1975,13 +1942,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     Some(later_indexing_loc) if later_indexing_loc < target_indexing_loc => {
                         let target_indexing_line = mem::replace(
                             &mut code[target_indexing_loc],
-                            Line::Control(ControlInstruction::RevJmpBy(
-                                target_indexing_loc - later_indexing_loc,
-                            )),
+                            Instruction::RevJmpBy(target_indexing_loc - later_indexing_loc),
                         );
 
                         match target_indexing_line {
-                            Line::IndexingCode(indexing_code) => {
+                            Instruction::IndexingCode(indexing_code) => {
                                 self.payload.retraction_info.push_record(
                                     RetractionRecord::ReplacedIndexingLine(
                                         target_indexing_loc,
@@ -2073,7 +2038,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                             );
 
                             match &mut code[preceding_choice_instr_loc] {
-                                Line::Choice(ChoiceInstruction::TryMeElse(0)) => {
+                                Instruction::TryMeElse(0) => {
                                     set_switch_var_offset(
                                         code,
                                         index_loc,
index 9b02d191edf75ed657f9f14e9235464701651314..6f5d9d02c6cbc9960c2386ec8a6293518764b17d 100644 (file)
@@ -3,1277 +3,4872 @@ use crate::atom_table::*;
 use crate::instructions::*;
 use crate::machine::*;
 use crate::machine::arithmetic_ops::*;
-use crate::machine::code_repo::*;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_state::*;
 use crate::types::*;
 
 use crate::try_numeric_result;
 
-impl Machine {
-    #[inline(always)]
-    pub(super) fn dispatch_instr(&mut self, instr: OwnedOrIndexed) {
-        match instr.as_ref(&self.code_repo.code) {
-            &Line::Arithmetic(ref arith_instr) => {
-                let stub_gen = || functor_stub(atom!("is"), 2);
-
-                match arith_instr {
-                    &ArithmeticInstruction::Add(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
-
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Sub(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+macro_rules! step_or_fail {
+    ($self:expr, $step_e:expr) => {
+        if $self.machine_st.fail {
+            $self.machine_st.backtrack();
+        } else {
+            $step_e;
+        }
+    };
+}
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Mul(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+macro_rules! try_or_throw {
+    ($s:expr, $e:expr) => {{
+        match $e {
+            Ok(val) => val,
+            Err(msg) => {
+                $s.throw_exception(msg);
+                $s.backtrack();
+                continue;
+            }
+        }
+    }};
+}
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Max(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+macro_rules! try_or_throw_gen {
+    ($s:expr, $e:expr) => {{
+        match $e {
+            Ok(val) => val,
+            Err(msg_fn) => {
+                let e = msg_fn($s);
+                $s.throw_exception(e);
+                $s.backtrack();
+                continue;
+            }
+        }
+    }};
+}
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            max(n1, n2)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Min(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256;
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            min(n1, n2)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::IntPow(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+impl MachineState {
+    #[inline(always)]
+    fn compare(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("compare"), 3);
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            int_pow(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Gcd(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        let a1 = self.store(self.deref(self.registers[1]));
+        let a2 = self.registers[2];
+        let a3 = self.registers[3];
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            gcd(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        read_heap_cell!(a1,
+            (HeapCellValueTag::Str, s) => {
+                let (name, arity) = cell_as_atom_cell!(self.heap[s])
+                    .get_name_and_arity();
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            pow(n1, n2, atom!("**"))
-                        );
-                        self.machine_st.p += 1;
+                match name {
+                    atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
                     }
-                    &ArithmeticInstruction::RDiv(ref a1, ref a2, t) => {
-                        let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
-
-                        let r1 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a1, stub_gen));
-                        let r2 = try_or_fail!(self.machine_st, self.machine_st.get_rational(a2, stub_gen));
-
-                        self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
-                            try_or_fail_gen!(&mut self.machine_st, rdiv(r1, r2)),
-                            self.machine_st.arena
-                        ));
-                        self.machine_st.p += 1;
+                    _ => {
+                        let err = self.domain_error(DomainErrorType::Order, a1);
+                        return Err(self.error_form(err, stub_gen()));
                     }
-                    &ArithmeticInstruction::IntFloorDiv(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+                }
+            }
+            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+            }
+            _ => {
+                let err = self.type_error(ValidType::Atom, a1);
+                return Err(self.error_form(err, stub_gen()));
+            }
+        );
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            int_floor_div(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::IDiv(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        let atom = match compare_term_test!(self, a2, a3) {
+            Some(Ordering::Greater) => {
+                atom!(">")
+            }
+            Some(Ordering::Equal) => {
+                atom!("=")
+            }
+            None | Some(Ordering::Less) => {
+                atom!("<")
+            }
+        };
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            idiv(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Abs(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        self.unify_atom(atom, a1);
+        Ok(())
+    }
 
-                        self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena);
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Sign(ref a1, t) => {
-                        let n = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+    pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) {
+        let old_h = self.heap.len();
 
-                        self.machine_st.interms[t - 1] = sign(n);
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Neg(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        let a1 = self.registers[1];
+        let a2 = self.registers[2];
 
-                        self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena);
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::BitwiseComplement(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        copy_term(CopyTerm::new(self), a1, attr_var_policy);
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            bitwise_complement(n1, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Div(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        unify_fn!(*self, heap_loc_as_cell!(old_h), a2);
+    }
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            div(n1, n2)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Shr(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+    fn sort(&mut self) -> CallResult {
+        self.check_sort_errors()?;
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            shr(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Shl(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        let stub_gen = || functor_stub(atom!("sort"), 2);
+        let mut list = self.try_from_list(self.registers[1], stub_gen)?;
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            shl(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Xor(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        list.sort_unstable_by(|v1, v2| {
+            compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less)
+        });
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            xor(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::And(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        list.dedup_by(|v1, v2| {
+            compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal)
+        });
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            and(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Or(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        let heap_addr = heap_loc_as_cell!(
+            iter_to_heap_list(&mut self.heap, list.into_iter())
+        );
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            or(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Mod(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        let target_addr = self.registers[2];
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            modulus(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Rem(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        unify_fn!(*self, target_addr, heap_addr);
+        Ok(())
+    }
 
-                        self.machine_st.interms[t - 1] = try_or_fail_gen!(
-                            &mut self.machine_st,
-                            remainder(n1, n2, &mut self.machine_st.arena)
-                        );
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Cos(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+    fn keysort(&mut self) -> CallResult {
+        self.check_keysort_errors()?;
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, cos(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Sin(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        let stub_gen = || functor_stub(atom!("keysort"), 2);
+        let list = self.try_from_list(self.registers[1], stub_gen)?;
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, sin(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Tan(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        let mut key_pairs = Vec::with_capacity(list.len());
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, tan(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Sqrt(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        for val in list {
+            let key = self.project_onto_key(val)?;
+            key_pairs.push((key, val));
+        }
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, sqrt(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Log(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        key_pairs.sort_by(|a1, a2| {
+            compare_term_test!(self, a1.0, a2.0).unwrap_or(Ordering::Less)
+        });
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, log(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Exp(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        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)
+        );
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, exp(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::ACos(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        let target_addr = self.registers[2];
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, acos(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::ASin(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        unify_fn!(*self, target_addr, heap_addr);
+        Ok(())
+    }
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, asin(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::ATan(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+    fn is(&mut self, r: RegType, at: ArithmeticTerm) -> CallResult {
+        let n1 = self.store(self.deref(self[r]));
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, atan(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::ATan2(ref a1, ref a2, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-                        let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(a2));
+        match self.get_number(&at)? {
+            Number::Fixnum(n) => self.unify_fixnum(n, n1),
+            Number::Float(n) => {
+                // TODO: argghh.. allocate floats to their own area.
+                let n = arena_alloc!(n, &mut self.arena);
+                self.unify_f64(n, n1)
+            }
+            Number::Integer(n) => self.unify_big_int(n, n1),
+            Number::Rational(n) => self.unify_rational(n, n1),
+        }
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, atan2(n1, n2))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Float(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        Ok(())
+    }
+}
 
-                        self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
-                            try_or_fail_gen!(&mut self.machine_st, float(n1))
-                        ));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Truncate(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+impl Machine {
+    fn read(&mut self) -> CallResult {
+        let stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("read"),
+            2,
+        )?;
+
+        match self.machine_st.read(stream, &self.indices.op_dir) {
+            Ok(offset) => {
+                let value = self.machine_st.registers[2];
+                unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
+            }
+            Err(ParserError::UnexpectedEOF) => {
+                let value = self.machine_st.registers[2];
+                self.machine_st.unify_atom(atom!("end_of_file"), value);
+            }
+            Err(e) => {
+                let stub = functor_stub(atom!("read"), 2);
+                let err = self.machine_st.syntax_error(e);
 
-                        self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena);
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Round(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+                return Err(self.machine_st.error_form(err, stub));
+            }
+        };
 
-                        self.machine_st.interms[t - 1] =
-                            try_or_fail_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena));
-                        self.machine_st.p += 1;
-                    }
-                    &ArithmeticInstruction::Ceiling(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
+        Ok(())
+    }
 
-                        self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena);
-                        self.machine_st.p += 1;
+    pub(super) fn find_living_dynamic_else(&self, mut p: usize) -> Option<(usize, usize)> {
+        loop {
+            match &self.code[p] {
+                &Instruction::DynamicElse(
+                    birth,
+                    death,
+                    NextOrFail::Next(i),
+                ) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, i));
+                    } else if i > 0 {
+                        p += i;
+                    } else {
+                        return None;
                     }
-                    &ArithmeticInstruction::Floor(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-
-                        self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena);
-                        self.machine_st.p += 1;
+                }
+                &Instruction::DynamicElse(
+                    birth,
+                    death,
+                    NextOrFail::Fail(_),
+                ) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, 0));
+                    } else {
+                        return None;
                     }
-                    &ArithmeticInstruction::Plus(ref a1, t) => {
-                        let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(a1));
-
-                        self.machine_st.interms[t - 1] = n1;
-                        self.machine_st.p += 1;
+                }
+                &Instruction::DynamicInternalElse(
+                    birth,
+                    death,
+                    NextOrFail::Next(i),
+                ) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, i));
+                    } else if i > 0 {
+                        p += i;
+                    } else {
+                        return None;
+                    }
+                }
+                &Instruction::DynamicInternalElse(
+                    birth,
+                    death,
+                    NextOrFail::Fail(_),
+                ) => {
+                    if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                        return Some((p, 0));
+                    } else {
+                        return None;
                     }
                 }
+                &Instruction::RevJmpBy(i) => {
+                    p -= i;
+                }
+                _ => {
+                    unreachable!();
+                }
             }
-            &Line::Choice(ref choice_instr) => {
-                match choice_instr {
-                    &ChoiceInstruction::DynamicElse(..) => {
-                        if let FirstOrNext::First = self.machine_st.dynamic_mode {
-                            self.machine_st.cc = self.machine_st.global_clock;
-                        }
-
-                        let p = self.machine_st.p.local().abs_loc();
+        }
+    }
 
-                        match self.find_living_dynamic_else(p) {
-                            Some((p, next_i)) => {
-                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+    pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> {
+        let p = self.machine_st.p;
 
-                                match self.machine_st.dynamic_mode {
-                                    FirstOrNext::First if next_i == 0 => {
-                                        self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
-                                    }
-                                    FirstOrNext::First => {
-                                        self.machine_st.cc = self.machine_st.global_clock;
+        let indexed_choice_instrs = match &self.code[p] {
+            Instruction::IndexingCode(ref indexing_code) => match &indexing_code[oi as usize] {
+                IndexingLine::DynamicIndexedChoice(ref indexed_choice_instrs) => {
+                    indexed_choice_instrs
+                }
+                _ => unreachable!(),
+            },
+            _ => unreachable!(),
+        };
+
+        loop {
+            match &indexed_choice_instrs.get(ii as usize) {
+                Some(&offset) => match &self.code[p + offset - 1] {
+                    &Instruction::DynamicInternalElse(
+                        birth,
+                        death,
+                        next_or_fail,
+                    ) => {
+                        if birth < self.machine_st.cc && Death::Finite(self.machine_st.cc) <= death {
+                            return Some((offset, oi, ii, next_or_fail.is_next()));
+                        } else {
+                            ii += 1;
+                        }
+                    }
+                    _ => unreachable!(),
+                },
+                None => return None,
+            }
+        }
+    }
 
-                                        match self.find_living_dynamic_else(p + next_i) {
-                                            Some(_) => {
-                                                self.machine_st.registers[self.machine_st.num_of_args + 1] =
-                                                    fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+    #[inline(always)]
+    fn execute_switch_on_term(&mut self) {
+        #[inline(always)]
+        fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool {
+            match &machine.code[p] {
+                Instruction::DynamicInternalElse(..) => {
+                    machine.machine_st.dynamic_mode = FirstOrNext::First;
+                    return true;
+                }
+                _ => {}
+            }
 
-                                                self.machine_st.num_of_args += 1;
-                                                self.machine_st.try_me_else(next_i);
-                                                self.machine_st.num_of_args -= 1;
-                                            }
-                                            None => {
-                                                self.machine_st.p += 1;
-                                            }
-                                        }
-                                    }
-                                    FirstOrNext::Next => {
-                                        let n = self.machine_st
-                                            .stack
-                                            .index_or_frame(self.machine_st.b)
-                                            .prelude
-                                            .univ_prelude
-                                            .num_cells;
-
-                                        self.machine_st.cc = cell_as_fixnum!(
-                                            self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
-                                        ).get_num() as usize;
-
-                                        if next_i > 0 {
-                                            match self.find_living_dynamic_else(p + next_i) {
-                                                Some(_) => {
-                                                    self.retry_me_else(next_i);
+            match &machine.code[p - 1] {
+                &Instruction::DynamicInternalElse(birth, death, _) => {
+                    if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death {
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+                _ => {}
+            }
 
-                                                    try_or_fail!(
-                                                        self.machine_st,
-                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                                    );
-                                                }
-                                                None => {
-                                                    self.trust_me();
+            true
+        }
 
-                                                    try_or_fail!(
-                                                        self.machine_st,
-                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                                    );
-                                                }
-                                            }
-                                        } else {
-                                            self.trust_me();
+        let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap();
 
-                                            try_or_fail!(
-                                                self.machine_st,
-                                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                            );
-                                        }
-                                    }
+        let mut index = 0;
+        let addr = match &indexing_lines[0] {
+            &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg]))
+            }
+            _ => {
+                unreachable!()
+            }
+        };
+
+        loop {
+            match &indexing_lines[index] {
+                &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
+                    let offset = read_heap_cell!(addr,
+                        (HeapCellValueTag::Var |
+                         HeapCellValueTag::StackVar |
+                         HeapCellValueTag::AttrVar) => {
+                            v
+                        }
+                        (HeapCellValueTag::PStrLoc |
+                         HeapCellValueTag::Lis |
+                         HeapCellValueTag::CStr) => {
+                            l
+                        }
+                        (HeapCellValueTag::Fixnum |
+                         HeapCellValueTag::Char |
+                         HeapCellValueTag::F64) => {
+                            c
+                        }
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            // if arity == 0 { c } else { s }
+                            debug_assert!(arity == 0);
+                            c
+                        }
+                        (HeapCellValueTag::Str) => {
+                            s
+                        }
+                        (HeapCellValueTag::Cons, ptr) => {
+                            match ptr.get_tag() {
+                                ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
+                                ArenaHeaderTag::F64 => {
+                                    c
+                                }
+                                _ => {
+                                    IndexingCodePtr::Fail
                                 }
-                            }
-                            None => {
-                                self.machine_st.fail = true;
                             }
                         }
+                        _ => {
+                            unreachable!();
+                        }
+                    );
 
-                        self.machine_st.dynamic_mode = FirstOrNext::Next;
-                    }
-                    &ChoiceInstruction::DynamicInternalElse(..) => {
-                        let p = self.machine_st.p.local().abs_loc();
-
-                        match self.find_living_dynamic_else(p) {
-                            Some((p, next_i)) => {
-                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.machine_st.fail = true;
+                            break;
+                        }
+                        IndexingCodePtr::DynamicExternal(o) => {
+                            // either points directly to a
+                            // DynamicInternalElse, or just ahead of
+                            // one. Or neither!
+                            let p = self.machine_st.p;
 
-                                match self.machine_st.dynamic_mode {
-                                    FirstOrNext::First if next_i == 0 => {
-                                        self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p + 1));
-                                    }
-                                    FirstOrNext::First => {
-                                        match self.find_living_dynamic_else(p + next_i) {
-                                            Some(_) => {
-                                                self.machine_st.registers[self.machine_st.num_of_args + 1] =
-                                                    fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+                            if !dynamic_external_of_clause_is_valid(self, p + o) {
+                                self.machine_st.fail = true;
+                            } else {
+                                self.machine_st.p += o;
+                            }
 
-                                                self.machine_st.num_of_args += 1;
-                                                self.machine_st.try_me_else(next_i);
-                                                self.machine_st.num_of_args -= 1;
-                                            }
-                                            None => {
-                                                self.machine_st.p += 1;
-                                            }
-                                        }
-                                    }
-                                    FirstOrNext::Next => {
-                                        let n = self.machine_st
-                                            .stack
-                                            .index_or_frame(self.machine_st.b)
-                                            .prelude
-                                            .univ_prelude
-                                            .num_cells;
-
-                                        self.machine_st.cc = cell_as_fixnum!(
-                                            self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
-                                        ).get_num() as usize;
-
-                                        if next_i > 0 {
-                                            match self.find_living_dynamic_else(p + next_i) {
-                                                Some(_) => {
-                                                    self.retry_me_else(next_i);
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            self.machine_st.p += o;
+                            break;
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            index += o;
+                        }
+                    }
+                }
+                &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
+                    let lit = read_heap_cell!(addr,
+                        (HeapCellValueTag::Char, c) => {
+                            Literal::Char(c)
+                        }
+                        (HeapCellValueTag::Fixnum, n) => {
+                            Literal::Fixnum(n)
+                        }
+                        (HeapCellValueTag::F64, f) => {
+                            Literal::Float(f)
+                        }
+                        (HeapCellValueTag::Atom, (atom, arity)) => {
+                            debug_assert_eq!(arity, 0);
+                            Literal::Atom(atom)
+                        }
+                        (HeapCellValueTag::Cons, cons_ptr) => {
+                            match_untyped_arena_ptr!(cons_ptr,
+                                (ArenaHeaderTag::Rational, r) => {
+                                    Literal::Rational(r)
+                                }
+                                (ArenaHeaderTag::F64, f) => {
+                                    Literal::Float(F64Ptr(f))
+                                }
+                                (ArenaHeaderTag::Integer, n) => {
+                                    Literal::Integer(n)
+                                }
+                                _ => {
+                                    unreachable!()
+                                }
+                            )
+                        }
+                        _ => {
+                            unreachable!()
+                        }
+                    );
 
-                                                    try_or_fail!(
-                                                        self.machine_st,
-                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                                    );
-                                                }
-                                                None => {
-                                                    self.trust_me();
+                    let offset = match hm.get(&lit) {
+                        Some(offset) => *offset,
+                        _ => IndexingCodePtr::Fail,
+                    };
 
-                                                    try_or_fail!(
-                                                        self.machine_st,
-                                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                                    );
-                                                }
-                                            }
-                                        } else {
-                                            self.trust_me();
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.machine_st.fail = true;
+                            break;
+                        }
+                        IndexingCodePtr::DynamicExternal(o) => {
+                            // either points directly to a
+                            // DynamicInternalElse, or just ahead of
+                            // one. Or neither!
+                            let p = self.machine_st.p;
 
-                                            try_or_fail!(
-                                                self.machine_st,
-                                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                            );
-                                        }
-                                    }
-                                }
-                            }
-                            None => {
+                            if !dynamic_external_of_clause_is_valid(self, p + o) {
                                 self.machine_st.fail = true;
+                            } else {
+                                self.machine_st.p += o;
                             }
-                        }
-
-                        self.machine_st.dynamic_mode = FirstOrNext::Next;
-                    }
-                    &ChoiceInstruction::TryMeElse(offset) => {
-                        self.machine_st.try_me_else(offset);
-                    }
-                    &ChoiceInstruction::DefaultRetryMeElse(offset) => {
-                        self.retry_me_else(offset);
-                    }
-                    &ChoiceInstruction::DefaultTrustMe(_) => {
-                        self.trust_me();
-                    }
-                    &ChoiceInstruction::RetryMeElse(offset) => {
-                        self.retry_me_else(offset);
-
-                        try_or_fail!(
-                            self.machine_st,
-                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                        );
-                    }
-                    &ChoiceInstruction::TrustMe(_) => {
-                        self.trust_me();
 
-                        try_or_fail!(
-                            self.machine_st,
-                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                        );
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            self.machine_st.p += o;
+                            break;
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            index += o;
+                        }
                     }
                 }
-            }
-            &Line::Cut(ref cut_instr) => {
-                match cut_instr {
-                    &CutInstruction::NeckCut => {
-                        let b = self.machine_st.b;
-                        let b0 = self.machine_st.b0;
-
-                        if b > b0 {
-                            self.machine_st.b = b0;
+                &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
+                    let offset = read_heap_cell!(addr,
+                        (HeapCellValueTag::Atom, (name, arity)) => {
+                            match hm.get(&(name, arity)) {
+                                Some(offset) => *offset,
+                                None => IndexingCodePtr::Fail,
+                            }
+                        }
+                        (HeapCellValueTag::Str, s) => {
+                            let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+                                .get_name_and_arity();
 
-                            if b > self.machine_st.e {
-                                self.machine_st.stack.truncate(b);
+                            match hm.get(&(name, arity)) {
+                                Some(offset) => *offset,
+                                None => IndexingCodePtr::Fail,
                             }
                         }
+                        _ => {
+                            IndexingCodePtr::Fail
+                        }
+                    );
 
-                        self.machine_st.p += 1;
-                    }
-                    &CutInstruction::GetLevel(r) => {
-                        let b0 = self.machine_st.b0;
-
-                        self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64));
-                        self.machine_st.p += 1;
-                    }
-                    &CutInstruction::GetLevelAndUnify(r) => {
-                        let b0 = self.machine_st[perm_v!(1)];
-                        let a = self.machine_st[r];
+                    match offset {
+                        IndexingCodePtr::Fail => {
+                            self.machine_st.fail = true;
+                            break;
+                        }
+                        IndexingCodePtr::DynamicExternal(o) => {
+                            let p = self.machine_st.p;
 
-                        unify_fn!(&mut self.machine_st, a, b0);
-                        self.machine_st.p += 1;
-                    }
-                    &CutInstruction::Cut(r) => {
-                        let value = self.machine_st[r];
-                        self.machine_st.cut_body(value);
+                            if !dynamic_external_of_clause_is_valid(self, p + o) {
+                                self.machine_st.fail = true;
+                            } else {
+                                self.machine_st.p += o;
+                            }
 
-                        if !self.machine_st.fail && !(self.machine_st.run_cleaners_fn)(self) {
-                            self.machine_st.p += 1;
+                            break;
+                        }
+                        IndexingCodePtr::External(o) => {
+                            self.machine_st.p += o;
+                            break;
+                        }
+                        IndexingCodePtr::Internal(o) => {
+                            index += o;
                         }
                     }
                 }
+                &IndexingLine::IndexedChoice(_) => {
+                    self.machine_st.oip = index as u32;
+                    self.machine_st.iip = 0;
+
+                    break;
+                }
+                &IndexingLine::DynamicIndexedChoice(_) => {
+                    self.machine_st.dynamic_mode = FirstOrNext::First;
+
+                    self.machine_st.oip = index as u32;
+                    self.machine_st.iip = 0;
+
+                    break;
+                }
             }
-            &Line::Control(ref ctrl_instr) => {
-                match ctrl_instr {
-                    &ControlInstruction::Allocate(num_cells) =>
-                        self.machine_st.allocate(num_cells),
-                    &ControlInstruction::CallClause(ref ct, arity, _, lco, use_default_cp) => {
-                        let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
-
-                        match 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();
-                                    return;
-                                }
-                            }
-                            Err(_) => unreachable!(),
-                        }
+        }
+    }
 
-                        self.machine_st.last_call = lco;
+    #[inline(always)]
+    pub(super) fn dispatch_loop(&mut self) {
+        'outer: loop {
+        for _ in 0 .. INSTRUCTIONS_PER_INTERRUPT_POLL {
+            match &self.code[self.machine_st.p] {
+                &Instruction::BreakFromDispatchLoop => {
+                    break 'outer;
+                }
+                &Instruction::InstallVerifyAttr => {
+                    self.machine_st.p = self.machine_st.attr_var_init.p;
 
-                        match ct {
-                            &ClauseType::BuiltIn(ref ct) => {
-                                let ct = ct.clone();
+                    if self.code[self.machine_st.p].is_execute() {
+                        self.machine_st.p = self.machine_st.attr_var_init.cp;
+                    } else {
+                        self.machine_st.p += 1;
+                        self.machine_st.cp = self.machine_st.attr_var_init.cp;
+                    }
 
-                                try_or_fail!(
-                                    self.machine_st,
-                                    self.call_builtin(&ct)
-                                );
+                    let mut p = self.machine_st.p;
 
-                                if !use_default_cp {
-                                    try_or_fail!(
-                                        self.machine_st,
-                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                    );
-                                }
-                            }
-                            &ClauseType::CallN => {
-                                try_or_fail!(
-                                    self.machine_st,
-                                    self.call_n(atom!("user"), arity)
-                                );
-
-                                if !use_default_cp {
-                                    try_or_fail!(
-                                        self.machine_st,
-                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                    );
-                                }
-                            }
-                            &ClauseType::Inlined(ref ct) => {
-                                let ct = ct.clone();
-                                self.execute_inlined(&ct);
+                    while self.code[p].is_head_instr() {
+                        p += 1;
+                    }
 
-                                if lco {
-                                    self.machine_st.p = CodePtr::Local(self.machine_st.cp);
-                                }
-                            }
-                            &ClauseType::Named(name, _, ref idx) => {
-                                let idx = idx.clone();
+                    let instr = std::mem::replace(
+                        &mut self.code[p],
+                        Instruction::VerifyAttrInterrupt,
+                    );
 
-                                try_or_fail!(
-                                    self.machine_st,
-                                    self.context_call(name, arity, idx) // TODO: change to idx.get() ???
-                                );
+                    self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr;
+                    self.machine_st.attr_var_init.cp = p;
+                }
+                &Instruction::VerifyAttrInterrupt => {
+                    self.run_verify_attr_interrupt();
+                }
+                &Instruction::Add(ref a1, ref a2, t) => {
+                    let stub_gen = || functor_stub(atom!("is"), 2);
 
-                                if !use_default_cp {
-                                    try_or_fail!(
-                                        self.machine_st,
-                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                    );
-                                }
-                            }
-                            &ClauseType::System(ref ct) => {
-                                let ct = ct.clone();
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                try_or_fail!(
-                                    self.machine_st,
-                                    self.system_call(&ct)
-                                );
-                            }
-                        };
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        try_numeric_result!(add(n1, n2, &mut self.machine_st.arena), stub_gen)
+                    );
 
-                        self.machine_st.last_call = false;
-                    }
-                    &ControlInstruction::Deallocate =>
-                        self.machine_st.deallocate(),
-                    &ControlInstruction::JmpBy(arity, offset, _, lco) => {
-                        if !lco {
-                            self.machine_st.cp.assign_if_local(self.machine_st.p.clone() + 1);
-                        }
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Sub(ref a1, ref a2, t) => {
+                    let stub_gen = || functor_stub(atom!("is"), 2);
 
-                        self.machine_st.num_of_args = arity;
-                        self.machine_st.b0 = self.machine_st.b;
-                        self.machine_st.p += offset;
-                    }
-                    &ControlInstruction::RevJmpBy(offset) => {
-                        self.machine_st.p -= offset;
-                    }
-                    &ControlInstruction::Proceed => {
-                        self.machine_st.p = CodePtr::Local(self.machine_st.cp);
-                    }
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        try_numeric_result!(sub(n1, n2, &mut self.machine_st.arena), stub_gen)
+                    );
+                    self.machine_st.p += 1;
                 }
-            }
-            &Line::Fact(ref fact_instr) => {
-                match fact_instr {
-                    &FactInstruction::GetConstant(_, c, reg) => {
-                        let value = self.machine_st.deref(self.machine_st[reg]);
-                        self.machine_st.write_literal_to_var(value, c);
-                    }
-                    &FactInstruction::GetList(_, reg) => {
-                        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::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.mode = MachineMode::Read;
-                            }
-                            (HeapCellValueTag::CStr) => {
-                                let h = self.machine_st.heap.len();
-                                self.machine_st.heap.push(store_v);
+                &Instruction::Mul(ref a1, ref a2, t) => {
+                    let stub_gen = || functor_stub(atom!("is"), 2);
 
-                                self.machine_st.s = HeapPtr::PStrChar(h, 0);
-                                self.machine_st.mode = MachineMode::Read;
-                            }
-                            (HeapCellValueTag::Lis, l) => {
-                                self.machine_st.s = HeapPtr::HeapCell(l);
-                                self.machine_st.mode = MachineMode::Read;
-                            }
-                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                                let h = self.machine_st.heap.len();
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                self.machine_st.heap.push(list_loc_as_cell!(h+1));
-                                self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        try_numeric_result!(mul(n1, n2, &mut self.machine_st.arena), stub_gen)
+                    );
 
-                                self.machine_st.mode = MachineMode::Write;
-                            }
-                            _ => {
-                                self.machine_st.fail = true;
-                            }
-                        );
-                    }
-                    &FactInstruction::GetPartialString(_, string, reg, has_tail) => {
-                        let deref_v = self.machine_st.deref(self.machine_st[reg]);
-                        let store_v = self.machine_st.store(deref_v);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Max(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                        read_heap_cell!(store_v,
-                            (HeapCellValueTag::Str | HeapCellValueTag::Lis |
-                             HeapCellValueTag::PStrLoc | HeapCellValueTag::AttrVar |
-                             HeapCellValueTag::StackVar | HeapCellValueTag::Var |
-                             HeapCellValueTag::CStr) => {
-                                self.machine_st.match_partial_string(store_v, string, has_tail);
-                            }
-                            _ => {
-                                self.machine_st.fail = true;
-                            }
-                        );
-                    }
-                    &FactInstruction::GetStructure(ref ct, arity, reg) => {
-                        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, a) => {
-                                let result = self.machine_st.heap[a];
-
-                                read_heap_cell!(result,
-                                    (HeapCellValueTag::Atom, (name, narity)) => {
-                                        if narity == arity && ct.name() == name {
-                                            self.machine_st.s = HeapPtr::HeapCell(a + 1);
-                                            self.machine_st.mode = MachineMode::Read;
-                                        } else {
-                                            self.machine_st.fail = true;
-                                        }
-                                    }
-                                    _ => {
-                                        unreachable!();
-                                    }
-                                );
-                            }
-                            (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                                let h = self.machine_st.heap.len();
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        max(n1, n2)
+                    );
 
-                                self.machine_st.heap.push(str_loc_as_cell!(h+1));
-                                self.machine_st.heap.push(atom_as_cell!(ct.name(), arity));
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Min(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                self.machine_st.bind(store_v.as_var().unwrap(), heap_loc_as_cell!(h));
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        min(n1, n2)
+                    );
 
-                                self.machine_st.mode = MachineMode::Write;
-                            }
-                            _ => {
-                                self.machine_st.fail = true;
-                            }
-                        );
-                    }
-                    &FactInstruction::GetVariable(norm, arg) => {
-                        self.machine_st[norm] = self.machine_st.registers[arg];
-                    }
-                    &FactInstruction::GetValue(norm, arg) => {
-                        let norm_addr = self.machine_st[norm];
-                        let reg_addr = self.machine_st.registers[arg];
+                    self.machine_st.p += 1;
+                }
+                &Instruction::IntPow(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                        unify_fn!(&mut self.machine_st, norm_addr, reg_addr);
-                    }
-                    &FactInstruction::UnifyConstant(v) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let addr = self.machine_st.read_s();
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        int_pow(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                                self.machine_st.write_literal_to_var(addr, v);
-                                self.machine_st.increment_s_ptr(1);
-                            }
-                            MachineMode::Write => {
-                                self.machine_st.heap.push(v);
-                            }
-                        };
-                    }
-                    &FactInstruction::UnifyVariable(reg) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                self.machine_st[reg] = self.machine_st.read_s();
-                                self.machine_st.increment_s_ptr(1);
-                            }
-                            MachineMode::Write => {
-                                let h = self.machine_st.heap.len();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Gcd(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                self.machine_st.heap.push(heap_loc_as_cell!(h));
-                                self.machine_st[reg] = heap_loc_as_cell!(h);
-                            }
-                        };
-                    }
-                    &FactInstruction::UnifyLocalValue(reg) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let reg_addr = self.machine_st[reg];
-                                let value = self.machine_st.read_s();
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        gcd(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                                unify_fn!(&mut self.machine_st, reg_addr, value);
-                                self.machine_st.increment_s_ptr(1);
-                            }
-                            MachineMode::Write => {
-                                let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg]));
-                                let h = self.machine_st.heap.len();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Pow(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                read_heap_cell!(value,
-                                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
-                                        let value = self.machine_st.heap[hc];
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        pow(n1, n2, atom!("**"))
+                    );
 
-                                        self.machine_st.heap.push(value);
-                                        self.machine_st.increment_s_ptr(1);
-                                    }
-                                    _ => {
-                                        self.machine_st.heap.push(heap_loc_as_cell!(h));
-                                        (self.machine_st.bind_fn)(
-                                            &mut self.machine_st,
-                                            Ref::heap_cell(h),
-                                            value,
-                                        );
-                                    }
-                                );
-                            }
-                        };
-                    }
-                    &FactInstruction::UnifyValue(reg) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                let reg_addr = self.machine_st[reg];
-                                let value = self.machine_st.read_s();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::RDiv(ref a1, ref a2, t) => {
+                    let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
 
-                                unify_fn!(&mut self.machine_st, reg_addr, value);
-                                self.machine_st.increment_s_ptr(1);
-                            }
-                            MachineMode::Write => {
-                                let h = self.machine_st.heap.len();
-                                self.machine_st.heap.push(heap_loc_as_cell!(h));
+                    let r1 = try_or_throw!(self.machine_st, self.machine_st.get_rational(a1, stub_gen));
+                    let r2 = try_or_throw!(self.machine_st, self.machine_st.get_rational(a2, stub_gen));
 
-                                let addr = self.machine_st.store(self.machine_st[reg]);
-                                (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+                    self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
+                        try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
+                        self.machine_st.arena
+                    ));
 
-                                // the former code of this match arm was:
+                    self.machine_st.p += 1;
+                }
+                &Instruction::IntFloorDiv(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        int_floor_div(n1, n2, &mut self.machine_st.arena)
+                    );
+                    self.machine_st.p += 1;
+                }
+                &Instruction::IDiv(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        idiv(n1, n2, &mut self.machine_st.arena)
+                    );
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Abs(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                                // let addr = self.machine_st.store(self.machine_st[reg]);
-                                // self.machine_st.heap.push(HeapCellValue::Addr(addr));
+                    self.machine_st.interms[t - 1] = abs(n1, &mut self.machine_st.arena);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Sign(ref a1, t) => {
+                    let n = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                                // the old code didn't perform the occurs
-                                // check when enabled and so it was changed to
-                                // the above, which is only slightly less
-                                // efficient when the occurs_check is disabled.
-                            }
-                        };
-                    }
-                    &FactInstruction::UnifyVoid(n) => {
-                        match self.machine_st.mode {
-                            MachineMode::Read => {
-                                self.machine_st.increment_s_ptr(n);
-                            }
-                            MachineMode::Write => {
-                                let h = self.machine_st.heap.len();
+                    self.machine_st.interms[t - 1] = sign(n);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Neg(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                                for i in h..h + n {
-                                    self.machine_st.heap.push(heap_loc_as_cell!(i));
-                                }
-                            }
-                        };
-                    }
+                    self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena);
+                    self.machine_st.p += 1;
                 }
-                self.machine_st.p += 1;
-            }
-            &Line::IndexingCode(ref indexing_lines) => {
-                #[inline(always)]
-                fn dynamic_external_of_clause_is_valid(machine: &mut Machine, p: usize) -> bool {
-                    match &machine.code_repo.code[p] {
-                        Line::Choice(ChoiceInstruction::DynamicInternalElse(..)) => {
-                            machine.machine_st.dynamic_mode = FirstOrNext::First;
-                            return true;
-                        }
-                        _ => {}
-                    }
+                &Instruction::BitwiseComplement(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                    match &machine.code_repo.code[p - 1] {
-                        &Line::Choice(ChoiceInstruction::DynamicInternalElse(birth, death, _)) => {
-                            if birth < machine.machine_st.cc && Death::Finite(machine.machine_st.cc) <= death {
-                                return true;
-                            } else {
-                                return false;
-                            }
-                        }
-                        _ => {}
-                    }
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        bitwise_complement(n1, &mut self.machine_st.arena)
+                    );
 
-                    true
+                    self.machine_st.p += 1;
                 }
+                &Instruction::Div(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                let mut index = 0;
-                let addr = match &indexing_lines[0] {
-                    &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
-                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[arg]))
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                };
-
-                loop {
-                    match &indexing_lines[index] {
-                        &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
-                            let offset = read_heap_cell!(addr,
-                                (HeapCellValueTag::Var |
-                                 HeapCellValueTag::StackVar |
-                                 HeapCellValueTag::AttrVar) => {
-                                    v
-                                }
-                                (HeapCellValueTag::PStrLoc |
-                                 HeapCellValueTag::Lis |
-                                 HeapCellValueTag::CStr) => {
-                                    l
-                                }
-                                (HeapCellValueTag::Fixnum |
-                                 HeapCellValueTag::Char |
-                                 HeapCellValueTag::F64) => {
-                                    c
-                                }
-                                (HeapCellValueTag::Atom, (_name, arity)) => {
-                                    // if arity == 0 { c } else { s }
-                                    debug_assert!(arity == 0);
-                                    c
-                                }
-                                (HeapCellValueTag::Str) => {
-                                    s
-                                }
-                                (HeapCellValueTag::Cons, ptr) => {
-                                    match ptr.get_tag() {
-                                        ArenaHeaderTag::Rational | ArenaHeaderTag::Integer |
-                                        ArenaHeaderTag::F64 => {
-                                            c
-                                        }
-                                        _ => {
-                                            IndexingCodePtr::Fail
-                                        }
-                                    }
-                                }
-                                _ => {
-                                    unreachable!();
-                                }
-                            );
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        div(n1, n2)
+                    );
 
-                            match offset {
-                                IndexingCodePtr::Fail => {
-                                    self.machine_st.fail = true;
-                                    break;
-                                }
-                                IndexingCodePtr::DynamicExternal(o) => {
-                                    // either points directly to a
-                                    // DynamicInternalElse, or just ahead of
-                                    // one. Or neither!
-                                    let p = self.machine_st.p.local().abs_loc();
-
-                                    if !dynamic_external_of_clause_is_valid(self, p + o) {
-                                        self.machine_st.fail = true;
-                                    } else {
-                                        self.machine_st.p += o;
-                                    }
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Shr(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                    break;
-                                }
-                                IndexingCodePtr::External(o) => {
-                                    self.machine_st.p += o;
-                                    break;
-                                }
-                                IndexingCodePtr::Internal(o) => {
-                                    index += o;
-                                }
-                            }
-                        }
-                        &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
-                            let lit = read_heap_cell!(addr,
-                                (HeapCellValueTag::Char, c) => {
-                                    Literal::Char(c)
-                                }
-                                (HeapCellValueTag::Fixnum, n) => {
-                                    Literal::Fixnum(n)
-                                }
-                                (HeapCellValueTag::F64, f) => {
-                                    Literal::Float(f)
-                                }
-                                (HeapCellValueTag::Atom, (atom, arity)) => {
-                                    debug_assert_eq!(arity, 0);
-                                    Literal::Atom(atom)
-                                }
-                                (HeapCellValueTag::Cons, cons_ptr) => {
-                                    match_untyped_arena_ptr!(cons_ptr,
-                                        (ArenaHeaderTag::Rational, r) => {
-                                            Literal::Rational(r)
-                                        }
-                                        (ArenaHeaderTag::F64, f) => {
-                                            Literal::Float(F64Ptr(f))
-                                        }
-                                        (ArenaHeaderTag::Integer, n) => {
-                                            Literal::Integer(n)
-                                        }
-                                        _ => {
-                                            unreachable!()
-                                        }
-                                    )
-                                }
-                                _ => {
-                                    unreachable!()
-                                }
-                            );
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        shr(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                            let offset = match hm.get(&lit) {
-                                Some(offset) => *offset,
-                                _ => IndexingCodePtr::Fail,
-                            };
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Shl(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                            match offset {
-                                IndexingCodePtr::Fail => {
-                                    self.machine_st.fail = true;
-                                    break;
-                                }
-                                IndexingCodePtr::DynamicExternal(o) => {
-                                    // either points directly to a
-                                    // DynamicInternalElse, or just ahead of
-                                    // one. Or neither!
-                                    let p = self.machine_st.p.local().abs_loc();
-
-                                    if !dynamic_external_of_clause_is_valid(self, p + o) {
-                                        self.machine_st.fail = true;
-                                    } else {
-                                        self.machine_st.p += o;
-                                    }
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        shl(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                                    break;
-                                }
-                                IndexingCodePtr::External(o) => {
-                                    self.machine_st.p += o;
-                                    break;
-                                }
-                                IndexingCodePtr::Internal(o) => {
-                                    index += o;
-                                }
-                            }
-                        }
-                        &IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
-                            let offset = read_heap_cell!(addr,
-                                (HeapCellValueTag::Atom, (name, arity)) => {
-                                    match hm.get(&(name, arity)) {
-                                        Some(offset) => *offset,
-                                        None => IndexingCodePtr::Fail,
-                                    }
-                                }
-                                (HeapCellValueTag::Str, s) => {
-                                    let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
-                                        .get_name_and_arity();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Xor(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                    match hm.get(&(name, arity)) {
-                                        Some(offset) => *offset,
-                                        None => IndexingCodePtr::Fail,
-                                    }
-                                }
-                                _ => {
-                                    IndexingCodePtr::Fail
-                                }
-                            );
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        xor(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                            match offset {
-                                IndexingCodePtr::Fail => {
-                                    self.machine_st.fail = true;
-                                    break;
-                                }
-                                IndexingCodePtr::DynamicExternal(o) => {
-                                    let p = self.machine_st.p.local().abs_loc();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::And(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                                    if !dynamic_external_of_clause_is_valid(self, p + o) {
-                                        self.machine_st.fail = true;
-                                    } else {
-                                        self.machine_st.p += o;
-                                    }
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        and(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                                    break;
-                                }
-                                IndexingCodePtr::External(o) => {
-                                    self.machine_st.p += o;
-                                    break;
-                                }
-                                IndexingCodePtr::Internal(o) => {
-                                    index += o;
-                                }
-                            }
-                        }
-                        &IndexingLine::IndexedChoice(_) => {
-                            if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() {
-                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-                                self.machine_st.oip = index as u32;
-                                self.machine_st.iip = 0;
-                            } else {
-                                unreachable!()
-                            }
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Or(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                            break;
-                        }
-                        &IndexingLine::DynamicIndexedChoice(_) => {
-                            self.machine_st.dynamic_mode = FirstOrNext::First;
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        or(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                            if let LocalCodePtr::DirEntry(p) = self.machine_st.p.local() {
-                                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
-                                self.machine_st.oip = index as u32;
-                                self.machine_st.iip = 0;
-                            } else {
-                                unreachable!()
-                            }
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Mod(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                            break;
-                        }
-                    }
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        modulus(n1, n2, &mut self.machine_st.arena)
+                    );
+
+                    self.machine_st.p += 1;
                 }
-            }
-            &Line::IndexedChoice(ref choice_instr) => {
-                match choice_instr {
-                    &IndexedChoiceInstruction::Try(offset) => {
-                        self.machine_st.indexed_try(offset);
-                    }
-                    &IndexedChoiceInstruction::Retry(l) => {
-                        self.retry(l);
+                &Instruction::Rem(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
 
-                        try_or_fail!(
-                            self.machine_st,
-                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                        );
-                    }
-                    &IndexedChoiceInstruction::Trust(l) => {
-                        self.trust(l);
+                    self.machine_st.interms[t - 1] = try_or_throw_gen!(
+                        &mut self.machine_st,
+                        remainder(n1, n2, &mut self.machine_st.arena)
+                    );
 
-                        try_or_fail!(
-                            self.machine_st,
-                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                        );
-                    }
+                    self.machine_st.p += 1;
                 }
-            }
-            &Line::DynamicIndexedChoice(_) => self.execute_dynamic_indexed_choice_instr(),
-            &Line::Query(ref query_instr) => {
-                match query_instr {
-                    &QueryInstruction::GetVariable(norm, arg) => {
-                        self.machine_st[norm] = self.machine_st.registers[arg];
-                    }
-                    &QueryInstruction::PutConstant(_, c, reg) => {
-                        self.machine_st[reg] = c;
-                    }
-                    &QueryInstruction::PutList(_, reg) => {
-                        self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.len());
-                    }
-                    &QueryInstruction::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));
+                &Instruction::Cos(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                                // the tail will be pushed by the next
-                                // instruction, so don't push one here.
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, cos(n1))
+                    ));
 
-                                pstr_loc_as_cell!(h)
-                            } else {
-                                empty_list_as_cell!()
-                            }
-                        } else {
-                            string_as_cstr_cell!(string)
-                        };
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Sin(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                        self.machine_st[reg] = pstr_addr;
-                    }
-                    &QueryInstruction::PutStructure(ref ct, arity, reg) => {
-                        let h = self.machine_st.heap.len();
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, sin(n1))
+                    ));
 
-                        self.machine_st.heap.push(atom_as_cell!(ct.name(), arity));
-                        self.machine_st[reg] = str_loc_as_cell!(h);
-                    }
-                    &QueryInstruction::PutUnsafeValue(n, arg) => {
-                        let s = stack_loc!(AndFrame, self.machine_st.e, n);
-                        let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s)));
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Tan(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                        if addr.is_protected(self.machine_st.e) {
-                            self.machine_st.registers[arg] = addr;
-                        } else {
-                            let h = self.machine_st.heap.len();
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, tan(n1))
+                    ));
 
-                            self.machine_st.heap.push(heap_loc_as_cell!(h));
-                            (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Sqrt(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                            self.machine_st.registers[arg] = heap_loc_as_cell!(h);
-                        }
-                    }
-                    &QueryInstruction::PutValue(norm, arg) => {
-                        self.machine_st.registers[arg] = self.machine_st[norm];
-                    }
-                    &QueryInstruction::PutVariable(norm, arg) => {
-                        match norm {
-                            RegType::Perm(n) => {
-                                self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n);
-                                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));
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, sqrt(n1))
+                    ));
 
-                                self.machine_st[norm] = heap_loc_as_cell!(h);
-                                self.machine_st.registers[arg] = heap_loc_as_cell!(h);
-                            }
-                        };
-                    }
-                    &QueryInstruction::SetConstant(c) => {
-                        self.machine_st.heap.push(c);
-                    }
-                    &QueryInstruction::SetLocalValue(reg) => {
-                        let addr = self.machine_st.deref(self.machine_st[reg]);
-                        let stored_v = self.machine_st.store(addr);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Log(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                        if stored_v.is_stack_var() {
-                            let h = self.machine_st.heap.len();
-                            self.machine_st.heap.push(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);
-                        }
-                    }
-                    &QueryInstruction::SetVariable(reg) => {
-                        let h = self.machine_st.heap.len();
-                        self.machine_st.heap.push(heap_loc_as_cell!(h));
-                        self.machine_st[reg] = heap_loc_as_cell!(h);
-                    }
-                    &QueryInstruction::SetValue(reg) => {
-                        let heap_val = self.machine_st.store(self.machine_st[reg]);
-                        self.machine_st.heap.push(heap_val);
-                    }
-                    &QueryInstruction::SetVoid(n) => {
-                        let h = self.machine_st.heap.len();
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, log(n1))
+                    ));
 
-                        for i in h..h + n {
-                            self.machine_st.heap.push(heap_loc_as_cell!(i));
-                        }
-                    }
+                    self.machine_st.p += 1;
                 }
+                &Instruction::Exp(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
 
-                self.machine_st.p += 1;
-            }
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, exp(n1))
+                    ));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ACos(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, acos(n1))
+                    ));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ASin(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, asin(n1))
+                    ));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ATan(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, atan(n1))
+                    ));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ATan2(ref a1, ref a2, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(a2));
+
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, atan2(n1, n2))
+                    ));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Float(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = Number::Float(OrderedFloat(
+                        try_or_throw_gen!(&mut self.machine_st, float(n1))
+                    ));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Truncate(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = truncate(n1, &mut self.machine_st.arena);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Round(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] =
+                        try_or_throw_gen!(&mut self.machine_st, round(n1, &mut self.machine_st.arena));
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Ceiling(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = ceiling(n1, &mut self.machine_st.arena);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Floor(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = floor(n1, &mut self.machine_st.arena);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Plus(ref a1, t) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+                    self.machine_st.interms[t - 1] = n1;
+                    self.machine_st.p += 1;
+                }
+                &Instruction::DynamicElse(..) => {
+                    if let FirstOrNext::First = self.machine_st.dynamic_mode {
+                        self.machine_st.cc = self.machine_st.global_clock;
+                    }
+
+                    let p = self.machine_st.p;
+
+                    match self.find_living_dynamic_else(p) {
+                        Some((p, next_i)) => {
+                            self.machine_st.p = p;
+
+                            match self.machine_st.dynamic_mode {
+                                FirstOrNext::First if next_i == 0 => {
+                                    self.machine_st.p += 1;
+                                }
+                                FirstOrNext::First => {
+                                    self.machine_st.cc = self.machine_st.global_clock;
+
+                                    match self.find_living_dynamic_else(p + next_i) {
+                                        Some(_) => {
+                                            self.machine_st.registers[self.machine_st.num_of_args + 1] =
+                                                fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+                                            self.machine_st.num_of_args += 1;
+                                            self.machine_st.try_me_else(next_i);
+                                            self.machine_st.num_of_args -= 1;
+                                        }
+                                        None => {
+                                            self.machine_st.p += 1;
+                                        }
+                                    }
+                                }
+                                FirstOrNext::Next => {
+                                    let n = self.machine_st
+                                        .stack
+                                        .index_or_frame(self.machine_st.b)
+                                        .prelude
+                                        .univ_prelude
+                                        .num_cells;
+
+                                    self.machine_st.cc = cell_as_fixnum!(
+                                        self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
+                                    ).get_num() as usize;
+
+                                    if next_i > 0 {
+                                        match self.find_living_dynamic_else(p + next_i) {
+                                            Some(_) => {
+                                                self.retry_me_else(next_i);
+
+                                                try_or_throw!(
+                                                    self.machine_st,
+                                                    (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                );
+                                            }
+                                            None => {
+                                                self.trust_me();
+
+                                                try_or_throw!(
+                                                    self.machine_st,
+                                                    (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                );
+                                            }
+                                        }
+                                    } else {
+                                        self.trust_me();
+
+                                        try_or_throw!(
+                                            self.machine_st,
+                                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                        );
+                                    }
+                                }
+                            }
+                        }
+                        None => {
+                            self.machine_st.fail = true;
+                        }
+                    }
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                        continue;
+                    }
+
+                    self.machine_st.dynamic_mode = FirstOrNext::Next;
+                }
+                &Instruction::DynamicInternalElse(..) => {
+                    let p = self.machine_st.p;
+
+                    match self.find_living_dynamic_else(p) {
+                        Some((p, next_i)) => {
+                            self.machine_st.p = p;
+
+                            match self.machine_st.dynamic_mode {
+                                FirstOrNext::First if next_i == 0 => {
+                                    self.machine_st.p += 1;
+                                }
+                                FirstOrNext::First => {
+                                    match self.find_living_dynamic_else(p + next_i) {
+                                        Some(_) => {
+                                            self.machine_st.registers[self.machine_st.num_of_args + 1] =
+                                                fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+                                            self.machine_st.num_of_args += 1;
+                                            self.machine_st.try_me_else(next_i);
+                                            self.machine_st.num_of_args -= 1;
+                                        }
+                                        None => {
+                                            self.machine_st.p += 1;
+                                        }
+                                    }
+                                }
+                                FirstOrNext::Next => {
+                                    let n = self.machine_st
+                                        .stack
+                                        .index_or_frame(self.machine_st.b)
+                                        .prelude
+                                        .univ_prelude
+                                        .num_cells;
+
+                                    self.machine_st.cc = cell_as_fixnum!(
+                                        self.machine_st.stack[stack_loc!(OrFrame, self.machine_st.b, n-1)]
+                                    ).get_num() as usize;
+
+                                    if next_i > 0 {
+                                        match self.find_living_dynamic_else(p + next_i) {
+                                            Some(_) => {
+                                                self.retry_me_else(next_i);
+
+                                                try_or_throw!(
+                                                    self.machine_st,
+                                                    (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                );
+                                            }
+                                            None => {
+                                                self.trust_me();
+
+                                                try_or_throw!(
+                                                    self.machine_st,
+                                                    (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                );
+                                            }
+                                        }
+                                    } else {
+                                        self.trust_me();
+
+                                        try_or_throw!(
+                                            self.machine_st,
+                                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                        );
+                                    }
+                                }
+                            }
+                        }
+                        None => {
+                            self.machine_st.fail = true;
+                        }
+                    }
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                        continue;
+                    }
+
+                    self.machine_st.dynamic_mode = FirstOrNext::Next;
+                }
+                &Instruction::TryMeElse(offset) => {
+                    self.machine_st.try_me_else(offset);
+                }
+                &Instruction::DefaultRetryMeElse(offset) => {
+                    self.retry_me_else(offset);
+                }
+                &Instruction::DefaultTrustMe(_) => {
+                    self.trust_me();
+                }
+                &Instruction::RetryMeElse(offset) => {
+                    self.retry_me_else(offset);
+
+                    try_or_throw!(
+                        self.machine_st,
+                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                    );
+                }
+                &Instruction::TrustMe(_) => {
+                    self.trust_me();
+
+                    try_or_throw!(
+                        self.machine_st,
+                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                    );
+                }
+                &Instruction::NeckCut => {
+                    let b = self.machine_st.b;
+                    let b0 = self.machine_st.b0;
+
+                    if b > b0 {
+                        self.machine_st.b = b0;
+
+                        if b > self.machine_st.e {
+                            self.machine_st.stack.truncate(b);
+                        }
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::GetLevel(r) => {
+                    let b0 = self.machine_st.b0;
+
+                    self.machine_st[r] = fixnum_as_cell!(Fixnum::build_with(b0 as i64));
+                    self.machine_st.p += 1;
+                }
+                &Instruction::GetLevelAndUnify(r) => {
+                    // let b0 = self.machine_st[perm_v!(1)];
+                    let b0 = cell_as_fixnum!(
+                        self.machine_st.stack[stack_loc!(AndFrame, self.machine_st.e, 1)]
+                    );
+                    let a = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    // unify_fn!(&mut self.machine_st, a, b0);
+                    self.machine_st.unify_fixnum(b0, a);
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::Cut(r) => {
+                    let value = self.machine_st[r];
+                    self.machine_st.cut_body(value);
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                        continue;
+                    }
+
+                    if (self.machine_st.run_cleaners_fn)(self) {
+                       continue;
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::Allocate(num_cells) => {
+                    self.machine_st.allocate(num_cells);
+                }
+                &Instruction::DefaultCallAcyclicTerm(_) => {
+                    let addr = self.machine_st.registers[1];
+
+                    if self.machine_st.is_cyclic_term(addr) {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::DefaultExecuteAcyclicTerm(_) => {
+                    let addr = self.machine_st.registers[1];
+
+                    if self.machine_st.is_cyclic_term(addr) {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallArg(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_arg());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteArg(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_arg());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::DefaultCallCompare(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.compare());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteCompare(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.compare());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::DefaultCallTermGreaterThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.p += 1;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::DefaultExecuteTermGreaterThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.p = self.machine_st.cp;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::DefaultCallTermLessThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.p += 1;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::DefaultExecuteTermLessThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.p = self.machine_st.cp;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::DefaultCallTermGreaterThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Greater | Ordering::Equal) => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteTermGreaterThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Greater | Ordering::Equal) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallTermLessThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Less | Ordering::Equal) => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteTermLessThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Less | Ordering::Equal) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallRead(_) => {
+                    try_or_throw!(self.machine_st, self.read());
+
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteRead(_) => {
+                    try_or_throw!(self.machine_st, self.read());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallCopyTerm(_) => {
+                    self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteCopyTerm(_) => {
+                    self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallTermEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if self.machine_st.eq_test(a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::DefaultExecuteTermEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if self.machine_st.eq_test(a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallGround(_) => {
+                    if self.machine_st.ground_test() {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::DefaultExecuteGround(_) => {
+                    if self.machine_st.ground_test() {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallFunctor(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteFunctor(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallTermNotEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::DefaultExecuteTermNotEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallSort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.sort());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteSort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.sort());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::DefaultCallKeySort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.keysort());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteKeySort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.keysort());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::DefaultCallIs(r, at, _) => {
+                    try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::DefaultExecuteIs(r, at, _) => {
+                    try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallAcyclicTerm(_) => {
+                    let addr = self.machine_st.registers[1];
+
+                    if self.machine_st.is_cyclic_term(addr) {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteAcyclicTerm(_) => {
+                    let addr = self.machine_st.registers[1];
+
+                    if self.machine_st.is_cyclic_term(addr) {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallArg(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_arg());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteArg(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_arg());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallCompare(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.compare());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteCompare(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.compare());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallTermGreaterThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::ExecuteTermGreaterThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Greater) = compare_term_test!(self.machine_st, a1, a2) {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::CallTermLessThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::ExecuteTermLessThan(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Less) = compare_term_test!(self.machine_st, a1, a2) {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    } else {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::CallTermGreaterThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Greater | Ordering::Equal) => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteTermGreaterThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Greater | Ordering::Equal) => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallTermLessThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Less | Ordering::Equal) => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteTermLessThanOrEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    match compare_term_test!(self.machine_st, a1, a2) {
+                        Some(Ordering::Less | Ordering::Equal) => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallRead(_) => {
+                    try_or_throw!(self.machine_st, self.read());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteRead(_) => {
+                    try_or_throw!(self.machine_st, self.read());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallCopyTerm(_) => {
+                    self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteCopyTerm(_) => {
+                    self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallTermEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if self.machine_st.eq_test(a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteTermEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if self.machine_st.eq_test(a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallGround(_) => {
+                    if self.machine_st.ground_test() {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteGround(_) => {
+                    if self.machine_st.ground_test() {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallFunctor(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteFunctor(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.try_functor());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallTermNotEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteTermNotEqual(_) => {
+                    let a1 = self.machine_st.registers[1];
+                    let a2 = self.machine_st.registers[2];
+
+                    if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallSort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.sort());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteSort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.sort());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallKeySort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.keysort());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteKeySort(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.keysort());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallIs(r, at, _) => {
+                    try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteIs(r, at, _) => {
+                    try_or_throw!(self.machine_st, self.machine_st.is(r, at));
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallN(arity, _) => {
+                    let pred = self.machine_st.registers[1];
+
+                    for i in 2..arity + 1 {
+                        self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+                    }
+
+                    self.machine_st.registers[arity] = pred;
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.call_n(atom!("user"), arity)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                }
+                &Instruction::ExecuteN(arity, _) => {
+                    let pred = self.machine_st.registers[1];
+
+                    for i in 2..arity + 1 {
+                        self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+                    }
+
+                    self.machine_st.registers[arity] = pred;
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.execute_n(atom!("user"), arity)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                }
+                &Instruction::DefaultCallN(arity, _) => {
+                    let pred = self.machine_st.registers[1];
+
+                    for i in 2..arity + 1 {
+                        self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+                    }
+
+                    self.machine_st.registers[arity] = pred;
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.call_n(atom!("user"), arity)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::DefaultExecuteN(arity, _) => {
+                    let pred = self.machine_st.registers[1];
+
+                    for i in 2..arity + 1 {
+                        self.machine_st.registers[i - 1] = self.machine_st.registers[i];
+                    }
+
+                    self.machine_st.registers[arity] = pred;
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.execute_n(atom!("user"), arity)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::CallNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less | Ordering::Equal => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less | Ordering::Equal => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallNumberEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteNumberEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallNumberNotEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            self.machine_st.backtrack();
+                        }
+                        _ => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                    }
+                }
+                &Instruction::ExecuteNumberNotEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            self.machine_st.backtrack();
+                        }
+                        _ => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                    }
+                }
+                &Instruction::CallNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater | Ordering::Equal => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater | Ordering::Equal => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallNumberGreaterThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteNumberGreaterThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallNumberLessThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteNumberLessThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less => {
+                            try_or_throw!(
+                                self.machine_st,
+                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                            );
+
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less | Ordering::Equal => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteNumberLessThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less | Ordering::Equal => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallNumberNotEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            self.machine_st.backtrack();
+                        }
+                        _ => {
+                            self.machine_st.p += 1;
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteNumberNotEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            self.machine_st.backtrack();
+                        }
+                        _ => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                    }
+                }
+                &Instruction::DefaultCallNumberEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteNumberEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Equal => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater | Ordering::Equal => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteNumberGreaterThanOrEqual(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater | Ordering::Equal => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallNumberGreaterThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteNumberGreaterThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Greater => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultCallNumberLessThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::DefaultExecuteNumberLessThan(ref at_1, ref at_2, _) => {
+                    let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_1));
+                    let n2 = try_or_throw!(self.machine_st, self.machine_st.get_number(at_2));
+
+                    match n1.cmp(&n2) {
+                        Ordering::Less => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                //
+                &Instruction::CallIsAtom(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            if arity == 0 {
+                                self.machine_st.p += 1;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        (HeapCellValueTag::Char) => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::ExecuteIsAtom(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            if arity == 0 {
+                                self.machine_st.p = self.machine_st.cp;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        (HeapCellValueTag::Char) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::CallIsAtomic(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+                         HeapCellValueTag::Cons) => {
+                            self.machine_st.p += 1;
+                        }
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            if arity == 0 {
+                                self.machine_st.p += 1;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::ExecuteIsAtomic(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
+                         HeapCellValueTag::Cons) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            if arity == 0 {
+                                self.machine_st.p = self.machine_st.cp;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::CallIsCompound(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+                         HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+                            self.machine_st.p += 1;
+                        }
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            if arity > 0 {
+                                self.machine_st.p += 1;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::ExecuteIsCompound(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Str | HeapCellValueTag::Lis |
+                         HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        (HeapCellValueTag::Atom, (_name, arity)) => {
+                            if arity > 0 {
+                                self.machine_st.p = self.machine_st.cp;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::CallIsInteger(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match Number::try_from(d) {
+                        Ok(Number::Fixnum(_) | Number::Integer(_)) => {
+                            self.machine_st.p += 1;
+                        }
+                        Ok(Number::Rational(n)) => {
+                            if n.denom() == &1 {
+                                self.machine_st.p += 1;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteIsInteger(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match Number::try_from(d) {
+                        Ok(Number::Fixnum(_) | Number::Integer(_)) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        Ok(Number::Rational(n)) => {
+                            if n.denom() == &1 {
+                                self.machine_st.p = self.machine_st.cp;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallIsNumber(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match Number::try_from(d) {
+                        Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
+                            self.machine_st.p += 1;
+                        }
+                        Ok(Number::Rational(n)) => {
+                            if n.denom() == &1 {
+                                self.machine_st.p += 1;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteIsNumber(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match Number::try_from(d) {
+                        Ok(Number::Fixnum(_) | Number::Integer(_) | Number::Float(_)) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        Ok(Number::Rational(n)) => {
+                            if n.denom() == &1 {
+                                self.machine_st.p = self.machine_st.cp;
+                            } else {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallIsRational(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Cons, ptr) => {
+                            match_untyped_arena_ptr!(ptr,
+                                                     (ArenaHeaderTag::Rational, _r) => {
+                                                         self.machine_st.p += 1;
+                                                     }
+                                                     _ => {
+                                                         self.machine_st.backtrack();
+                                                     }
+                            );
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::ExecuteIsRational(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    read_heap_cell!(d,
+                        (HeapCellValueTag::Cons, ptr) => {
+                            match_untyped_arena_ptr!(ptr,
+                                 (ArenaHeaderTag::Rational, _r) => {
+                                     self.machine_st.p = self.machine_st.cp;
+                                 }
+                                 _ => {
+                                     self.machine_st.backtrack();
+                                 }
+                            );
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    );
+                }
+                &Instruction::CallIsFloat(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match Number::try_from(d) {
+                        Ok(Number::Float(_)) => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteIsFloat(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match Number::try_from(d) {
+                        Ok(Number::Float(_)) => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallIsNonVar(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match d.get_tag() {
+                        HeapCellValueTag::AttrVar |
+                        HeapCellValueTag::Var |
+                        HeapCellValueTag::StackVar => {
+                            self.machine_st.backtrack();
+                        }
+                        _ => {
+                            self.machine_st.p += 1;
+                        }
+                    }
+                }
+                &Instruction::ExecuteIsNonVar(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match d.get_tag() {
+                        HeapCellValueTag::AttrVar |
+                        HeapCellValueTag::Var |
+                        HeapCellValueTag::StackVar => {
+                            self.machine_st.backtrack();
+                        }
+                        _ => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                    }
+                }
+                &Instruction::CallIsVar(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match d.get_tag() {
+                        HeapCellValueTag::AttrVar |
+                        HeapCellValueTag::Var |
+                        HeapCellValueTag::StackVar => {
+                            self.machine_st.p += 1;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::ExecuteIsVar(r, _) => {
+                    let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+
+                    match d.get_tag() {
+                        HeapCellValueTag::AttrVar |
+                        HeapCellValueTag::Var |
+                        HeapCellValueTag::StackVar => {
+                            self.machine_st.p = self.machine_st.cp;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                        }
+                    }
+                }
+                &Instruction::CallNamed(arity, name, ref idx, _) => {
+                    let idx = idx.get();
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.try_call(name, arity, idx)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                }
+                &Instruction::ExecuteNamed(arity, name, ref idx, _) => {
+                    let idx = idx.get();
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.try_execute(name, arity, idx)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        try_or_throw!(
+                            self.machine_st,
+                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                        );
+                    }
+                }
+                &Instruction::DefaultCallNamed(arity, name, ref idx, _) => {
+                    let idx = idx.get();
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.try_call(name, arity, idx)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::DefaultExecuteNamed(arity, name, ref idx, _) => {
+                    let idx = idx.get();
+
+                    try_or_throw!(
+                        self.machine_st,
+                        self.try_execute(name, arity, idx)
+                    );
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::Deallocate => {
+                    self.machine_st.deallocate()
+                }
+                &Instruction::JmpByCall(arity, offset, _) => {
+                    self.machine_st.num_of_args = arity;
+                    self.machine_st.b0 = self.machine_st.b;
+                    self.machine_st.cp = self.machine_st.p + 1;
+                    self.machine_st.p += offset;
+                }
+                &Instruction::JmpByExecute(arity, offset, _) => {
+                    self.machine_st.num_of_args = arity;
+                    self.machine_st.b0 = self.machine_st.b;
+                    self.machine_st.p += offset;
+                }
+                &Instruction::RevJmpBy(offset) => {
+                    self.machine_st.p -= offset;
+                }
+                &Instruction::Proceed => {
+                    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);
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::GetList(_, reg) => {
+                    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::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.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.mode = MachineMode::Read;
+                        }
+                        (HeapCellValueTag::Lis, l) => {
+                            self.machine_st.s = HeapPtr::HeapCell(l);
+                            self.machine_st.mode = MachineMode::Read;
+                        }
+                        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                            let h = self.machine_st.heap.len();
+
+                            self.machine_st.heap.push(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;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                            continue;
+                        }
+                    );
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::GetPartialString(_, string, reg, has_tail) => {
+                    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::AttrVar |
+                         HeapCellValueTag::StackVar | HeapCellValueTag::Var |
+                         HeapCellValueTag::CStr) => {
+                            self.machine_st.match_partial_string(store_v, string, has_tail);
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                            continue;
+                        }
+                    );
+
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::GetStructure(name, arity, reg) => {
+                    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, a) => {
+                            read_heap_cell!(self.machine_st.heap[a],
+                                (HeapCellValueTag::Atom, (result_name, result_arity)) => {
+                                    if arity == result_arity && name == result_name {
+                                        self.machine_st.s = HeapPtr::HeapCell(a + 1);
+                                        self.machine_st.mode = MachineMode::Read;
+                                    } else {
+                                        self.machine_st.backtrack();
+                                        continue;
+                                    }
+                                }
+                                _ => {
+                                    unreachable!();
+                                }
+                            );
+                        }
+                        (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                            let h = self.machine_st.heap.len();
+
+                            self.machine_st.heap.push(str_loc_as_cell!(h+1));
+                            self.machine_st.heap.push(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;
+                        }
+                        _ => {
+                            self.machine_st.backtrack();
+                            continue;
+                        }
+                    );
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::GetVariable(norm, arg) => {
+                    self.machine_st[norm] = self.machine_st.registers[arg];
+                    self.machine_st.p += 1;
+                }
+                &Instruction::GetValue(norm, arg) => {
+                    let norm_addr = self.machine_st[norm];
+                    let reg_addr = self.machine_st.registers[arg];
+
+                    unify_fn!(&mut self.machine_st, norm_addr, reg_addr);
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                        continue;
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::UnifyConstant(v) => {
+                    match self.machine_st.mode {
+                        MachineMode::Read => {
+                            let addr = self.machine_st.read_s();
+
+                            self.machine_st.write_literal_to_var(addr, v);
+
+                            if self.machine_st.fail {
+                                self.machine_st.backtrack();
+                                continue;
+                            } else {
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                        }
+                        MachineMode::Write => {
+                            self.machine_st.heap.push(v);
+                        }
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::UnifyLocalValue(reg) => {
+                    match self.machine_st.mode {
+                        MachineMode::Read => {
+                            let reg_addr = self.machine_st[reg];
+                            let value = self.machine_st.read_s();
+
+                            unify_fn!(&mut self.machine_st, reg_addr, value);
+
+                            if self.machine_st.fail {
+                                self.machine_st.backtrack();
+                                continue;
+                            } else {
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                        }
+                        MachineMode::Write => {
+                            let value = self.machine_st.store(self.machine_st.deref(self.machine_st[reg]));
+                            let h = self.machine_st.heap.len();
+
+                            read_heap_cell!(value,
+                                (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, hc) => {
+                                    let value = self.machine_st.heap[hc];
+
+                                    self.machine_st.heap.push(value);
+                                    self.machine_st.increment_s_ptr(1);
+                                }
+                                _ => {
+                                    self.machine_st.heap.push(heap_loc_as_cell!(h));
+                                    (self.machine_st.bind_fn)(
+                                        &mut self.machine_st,
+                                        Ref::heap_cell(h),
+                                        value,
+                                    );
+                                }
+                            );
+                        }
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::UnifyVariable(reg) => {
+                    match self.machine_st.mode {
+                        MachineMode::Read => {
+                            self.machine_st[reg] = self.machine_st.read_s();
+                            self.machine_st.increment_s_ptr(1);
+                        }
+                        MachineMode::Write => {
+                            let h = self.machine_st.heap.len();
+
+                            self.machine_st.heap.push(heap_loc_as_cell!(h));
+                            self.machine_st[reg] = heap_loc_as_cell!(h);
+                        }
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::UnifyValue(reg) => {
+                    match self.machine_st.mode {
+                        MachineMode::Read => {
+                            let reg_addr = self.machine_st[reg];
+                            let value = self.machine_st.read_s();
+
+                            unify_fn!(&mut self.machine_st, reg_addr, value);
+
+                            if self.machine_st.fail {
+                                self.machine_st.backtrack();
+                                continue;
+                            } else {
+                                self.machine_st.increment_s_ptr(1);
+                            }
+                        }
+                        MachineMode::Write => {
+                            let h = self.machine_st.heap.len();
+                            self.machine_st.heap.push(heap_loc_as_cell!(h));
+
+                            let addr = self.machine_st.store(self.machine_st[reg]);
+                            (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+
+                            // 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));
+
+                            // the old code didn't perform the occurs
+                            // check when enabled and so it was changed to
+                            // the above, which is only slightly less
+                            // efficient when the occurs_check is disabled.
+                        }
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::UnifyVoid(n) => {
+                    match self.machine_st.mode {
+                        MachineMode::Read => {
+                            self.machine_st.increment_s_ptr(n);
+                        }
+                        MachineMode::Write => {
+                            let h = self.machine_st.heap.len();
+
+                            for i in h..h + n {
+                                self.machine_st.heap.push(heap_loc_as_cell!(i));
+                            }
+                        }
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::IndexingCode(ref indexing_lines) => {
+                    match &indexing_lines[self.machine_st.oip as usize] {
+                        IndexingLine::Indexing(_) => {
+                            self.execute_switch_on_term();
+
+                            if self.machine_st.fail {
+                                self.machine_st.backtrack();
+                            }
+                        }
+                        IndexingLine::IndexedChoice(ref indexed_choice) => {
+                            match &indexed_choice[self.machine_st.iip as usize] {
+                                &IndexedChoiceInstruction::Try(offset) => {
+                                    self.machine_st.indexed_try(offset);
+                                }
+                                &IndexedChoiceInstruction::Retry(l) => {
+                                    self.retry(l);
+
+                                    try_or_throw!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                                &IndexedChoiceInstruction::Trust(l) => {
+                                    self.trust(l);
+
+                                    try_or_throw!(
+                                        self.machine_st,
+                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                    );
+                                }
+                            }
+                        }
+                        IndexingLine::DynamicIndexedChoice(_) => {
+                            let p = self.machine_st.p;
+
+                            match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
+                                Some((offset, oi, ii, is_next_clause)) => {
+                                    self.machine_st.p = p;
+                                    self.machine_st.oip = oi;
+                                    self.machine_st.iip = ii;
+
+                                    match self.machine_st.dynamic_mode {
+                                        FirstOrNext::First if !is_next_clause => {
+                                            self.machine_st.p = p + offset;
+                                        }
+                                        FirstOrNext::First => {
+                                            // there's a leading DynamicElse that sets self.machine_st.cc.
+                                            // self.machine_st.cc = self.machine_st.global_clock;
+
+                                            // see that there is a following dynamic_else
+                                            // clause so we avoid generating a choice
+                                            // point in case there isn't.
+                                            match self.find_living_dynamic(oi, ii + 1) {
+                                                Some(_) => {
+                                                    self.machine_st.registers[self.machine_st.num_of_args + 1] =
+                                                        fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
+
+                                                    self.machine_st.num_of_args += 2;
+                                                    self.machine_st.indexed_try(offset);
+                                                    self.machine_st.num_of_args -= 2;
+                                                }
+                                                None => {
+                                                    self.machine_st.p = p + offset;
+                                                    self.machine_st.oip = 0;
+                                                    self.machine_st.iip = 0;
+                                                }
+                                            }
+                                        }
+                                        FirstOrNext::Next => {
+                                            let b = self.machine_st.b;
+                                            let n = self.machine_st
+                                                .stack
+                                                .index_or_frame(b)
+                                                .prelude
+                                                .univ_prelude
+                                                .num_cells;
+
+                                            self.machine_st.cc = cell_as_fixnum!(
+                                                self.machine_st.stack[stack_loc!(OrFrame, b, n-2)]
+                                            ).get_num() as usize;
+
+                                            if is_next_clause {
+                                                match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
+                                                    Some(_) => {
+                                                        self.retry(offset);
+
+                                                        try_or_throw!(
+                                                            self.machine_st,
+                                                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                        );
+                                                    }
+                                                    None => {
+                                                        self.trust(offset);
+
+                                                        try_or_throw!(
+                                                            self.machine_st,
+                                                            (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                        );
+                                                    }
+                                                }
+                                            } else {
+                                                self.trust(offset);
+
+                                                try_or_throw!(
+                                                    self.machine_st,
+                                                    (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+                                                );
+                                            }
+                                        }
+                                    }
+                                }
+                                None => {
+                                    self.machine_st.fail = true;
+                                }
+                            }
+
+                            if self.machine_st.fail {
+                                self.machine_st.backtrack();
+                            } else {
+                                self.machine_st.dynamic_mode = FirstOrNext::Next;
+                            }
+                        }
+                    }
+                }
+                &Instruction::PutConstant(_, c, reg) => {
+                    self.machine_st[reg] = c;
+                    self.machine_st.p += 1;
+                }
+                &Instruction::PutList(_, reg) => {
+                    self.machine_st[reg] = list_loc_as_cell!(self.machine_st.heap.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)
+                    };
+
+                    self.machine_st[reg] = pstr_addr;
+                    self.machine_st.p += 1;
+                }
+                &Instruction::PutStructure(name, arity, reg) => {
+                    let h = self.machine_st.heap.len();
+
+                    self.machine_st.heap.push(atom_as_cell!(name, arity));
+                    self.machine_st[reg] = str_loc_as_cell!(h);
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::PutUnsafeValue(n, arg) => {
+                    let s = stack_loc!(AndFrame, self.machine_st.e, n);
+                    let addr = self.machine_st.store(self.machine_st.deref(stack_loc_as_cell!(s)));
+
+                    if addr.is_protected(self.machine_st.e) {
+                        self.machine_st.registers[arg] = addr;
+                    } else {
+                        let h = self.machine_st.heap.len();
+
+                        self.machine_st.heap.push(heap_loc_as_cell!(h));
+                        (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), addr);
+
+                        self.machine_st.registers[arg] = heap_loc_as_cell!(h);
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::PutValue(norm, arg) => {
+                    self.machine_st.registers[arg] = self.machine_st[norm];
+                    self.machine_st.p += 1;
+                }
+                &Instruction::PutVariable(norm, arg) => {
+                    match norm {
+                        RegType::Perm(n) => {
+                            self.machine_st[norm] = stack_loc_as_cell!(AndFrame, self.machine_st.e, n);
+                            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));
+
+                            self.machine_st[norm] = heap_loc_as_cell!(h);
+                            self.machine_st.registers[arg] = heap_loc_as_cell!(h);
+                        }
+                    };
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::SetConstant(c) => {
+                    self.machine_st.heap.push(c);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::SetLocalValue(reg) => {
+                    let addr = self.machine_st.deref(self.machine_st[reg]);
+                    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));
+                        (self.machine_st.bind_fn)(&mut self.machine_st, Ref::heap_cell(h), stored_v);
+                    } else {
+                        self.machine_st.heap.push(stored_v);
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                &Instruction::SetVariable(reg) => {
+                    let h = self.machine_st.heap.len();
+
+                    self.machine_st.heap.push(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);
+                    self.machine_st.p += 1;
+                }
+                &Instruction::SetVoid(n) => {
+                    let h = self.machine_st.heap.len();
+
+                    for i in h..h + n {
+                        self.machine_st.heap.push(heap_loc_as_cell!(i));
+                    }
+
+                    self.machine_st.p += 1;
+                }
+                //
+                &Instruction::CallAtomChars(_) => {
+                    self.atom_chars();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteAtomChars(_) => {
+                    self.atom_chars();
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallAtomCodes(_) => {
+                    try_or_throw!(self.machine_st, self.atom_codes());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteAtomCodes(_) => {
+                    try_or_throw!(self.machine_st, self.atom_codes());
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    } else {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallAtomLength(_) => {
+                    self.atom_length();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteAtomLength(_) => {
+                    self.atom_length();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallBindFromRegister(_) => {
+                    self.bind_from_register();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteBindFromRegister(_) => {
+                    self.bind_from_register();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallContinuation(_) => {
+                    try_or_throw!(self.machine_st, self.call_continuation(false));
+                }
+                &Instruction::ExecuteContinuation(_) => {
+                    try_or_throw!(self.machine_st, self.call_continuation(true));
+                }
+                &Instruction::CallCharCode(_) => {
+                    try_or_throw!(self.machine_st, self.char_code());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCharCode(_) => {
+                    try_or_throw!(self.machine_st, self.char_code());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCharType(_) => {
+                    self.char_type();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCharType(_) => {
+                    self.char_type();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCharsToNumber(_) => {
+                    try_or_throw!(self.machine_st, self.chars_to_number());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCharsToNumber(_) => {
+                    try_or_throw!(self.machine_st, self.chars_to_number());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCodesToNumber(_) => {
+                    try_or_throw!(self.machine_st, self.codes_to_number());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCodesToNumber(_) => {
+                    try_or_throw!(self.machine_st, self.codes_to_number());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCopyTermWithoutAttrVars(_) => {
+                    self.copy_term_without_attr_vars();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCopyTermWithoutAttrVars(_) => {
+                    self.copy_term_without_attr_vars();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCheckCutPoint(_) => {
+                    self.check_cut_point();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCheckCutPoint(_) => {
+                    self.check_cut_point();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallClose(_) => {
+                    try_or_throw!(self.machine_st, self.close());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteClose(_) => {
+                    try_or_throw!(self.machine_st, self.close());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallCopyToLiftedHeap(_) => {
+                    self.copy_to_lifted_heap();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteCopyToLiftedHeap(_) => {
+                    self.copy_to_lifted_heap();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallCreatePartialString(_) => {
+                    self.create_partial_string();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCreatePartialString(_) => {
+                    self.create_partial_string();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCurrentHostname(_) => {
+                    self.current_hostname();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCurrentHostname(_) => {
+                    self.current_hostname();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCurrentInput(_) => {
+                    try_or_throw!(self.machine_st, self.current_input());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCurrentInput(_) => {
+                    try_or_throw!(self.machine_st, self.current_input());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCurrentOutput(_) => {
+                    try_or_throw!(self.machine_st, self.current_output());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCurrentOutput(_) => {
+                    try_or_throw!(self.machine_st, self.current_output());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDirectoryFiles(_) => {
+                    try_or_throw!(self.machine_st, self.directory_files());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDirectoryFiles(_) => {
+                    try_or_throw!(self.machine_st, self.directory_files());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallFileSize(_) => {
+                    self.file_size();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteFileSize(_) => {
+                    self.file_size();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallFileExists(_) => {
+                    self.file_exists();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteFileExists(_) => {
+                    self.file_exists();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDirectoryExists(_) => {
+                    self.directory_exists();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDirectoryExists(_) => {
+                    self.directory_exists();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDirectorySeparator(_) => {
+                    self.directory_separator();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDirectorySeparator(_) => {
+                    self.directory_separator();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallMakeDirectory(_) => {
+                    self.make_directory();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteMakeDirectory(_) => {
+                    self.make_directory();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallMakeDirectoryPath(_) => {
+                    self.make_directory_path();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteMakeDirectoryPath(_) => {
+                    self.make_directory_path();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDeleteFile(_) => {
+                    self.delete_file();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDeleteFile(_) => {
+                    self.delete_file();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallRenameFile(_) => {
+                    self.rename_file();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteRenameFile(_) => {
+                    self.rename_file();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallWorkingDirectory(_) => {
+                    try_or_throw!(self.machine_st, self.working_directory());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteWorkingDirectory(_) => {
+                    try_or_throw!(self.machine_st, self.working_directory());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDeleteDirectory(_) => {
+                    self.delete_directory();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDeleteDirectory(_) => {
+                    self.delete_directory();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPathCanonical(_) => {
+                    try_or_throw!(self.machine_st, self.path_canonical());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePathCanonical(_) => {
+                    try_or_throw!(self.machine_st, self.path_canonical());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallFileTime(_) => {
+                    self.file_time();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteFileTime(_) => {
+                    self.file_time();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDeleteAttribute(_) => {
+                    self.delete_attribute();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteDeleteAttribute(_) => {
+                    self.delete_attribute();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallDeleteHeadAttribute(_) => {
+                    self.delete_head_attribute();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteDeleteHeadAttribute(_) => {
+                    self.delete_head_attribute();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallDynamicModuleResolution(arity, _) => {
+                    let (module_name, key) = try_or_throw!(
+                        self.machine_st,
+                        self.dynamic_module_resolution(arity - 2)
+                    );
+
+                    try_or_throw!(self.machine_st, self.call_clause(module_name, key));
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::ExecuteDynamicModuleResolution(arity, _) => {
+                    let (module_name, key) = try_or_throw!(
+                        self.machine_st,
+                        self.dynamic_module_resolution(arity - 2)
+                    );
+
+                    try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
+
+                    if self.machine_st.fail {
+                        self.machine_st.backtrack();
+                    }
+                }
+                &Instruction::CallEnqueueAttributedVar(_) => {
+                    self.enqueue_attributed_var();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteEnqueueAttributedVar(_) => {
+                    self.enqueue_attributed_var();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallFetchGlobalVar(_) => {
+                    self.fetch_global_var();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteFetchGlobalVar(_) => {
+                    self.fetch_global_var();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallFirstStream(_) => {
+                    self.first_stream();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteFirstStream(_) => {
+                    self.first_stream();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallFlushOutput(_) => {
+                    try_or_throw!(self.machine_st, self.flush_output());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteFlushOutput(_) => {
+                    try_or_throw!(self.machine_st, self.flush_output());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallGetByte(_) => {
+                    try_or_throw!(self.machine_st, self.get_byte());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetByte(_) => {
+                    try_or_throw!(self.machine_st, self.get_byte());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetChar(_) => {
+                    try_or_throw!(self.machine_st, self.get_char());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetChar(_) => {
+                    try_or_throw!(self.machine_st, self.get_char());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetNChars(_) => {
+                    try_or_throw!(self.machine_st, self.get_n_chars());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetNChars(_) => {
+                    try_or_throw!(self.machine_st, self.get_n_chars());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetCode(_) => {
+                    try_or_throw!(self.machine_st, self.get_code());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetCode(_) => {
+                    try_or_throw!(self.machine_st, self.get_code());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetSingleChar(_) => {
+                    try_or_throw!(self.machine_st, self.get_single_char());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetSingleChar(_) => {
+                    try_or_throw!(self.machine_st, self.get_single_char());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallResetAttrVarState(_) => {
+                    self.reset_attr_var_state();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteResetAttrVarState(_) => {
+                    self.reset_attr_var_state();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff(_) => {
+                    self.truncate_if_no_lifted_heap_growth_diff();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff(_) => {
+                    self.truncate_if_no_lifted_heap_growth_diff();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallTruncateIfNoLiftedHeapGrowth(_) => {
+                    self.truncate_if_no_lifted_heap_growth();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth(_) => {
+                    self.truncate_if_no_lifted_heap_growth();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetAttributedVariableList(_) => {
+                    self.get_attributed_variable_list();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetAttributedVariableList(_) => {
+                    self.get_attributed_variable_list();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetAttrVarQueueDelimiter(_) => {
+                    self.get_attr_var_queue_delimiter();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetAttrVarQueueDelimiter(_) => {
+                    self.get_attr_var_queue_delimiter();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetAttrVarQueueBeyond(_) => {
+                    self.get_attr_var_queue_beyond();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetAttrVarQueueBeyond(_) => {
+                    self.get_attr_var_queue_beyond();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetBValue(_) => {
+                    self.get_b_value();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetBValue(_) => {
+                    self.get_b_value();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetContinuationChunk(_) => {
+                    self.get_continuation_chunk();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetContinuationChunk(_) => {
+                    self.get_continuation_chunk();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetNextDBRef(_) => {
+                    self.get_next_db_ref();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetNextDBRef(_) => {
+                    self.get_next_db_ref();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetNextOpDBRef(_) => {
+                    self.get_next_op_db_ref();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetNextOpDBRef(_) => {
+                    self.get_next_op_db_ref();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallIsPartialString(_) => {
+                    self.is_partial_string();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteIsPartialString(_) => {
+                    self.is_partial_string();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallHalt(_) => {
+                    self.halt();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteHalt(_) => {
+                    self.halt();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallGetLiftedHeapFromOffset(_) => {
+                    self.get_lifted_heap_from_offset();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetLiftedHeapFromOffset(_) => {
+                    self.get_lifted_heap_from_offset();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetLiftedHeapFromOffsetDiff(_) => {
+                    self.get_lifted_heap_from_offset_diff();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetLiftedHeapFromOffsetDiff(_) => {
+                    self.get_lifted_heap_from_offset_diff();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetSCCCleaner(_) => {
+                    self.get_scc_cleaner();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetSCCCleaner(_) => {
+                    self.get_scc_cleaner();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallHeadIsDynamic(_) => {
+                    self.head_is_dynamic();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteHeadIsDynamic(_) => {
+                    self.head_is_dynamic();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallInstallSCCCleaner(_) => {
+                    self.install_scc_cleaner();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteInstallSCCCleaner(_) => {
+                    self.install_scc_cleaner();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallInstallInferenceCounter(_) => {
+                    try_or_throw!(self.machine_st, self.install_inference_counter());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteInstallInferenceCounter(_) => {
+                    try_or_throw!(self.machine_st, self.install_inference_counter());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLiftedHeapLength(_) => {
+                    self.lifted_heap_length();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLiftedHeapLength(_) => {
+                    self.lifted_heap_length();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadLibraryAsStream(_) => {
+                    try_or_throw!(self.machine_st, self.load_library_as_stream());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadLibraryAsStream(_) => {
+                    try_or_throw!(self.machine_st, self.load_library_as_stream());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallModuleExists(_) => {
+                    self.module_exists();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteModuleExists(_) => {
+                    self.module_exists();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallNextEP(_) => {
+                    self.next_ep();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteNextEP(_) => {
+                    self.next_ep();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallNoSuchPredicate(_) => {
+                    try_or_throw!(self.machine_st, self.no_such_predicate());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteNoSuchPredicate(_) => {
+                    try_or_throw!(self.machine_st, self.no_such_predicate());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallNumberToChars(_) => {
+                    self.number_to_chars();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteNumberToChars(_) => {
+                    self.number_to_chars();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallNumberToCodes(_) => {
+                    self.number_to_codes();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteNumberToCodes(_) => {
+                    self.number_to_codes();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallOpDeclaration(_) => {
+                    try_or_throw!(self.machine_st, self.op_declaration());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteOpDeclaration(_) => {
+                    try_or_throw!(self.machine_st, self.op_declaration());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallOpen(_) => {
+                    try_or_throw!(self.machine_st, self.open());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteOpen(_) => {
+                    try_or_throw!(self.machine_st, self.open());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSetStreamOptions(_) => {
+                    try_or_throw!(self.machine_st, self.set_stream_options());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetStreamOptions(_) => {
+                    try_or_throw!(self.machine_st, self.set_stream_options());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallNextStream(_) => {
+                    self.next_stream();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteNextStream(_) => {
+                    self.next_stream();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPartialStringTail(_) => {
+                    self.partial_string_tail();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePartialStringTail(_) => {
+                    self.partial_string_tail();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPeekByte(_) => {
+                    try_or_throw!(self.machine_st, self.peek_byte());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePeekByte(_) => {
+                    try_or_throw!(self.machine_st, self.peek_byte());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPeekChar(_) => {
+                    try_or_throw!(self.machine_st, self.peek_char());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePeekChar(_) => {
+                    try_or_throw!(self.machine_st, self.peek_char());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPeekCode(_) => {
+                    try_or_throw!(self.machine_st, self.peek_code());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePeekCode(_) => {
+                    try_or_throw!(self.machine_st, self.peek_code());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPointsToContinuationResetMarker(_) => {
+                    self.points_to_continuation_reset_marker();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePointsToContinuationResetMarker(_) => {
+                    self.points_to_continuation_reset_marker();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPutByte(_) => {
+                    try_or_throw!(self.machine_st, self.put_byte());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecutePutByte(_) => {
+                    try_or_throw!(self.machine_st, self.put_byte());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallPutChar(_) => {
+                    try_or_throw!(self.machine_st, self.put_char());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecutePutChar(_) => {
+                    try_or_throw!(self.machine_st, self.put_char());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallPutChars(_) => {
+                    try_or_throw!(self.machine_st, self.put_chars());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePutChars(_) => {
+                    try_or_throw!(self.machine_st, self.put_chars());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPutCode(_) => {
+                    try_or_throw!(self.machine_st, self.put_code());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecutePutCode(_) => {
+                    try_or_throw!(self.machine_st, self.put_code());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallReadQueryTerm(_) => {
+                    try_or_throw!(self.machine_st, self.read_query_term());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteReadQueryTerm(_) => {
+                    try_or_throw!(self.machine_st, self.read_query_term());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallReadTerm(_) => {
+                    try_or_throw!(self.machine_st, self.read_term());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteReadTerm(_) => {
+                    try_or_throw!(self.machine_st, self.read_term());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallRedoAttrVarBinding(_) => {
+                    self.redo_attr_var_binding();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteRedoAttrVarBinding(_) => {
+                    self.redo_attr_var_binding();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallRemoveCallPolicyCheck(_) => {
+                    self.remove_call_policy_check();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteRemoveCallPolicyCheck(_) => {
+                    self.remove_call_policy_check();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallRemoveInferenceCounter(_) => {
+                    self.remove_inference_counter();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteRemoveInferenceCounter(_) => {
+                    self.remove_inference_counter();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallResetContinuationMarker(_) => {
+                    self.reset_continuation_marker();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteResetContinuationMarker(_) => {
+                    self.reset_continuation_marker();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallRestoreCutPolicy(_) => {
+                    self.restore_cut_policy();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteRestoreCutPolicy(_) => {
+                    self.restore_cut_policy();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallSetCutPoint(r, _) => {
+                    if !self.set_cut_point(r) {
+                        step_or_fail!(self, self.machine_st.p += 1);
+                    }
+                }
+                &Instruction::ExecuteSetCutPoint(r, _) => {
+                    let cp = self.machine_st.cp;
+
+                    if !self.set_cut_point(r) {
+                        step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                    } else {
+                        // run_cleaners in set_cut_point calls call_by_index.
+                        // replace the effect of call_by_index with that
+                        // of execute_by_index here.
+
+                        self.machine_st.cp = cp;
+                    }
+                }
+                &Instruction::CallSetInput(_) => {
+                    try_or_throw!(self.machine_st, self.set_input());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetInput(_) => {
+                    try_or_throw!(self.machine_st, self.set_input());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallSetOutput(_) => {
+                    try_or_throw!(self.machine_st, self.set_output());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetOutput(_) => {
+                    try_or_throw!(self.machine_st, self.set_output());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallStoreBacktrackableGlobalVar(_) => {
+                    self.store_backtrackable_global_var();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteStoreBacktrackableGlobalVar(_) => {
+                    self.store_backtrackable_global_var();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallStoreGlobalVar(_) => {
+                    self.store_global_var();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteStoreGlobalVar(_) => {
+                    self.store_global_var();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallStreamProperty(_) => {
+                    try_or_throw!(self.machine_st, self.stream_property());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteStreamProperty(_) => {
+                    try_or_throw!(self.machine_st, self.stream_property());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSetStreamPosition(_) => {
+                    try_or_throw!(self.machine_st, self.set_stream_position());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSetStreamPosition(_) => {
+                    try_or_throw!(self.machine_st, self.set_stream_position());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallInferenceLevel(_) => {
+                    self.inference_level();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteInferenceLevel(_) => {
+                    self.inference_level();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCleanUpBlock(_) => {
+                    self.clean_up_block();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteCleanUpBlock(_) => {
+                    self.clean_up_block();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallEraseBall(_) => {
+                    self.erase_ball();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteEraseBall(_) => {
+                    self.erase_ball();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallFail(_) | &Instruction::ExecuteFail(_) => {
+                    self.machine_st.backtrack();
+                }
+                &Instruction::CallGetBall(_) => {
+                    self.get_ball();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetBall(_) => {
+                    self.get_ball();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetCurrentBlock(_) => {
+                    self.get_current_block();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetCurrentBlock(_) => {
+                    self.get_current_block();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetCutPoint(_) => {
+                    self.get_cut_point();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetCutPoint(_) => {
+                    self.get_cut_point();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetStaggeredCutPoint(_) => {
+                    self.get_staggered_cut_point();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetStaggeredCutPoint(_) => {
+                    self.get_staggered_cut_point();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetDoubleQuotes(_) => {
+                    self.get_double_quotes();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetDoubleQuotes(_) => {
+                    self.get_double_quotes();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallInstallNewBlock(_) => {
+                    self.machine_st.install_new_block(self.machine_st.registers[1]);
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteInstallNewBlock(_) => {
+                    self.machine_st.install_new_block(self.machine_st.registers[1]);
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallMaybe(_) => {
+                    self.maybe();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteMaybe(_) => {
+                    self.maybe();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCpuNow(_) => {
+                    self.cpu_now();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCpuNow(_) => {
+                    self.cpu_now();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCurrentTime(_) => {
+                    self.current_time();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCurrentTime(_) => {
+                    self.current_time();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallQuotedToken(_) => {
+                    self.quoted_token();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteQuotedToken(_) => {
+                    self.quoted_token();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallReadTermFromChars(_) => {
+                    try_or_throw!(self.machine_st, self.read_term_from_chars());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteReadTermFromChars(_) => {
+                    try_or_throw!(self.machine_st, self.read_term_from_chars());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallResetBlock(_) => {
+                    self.reset_block();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteResetBlock(_) => {
+                    self.reset_block();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallReturnFromVerifyAttr(_) |
+                &Instruction::ExecuteReturnFromVerifyAttr(_) => {
+                    self.return_from_verify_attr();
+                }
+                &Instruction::CallSetBall(_) => {
+                    self.set_ball();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetBall(_) => {
+                    self.set_ball();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallSetCutPointByDefault(r, _) => {
+                    self.set_cut_point_by_default(r);
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSetCutPointByDefault(r, _) => {
+                    self.set_cut_point_by_default(r);
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSetDoubleQuotes(_) => {
+                    self.set_double_quotes();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSetDoubleQuotes(_) => {
+                    self.set_double_quotes();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSetSeed(_) => {
+                    self.set_seed();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSetSeed(_) => {
+                    self.set_seed();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSkipMaxList(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.skip_max_list());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSkipMaxList(_) => {
+                    try_or_throw!(self.machine_st, self.machine_st.skip_max_list());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSleep(_) => {
+                    self.sleep();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSleep(_) => {
+                    self.sleep();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallSocketClientOpen(_) => {
+                    try_or_throw!(self.machine_st, self.socket_client_open());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSocketClientOpen(_) => {
+                    try_or_throw!(self.machine_st, self.socket_client_open());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSocketServerOpen(_) => {
+                    try_or_throw!(self.machine_st, self.socket_server_open());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSocketServerOpen(_) => {
+                    try_or_throw!(self.machine_st, self.socket_server_open());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSocketServerAccept(_) => {
+                    try_or_throw!(self.machine_st, self.socket_server_accept());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteSocketServerAccept(_) => {
+                    try_or_throw!(self.machine_st, self.socket_server_accept());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSocketServerClose(_) => {
+                    try_or_throw!(self.machine_st, self.socket_server_close());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSocketServerClose(_) => {
+                    try_or_throw!(self.machine_st, self.socket_server_close());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallTLSAcceptClient(_) => {
+                    try_or_throw!(self.machine_st, self.tls_accept_client());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTLSAcceptClient(_) => {
+                    try_or_throw!(self.machine_st, self.tls_accept_client());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallTLSClientConnect(_) => {
+                    try_or_throw!(self.machine_st, self.tls_client_connect());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTLSClientConnect(_) => {
+                    try_or_throw!(self.machine_st, self.tls_client_connect());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSucceed(_) => {
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSucceed(_) => {
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallTermAttributedVariables(_) => {
+                    self.term_attributed_variables();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTermAttributedVariables(_) => {
+                    self.term_attributed_variables();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallTermVariables(_) => {
+                    self.term_variables();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTermVariables(_) => {
+                    self.term_variables();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallTermVariablesUnderMaxDepth(_) => {
+                    self.term_variables_under_max_depth();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteTermVariablesUnderMaxDepth(_) => {
+                    self.term_variables_under_max_depth();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallTruncateLiftedHeapTo(_) => {
+                    self.truncate_lifted_heap_to();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteTruncateLiftedHeapTo(_) => {
+                    self.truncate_lifted_heap_to();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallUnifyWithOccursCheck(_) => {
+                    self.unify_with_occurs_check();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteUnifyWithOccursCheck(_) => {
+                    self.unify_with_occurs_check();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallUnwindEnvironments(_) => {
+                    if !self.unwind_environments() {
+                        self.machine_st.p += 1;
+                    }
+                }
+                &Instruction::ExecuteUnwindEnvironments(_) => {
+                    if !self.unwind_environments() {
+                        self.machine_st.p = self.machine_st.cp;
+                    }
+                }
+                &Instruction::CallUnwindStack(_) | &Instruction::ExecuteUnwindStack(_) => {
+                    self.machine_st.unwind_stack();
+                    self.machine_st.backtrack();
+                }
+                &Instruction::CallWAMInstructions(_) => {
+                    try_or_throw!(self.machine_st, self.wam_instructions());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteWAMInstructions(_) => {
+                    try_or_throw!(self.machine_st, self.wam_instructions());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallWriteTerm(_) => {
+                    try_or_throw!(self.machine_st, self.write_term());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteWriteTerm(_) => {
+                    try_or_throw!(self.machine_st, self.write_term());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallWriteTermToChars(_) => {
+                    try_or_throw!(self.machine_st, self.write_term_to_chars());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteWriteTermToChars(_) => {
+                    try_or_throw!(self.machine_st, self.write_term_to_chars());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallScryerPrologVersion(_) => {
+                    self.scryer_prolog_version();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteScryerPrologVersion(_) => {
+                    self.scryer_prolog_version();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoRandomByte(_) => {
+                    self.crypto_random_byte();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoRandomByte(_) => {
+                    self.crypto_random_byte();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoDataHash(_) => {
+                    self.crypto_data_hash();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoDataHash(_) => {
+                    self.crypto_data_hash();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoDataHKDF(_) => {
+                    self.crypto_data_hkdf();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoDataHKDF(_) => {
+                    self.crypto_data_hkdf();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoPasswordHash(_) => {
+                    self.crypto_password_hash();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoPasswordHash(_) => {
+                    self.crypto_password_hash();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoDataEncrypt(_) => {
+                    self.crypto_data_encrypt();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoDataEncrypt(_) => {
+                    self.crypto_data_encrypt();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoDataDecrypt(_) => {
+                    self.crypto_data_decrypt();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoDataDecrypt(_) => {
+                    self.crypto_data_decrypt();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCryptoCurveScalarMult(_) => {
+                    self.crypto_curve_scalar_mult();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCryptoCurveScalarMult(_) => {
+                    self.crypto_curve_scalar_mult();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallEd25519Sign(_) => {
+                    self.ed25519_sign();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteEd25519Sign(_) => {
+                    self.ed25519_sign();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallEd25519Verify(_) => {
+                    self.ed25519_verify();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteEd25519Verify(_) => {
+                    self.ed25519_verify();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallEd25519NewKeyPair(_) => {
+                    self.ed25519_new_key_pair();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteEd25519NewKeyPair(_) => {
+                    self.ed25519_new_key_pair();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallEd25519KeyPairPublicKey(_) => {
+                    self.ed25519_key_pair_public_key();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteEd25519KeyPairPublicKey(_) => {
+                    self.ed25519_key_pair_public_key();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCurve25519ScalarMult(_) => {
+                    self.curve25519_scalar_mult();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCurve25519ScalarMult(_) => {
+                    self.curve25519_scalar_mult();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallFirstNonOctet(_) => {
+                    self.first_non_octet();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteFirstNonOctet(_) => {
+                    self.first_non_octet();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadHTML(_) => {
+                    self.load_html();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadHTML(_) => {
+                    self.load_html();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadXML(_) => {
+                    self.load_xml();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadXML(_) => {
+                    self.load_xml();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallGetEnv(_) => {
+                    self.get_env();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteGetEnv(_) => {
+                    self.get_env();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSetEnv(_) => {
+                    self.set_env();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetEnv(_) => {
+                    self.set_env();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallUnsetEnv(_) => {
+                    self.unset_env();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteUnsetEnv(_) => {
+                    self.unset_env();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallShell(_) => {
+                    self.shell();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteShell(_) => {
+                    self.shell();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPID(_) => {
+                    self.pid();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePID(_) => {
+                    self.pid();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallCharsBase64(_) => {
+                    try_or_throw!(self.machine_st, self.chars_base64());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteCharsBase64(_) => {
+                    try_or_throw!(self.machine_st, self.chars_base64());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDevourWhitespace(_) => {
+                    try_or_throw!(self.machine_st, self.devour_whitespace());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDevourWhitespace(_) => {
+                    try_or_throw!(self.machine_st, self.devour_whitespace());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallIsSTOEnabled(_) => {
+                    self.is_sto_enabled();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteIsSTOEnabled(_) => {
+                    self.is_sto_enabled();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallSetSTOAsUnify(_) => {
+                    self.set_sto_as_unify();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetSTOAsUnify(_) => {
+                    self.set_sto_as_unify();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallSetNSTOAsUnify(_) => {
+                    self.set_nsto_as_unify();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetNSTOAsUnify(_) => {
+                    self.set_nsto_as_unify();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallSetSTOWithErrorAsUnify(_) => {
+                    self.set_sto_with_error_as_unify();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteSetSTOWithErrorAsUnify(_) => {
+                    self.set_sto_with_error_as_unify();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallHomeDirectory(_) => {
+                    self.home_directory();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteHomeDirectory(_) => {
+                    self.home_directory();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDebugHook(_) => {
+                    self.debug_hook();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteDebugHook(_) => {
+                    self.debug_hook();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallPopCount(_) => {
+                    self.pop_count();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePopCount(_) => {
+                    self.pop_count();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallAddDiscontiguousPredicate(_) => {
+                    try_or_throw!(self.machine_st, self.add_discontiguous_predicate());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddDiscontiguousPredicate(_) => {
+                    try_or_throw!(self.machine_st, self.add_discontiguous_predicate());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAddDynamicPredicate(_) => {
+                    try_or_throw!(self.machine_st, self.add_dynamic_predicate());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddDynamicPredicate(_) => {
+                    try_or_throw!(self.machine_st, self.add_dynamic_predicate());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAddMultifilePredicate(_) => {
+                    try_or_throw!(self.machine_st, self.add_multifile_predicate());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddMultifilePredicate(_) => {
+                    try_or_throw!(self.machine_st, self.add_multifile_predicate());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAddGoalExpansionClause(_) => {
+                    try_or_throw!(self.machine_st, self.add_goal_expansion_clause());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddGoalExpansionClause(_) => {
+                    try_or_throw!(self.machine_st, self.add_goal_expansion_clause());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAddTermExpansionClause(_) => {
+                    try_or_throw!(self.machine_st, self.add_term_expansion_clause());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddTermExpansionClause(_) => {
+                    try_or_throw!(self.machine_st, self.add_term_expansion_clause());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAddInSituFilenameModule(_) => {
+                    try_or_throw!(self.machine_st, self.add_in_situ_filename_module());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddInSituFilenameModule(_) => {
+                    try_or_throw!(self.machine_st, self.add_in_situ_filename_module());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallClauseToEvacuable(_) => {
+                    try_or_throw!(self.machine_st, self.clause_to_evacuable());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteClauseToEvacuable(_) => {
+                    try_or_throw!(self.machine_st, self.clause_to_evacuable());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallScopedClauseToEvacuable(_) => {
+                    try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteScopedClauseToEvacuable(_) => {
+                    try_or_throw!(self.machine_st, self.scoped_clause_to_evacuable());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallConcludeLoad(_) => {
+                    try_or_throw!(self.machine_st, self.conclude_load());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteConcludeLoad(_) => {
+                    try_or_throw!(self.machine_st, self.conclude_load());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallDeclareModule(_) => {
+                    try_or_throw!(self.machine_st, self.declare_module());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteDeclareModule(_) => {
+                    try_or_throw!(self.machine_st, self.declare_module());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallLoadCompiledLibrary(_) => {
+                    try_or_throw!(self.machine_st, self.load_compiled_library());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadCompiledLibrary(_) => {
+                    try_or_throw!(self.machine_st, self.load_compiled_library());
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadContextSource(_) => {
+                    self.load_context_source();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadContextSource(_) => {
+                    self.load_context_source();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadContextFile(_) => {
+                    self.load_context_file();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadContextFile(_) => {
+                    self.load_context_file();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadContextDirectory(_) => {
+                    self.load_context_directory();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadContextDirectory(_) => {
+                    self.load_context_directory();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadContextModule(_) => {
+                    self.load_context_module();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadContextModule(_) => {
+                    self.load_context_module();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallLoadContextStream(_) => {
+                    self.load_context_stream();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteLoadContextStream(_) => {
+                    self.load_context_stream();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallPopLoadContext(_) => {
+                    self.pop_load_context();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecutePopLoadContext(_) => {
+                    self.pop_load_context();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallPopLoadStatePayload(_) => {
+                    self.pop_load_state_payload();
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecutePopLoadStatePayload(_) => {
+                    self.pop_load_state_payload();
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallPushLoadContext(_) => {
+                    try_or_throw!(self.machine_st, self.push_load_context());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecutePushLoadContext(_) => {
+                    try_or_throw!(self.machine_st, self.push_load_context());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallPushLoadStatePayload(_) => {
+                    self.push_load_state_payload();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecutePushLoadStatePayload(_) => {
+                    self.push_load_state_payload();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallUseModule(_) => {
+                    try_or_throw!(self.machine_st, self.use_module());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteUseModule(_) => {
+                    try_or_throw!(self.machine_st, self.use_module());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallBuiltInProperty(_) => {
+                    self.builtin_property();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteBuiltInProperty(_) => {
+                    self.builtin_property();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallMetaPredicateProperty(_) => {
+                    self.meta_predicate_property();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteMetaPredicateProperty(_) => {
+                    self.meta_predicate_property();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallMultifileProperty(_) => {
+                    self.multifile_property();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteMultifileProperty(_) => {
+                    self.multifile_property();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDiscontiguousProperty(_) => {
+                    self.discontiguous_property();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDiscontiguousProperty(_) => {
+                    self.discontiguous_property();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallDynamicProperty(_) => {
+                    self.dynamic_property();
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteDynamicProperty(_) => {
+                    self.dynamic_property();
+                    step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+                }
+                &Instruction::CallAbolishClause(_) => {
+                    try_or_throw!(self.machine_st, self.abolish_clause());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAbolishClause(_) => {
+                    try_or_throw!(self.machine_st, self.abolish_clause());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAsserta(_) => {
+                    try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Prepend));
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAsserta(_) => {
+                    try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Prepend));
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAssertz(_) => {
+                    try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Append));
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAssertz(_) => {
+                    try_or_throw!(self.machine_st, self.compile_assert(AppendOrPrepend::Append));
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallRetract(_) => {
+                    try_or_throw!(self.machine_st, self.retract_clause());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteRetract(_) => {
+                    try_or_throw!(self.machine_st, self.retract_clause());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallIsConsistentWithTermQueue(_) => {
+                    try_or_throw!(self.machine_st, self.is_consistent_with_term_queue());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::ExecuteIsConsistentWithTermQueue(_) => {
+                    try_or_throw!(self.machine_st, self.is_consistent_with_term_queue());
+                    step_or_fail!(self, self.machine_st.p += 1);
+                }
+                &Instruction::CallFlushTermQueue(_) => {
+                    try_or_throw!(self.machine_st, self.flush_term_queue());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteFlushTermQueue(_) => {
+                    try_or_throw!(self.machine_st, self.flush_term_queue());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallRemoveModuleExports(_) => {
+                    try_or_throw!(self.machine_st, self.remove_module_exports());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteRemoveModuleExports(_) => {
+                    try_or_throw!(self.machine_st, self.remove_module_exports());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+                &Instruction::CallAddNonCountedBacktracking(_) => {
+                    try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
+                    self.machine_st.p += 1;
+                }
+                &Instruction::ExecuteAddNonCountedBacktracking(_) => {
+                    try_or_throw!(self.machine_st, self.add_non_counted_backtracking());
+                    self.machine_st.p = self.machine_st.cp;
+                }
+            }
+        }
+
+        let interrupted = INTERRUPT.load(std::sync::atomic::Ordering::Relaxed);
+
+        match 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();
+                }
+            }
+            Err(_) => unreachable!(),
+        }
         }
     }
 }
index 1b7f83fee35a17ac04730e6241857d94ba786c58..1f9c80dce7637cc84d98c37bfbde4f55b9d3d932 100644 (file)
@@ -4,7 +4,6 @@ use crate::types::*;
 
 use core::marker::PhantomData;
 
-// TODO: rename to 'unmark_if_iter', 'mark_if_gc'
 pub(crate) trait UnmarkPolicy {
     fn unmark(heap: &mut [HeapCellValue], current: usize) -> bool;
     fn mark(heap: &mut [HeapCellValue], current: usize);
index cb166b692233a690cbd177a93d40dee8410aefa1..6a5e14ef7115d4218176f0e535dc9feda8f25413 100644 (file)
@@ -1,7 +1,6 @@
 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::types::*;
@@ -251,7 +250,7 @@ where
     filtered_iter_to_heap_list(heap, values, |_, _| true)
 }
 
-pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<LocalCodePtr> {
+pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<usize> {
     let extract_integer = |s: usize| -> Option<usize> {
         match Number::try_from(heap[s]) {
             Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
@@ -265,7 +264,7 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<Loca
             let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
 
             if name == atom!("dir_entry") && arity == 1 {
-                extract_integer(s+1).map(LocalCodePtr::DirEntry)
+                extract_integer(s+1)
             } else {
                 panic!(
                     "to_local_code_ptr crashed with p.i. {}/{}",
@@ -279,182 +278,3 @@ pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option<Loca
         }
     )
 }
-
-/*
-impl<T: RawBlockTraits> HeapTemplate<T> {
-    #[inline]
-    pub(crate) fn new() -> Self {
-        HeapTemplate {
-            buf: RawBlock::new(),
-            _marker: PhantomData,
-        }
-    }
-
-    /*
-        // TODO: move this to the WAM, then remove the temporary (and by
-        // then, unnecessary and impossible) "arena" argument. OR, remove
-        // this thing totally!  if we can. by that I mean, just convert a
-        // little to a HeapCellValue. don't bother writing to the
-        // heap at all. Each of these data is either already inlinable in a
-        // HeapCellValue or a pointer to an GC'ed location in memory.
-        #[inline]
-        pub(crate) fn put_literal(&mut self, literal: Literal) -> HeapCellValue {
-            match literal {
-                Literal::Atom(name) => atom_as_cell!(name),
-                Literal::Char(c) => char_as_cell!(c),
-                Literal::EmptyList => empty_list_as_cell!(),
-                Literal::Fixnum(n) => fixnum_as_cell!(n),
-                Literal::Integer(bigint_ptr) => {
-                    let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr));
-                    self[h]
-                }
-                Literal::Rational(bigint_ptr) => {
-                    let h = self.push(typed_arena_ptr_as_cell!(bigint_ptr));
-                    self[h]
-                }
-                Literal::Float(f) => typed_arena_ptr_as_cell!(f),
-                Literal::String(s) => {
-                    if s.as_str().is_empty() {
-                        empty_list_as_cell!()
-                    } else {
-                        // TODO: how do we know where the tail is located?? well, there is no tail. separate tag?
-                        untyped_arena_ptr_as_cell!(s) // self.put_complete_string(arena, &s)
-                    }
-                } // Literal::Usize(n) => Addr::Usize(n),
-            }
-        }
-    */
-
-    #[inline]
-    pub(crate) fn is_empty(&self) -> bool {
-        self.h() == 0
-    }
-
-    #[inline]
-    pub(crate) fn pop(&mut self) {
-        let h = self.h();
-
-        if h > 0 {
-            self.truncate(h - 1);
-        }
-    }
-
-    #[inline]
-    pub(crate) fn push(&mut self, val: HeapCellValue) -> usize {
-        let h = self.h();
-
-        unsafe {
-            let new_ptr = self.buf.alloc(mem::size_of::<HeapCellValue>());
-            ptr::write(new_ptr as *mut _, val);
-        }
-
-        h
-    }
-
-    /*
-    #[inline]
-    pub(crate) fn atom_at(&self, h: usize) -> bool {
-        if let HeapCellValue::Atom(..) = &self[h] {
-            true
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub(crate) fn to_unifiable(&mut self, non_heap_value: HeapCellValue) -> Addr {
-        match non_heap_value {
-            HeapCellValue::Addr(addr) => addr,
-            val @ HeapCellValue::Atom(..)
-            | val @ HeapCellValue::Integer(_)
-            | val @ HeapCellValue::DBRef(_)
-            | val @ HeapCellValue::Rational(_) => Addr::Con(self.push(val)),
-            val @ HeapCellValue::LoadStatePayload(_) => Addr::LoadStatePayload(self.push(val)),
-            val @ HeapCellValue::NamedStr(..) => Addr::Str(self.push(val)),
-            HeapCellValue::PartialString(pstr, has_tail) => {
-                let h = self.push(HeapCellValue::PartialString(pstr, has_tail));
-
-                if has_tail {
-                    self.push(HeapCellValue::Addr(Addr::EmptyList));
-                }
-
-                Addr::Con(h)
-            }
-            val @ HeapCellValue::Stream(..) => Addr::Stream(self.push(val)),
-            val @ HeapCellValue::TcpListener(..) => Addr::TcpListener(self.push(val)),
-        }
-    }
-    */
-
-    #[inline]
-    pub(crate) fn truncate(&mut self, h: usize) {
-        let new_ptr = self.buf.top as usize - h * mem::size_of::<HeapCellValue>();
-        self.buf.ptr = new_ptr as *mut _;
-    }
-
-    #[inline]
-    pub(crate) fn h(&self) -> usize {
-        (self.buf.top as usize - self.buf.ptr as usize) / mem::size_of::<HeapCellValue>()
-    }
-
-    pub(crate) fn append(&mut self, vals: Vec<HeapCellValue>) {
-        for val in vals {
-            self.push(val);
-        }
-    }
-
-    pub(crate) fn clear(&mut self) {
-        if !self.buf.base.is_null() {
-            self.truncate(0);
-            self.buf.top = self.buf.base;
-        }
-    }
-
-    /* TODO: get rid of this!!
-    #[inline]
-    pub(crate) fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
-        match addr {
-            &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
-                RefOrOwned::Borrowed(&self[h])
-            }
-            addr => RefOrOwned::Owned(HeapCellValue::Addr(*addr)),
-        }
-    }
-    */
-}
-
-impl<T: RawBlockTraits> Index<u64> for HeapTemplate<T> {
-    type Output = HeapCellValue;
-
-    #[inline]
-    fn index(&self, index: u64) -> &Self::Output {
-        unsafe {
-            let ptr =
-                self.buf.top as usize - (index as usize + 1) * mem::size_of::<HeapCellValue>();
-            &*(ptr as *const HeapCellValue)
-        }
-    }
-}
-
-impl<T: RawBlockTraits> Index<usize> for HeapTemplate<T> {
-    type Output = HeapCellValue;
-
-    #[inline]
-    fn index(&self, index: usize) -> &Self::Output {
-        unsafe {
-            let ptr = self.buf.top as usize - (index + 1) * mem::size_of::<HeapCellValue>();
-            &*(ptr as *const HeapCellValue)
-        }
-    }
-}
-
-impl<T: RawBlockTraits> IndexMut<usize> for HeapTemplate<T> {
-    #[inline]
-    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
-        unsafe {
-            let ptr = self.buf.top as usize - (index + 1) * mem::size_of::<HeapCellValue>();
-            &mut *(ptr as *mut HeapCellValue)
-        }
-    }
-}
-*/
index 036c31d78b27043645c1ae040844a663989632f4..1ad94f157c4317283d11bd2f92f700bab668def7 100644 (file)
@@ -1,4 +1,3 @@
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
@@ -8,6 +7,7 @@ use crate::machine::term_stream::*;
 use crate::machine::*;
 use crate::parser::ast::*;
 
+use fxhash::FxBuildHasher;
 use indexmap::IndexSet;
 use ref_thread_local::RefThreadLocal;
 use slice_deque::{sdeq, SliceDeque};
@@ -753,7 +753,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
     pub(super) fn get_clause_type(&mut self, name: Atom, arity: usize) -> ClauseType {
         match ClauseType::from(name, arity) {
-            ClauseType::Named(name, arity, _) => {
+            ClauseType::Named(arity, name, _) => {
                 let payload_compilation_target = self.payload.compilation_target;
 
                 let idx = self.get_or_insert_code_index(
@@ -761,7 +761,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     payload_compilation_target,
                 );
 
-                ClauseType::Named(name, arity, idx)
+                ClauseType::Named(arity, name, idx)
             }
             ct => ct,
         }
@@ -774,11 +774,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
         arity: usize,
     ) -> ClauseType {
         match ClauseType::from(name, arity) {
-            ClauseType::Named(name, arity, _) => {
+            ClauseType::Named(arity, name, _) => {
                 let key = (name, arity);
                 let idx = self.get_or_insert_qualified_code_index(module_name, key);
 
-                ClauseType::Named(name, arity, idx)
+                ClauseType::Named(arity, name, idx)
             }
             ct => ct,
         }
@@ -922,7 +922,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
                 let local_extensible_predicates = mem::replace(
                     &mut module.local_extensible_predicates,
-                    LocalExtensiblePredicates::new(),
+                    LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
                 );
 
                 for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() {
@@ -1162,11 +1162,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
             let subloader: Loader<'_, BootstrappingLoadState> = Loader {
                 payload: BootstrappingLoadState(
-                    LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream)
+                    LoadStatePayload::new(self.wam_prelude.code.len(), term_stream)
                 ),
                 wam_prelude: MachinePreludeView {
                     indices: self.wam_prelude.indices,
-                    code_repo: self.wam_prelude.code_repo,
+                    code: self.wam_prelude.code,
                     load_contexts: self.wam_prelude.load_contexts,
                 }
             };
@@ -1225,11 +1225,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
 
             let subloader: Loader<'_, BootstrappingLoadState> = Loader {
                 payload: BootstrappingLoadState(
-                    LoadStatePayload::new(self.wam_prelude.code_repo.code.len(), term_stream),
+                    LoadStatePayload::new(self.wam_prelude.code.len(), term_stream),
                 ),
                 wam_prelude: MachinePreludeView {
                     indices: self.wam_prelude.indices,
-                    code_repo: self.wam_prelude.code_repo,
+                    code: self.wam_prelude.code,
                     load_contexts: self.wam_prelude.load_contexts,
                 }
             };
index 061452abc8427af2df02df1bb6a7f7295bcbe3f5..e4a40a20e1defab389e81046d8d23a0871bc11e8 100644 (file)
@@ -1,6 +1,5 @@
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
 use crate::indexing::*;
@@ -327,7 +326,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
             loader.compile_and_submit()?;
         }
 
-        let repo_len = loader.wam_prelude.code_repo.code.len();
+        let repo_len = loader.wam_prelude.code.len();
 
         loader
             .payload
@@ -363,7 +362,7 @@ pub struct Loader<'a, LS: LoadState<'a>> {
 impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
     #[inline]
     pub(super) fn new(wam: &'a mut Machine, term_stream: <LS as LoadState<'a>>::TS) -> Self {
-        let payload = LoadStatePayload::new(wam.code_repo.code.len(), term_stream);
+        let payload = LoadStatePayload::new(wam.code.len(), term_stream);
         let (wam_prelude, machine_st) = wam.prelude_view_and_machine_st();
 
         Self {
@@ -696,8 +695,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                 RetractionRecord::AddedIndex(index_key, clause_loc) => {
                     // WAS: inner_index_locs) => {
                     if let Some(index_loc) = index_key.switch_on_term_loc() {
-                        let indexing_code = match &mut self.wam_prelude.code_repo.code[index_loc] {
-                            Line::IndexingCode(indexing_code) => indexing_code,
+                        let indexing_code = match &mut self.wam_prelude.code[index_loc] {
+                            Instruction::IndexingCode(indexing_code) => indexing_code,
                             _ => {
                                 unreachable!()
                             }
@@ -743,10 +742,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     // write the retraction logic of this arm.
                 }
                 RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => {
-                    match self.wam_prelude.code_repo.code[instr_loc] {
-                        Line::Choice(ChoiceInstruction::TryMeElse(ref mut o))
-                        | Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o))
-                        | Line::Choice(ChoiceInstruction::DefaultRetryMeElse(ref mut o)) => {
+                    match self.wam_prelude.code[instr_loc] {
+                        Instruction::TryMeElse(ref mut o) |
+                        Instruction::RetryMeElse(ref mut o) |
+                        Instruction::DefaultRetryMeElse(ref mut o) => {
                             *o = offset;
                         }
                         _ => {
@@ -755,22 +754,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     }
                 }
                 RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => {
-                    match self.wam_prelude.code_repo.code[instr_loc] {
-                        Line::Choice(ref mut choice_instr) => {
-                            *choice_instr = if is_default {
-                                ChoiceInstruction::DefaultTrustMe(offset)
-                            } else {
-                                ChoiceInstruction::TrustMe(offset)
-                            };
-                        }
-                        _ => {
-                            unreachable!();
-                        }
-                    }
+                    self.wam_prelude.code[instr_loc] = if is_default {
+                        Instruction::DefaultTrustMe(offset)
+                    } else {
+                        Instruction::TrustMe(offset)
+                    };
                 }
                 RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => {
-                    match self.wam_prelude.code_repo.code[index_loc] {
-                        Line::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] {
+                    match self.wam_prelude.code[index_loc] {
+                        Instruction::IndexingCode(ref mut indexing_code) => match &mut indexing_code[0] {
                             IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(
                                 _,
                                 ref mut v,
@@ -784,16 +776,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     }
                 }
                 RetractionRecord::ModifiedTryMeElse(instr_loc, o) => {
-                    self.wam_prelude.code_repo.code[instr_loc] =
-                        Line::Choice(ChoiceInstruction::TryMeElse(o));
+                    self.wam_prelude.code[instr_loc] = Instruction::TryMeElse(o);
                 }
                 RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => {
-                    self.wam_prelude.code_repo.code[instr_loc] =
-                        Line::Choice(ChoiceInstruction::RetryMeElse(o));
+                    self.wam_prelude.code[instr_loc] = Instruction::RetryMeElse(o);
                 }
                 RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => {
-                    self.wam_prelude.code_repo.code[instr_loc] =
-                        Line::Control(ControlInstruction::RevJmpBy(o));
+                    self.wam_prelude.code[instr_loc] = Instruction::RevJmpBy(o);
                 }
                 RetractionRecord::SkeletonClausePopBack(compilation_target, key) => {
                     match self
@@ -959,7 +948,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     }
                 }
                 RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => {
-                    self.wam_prelude.code_repo.code[index_loc] = Line::IndexingCode(indexing_code);
+                    self.wam_prelude.code[index_loc] = Instruction::IndexingCode(indexing_code);
                 }
                 RetractionRecord::RemovedLocalSkeletonClauseLocations(
                     compilation_target,
@@ -992,34 +981,34 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
                     }
                 }
                 RetractionRecord::ReplacedDynamicElseOffset(instr_loc, next) => {
-                    match self.wam_prelude.code_repo.code[instr_loc] {
-                        Line::Choice(ChoiceInstruction::DynamicElse(
+                    match self.wam_prelude.code[instr_loc] {
+                        Instruction::DynamicElse(
                             _,
                             _,
                             NextOrFail::Next(ref mut o),
-                        ))
-                        | Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                        )
+                        | Instruction::DynamicInternalElse(
                             _,
                             _,
                             NextOrFail::Next(ref mut o),
-                        )) => {
+                        ) => {
                             *o = next;
                         }
                         _ => {}
                     }
                 }
                 RetractionRecord::AppendedNextOrFail(instr_loc, fail) => {
-                    match self.wam_prelude.code_repo.code[instr_loc] {
-                        Line::Choice(ChoiceInstruction::DynamicElse(
+                    match self.wam_prelude.code[instr_loc] {
+                        Instruction::DynamicElse(
                             _,
                             _,
                             ref mut next_or_fail,
-                        ))
-                        | Line::Choice(ChoiceInstruction::DynamicInternalElse(
+                        )
+                        | Instruction::DynamicInternalElse(
                             _,
                             _,
                             ref mut next_or_fail,
-                        )) => {
+                        ) => {
                             *next_or_fail = fail;
                         }
                         _ => {}
@@ -1384,7 +1373,7 @@ impl<'a> MachinePreludeView<'a> {
 }
 
 impl Machine {
-    pub(crate) fn use_module(&mut self) {
+    pub(crate) fn use_module(&mut self) -> CallResult {
         let subevacuable_addr = self
             .machine_st
             .store(self.machine_st.deref(self.machine_st.registers[2]));
@@ -1395,7 +1384,7 @@ impl Machine {
             match payload.compilation_target {
                 CompilationTarget::Module(module_name) => module_name,
                 CompilationTarget::User => {
-                    return;
+                    return Ok(());
                 }
             }
         });
@@ -1415,10 +1404,10 @@ impl Machine {
         };
 
         let result = use_module();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn load_compiled_library(&mut self) {
+    pub(crate) fn load_compiled_library(&mut self) -> CallResult {
         let library = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -1426,7 +1415,7 @@ impl Machine {
         if let Some(module) = self.indices.modules.get(&library) {
             if let ListingSource::DynamicallyGenerated = module.listing_src {
                 self.machine_st.fail = true;
-                return;
+                return Ok(());
             }
 
             let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
@@ -1444,13 +1433,14 @@ impl Machine {
             };
 
             let result = import_module();
-            self.restore_load_state_payload(result);
+            self.restore_load_state_payload(result)
         } else {
             self.machine_st.fail = true;
+            Ok(())
         }
     }
 
-    pub(crate) fn declare_module(&mut self) {
+    pub(crate) fn declare_module(&mut self) -> CallResult {
         let module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -1471,34 +1461,34 @@ impl Machine {
         };
 
         let result = declare_module();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
     #[inline]
-    pub(crate) fn add_discontiguous_predicate(&mut self) {
+    pub(crate) fn add_discontiguous_predicate(&mut self) -> CallResult {
         self.add_extensible_predicate_declaration(
             |loader, compilation_target, clause_name, arity| {
                 loader.add_discontiguous_predicate(compilation_target, clause_name, arity)
             },
-        );
+        )
     }
 
     #[inline]
-    pub(crate) fn add_dynamic_predicate(&mut self) {
+    pub(crate) fn add_dynamic_predicate(&mut self) -> CallResult {
         self.add_extensible_predicate_declaration(
             |loader, compilation_target, clause_name, arity| {
                 loader.add_dynamic_predicate(compilation_target, clause_name, arity)
             },
-        );
+        )
     }
 
     #[inline]
-    pub(crate) fn add_multifile_predicate(&mut self) {
+    pub(crate) fn add_multifile_predicate(&mut self) -> CallResult {
         self.add_extensible_predicate_declaration(
             |loader, compilation_target, clause_name, arity| {
                 loader.add_multifile_predicate(compilation_target, clause_name, arity)
             },
-        );
+        )
     }
 
     fn add_extensible_predicate_declaration(
@@ -1509,7 +1499,7 @@ impl Machine {
             Atom,
             usize,
         ) -> Result<(), SessionError>,
-    ) {
+    ) -> CallResult {
         let module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -1543,10 +1533,10 @@ impl Machine {
         };
 
         let result = add_predicate_decl();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn add_term_expansion_clause(&mut self) {
+    pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
         let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
 
         let add_clause = || {
@@ -1564,10 +1554,10 @@ impl Machine {
         };
 
         let result = add_clause();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn add_goal_expansion_clause(&mut self) {
+    pub(crate) fn add_goal_expansion_clause(&mut self) -> CallResult {
         let target_module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -1594,10 +1584,10 @@ impl Machine {
         };
 
         let result = add_clause();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn add_in_situ_filename_module(&mut self) {
+    pub(crate) fn add_in_situ_filename_module(&mut self) -> CallResult {
         let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
 
         let add_in_situ_filename_module = || {
@@ -1643,7 +1633,7 @@ impl Machine {
         };
 
         let result = add_in_situ_filename_module();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
     pub(crate) fn loader_from_heap_evacuable<'a>(
@@ -1668,15 +1658,13 @@ impl Machine {
     pub(crate) fn push_load_state_payload(&mut self) {
         let payload = arena_alloc!(
             LoadStatePayload::new(
-                self.code_repo.code.len(),
+                self.code.len(),
                 LiveTermStream::new(ListingSource::User),
             ),
             &mut self.machine_st.arena
         );
 
-        let var = self.machine_st.deref(
-            self.machine_st.registers[1]
-        );
+        let var = self.machine_st.deref(self.machine_st.registers[1]);
 
         self.machine_st.bind(
             var.as_var().unwrap(),
@@ -1718,38 +1706,40 @@ impl Machine {
         self.load_contexts.pop();
     }
 
-    pub(crate) fn push_load_context(&mut self) {
-        let stream = try_or_fail!(
-            self.machine_st,
-            self.machine_st.get_stream_or_alias(
-                self.machine_st.registers[1],
-                &self.indices.stream_aliases,
-                atom!("$push_load_context"),
-                2,
-            )
-        );
+    pub(crate) fn push_load_context(&mut self) -> CallResult {
+        let stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("$push_load_context"),
+            2,
+        )?;
 
         let path = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
         );
 
         self.load_contexts.push(LoadContext::new(path.as_str(), stream));
+        Ok(())
     }
 
     pub(crate) fn restore_load_state_payload(
         &mut self,
         result: Result<TypedArenaPtr<LiveLoadState>, SessionError>,
-    ) {
+    ) -> CallResult {
         match result {
             Ok(_payload) => {
+                Ok(())
             }
             Err(e) => {
-                self.throw_session_error(e, (atom!("load"), 1));
+                let err = self.machine_st.session_error(e);
+                let stub = functor_stub(atom!("load"), 1);
+
+                Err(self.machine_st.error_form(err, stub))
             }
         }
     }
 
-    pub(crate) fn scoped_clause_to_evacuable(&mut self) {
+    pub(crate) fn scoped_clause_to_evacuable(&mut self) -> CallResult {
         let module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -1762,18 +1752,18 @@ impl Machine {
         };
 
         let result = loader.read_and_enqueue_term(temp_v!(2), compilation_target);
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn clause_to_evacuable(&mut self) {
+    pub(crate) fn clause_to_evacuable(&mut self) -> CallResult {
         let loader = self.loader_from_heap_evacuable(temp_v!(2));
         let compilation_target = loader.payload.compilation_target;
 
         let result = loader.read_and_enqueue_term(temp_v!(1), compilation_target);
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn conclude_load(&mut self) {
+    pub(crate) fn conclude_load(&mut self) -> CallResult {
         let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
 
         let compile_final_terms = || {
@@ -1786,7 +1776,7 @@ impl Machine {
         };
 
         let result = compile_final_terms();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
     pub(crate) fn load_context_source(&mut self) {
@@ -1852,7 +1842,7 @@ impl Machine {
         }
     }
 
-    pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) {
+    pub(crate) fn compile_assert<'a>(&'a mut self, append_or_prepend: AppendOrPrepend) -> CallResult {
         let key = self
             .machine_st
             .read_predicate_key(self.machine_st[temp_v!(3)], self.machine_st[temp_v!(4)]);
@@ -1906,26 +1896,27 @@ impl Machine {
         };
 
         match compile_assert() {
-            Ok(_) => {}
+            Ok(_) => Ok(()),
             Err(e) => {
-                let error_pi = match append_or_prepend {
-                    AppendOrPrepend::Append  => (atom!("assertz"), 1),
-                    AppendOrPrepend::Prepend => (atom!("asserta"), 1),
+                let stub = match append_or_prepend {
+                    AppendOrPrepend::Append  => functor_stub(atom!("assertz"), 1),
+                    AppendOrPrepend::Prepend => functor_stub(atom!("asserta"), 1),
                 };
+                let err = self.machine_st.session_error(e);
 
-                self.throw_session_error(e, error_pi);
+                Err(self.machine_st.error_form(err, stub))
             }
         }
     }
 
-    pub(crate) fn abolish_clause(&mut self) {
+    pub(crate) fn abolish_clause(&mut self) -> CallResult {
         let module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
 
         let key = self
             .machine_st
-            .read_predicate_key(self.machine_st[temp_v!(2)], self.machine_st[temp_v!(3)]);
+            .read_predicate_key(self.machine_st.registers[2], self.machine_st.registers[3]);
 
         let compilation_target = match module_name {
             atom!("user") => CompilationTarget::User,
@@ -2000,14 +1991,16 @@ impl Machine {
         };
 
         match abolish_clause() {
-            Ok(_) => {}
+            Ok(_) => Ok(()),
             Err(e) => {
-                self.throw_session_error(e, (atom!("abolish"), 1));
+                let stub = functor_stub(atom!("abolish"), 1);
+                let err = self.machine_st.session_error(e);
+                Err(self.machine_st.error_form(err, stub))
             }
         }
     }
 
-    pub(crate) fn retract_clause(&mut self) {
+    pub(crate) fn retract_clause(&mut self) -> CallResult {
         let key = self
             .machine_st
             .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]);
@@ -2066,14 +2059,17 @@ impl Machine {
         };
 
         match retract_clause() {
-            Ok(_) => {}
+            Ok(_) => Ok(()),
             Err(e) => {
-                self.throw_session_error(e, (atom!("retract"), 1));
+                let stub = functor_stub(atom!("retract"), 1);
+                let err = self.machine_st.session_error(e);
+
+                Err(self.machine_st.error_form(err, stub))
             }
         }
     }
 
-    pub(crate) fn is_consistent_with_term_queue(&mut self) {
+    pub(crate) fn is_consistent_with_term_queue(&mut self) -> CallResult {
         let module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -2095,10 +2091,10 @@ impl Machine {
              || !key.is_consistent(&loader.payload.predicates);
 
         let result = LiveLoadAndMachineState::evacuate(loader);
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn flush_term_queue(&mut self) {
+    pub(crate) fn flush_term_queue(&mut self) -> CallResult {
         let mut loader = self.loader_from_heap_evacuable(temp_v!(1));
 
         let flush_term_queue = || {
@@ -2110,10 +2106,10 @@ impl Machine {
         };
 
         let result = flush_term_queue();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn remove_module_exports(&mut self) {
+    pub(crate) fn remove_module_exports(&mut self) -> CallResult {
         let module_name = cell_as_atom!(
             self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
         );
@@ -2126,10 +2122,10 @@ impl Machine {
         };
 
         let result = remove_module_exports();
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
-    pub(crate) fn add_non_counted_backtracking(&mut self) {
+    pub(crate) fn add_non_counted_backtracking(&mut self) -> CallResult {
         let key = self
             .machine_st
             .read_predicate_key(self.machine_st[temp_v!(1)], self.machine_st[temp_v!(2)]);
@@ -2138,7 +2134,7 @@ impl Machine {
         loader.payload.non_counted_bt_preds.insert(key);
 
         let result = LiveLoadAndMachineState::evacuate(loader);
-        self.restore_load_state_payload(result);
+        self.restore_load_state_payload(result)
     }
 
     pub(crate) fn meta_predicate_property(&mut self) {
@@ -2271,10 +2267,10 @@ impl Machine {
             .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
 
         match ClauseType::from(key.0, key.1) {
-            ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => {
+            ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN(_) => {
                 return;
             }
-            ClauseType::Named(name, arity, _) => {
+            ClauseType::Named(arity, name, _) => {
                 if let Some(module) = self.indices.modules.get(&(atom!("builtins"))) {
                     self.machine_st.fail = !module.code_dir.contains_key(&(name, arity));
                     return;
index cae977e556c938b630fef94e79ad595e687ee7a2..379100025b193a7aef042ae46e8be446ddae6bf8 100644 (file)
@@ -538,13 +538,18 @@ impl MachineState {
 
     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.into_iter());
 
-        self.registers[1] = str_loc_as_cell!(h);
+        self.registers[1] = if err_len == 1 {
+            heap_loc_as_cell!(h)
+        } else {
+            str_loc_as_cell!(h)
+        };
 
         self.set_ball();
         self.unwind_stack();
index 3f8d47e8f382a5144dbe068b0e7917e73b655d1c..5f9d08d5bab84ccfd08230750753b97b34574868 100644 (file)
@@ -2,30 +2,22 @@ use crate::parser::ast::*;
 
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::fixtures::*;
 use crate::forms::*;
 use crate::instructions::*;
-use crate::machine::*;
-use crate::machine::heap::*;
 use crate::machine::loader::*;
-use crate::machine::machine_errors::MachineStub;
 use crate::machine::machine_state::*;
 use crate::machine::streams::Stream;
 
+use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 
 use std::cell::Cell;
 use std::cmp::Ordering;
 use std::collections::BTreeSet;
-use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
+use std::ops::Deref;
 use std::rc::Rc;
 
-// these statics store the locations of one-off control instructions
-// in the code vector.
-
-pub static HALT_CODE: usize = 0;
-
 use crate::types::*;
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
@@ -134,6 +126,7 @@ impl Default for CodeIndex {
     }
 }
 
+/*
 #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
 pub enum REPLCodePtr {
     AddDiscontiguousPredicate,
@@ -174,156 +167,28 @@ pub enum REPLCodePtr {
 
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum CodePtr {
-    BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
-    CallN(usize, LocalCodePtr, bool),               // arity, local, last call.
-    Local(LocalCodePtr),
-    REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
+    BuiltInClause(BuiltInClauseType, usize), // local is the successor call.
+    CallN(usize, usize, bool),               // arity, local, last call.
+    Local(usize),
+    REPL(REPLCodePtr, usize), // the REPL code, the return pointer.
     VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
 }
 
 impl CodePtr {
-    pub(crate) fn local(&self) -> LocalCodePtr {
+    pub(crate) fn local(&self) -> usize {
         match self {
-            &CodePtr::BuiltInClause(_, ref local)
-            | &CodePtr::CallN(_, ref local, _)
-            | &CodePtr::Local(ref local) => local.clone(),
-            &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
-            &CodePtr::REPL(_, p) => p, // | &CodePtr::DynamicTransaction(_, p) => p,
+            &CodePtr::BuiltInClause(_, ref local) |
+            &CodePtr::CallN(_, ref local, _) |
+            &CodePtr::Local(ref local) => *local,
+            &CodePtr::VerifyAttrInterrupt(p) => p,
+            &CodePtr::REPL(_, p) => p,
         }
     }
 
-    #[inline]
-    pub(crate) fn is_halt(&self) -> bool {
-        if let CodePtr::Local(LocalCodePtr::Halt) = self {
-            true
-        } else {
-            false
-        }
-    }
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum LocalCodePtr {
-    DirEntry(usize), // offset
-    Halt,
-    // IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
-                                         // TopLevel(usize, usize), // chunk_num, offset
-}
-
-impl Machine {
-    pub(crate) fn is_reset_cont_marker(&self, p: LocalCodePtr) -> bool {
-        match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) {
-            Some(line) => match line.as_ref(&self.code_repo.code) {
-                Line::Control(ControlInstruction::CallClause(ref ct, ..)) => {
-                    if let ClauseType::System(SystemClauseType::ResetContinuationMarker) = *ct {
-                        return true;
-                    }
-                }
-                _ => {}
-            },
-            None => {}
-        }
-
-        false
-    }
-}
-
-impl LocalCodePtr {
-    pub fn assign_if_local(&mut self, cp: CodePtr) {
-        match cp {
-            CodePtr::Local(local) => *self = local,
-            _ => {}
-        }
-    }
-
-    #[inline]
-    pub fn abs_loc(&self) -> usize {
-        match self {
-            LocalCodePtr::DirEntry(ref p) => *p,
-            // LocalCodePtr::IndexingBuf(ref p, ..) => *p,
-            LocalCodePtr::Halt => unreachable!(),
-        }
-    }
-
-    pub(crate) fn as_functor(&self) -> MachineStub {
+    pub fn assign_if_local(&self, cp: &mut usize) {
         match self {
-            LocalCodePtr::DirEntry(p) => {
-                functor!(atom!("dir_entry"), [fixnum(*p)])
-            }
-            LocalCodePtr::Halt => {
-                functor!(atom!("halt"))
-            }
-            /*
-            LocalCodePtr::IndexingBuf(p, o, i) => {
-                functor!(
-                    atom!("indexed_buf"),
-                    [fixnum(*p), fixnum(*o), fixnum(*i)]
-                )
-            }
-            */
-        }
-    }
-}
-
-impl Default for CodePtr {
-    #[inline]
-    fn default() -> Self {
-        CodePtr::Local(LocalCodePtr::default())
-    }
-}
-
-impl Default for LocalCodePtr {
-    #[inline]
-    fn default() -> Self {
-        LocalCodePtr::DirEntry(0)
-    }
-}
-
-impl Add<usize> for LocalCodePtr {
-    type Output = LocalCodePtr;
-
-    #[inline]
-    fn add(self, rhs: usize) -> Self::Output {
-        match self {
-            LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs),
-            LocalCodePtr::Halt => unreachable!(),
-            // LocalCodePtr::IndexingBuf(p, o, i) => LocalCodePtr::IndexingBuf(p, o, i + rhs),
-        }
-    }
-}
-
-impl Sub<usize> for LocalCodePtr {
-    type Output = Option<LocalCodePtr>;
-
-    #[inline]
-    fn sub(self, rhs: usize) -> Self::Output {
-        match self {
-            LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
-            LocalCodePtr::Halt => unreachable!(),
-            // LocalCodePtr::IndexingBuf(p, o, i) => i
-            //     .checked_sub(rhs)
-            //     .map(|r| LocalCodePtr::IndexingBuf(p, o, r)),
-        }
-    }
-}
-
-impl SubAssign<usize> for LocalCodePtr {
-    #[inline]
-    fn sub_assign(&mut self, rhs: usize) {
-        match self {
-            LocalCodePtr::DirEntry(ref mut p) => *p -= rhs,
-            LocalCodePtr::Halt => unreachable!() // | LocalCodePtr::IndexingBuf(..) => unreachable!(),
-        }
-    }
-}
-
-impl AddAssign<usize> for LocalCodePtr {
-    #[inline]
-    fn add_assign(&mut self, rhs: usize) {
-        match self {
-            &mut LocalCodePtr::DirEntry(ref mut i) => *i += rhs,
-            // | &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
-            &mut LocalCodePtr::Halt => unreachable!(),
+            CodePtr::Local(local) => *cp = *local,
+            _ => {}
         }
     }
 }
@@ -333,7 +198,9 @@ impl Add<usize> for CodePtr {
 
     fn add(self, rhs: usize) -> Self::Output {
         match self {
-            p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => p,
+            p @ CodePtr::REPL(..) | p @ CodePtr::VerifyAttrInterrupt(_) => {
+                p
+            }
             CodePtr::Local(local) => CodePtr::Local(local + rhs),
             CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
                 CodePtr::Local(local + rhs)
@@ -362,20 +229,30 @@ impl SubAssign<usize> for CodePtr {
     }
 }
 
-pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue>;
-pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData>;
+impl Default for CodePtr {
+    #[inline]
+    fn default() -> Self {
+        CodePtr::Local(0)
+    }
+}
+*/
+
+pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
+pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
 
-pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>)>;
+pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
 
-pub(crate) type StreamAliasDir = IndexMap<Atom, Stream>;
+pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
 pub(crate) type StreamDir = BTreeSet<Stream>;
 
-pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
+pub(crate) type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>, FxBuildHasher>;
 
-pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton>;
+pub(crate) type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton, FxBuildHasher>;
 
 pub(crate) type LocalExtensiblePredicates =
-    IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>;
+    IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>;
+
+pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex, FxBuildHasher>;
 
 #[derive(Debug)]
 pub struct IndexStore {
@@ -504,14 +381,14 @@ impl IndexStore {
     ) -> Option<CodeIndex> {
         if module == atom!("user") {
             match ClauseType::from(name, arity) {
-                ClauseType::Named(name, arity, _) => self.code_dir.get(&(name, arity)).cloned(),
+                ClauseType::Named(arity, name, _) => self.code_dir.get(&(name, arity)).cloned(),
                 _ => None,
             }
         } else {
             self.modules
                 .get(&module)
                 .and_then(|module| match ClauseType::from(name, arity) {
-                    ClauseType::Named(name, arity, _) => {
+                    ClauseType::Named(arity, name, _) => {
                         module.code_dir.get(&(name, arity)).cloned()
                     }
                     _ => None,
@@ -561,8 +438,10 @@ impl IndexStore {
 
     #[inline]
     pub(super) fn new() -> Self {
-        index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
+        index_store!(
+            CodeDir::with_hasher(FxBuildHasher::default()),
+            default_op_dir(),
+            ModuleDir::with_hasher(FxBuildHasher::default())
+        )
     }
 }
-
-pub(crate) type CodeDir = IndexMap<PredicateKey, CodeIndex>;
index 6bd29da2ac644d942e66e0e27a9f0b5f334e0533..6da9674b28d78aa7389daa54cb84f67c882235fe 100644 (file)
@@ -55,14 +55,14 @@ pub struct MachineState {
     pub arena: Arena,
     pub(super) pdl: Vec<HeapCellValue>,
     pub(super) s: HeapPtr,
-    pub(super) p: CodePtr,
+    pub(super) p: usize,
     pub(super) oip: u32, // first internal code ptr
     pub(super) iip : u32, // second internal code ptr
     pub(super) b: usize,
     pub(super) b0: usize,
     pub(super) e: usize,
     pub(super) num_of_args: usize,
-    pub(super) cp: LocalCodePtr,
+    pub(super) cp: usize,
     pub(super) attr_var_init: AttrVarInitializer,
     pub(super) fail: bool,
     pub heap: Heap,
@@ -79,7 +79,6 @@ pub struct MachineState {
     // locations of cleaners, cut points, the previous block. for setup_call_cleanup.
     pub(super) cont_pts: Vec<(HeapCellValue, usize, usize)>,
     pub(super) cwil: CWIL,
-    pub(super) last_call: bool, // TODO: REMOVE THIS.
     pub(crate) flags: MachineFlags,
     pub(crate) cc: usize,
     pub(crate) global_clock: usize,
@@ -115,7 +114,6 @@ impl fmt::Debug for MachineState {
             .field("ball", &self.ball)
             .field("lifted_heap", &self.lifted_heap)
             .field("interms", &self.interms)
-            .field("last_call", &self.last_call)
             .field("flags", &self.flags)
             .field("cc", &self.cc)
             .field("global_clock", &self.global_clock)
@@ -365,6 +363,20 @@ impl<'a> CopierTarget for CopyBallTerm<'a> {
 }
 
 impl MachineState {
+    pub(crate) fn backtrack(&mut self) {
+        let b = self.b;
+        let or_frame = self.stack.index_or_frame(b);
+
+        self.b0 = or_frame.prelude.b0;
+        self.p = or_frame.prelude.bp;
+
+        self.oip = or_frame.prelude.boip;
+        self.iip = or_frame.prelude.biip;
+
+        self.pdl.clear();
+        self.fail = false;
+    }
+
     pub(crate) fn increment_call_count(&mut self) -> CallResult {
         if self.cwil.inference_limit_exceeded || self.ball.stub.len() > 0 {
             return Ok(());
@@ -422,17 +434,19 @@ impl MachineState {
         self.error_form(err, stub)
     }
 
-    pub(super) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) {
-        self.cp.assign_if_local(self.p + 1);
+    #[inline(always)]
+    pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
+        self.cp = self.p + 1;
+        self.p = p;
         self.num_of_args = arity;
         self.b0 = self.b;
-        self.p = CodePtr::Local(p);
     }
 
-    pub(super) fn execute_at_index(&mut self, arity: usize, p: LocalCodePtr) {
+    #[inline(always)]
+    pub(super) fn execute_at_index(&mut self, arity: usize, p: usize) {
         self.num_of_args = arity;
         self.b0 = self.b;
-        self.p = CodePtr::Local(p);
+        self.p = p;
     }
 
     pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
@@ -467,7 +481,7 @@ impl MachineState {
 
         if stream.past_end_of_stream() {
             if EOFAction::Reset != stream.options().eof_action() {
-                return return_from_clause!(self.last_call, self);
+                return Ok(());
             } else if self.fail {
                 return Ok(());
             }
@@ -710,7 +724,7 @@ impl MachineState {
         or_frame.prelude.e = self.e;
         or_frame.prelude.cp = self.cp;
         or_frame.prelude.b = self.b;
-        or_frame.prelude.bp = self.p.local() + offset;
+        or_frame.prelude.bp = self.p + offset;
         or_frame.prelude.boip = 0;
         or_frame.prelude.biip = 0;
         or_frame.prelude.tr = self.tr;
@@ -720,7 +734,7 @@ impl MachineState {
         self.b = b;
 
         for i in 0..n {
-            self.stack[stack_loc!(OrFrame, b, i)] = self.registers[i+1];
+            or_frame[i] = self.registers[i+1];
         }
 
         self.hb = self.heap.len();
@@ -737,7 +751,7 @@ impl MachineState {
         or_frame.prelude.e = self.e;
         or_frame.prelude.cp = self.cp;
         or_frame.prelude.b = self.b;
-        or_frame.prelude.bp = self.p.local(); // + 1; in self.iip now!
+        or_frame.prelude.bp = self.p; // + 1; in self.iip now!
         or_frame.prelude.boip = self.oip;
         or_frame.prelude.biip = self.iip + 1;
         or_frame.prelude.tr = self.tr;
@@ -751,7 +765,7 @@ impl MachineState {
         }
 
         self.hb = self.heap.len();
-        self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
+        self.p = self.p + offset;
 
         self.oip = 0;
         self.iip = 0;
index ee04d645b07059e352e00ea0ead42c3b074e0bed..6461f7f05309dcd0f5e4af65c05db6dbb8c0a521 100644 (file)
@@ -1,13 +1,11 @@
 use crate::arena::*;
 use crate::atom_table::*;
 use crate::types::*;
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
 use crate::machine::attributed_variables::*;
 use crate::machine::copier::*;
 use crate::machine::heap::*;
-use crate::machine::Machine;
 use crate::machine::machine_errors::*;
 use crate::machine::machine_indices::*;
 use crate::machine::machine_state::*;
@@ -23,11 +21,6 @@ use indexmap::IndexSet;
 use std::cmp::Ordering;
 use std::convert::TryFrom;
 
-// TODO: move this block to.. a place.
-impl Machine {
-
-}
-
 impl MachineState {
     pub(crate) fn new() -> Self {
         MachineState {
@@ -35,14 +28,14 @@ impl MachineState {
             atom_tbl: AtomTable::new(),
             pdl: Vec::with_capacity(1024),
             s: HeapPtr::default(),
-            p: CodePtr::default(),
+            p: 0,
             oip: 0,
             iip: 0,
             b: 0,
             b0: 0,
             e: 0,
             num_of_args: 0,
-            cp: LocalCodePtr::default(),
+            cp: 0,
             attr_var_init: AttrVarInitializer::new(0),
             fail: false,
             heap: Heap::with_capacity(256 * 256),
@@ -58,7 +51,6 @@ impl MachineState {
             interms: vec![Number::default();256],
             cont_pts: Vec::with_capacity(256),
             cwil: CWIL::new(),
-            last_call: false,
             flags: MachineFlags::default(),
             cc: 0,
             global_clock: 0,
@@ -202,16 +194,16 @@ impl MachineState {
             match r1.get_tag() {
                 RefTag::StackCell => {
                     self.stack[r1.get_value() as usize] = t2;
+                    self.trail(TrailRef::Ref(r1));
                 }
                 RefTag::HeapCell => {
                     self.heap[r1.get_value() as usize] = t2;
+                    self.trail(TrailRef::Ref(r1));
                 }
                 RefTag::AttrVar => {
                     self.bind_attr_var(r1.get_value() as usize, t2);
                 }
             };
-
-            self.trail(TrailRef::Ref(r1));
         } else {
             read_heap_cell!(a2,
                 (HeapCellValueTag::StackVar, s) => {
@@ -864,17 +856,6 @@ impl MachineState {
         );
     }
 
-    pub fn copy_term(&mut self, attr_var_policy: AttrVarPolicy) {
-        let old_h = self.heap.len();
-
-        let a1 = self.registers[1];
-        let a2 = self.registers[2];
-
-        copy_term(CopyTerm::new(self), a1, attr_var_policy);
-
-        unify_fn!(*self, heap_loc_as_cell!(old_h), a2);
-    }
-
     pub(super) fn unwind_stack(&mut self) {
         self.b = self.block;
         self.fail = true;
@@ -1912,9 +1893,6 @@ impl MachineState {
                 );
             }
             Some(PStrPrefixCmpResult { prefix_len, .. }) => {
-                // TODO: this is woefully insufficient! you need to
-                // match the remaining portion of string if offset <
-                // pstr.len().
                 let focus = heap_pstr_iter.focus();
                 let tail_addr = self.heap[focus];
 
@@ -1996,23 +1974,7 @@ impl MachineState {
         )
     }
 
-    pub(super) fn handle_internal_call_n(&mut self, arity: usize) {
-        let arity = arity + 1;
-        let pred = self.registers[1];
-
-        for i in 2..arity {
-            self.registers[i - 1] = self.registers[i];
-        }
-
-        if arity > 1 {
-            self.registers[arity - 1] = pred;
-            return;
-        }
-
-        self.fail = true;
-    }
-
-    pub(super) fn setup_call_n(&mut self, arity: usize) -> Option<PredicateKey> {
+    pub(super) fn setup_call_n(&mut self, arity: usize) -> Result<PredicateKey, MachineStub> {
         let addr = self.store(self.deref(self.registers[arity]));
 
         let (name, narity) = read_heap_cell!(addr,
@@ -2022,10 +1984,7 @@ impl MachineState {
                 if narity + arity > MAX_ARITY {
                     let stub = functor_stub(atom!("call"), arity + 1);
                     let err = self.representation_error(RepFlag::MaxArity);
-                    let representation_error = self.error_form(err, stub);
-
-                    self.throw_exception(representation_error);
-                    return None;
+                    return Err(self.error_form(err, stub));
                 }
 
                 for i in (1..arity).rev() {
@@ -2039,12 +1998,8 @@ impl MachineState {
                 (name, narity)
             }
             (HeapCellValueTag::Atom, (name, arity)) => {
-                if arity == 0 {
-                    (name, 0)
-                } else {
-                    self.fail = true;
-                    return None;
-                }
+                debug_assert_eq!(arity, 0);
+                (name, 0)
             }
             (HeapCellValueTag::Char, c) => {
                 (self.atom_tbl.build_with(&c.to_string()), 0)
@@ -2052,22 +2007,16 @@ impl MachineState {
             (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, _h) => {
                 let stub = functor_stub(atom!("call"), arity + 1);
                 let err = self.instantiation_error();
-                let instantiation_error = self.error_form(err, stub);
-
-                self.throw_exception(instantiation_error);
-                return None;
+                return Err(self.error_form(err, stub));
             }
             _ => {
                 let stub = functor_stub(atom!("call"), arity + 1);
                 let err = self.type_error(ValidType::Callable, addr);
-                let type_error = self.error_form(err, stub);
-
-                self.throw_exception(type_error);
-                return None;
+                return Err(self.error_form(err, stub));
             }
         );
 
-        Some((name, arity + narity - 1))
+        Ok((name, arity + narity - 1))
     }
 
     #[inline]
@@ -2233,45 +2182,6 @@ impl MachineState {
         Ok(())
     }
 
-    pub fn compare_numbers(&mut self, cmp: CompareNumberQT, n1: Number, n2: Number) {
-        let ordering = n1.cmp(&n2);
-
-        self.fail = match cmp {
-            CompareNumberQT::GreaterThan if ordering == Ordering::Greater => false,
-            CompareNumberQT::GreaterThanOrEqual if ordering != Ordering::Less => false,
-            CompareNumberQT::LessThan if ordering == Ordering::Less => false,
-            CompareNumberQT::LessThanOrEqual if ordering != Ordering::Greater => false,
-            CompareNumberQT::NotEqual if ordering != Ordering::Equal => false,
-            CompareNumberQT::Equal if ordering == Ordering::Equal => false,
-            _ => true,
-        };
-
-        self.p += 1;
-    }
-
-    pub fn compare_term(&mut self, qt: CompareTermQT) {
-        let a1 = self.registers[1];
-        let a2 = self.registers[2];
-
-        match compare_term_test!(self, a1, a2) {
-            Some(Ordering::Greater) => match qt {
-                CompareTermQT::GreaterThan | CompareTermQT::GreaterThanOrEqual => {}
-                _ => self.fail = true,
-            },
-            Some(Ordering::Equal) => match qt {
-                CompareTermQT::GreaterThanOrEqual | CompareTermQT::LessThanOrEqual => {}
-                _ => self.fail = true,
-            },
-            Some(Ordering::Less) => match qt {
-                CompareTermQT::LessThan | CompareTermQT::LessThanOrEqual => {}
-                _ => self.fail = true,
-            },
-            None => {
-                self.fail = true;
-            }
-        }
-    }
-
     // returns true on failure, false on success.
     pub fn eq_test(&mut self, h1: HeapCellValue, h2: HeapCellValue) -> bool {
         if h1 == h2 {
@@ -2652,12 +2562,14 @@ impl MachineState {
         )
     }
 
+    /*
     pub fn setup_built_in_call(&mut self, ct: BuiltInClauseType) {
         self.num_of_args = ct.arity();
         self.b0 = self.b;
 
         self.p = CodePtr::BuiltInClause(ct, self.p.local());
     }
+    */
 
     pub fn deallocate(&mut self) {
         let e = self.e;
index 7f73755ae6a40c6df061ce2109388d6b7f58df2e..0b4923daaa15704311946f7a90828643e988ce17 100644 (file)
@@ -227,7 +227,7 @@ impl Machine {
         let mut wam = Machine {
             machine_st,
             indices: IndexStore::new(),
-            code_repo: CodeRepo::new(),
+            code: Code::new(),
             user_input,
             user_output,
             user_error,
@@ -239,6 +239,8 @@ impl Machine {
         lib_path.pop();
         lib_path.push("lib");
 
+        wam.add_impls_to_indices();
+
         bootstrapping_compile(
             Stream::from_static_string(
                 LIBRARIES.borrow()["ops_and_meta_predicates"],
@@ -262,7 +264,7 @@ impl Machine {
         )
             .unwrap();
 
-        if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) {
+        if let Some(ref mut builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
             load_module(
                 &mut wam.indices.code_dir,
                 &mut wam.indices.op_dir,
@@ -270,6 +272,8 @@ impl Machine {
                 &CompilationTarget::User,
                 builtins,
             );
+
+            import_builtin_impls(&wam.indices.code_dir, builtins);
         } else {
             unreachable!()
         }
index b33df9d4a32ab06d669fe3067782a67ba1f55b22..7c2be32da4684542b6947370d6ac56f7a2709fe6 100644 (file)
@@ -1,6 +1,5 @@
 pub mod arithmetic_ops;
 pub mod attributed_variables;
-pub mod code_repo;
 pub mod code_walker;
 #[macro_use]
 pub mod loader;
@@ -22,11 +21,10 @@ pub mod streams;
 pub mod system_calls;
 pub mod term_stream;
 
-use crate::arena::*;
+use crate::arithmetic::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
-use crate::machine::code_repo::*;
+use crate::instructions::*;
 use crate::machine::compile::*;
 use crate::machine::copier::*;
 use crate::machine::heap::*;
@@ -57,7 +55,7 @@ lazy_static! {
 pub struct Machine {
     pub(super) machine_st: MachineState,
     pub(super) indices: IndexStore,
-    pub(super) code_repo: CodeRepo,
+    pub(super) code: Code,
     pub(super) user_input: Stream,
     pub(super) user_output: Stream,
     pub(super) user_error: Stream,
@@ -97,19 +95,74 @@ fn current_dir() -> PathBuf {
 
 include!(concat!(env!("OUT_DIR"), "/libraries.rs"));
 
+pub static BREAK_FROM_DISPATCH_LOOP_LOC: usize = 0;
+pub static INSTALL_VERIFY_ATTR_INTERRUPT: usize = 1;
+pub static VERIFY_ATTR_INTERRUPT_LOC: usize = 2;
+
 pub struct MachinePreludeView<'a> {
     pub indices: &'a mut IndexStore,
-    pub code_repo: &'a mut CodeRepo,
+    pub code: &'a mut Code,
     pub load_contexts: &'a mut Vec<LoadContext>,
 }
 
+pub(crate) fn import_builtin_impls(code_dir: &CodeDir, builtins: &mut Module) {
+    let keys = [
+        (atom!("@>"), 2),
+        (atom!("@<"), 2),
+        (atom!("@>="), 2),
+        (atom!("@=<"), 2),
+        (atom!("=="), 2),
+        (atom!("\\=="), 2),
+        (atom!(">"), 2),
+        (atom!("<"), 2),
+        (atom!(">="), 2),
+        (atom!("=<"), 2),
+        (atom!("=:="), 2),
+        (atom!("=\\="), 2),
+        (atom!("is"), 2),
+        (atom!("acyclic_term"), 1),
+        (atom!("arg"), 3),
+        (atom!("compare"), 3),
+        (atom!("copy_term"), 2),
+        (atom!("functor"), 3),
+        (atom!("ground"), 1),
+        (atom!("keysort"), 2),
+        (atom!("read"), 1),
+        (atom!("sort"), 2),
+        (atom!("$call"), 1),
+        (atom!("$call"), 2),
+        (atom!("$call"), 3),
+        (atom!("$call"), 4),
+        (atom!("$call"), 5),
+        (atom!("$call"), 6),
+        (atom!("$call"), 7),
+        (atom!("$call"), 8),
+        (atom!("$call"), 9),
+        (atom!("atom"), 1),
+        (atom!("atomic"), 1),
+        (atom!("compound"), 1),
+        (atom!("integer"), 1),
+        (atom!("number"), 1),
+        (atom!("rational"), 1),
+        (atom!("float"), 1),
+        (atom!("nonvar"), 1),
+        (atom!("var"), 1),
+    ];
+
+    for key in keys {
+        let idx = code_dir.get(&key).unwrap();
+        builtins.code_dir.insert(key, idx.clone());
+        builtins.module_decl.exports.push(ModuleExport::PredicateKey(key));
+    }
+}
+
 impl Machine {
     #[inline]
     pub fn prelude_view_and_machine_st(&mut self) -> (MachinePreludeView, &mut MachineState) {
         (
             MachinePreludeView {
                 indices: &mut self.indices,
-                code_repo: &mut self.code_repo,
+                code: &mut self.code,
                 load_contexts: &mut self.load_contexts,
             },
             &mut self.machine_st
@@ -122,7 +175,6 @@ impl Machine {
         let err = self.machine_st.error_form(err, stub);
 
         self.machine_st.throw_exception(err);
-        return;
     }
 
     fn run_module_predicate(&mut self, module_name: Atom, key: PredicateKey) {
@@ -130,10 +182,10 @@ impl Machine {
             if let Some(ref code_index) = module.code_dir.get(&key) {
                 let p = code_index.local().unwrap();
 
-                self.machine_st.cp = LocalCodePtr::Halt;
-                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
+                self.machine_st.cp = BREAK_FROM_DISPATCH_LOOP_LOC;
+                self.machine_st.p = p;
 
-                return self.run_query();
+                return self.dispatch_loop();
             }
         }
 
@@ -286,6 +338,61 @@ impl Machine {
         }
     }
 
+    pub(crate) fn add_impls_to_indices(&mut self) {
+        let impls_offset = self.code.len() + 3;
+
+        self.code.extend(vec![
+            Instruction::BreakFromDispatchLoop,
+            Instruction::InstallVerifyAttr,
+            Instruction::VerifyAttrInterrupt,
+            Instruction::ExecuteTermGreaterThan(0),
+            Instruction::ExecuteTermLessThan(0),
+            Instruction::ExecuteTermGreaterThanOrEqual(0),
+            Instruction::ExecuteTermLessThanOrEqual(0),
+            Instruction::ExecuteTermEqual(0),
+            Instruction::ExecuteTermNotEqual(0),
+            Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0),
+            Instruction::ExecuteAcyclicTerm(0),
+            Instruction::ExecuteArg(0),
+            Instruction::ExecuteCompare(0),
+            Instruction::ExecuteCopyTerm(0),
+            Instruction::ExecuteFunctor(0),
+            Instruction::ExecuteGround(0),
+            Instruction::ExecuteKeySort(0),
+            Instruction::ExecuteRead(0),
+            Instruction::ExecuteSort(0),
+            Instruction::ExecuteN(1, 0),
+            Instruction::ExecuteN(2, 0),
+            Instruction::ExecuteN(3, 0),
+            Instruction::ExecuteN(4, 0),
+            Instruction::ExecuteN(5, 0),
+            Instruction::ExecuteN(6, 0),
+            Instruction::ExecuteN(7, 0),
+            Instruction::ExecuteN(8, 0),
+            Instruction::ExecuteN(9, 0),
+            Instruction::ExecuteIsAtom(temp_v!(1), 0),
+            Instruction::ExecuteIsAtomic(temp_v!(1), 0),
+            Instruction::ExecuteIsCompound(temp_v!(1), 0),
+            Instruction::ExecuteIsInteger(temp_v!(1), 0),
+            Instruction::ExecuteIsNumber(temp_v!(1), 0),
+            Instruction::ExecuteIsRational(temp_v!(1), 0),
+            Instruction::ExecuteIsFloat(temp_v!(1), 0),
+            Instruction::ExecuteIsNonVar(temp_v!(1), 0),
+            Instruction::ExecuteIsVar(temp_v!(1), 0)
+        ].into_iter());
+
+        for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
+            let key = instr.to_name_and_arity();
+            self.indices.code_dir.insert(key, CodeIndex::new(IndexPtr::Index(p + impls_offset)));
+        }
+    }
+
     pub fn new() -> Self {
         use ref_thread_local::RefThreadLocal;
 
@@ -298,7 +405,7 @@ impl Machine {
         let mut wam = Machine {
             machine_st,
             indices: IndexStore::new(),
-            code_repo: CodeRepo::new(),
+            code: vec![],
             user_input,
             user_output,
             user_error,
@@ -310,6 +417,8 @@ impl Machine {
         lib_path.pop();
         lib_path.push("lib");
 
+        wam.add_impls_to_indices();
+
         bootstrapping_compile(
             Stream::from_static_string(
                 LIBRARIES.borrow()["ops_and_meta_predicates"],
@@ -333,7 +442,7 @@ impl Machine {
         )
         .unwrap();
 
-        if let Some(builtins) = wam.indices.modules.get(&atom!("builtins")) {
+        if let Some(builtins) = wam.indices.modules.get_mut(&atom!("builtins")) {
             load_module(
                 &mut wam.indices.code_dir,
                 &mut wam.indices.op_dir,
@@ -341,6 +450,8 @@ impl Machine {
                 &CompilationTarget::User,
                 builtins,
             );
+
+            import_builtin_impls(&wam.indices.code_dir, builtins);
         } else {
             unreachable!()
         }
@@ -399,509 +510,14 @@ impl Machine {
         self.indices.streams.insert(self.user_error);
     }
 
-    fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
-        match code_ptr {
-            REPLCodePtr::AddDiscontiguousPredicate => {
-                self.add_discontiguous_predicate();
-            }
-            REPLCodePtr::AddDynamicPredicate => {
-                self.add_dynamic_predicate();
-            }
-            REPLCodePtr::AddMultifilePredicate => {
-                self.add_multifile_predicate();
-            }
-            REPLCodePtr::AddGoalExpansionClause => {
-                self.add_goal_expansion_clause();
-            }
-            REPLCodePtr::AddTermExpansionClause => {
-                self.add_term_expansion_clause();
-            }
-            REPLCodePtr::AddInSituFilenameModule => {
-                self.add_in_situ_filename_module();
-            }
-            REPLCodePtr::ClauseToEvacuable => {
-                self.clause_to_evacuable();
-            }
-            REPLCodePtr::ScopedClauseToEvacuable => {
-                self.scoped_clause_to_evacuable();
-            }
-            REPLCodePtr::ConcludeLoad => {
-                self.conclude_load();
-            }
-            REPLCodePtr::PopLoadContext => {
-                self.pop_load_context();
-            }
-            REPLCodePtr::PushLoadContext => {
-                self.push_load_context();
-            }
-            REPLCodePtr::PopLoadStatePayload => {
-                self.pop_load_state_payload();
-            }
-            REPLCodePtr::UseModule => {
-                self.use_module();
-            }
-            REPLCodePtr::LoadCompiledLibrary => {
-                self.load_compiled_library();
-            }
-            REPLCodePtr::DeclareModule => {
-                self.declare_module();
-            }
-            REPLCodePtr::PushLoadStatePayload => {
-                self.push_load_state_payload();
-            }
-            REPLCodePtr::LoadContextSource => {
-                self.load_context_source();
-            }
-            REPLCodePtr::LoadContextFile => {
-                self.load_context_file();
-            }
-            REPLCodePtr::LoadContextDirectory => {
-                self.load_context_directory();
-            }
-            REPLCodePtr::LoadContextModule => {
-                self.load_context_module();
-            }
-            REPLCodePtr::LoadContextStream => {
-                self.load_context_stream();
-            }
-            REPLCodePtr::MetaPredicateProperty => {
-                self.meta_predicate_property();
-            }
-            REPLCodePtr::BuiltInProperty => {
-                self.builtin_property();
-            }
-            REPLCodePtr::MultifileProperty => {
-                self.multifile_property();
-            }
-            REPLCodePtr::DiscontiguousProperty => {
-                self.discontiguous_property();
-            }
-            REPLCodePtr::DynamicProperty => {
-                self.dynamic_property();
-            }
-            REPLCodePtr::Assertz => {
-                self.compile_assert(AppendOrPrepend::Append);
-            }
-            REPLCodePtr::Asserta => {
-                self.compile_assert(AppendOrPrepend::Prepend);
-            }
-            REPLCodePtr::Retract => {
-                self.retract_clause();
-            }
-            REPLCodePtr::AbolishClause => {
-                self.abolish_clause();
-            }
-            REPLCodePtr::IsConsistentWithTermQueue => {
-                self.is_consistent_with_term_queue();
-            }
-            REPLCodePtr::FlushTermQueue => {
-                self.flush_term_queue();
-            }
-            REPLCodePtr::RemoveModuleExports => {
-                self.remove_module_exports();
-            }
-            REPLCodePtr::AddNonCountedBacktracking => {
-                self.add_non_counted_backtracking();
-            }
-        }
-
-        self.machine_st.p = CodePtr::Local(p);
-    }
-
-    pub(crate) fn run_query(&mut self) {
-        while !self.machine_st.p.is_halt() {
-            self.query_stepper();
-
-            match self.machine_st.p {
-                CodePtr::REPL(code_ptr, p) => {
-                    self.handle_toplevel_command(code_ptr, p);
-
-                    if self.machine_st.fail {
-                        self.backtrack();
-                    }
-                }
-                _ => {
-                    break;
-                }
-            };
-        }
-    }
-
-    fn execute_instr(&mut self) {
-        let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) {
-            Some(instr) => instr,
-            None => return,
-        };
-
-        self.dispatch_instr(instr);
-    }
-
-    fn backtrack(&mut self) {
-        let b = self.machine_st.b;
-        let or_frame = self.machine_st.stack.index_or_frame(b);
-
-        self.machine_st.b0 = or_frame.prelude.b0;
-        self.machine_st.p = CodePtr::Local(or_frame.prelude.bp);
-
-        self.machine_st.oip = or_frame.prelude.boip;
-        self.machine_st.iip = or_frame.prelude.biip;
-
-        self.machine_st.pdl.clear();
-        self.machine_st.fail = false;
-    }
-
-    fn check_machine_index(&mut self) -> bool {
-        match self.machine_st.p {
-            CodePtr::Local(LocalCodePtr::DirEntry(p))
-                if p < self.code_repo.code.len() => {}
-            CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => {
-                return false;
-            }
-            _ => {}
-        }
-
-        true
-    }
-
-    // return true iff verify_attr_interrupt is called.
-    fn verify_attr_stepper(&mut self) -> bool {
-        loop {
-            let instr = match self.code_repo.lookup_instr(&self.machine_st, &self.machine_st.p) {
-                Some(instr) => {
-                    if instr.as_ref(&self.code_repo.code).is_head_instr() {
-                        instr
-                    } else {
-                        let cp = self.machine_st.p.local();
-                        self.run_verify_attr_interrupt(cp);
-                        return true;
-                    }
-                }
-                None => return false,
-            };
-
-            self.dispatch_instr(instr);
-
-            if self.machine_st.fail {
-                self.backtrack();
-            }
-
-            if !self.check_machine_index() {
-                return false;
-            }
-        }
-    }
-
-    fn run_verify_attr_interrupt(&mut self, cp: LocalCodePtr) {
+    #[inline(always)]
+    pub(crate) fn run_verify_attr_interrupt(&mut self) { //, cp: usize) {
         let p = self.machine_st.attr_var_init.verify_attrs_loc;
 
-        self.machine_st.attr_var_init.cp = cp;
+        // self.machine_st.attr_var_init.cp = cp;
         self.machine_st.verify_attr_interrupt(p);
     }
 
-    fn query_stepper(&mut self) {
-        loop {
-            self.execute_instr();
-
-            if self.machine_st.fail {
-                self.backtrack();
-            }
-
-            match self.machine_st.p {
-                CodePtr::VerifyAttrInterrupt(_) => {
-                    self.machine_st.p = CodePtr::Local(self.machine_st.attr_var_init.cp);
-
-                    let instigating_p = CodePtr::Local(self.machine_st.attr_var_init.instigating_p);
-                    let instigating_instr = self.code_repo
-                        .lookup_instr(&self.machine_st, &instigating_p)
-                        .unwrap();
-
-                    if !instigating_instr.as_ref(&self.code_repo.code).is_head_instr() {
-                        let cp = self.machine_st.p.local();
-                        self.run_verify_attr_interrupt(cp);
-                    } else if !self.verify_attr_stepper() {
-                        if self.machine_st.fail {
-                            break;
-                        }
-
-                        let cp = self.machine_st.p.local();
-                        self.run_verify_attr_interrupt(cp);
-                    }
-                }
-                _ => {
-                    if !self.check_machine_index() {
-                        break;
-                    }
-                }
-            }
-        }
-    }
-
-    pub fn execute_inlined(&mut self, inlined: &InlinedClauseType) {
-        match inlined {
-            &InlinedClauseType::CompareNumber(cmp, ref at_1, ref at_2) => {
-                let n1 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_1));
-                let n2 = try_or_fail!(self.machine_st, self.machine_st.get_number(at_2));
-
-                self.machine_st.compare_numbers(cmp, n1, n2);
-            }
-            &InlinedClauseType::IsAtom(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Atom, (_name, arity)) => {
-                        if arity == 0 {
-                            self.machine_st.p += 1;
-                        } else {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                    (HeapCellValueTag::Char) => {
-                        self.machine_st.p += 1;
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsAtomic(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Char | HeapCellValueTag::Fixnum | HeapCellValueTag::F64 |
-                     HeapCellValueTag::Cons) => {
-                        self.machine_st.p += 1;
-                    }
-                    (HeapCellValueTag::Atom, (_name, arity)) => {
-                        if arity == 0 {
-                            self.machine_st.p += 1;
-                        } else {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsInteger(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                match Number::try_from(d) {
-                    Ok(Number::Fixnum(_)) => {
-                        self.machine_st.p += 1;
-                    }
-                    Ok(Number::Integer(_)) => {
-                        self.machine_st.p += 1;
-                    }
-                    Ok(Number::Rational(n)) => {
-                        if n.denom() == &1 {
-                            self.machine_st.p += 1;
-                        } else {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                }
-            }
-            &InlinedClauseType::IsCompound(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Str | HeapCellValueTag::Lis |
-                     HeapCellValueTag::PStrLoc | HeapCellValueTag::CStr) => {
-                        self.machine_st.p += 1;
-                    }
-                    (HeapCellValueTag::Atom, (_name, arity)) => {
-                        if arity > 0 {
-                            self.machine_st.p += 1;
-                        } else {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsFloat(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                match Number::try_from(d) {
-                    Ok(Number::Float(_)) => {
-                        self.machine_st.p += 1;
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                }
-            }
-            &InlinedClauseType::IsNumber(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                match Number::try_from(d) {
-                    Ok(Number::Fixnum(_)) => {
-                        self.machine_st.p += 1;
-                    }
-                    Ok(Number::Integer(_)) => {
-                        self.machine_st.p += 1;
-                    }
-                    Ok(Number::Rational(n)) => {
-                        if n.denom() == &1 {
-                            self.machine_st.p += 1;
-                        } else {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                    Ok(Number::Float(_)) => {
-                        self.machine_st.p += 1;
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                }
-            }
-            &InlinedClauseType::IsRational(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                read_heap_cell!(d,
-                    (HeapCellValueTag::Cons, ptr) => {
-                        match_untyped_arena_ptr!(ptr,
-                             (ArenaHeaderTag::Rational, _r) => {
-                                 self.machine_st.p += 1;
-                             }
-                             _ => {
-                                 self.machine_st.fail = true;
-                             }
-                        );
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                );
-            }
-            &InlinedClauseType::IsNonVar(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                match d.get_tag() {
-                    HeapCellValueTag::AttrVar
-                    | HeapCellValueTag::Var
-                    | HeapCellValueTag::StackVar => {
-                        self.machine_st.fail = true;
-                    }
-                    _ => {
-                        self.machine_st.p += 1;
-                    }
-                }
-            }
-            &InlinedClauseType::IsVar(r1) => {
-                let d = self.machine_st.store(self.machine_st.deref(self.machine_st[r1]));
-
-                match d.get_tag() {
-                    HeapCellValueTag::AttrVar |
-                    HeapCellValueTag::Var |
-                    HeapCellValueTag::StackVar => {
-                        self.machine_st.p += 1;
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
-                }
-            }
-        }
-    }
-
-    #[inline(always)]
-    pub(super) fn execute_dynamic_indexed_choice_instr(&mut self) {
-        let p = self.machine_st.p.local();
-
-        match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
-            Some((offset, oi, ii, is_next_clause)) => {
-                self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc()));
-                self.machine_st.oip = oi;
-                self.machine_st.iip = ii;
-
-                match self.machine_st.dynamic_mode {
-                    FirstOrNext::First if !is_next_clause => {
-                        self.machine_st.p =
-                            CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
-                    }
-                    FirstOrNext::First => {
-                        // there's a leading DynamicElse that sets self.machine_st.cc.
-                        // self.machine_st.cc = self.machine_st.global_clock;
-
-                        // see that there is a following dynamic_else
-                        // clause so we avoid generating a choice
-                        // point in case there isn't.
-                        match self.find_living_dynamic(oi, ii + 1) {
-                            Some(_) => {
-                                self.machine_st.registers[self.machine_st.num_of_args + 1] =
-                                    fixnum_as_cell!(Fixnum::build_with(self.machine_st.cc as i64));
-
-                                self.machine_st.num_of_args += 2;
-                                self.machine_st.indexed_try(offset);
-                                self.machine_st.num_of_args -= 2;
-                            }
-                            None => {
-                                self.machine_st.p =
-                                    CodePtr::Local(LocalCodePtr::DirEntry(p.abs_loc() + offset));
-                                self.machine_st.oip = 0;
-                                self.machine_st.iip = 0;
-                            }
-                        }
-                    }
-                    FirstOrNext::Next => {
-                        let b = self.machine_st.b;
-                        let n = self.machine_st
-                            .stack
-                            .index_or_frame(b)
-                            .prelude
-                            .univ_prelude
-                            .num_cells;
-
-                        self.machine_st.cc = cell_as_fixnum!(
-                            self.machine_st.stack[stack_loc!(OrFrame, b, n-2)]
-                        ).get_num() as usize;
-
-                        if is_next_clause {
-                            match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip) {
-                                Some(_) => {
-                                    self.retry(offset);
-
-                                    try_or_fail!(
-                                        self.machine_st,
-                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                    );
-                                }
-                                None => {
-                                    self.trust(offset);
-
-                                    try_or_fail!(
-                                        self.machine_st,
-                                        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                                    );
-                                }
-                            }
-                        } else {
-                            self.trust(offset);
-
-                            try_or_fail!(
-                                self.machine_st,
-                                (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
-                            );
-                        }
-                    }
-                }
-            }
-            None => {
-                self.machine_st.fail = true;
-            }
-        }
-
-        self.machine_st.dynamic_mode = FirstOrNext::Next;
-    }
-
     #[inline(always)]
     fn retry_me_else(&mut self, offset: usize) {
         let b = self.machine_st.b;
@@ -916,7 +532,7 @@ impl Machine {
         self.machine_st.e = or_frame.prelude.e;
         self.machine_st.cp = or_frame.prelude.cp;
 
-        or_frame.prelude.bp = self.machine_st.p.local() + offset;
+        or_frame.prelude.bp = self.machine_st.p + offset;
 
         let old_tr = or_frame.prelude.tr;
         let curr_tr = self.machine_st.tr;
@@ -924,14 +540,15 @@ impl Machine {
 
         self.machine_st.tr = or_frame.prelude.tr;
 
-        self.machine_st.attr_var_init.reset();
+        self.reset_attr_var_state();
         self.machine_st.hb = self.machine_st.heap.len();
-        self.machine_st.p += 1;
 
         self.unwind_trail(old_tr, curr_tr);
 
         self.machine_st.trail.truncate(self.machine_st.tr);
         self.machine_st.heap.truncate(target_h);
+
+        self.machine_st.p += 1;
     }
 
     #[inline(always)]
@@ -948,7 +565,7 @@ impl Machine {
         self.machine_st.e = or_frame.prelude.e;
         self.machine_st.cp = or_frame.prelude.cp;
 
-        // WAS: or_frame.prelude.bp = self.machine_st.p.local() + 1;
+        // WAS: or_frame.prelude.bp = self.machine_st.p + 1;
         or_frame.prelude.biip += 1;
 
         let old_tr = or_frame.prelude.tr;
@@ -956,7 +573,7 @@ impl Machine {
         let target_h = or_frame.prelude.h;
 
         self.machine_st.tr = or_frame.prelude.tr;
-        self.machine_st.attr_var_init.reset();
+        self.reset_attr_var_state();
 
         self.unwind_trail(old_tr, curr_tr);
 
@@ -964,7 +581,7 @@ impl Machine {
         self.machine_st.heap.truncate(target_h);
 
         self.machine_st.hb = self.machine_st.heap.len();
-        self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset));
+        self.machine_st.p = self.machine_st.p + offset;
 
         self.machine_st.oip = 0;
         self.machine_st.iip = 0;
@@ -989,10 +606,9 @@ impl Machine {
         let target_h = or_frame.prelude.h;
 
         self.machine_st.tr = or_frame.prelude.tr;
-
-        self.machine_st.attr_var_init.reset();
         self.machine_st.b = or_frame.prelude.b;
 
+        self.reset_attr_var_state();
         self.unwind_trail(old_tr, curr_tr);
 
         self.machine_st.trail.truncate(self.machine_st.tr);
@@ -1000,7 +616,7 @@ impl Machine {
         self.machine_st.heap.truncate(target_h);
 
         self.machine_st.hb = self.machine_st.heap.len();
-        self.machine_st.p = CodePtr::Local(dir_entry!(self.machine_st.p.local().abs_loc() + offset));
+        self.machine_st.p = self.machine_st.p + offset;
 
         self.machine_st.oip = 0;
         self.machine_st.iip = 0;
@@ -1025,10 +641,9 @@ impl Machine {
         let target_h = or_frame.prelude.h;
 
         self.machine_st.tr = or_frame.prelude.tr;
-
-        self.machine_st.attr_var_init.reset();
         self.machine_st.b = or_frame.prelude.b;
 
+        self.reset_attr_var_state();
         self.unwind_trail(old_tr, curr_tr);
 
         self.machine_st.trail.truncate(self.machine_st.tr);
@@ -1040,30 +655,20 @@ impl Machine {
     }
 
     #[inline(always)]
-    fn context_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult {
-        if self.machine_st.last_call {
-            self.try_execute(name, arity, idx)
-        } else {
-            self.try_call(name, arity, idx)
-        }
-    }
-
-    #[inline(always)]
-    fn try_call(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult {
-        match idx.get() {
+    fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
+        match idx {
             IndexPtr::DynamicUndefined => {
                 self.machine_st.fail = true;
-                return Ok(());
             }
             IndexPtr::Undefined => {
                 return Err(self.machine_st.throw_undefined_error(name, arity));
             }
             IndexPtr::DynamicIndex(compiled_tl_index) => {
                 self.machine_st.dynamic_mode = FirstOrNext::First;
-                self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
+                self.machine_st.call_at_index(arity, compiled_tl_index);
             }
             IndexPtr::Index(compiled_tl_index) => {
-                self.machine_st.call_at_index(arity, dir_entry!(compiled_tl_index));
+                self.machine_st.call_at_index(arity, compiled_tl_index);
             }
         }
 
@@ -1071,21 +676,20 @@ impl Machine {
     }
 
     #[inline(always)]
-    fn try_execute(&mut self, name: Atom, arity: usize, idx: CodeIndex) -> CallResult {
-        match idx.get() {
+    fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
+        match idx {
             IndexPtr::DynamicUndefined => {
                 self.machine_st.fail = true;
-                return Ok(());
             }
             IndexPtr::Undefined => {
                 return Err(self.machine_st.throw_undefined_error(name, arity));
             }
             IndexPtr::DynamicIndex(compiled_tl_index) => {
                 self.machine_st.dynamic_mode = FirstOrNext::First;
-                self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index));
+                self.machine_st.execute_at_index(arity, compiled_tl_index);
             }
             IndexPtr::Index(compiled_tl_index) => {
-                self.machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
+                self.machine_st.execute_at_index(arity, compiled_tl_index)
             }
         }
 
@@ -1093,265 +697,67 @@ impl Machine {
     }
 
     #[inline(always)]
-    fn call_builtin(&mut self, ct: &BuiltInClauseType) -> CallResult {
-        match ct {
-            &BuiltInClauseType::AcyclicTerm => {
-                let addr = self.machine_st.registers[1];
-                self.machine_st.fail = self.machine_st.is_cyclic_term(addr);
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Arg => {
-                self.machine_st.try_arg()?;
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Compare => {
-                let stub_gen = || functor_stub(atom!("compare"), 3);
-
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let a2 = self.machine_st.registers[2];
-                let a3 = self.machine_st.registers[3];
-
-                read_heap_cell!(a1,
-                    (HeapCellValueTag::Str, s) => {
-                        let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
-                            .get_name_and_arity();
-
-                        match name {
-                            atom!(">") | atom!("<") | atom!("=") if arity == 2 => {
-                            }
-                            _ => {
-                                let err = self.machine_st.domain_error(DomainErrorType::Order, a1);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                    }
-                    (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                    }
-                    _ => {
-                        let err = self.machine_st.type_error(ValidType::Atom, a1);
-                        return Err(self.machine_st.error_form(err, stub_gen()));
-                    }
-                );
-
-                let atom = match compare_term_test!(self.machine_st, a2, a3) {
-                    Some(Ordering::Greater) => {
-                        atom!(">")
-                    }
-                    Some(Ordering::Equal) => {
-                        atom!("=")
-                    }
-                    None | Some(Ordering::Less) => {
-                        atom!("<")
-                    }
-                };
-
-                self.machine_st.unify_atom(atom, a1);
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::CompareTerm(qt) => {
-                self.machine_st.compare_term(qt);
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Read => {
-                let stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("read"),
-                    2,
-                )?;
-
-                match self.machine_st.read(stream, &self.indices.op_dir) {
-                    Ok(offset) => {
-                        let value = self.machine_st.registers[2];
-                        unify_fn!(&mut self.machine_st, value, heap_loc_as_cell!(offset.heap_loc));
-                    }
-                    Err(ParserError::UnexpectedEOF) => {
-                        let value = self.machine_st.registers[2];
-                        self.machine_st.unify_atom(atom!("end_of_file"), value);
-                    }
-                    Err(e) => {
-                        let stub = functor_stub(atom!("read"), 2);
-                        let err = self.machine_st.syntax_error(e);
-
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
-                };
-
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::CopyTerm => {
-                self.machine_st.copy_term(AttrVarPolicy::DeepCopy);
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Eq => {
-                let a1 = self.machine_st.registers[1];
-                let a2 = self.machine_st.registers[2];
-
-                self.machine_st.fail = self.machine_st.eq_test(a1, a2);
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Ground => {
-                self.machine_st.fail = self.machine_st.ground_test();
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Functor => {
-                self.machine_st.try_functor()?;
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::NotEq => {
-                let a1 = self.machine_st.registers[1];
-                let a2 = self.machine_st.registers[2];
-
-                self.machine_st.fail =
-                    if let Some(Ordering::Equal) = compare_term_test!(self.machine_st, a1, a2) {
-                        true
-                    } else {
-                        false
-                    };
-
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::Sort => {
-                self.machine_st.check_sort_errors()?;
-
-                let stub_gen = || functor_stub(atom!("sort"), 2);
-                let mut list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?;
-
-                list.sort_unstable_by(|v1, v2| {
-                    compare_term_test!(self.machine_st, *v1, *v2).unwrap_or(Ordering::Less)
-                });
-
-                list.dedup_by(|v1, v2| {
-                    compare_term_test!(self.machine_st, *v1, *v2) == Some(Ordering::Equal)
-                });
-
-                let heap_addr = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut self.machine_st.heap, list.into_iter())
-                );
-
-                let r2 = self.machine_st.registers[2];
-                unify_fn!(&mut self.machine_st, r2, heap_addr);
-
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
-            }
-            &BuiltInClauseType::KeySort => {
-                self.machine_st.check_keysort_errors()?;
-
-                let stub_gen = || functor_stub(atom!("keysort"), 2);
-                let list = self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen)?;
-
-                let mut key_pairs = Vec::with_capacity(list.len());
-
-                for val in list {
-                    let key = self.machine_st.project_onto_key(val)?;
-                    key_pairs.push((key, val));
-                }
-
-                key_pairs.sort_by(|a1, a2| {
-                    compare_term_test!(self.machine_st, a1.0, a2.0).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.machine_st.heap, key_pairs)
-                );
-
-                let r2 = self.machine_st.registers[2];
-                unify_fn!(&mut self.machine_st, r2, heap_addr);
+    fn call_clause(&mut self, module_name: Atom, key: PredicateKey) -> CallResult {
+        let (name, arity) = key;
 
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
+        if module_name == atom!("user") {
+            if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
+                self.try_call(name, arity, idx.get())
+            } else {
+                Err(self.machine_st.throw_undefined_error(name, arity))
             }
-            &BuiltInClauseType::Is(r, ref at) => {
-                let n1 = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
-                let n2 = self.machine_st.get_number(at)?;
-
-                match n2 {
-                    Number::Fixnum(n) => self.machine_st.unify_fixnum(n, n1),
-                    Number::Float(n) => {
-                        // TODO: argghh.. deal with it.
-                        let n = arena_alloc!(n, &mut self.machine_st.arena);
-                        self.machine_st.unify_f64(n, n1)
-                    }
-                    Number::Integer(n) => self.machine_st.unify_big_int(n, n1),
-                    Number::Rational(n) => self.machine_st.unify_rational(n, n1),
+        } else {
+            if let Some(module) = self.indices.modules.get(&module_name) {
+                if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
+                    self.try_call(name, arity, idx.get())
+                } else {
+                    Err(self.machine_st.throw_undefined_error(name, arity))
                 }
+            } else {
+                let stub = functor_stub(name, arity);
+                let err = self.machine_st.module_resolution_error(module_name, name, arity);
 
-                return_from_clause!(self.machine_st.last_call, self.machine_st)
+                Err(self.machine_st.error_form(err, stub))
             }
         }
     }
 
     #[inline(always)]
-    fn call_clause_type(&mut self, module_name: Atom, key: PredicateKey) -> CallResult {
+    fn execute_clause(&mut self, module_name: Atom, key: PredicateKey) -> CallResult {
         let (name, arity) = key;
 
-        match ClauseType::from(name, arity) {
-            ClauseType::BuiltIn(built_in) => {
-                self.machine_st.setup_built_in_call(built_in);
-                self.call_builtin(&built_in)?;
+        if module_name == atom!("user") {
+            if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
+                self.try_execute(name, arity, idx.get())
+            } else {
+                Err(self.machine_st.throw_undefined_error(name, arity))
             }
-            ClauseType::CallN => {
-                self.machine_st.handle_internal_call_n(arity);
-
-                if self.machine_st.fail {
-                    return Ok(());
-                }
-
-                self.machine_st.p = CodePtr::CallN(
-                    arity,
-                    self.machine_st.p.local(),
-                    self.machine_st.last_call,
-                );
-            }
-            ClauseType::Inlined(inlined) => {
-                self.execute_inlined(&inlined);
-
-                if self.machine_st.last_call {
-                    self.machine_st.p = CodePtr::Local(self.machine_st.cp);
-                }
-            }
-            ClauseType::Named(..) if module_name == atom!("user") => {
-                return if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
-                    self.context_call(name, arity, idx)
+        } else {
+            if let Some(module) = self.indices.modules.get(&module_name) {
+                if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
+                    self.try_execute(name, arity, idx.get())
                 } else {
                     Err(self.machine_st.throw_undefined_error(name, arity))
-                };
-            }
-            ClauseType::Named(..) => {
-                return if let Some(module) = self.indices.modules.get(&module_name) {
-                    if let Some(idx) = module.code_dir.get(&(name, arity)).cloned() {
-                        self.context_call(name, arity, idx)
-                    } else {
-                        Err(self.machine_st.throw_undefined_error(name, arity))
-                    }
-                } else {
-                    let stub = functor_stub(name, arity);
-                    let err = self.machine_st.module_resolution_error(module_name, name, arity);
-
-                    Err(self.machine_st.error_form(err, stub))
-                };
-            }
-            ClauseType::System(_) => {
-                let (name, arity) = key;
-                let name = functor!(name);
-
-                let stub = functor_stub(atom!("call"), arity + 1);
-                let err = self.machine_st.type_error(ValidType::Callable, name);
+                }
+            } else {
+                let stub = functor_stub(name, arity);
+                let err = self.machine_st.module_resolution_error(module_name, name, arity);
 
-                return Err(self.machine_st.error_form(err, stub));
+                Err(self.machine_st.error_form(err, stub))
             }
         }
-
-        Ok(())
     }
 
     #[inline(always)]
     fn call_n(&mut self, module_name: Atom, arity: usize) -> CallResult {
-        if let Some(key) = self.machine_st.setup_call_n(arity) {
-            self.call_clause_type(module_name, key)?;
-        }
+        let key = self.machine_st.setup_call_n(arity)?;
+        self.call_clause(module_name, key)
+    }
 
-        (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+    #[inline(always)]
+    fn execute_n(&mut self, module_name: Atom, arity: usize) -> CallResult {
+        let key = self.machine_st.setup_call_n(arity)?;
+        self.execute_clause(module_name, key)
     }
 
     #[inline(always)]
@@ -1383,21 +789,16 @@ impl Machine {
         if let Some(&(_, b_cutoff, prev_block)) = self.machine_st.cont_pts.last() {
             if self.machine_st.b < b_cutoff {
                 let (idx, arity) = if self.machine_st.block > prev_block {
-                    (dir_entry!(r_c_w_h), 0)
+                    (r_c_w_h, 0)
                 } else {
                     self.machine_st.registers[1] = fixnum_as_cell!(
                         Fixnum::build_with(b_cutoff as i64)
                     );
 
-                    (dir_entry!(r_c_wo_h), 1)
+                    (r_c_wo_h, 1)
                 };
 
-                if self.machine_st.last_call {
-                    self.machine_st.execute_at_index(arity, idx);
-                } else {
-                    self.machine_st.call_at_index(arity, idx);
-                }
-
+                self.machine_st.call_at_index(arity, idx);
                 return true;
             }
         }
@@ -1407,7 +808,7 @@ impl Machine {
 
     pub(super) fn unwind_trail(&mut self, a1: usize, a2: usize) {
         // the sequence is reversed to respect the chronology of trail
-        // additions, now that deleted attributes can be undeleted by
+        // additions now that deleted attributes can be undeleted by
         // backtracking.
         for i in (a1..a2).rev() {
             let h = self.machine_st.trail[i].get_value() as usize;
index c3711db001bd6c3ef0ab5080bbeddcdab247b3c9..50a469470fd869f70c715183d1279e4a152fde59 100644 (file)
@@ -1,6 +1,6 @@
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
+use crate::instructions::*;
 use crate::iterators::*;
 use crate::machine::loader::*;
 use crate::machine::machine_errors::*;
@@ -207,34 +207,6 @@ fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, Compilati
     }
 }
 
-/*
-fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, CompilationError> {
-    let dbl_quotes = *terms.pop().unwrap();
-
-    match terms[0].as_ref() {
-        Term::Literal(_, Literal::Atom(ref name, _))
-            if name.as_str() == "double_quotes" => {
-                match dbl_quotes {
-                    Term::Literal(_, Literal::Atom(name, _)) => {
-                        match name.as_str() {
-                            "atom"  => Ok(DoubleQuotes::Atom),
-                            "chars" => Ok(DoubleQuotes::Chars),
-                            "codes" => Ok(DoubleQuotes::Codes),
-                            _ => Err(CompilationError::InvalidDoubleQuotesDecl),
-                        }
-                    }
-                    _ => {
-                        Err(CompilationError::InvalidDoubleQuotesDecl)
-                    }
-                }
-            },
-        _ => {
-            Err(CompilationError::InvalidDoubleQuotesDecl)
-        }
-    }
-}
- */
-
 type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
 
 fn setup_qualified_import(
@@ -735,7 +707,7 @@ impl Preprocessor {
             },
             Term::Var(..) => Ok(QueryTerm::Clause(
                 Cell::default(),
-                ClauseType::CallN,
+                ClauseType::CallN(1),
                 vec![term],
                 false,
             )),
index b175917b1a2b57bf993a08aa6a99ddb1b469c1d6..388c3008203d4764f57083901d714ab1d9b24da8 100644 (file)
@@ -1,9 +1,7 @@
 use core::marker::PhantomData;
 
-use crate::types::*;
-
-use crate::machine::machine_indices::*;
 use crate::raw_block::*;
+use crate::types::*;
 
 use std::mem;
 use std::ops::{Index, IndexMut};
@@ -47,8 +45,7 @@ pub(crate) struct FramePrelude {
 pub(crate) struct AndFramePrelude {
     pub(crate) univ_prelude: FramePrelude,
     pub(crate) e: usize,
-    pub(crate) cp: LocalCodePtr,
-    pub(crate) interrupt_cp: LocalCodePtr, // TODO: get rid of it!
+    pub(crate) cp: usize,
 }
 
 #[derive(Debug)]
@@ -118,9 +115,9 @@ impl IndexMut<usize> for Stack {
 pub(crate) struct OrFramePrelude {
     pub(crate) univ_prelude: FramePrelude,
     pub(crate) e: usize,
-    pub(crate) cp: LocalCodePtr,
+    pub(crate) cp: usize,
     pub(crate) b: usize,
-    pub(crate) bp: LocalCodePtr,
+    pub(crate) bp: usize,
     pub(crate) boip: u32,
     pub(crate) biip: u32,
     pub(crate) tr: usize,
index d84c2ea988451caad3c4cec0209e0b905b93574e..08a99f30d90ab830dbe0f68711ee17768dbbaa55 100644 (file)
@@ -5,13 +5,12 @@ use lazy_static::lazy_static;
 
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::heap_iter::*;
 use crate::heap_print::*;
 use crate::instructions::*;
 use crate::machine;
-use crate::machine::Machine;
+use crate::machine::{Machine, VERIFY_ATTR_INTERRUPT_LOC};
 use crate::machine::code_walker::*;
 use crate::machine::copier::*;
 use crate::machine::heap::*;
@@ -24,6 +23,7 @@ use crate::machine::stack::*;
 use crate::machine::streams::*;
 use crate::parser::char_reader::*;
 use crate::parser::rug::Integer;
+use crate::parser::rug::rand::RandState;
 use crate::read::*;
 use crate::types::*;
 
@@ -31,7 +31,7 @@ use ordered_float::OrderedFloat;
 
 use indexmap::IndexSet;
 
-use ref_thread_local::RefThreadLocal;
+use ref_thread_local::{RefThreadLocal, ref_thread_local};
 
 use std::collections::BTreeSet;
 use std::convert::TryFrom;
@@ -39,6 +39,7 @@ use std::env;
 use std::fs;
 use std::io::{ErrorKind, Read, Write};
 use std::iter::{once, FromIterator};
+use std::mem;
 use std::net::{TcpListener, TcpStream};
 use std::num::NonZeroU32;
 use std::ops::Sub;
@@ -72,6 +73,10 @@ use base64;
 use roxmltree;
 use select;
 
+ref_thread_local! {
+    pub(crate) static managed RANDOM_STATE: RandState<'static> = RandState::new();
+}
+
 pub(crate) fn get_key() -> KeyEvent {
     let key;
     enable_raw_mode().expect("failed to enable raw mode");
@@ -326,7 +331,7 @@ impl MachineState {
         let deref_v = self.deref(value);
         let store_v = self.store(deref_v);
 
-        // let mut pstr_chars = 0;
+        let mut pstr_chars = 0;
 
         let hare = read_heap_cell!(store_v,
             (HeapCellValueTag::Lis, offset) => {
@@ -337,14 +342,29 @@ impl MachineState {
                 }
             }
             (HeapCellValueTag::PStrLoc, h) => {
-                let (h_offset, _n) = pstr_loc_and_offset(&self.heap, h);
+                let (h_offset, n) = pstr_loc_and_offset(&self.heap, h);
+                let n = n.get_num() as usize;
+                let pstr = cell_as_string!(self.heap[h_offset]);
 
-                if self.heap[h].get_tag() == HeapCellValueTag::PStr {
-                    h_offset+1
-                } else {
+                pstr_chars = pstr.as_str_from(n).chars().count() - 1;
+
+                if self.heap[h].get_tag() == HeapCellValueTag::PStrOffset {
                     debug_assert!(self.heap[h].get_tag() == HeapCellValueTag::PStrOffset);
-                    h
+
+                    if self.heap[h_offset].get_tag() == HeapCellValueTag::CStr {
+                        return if pstr_chars + 1 <= max_steps {
+                            CycleSearchResult::ProperList(pstr_chars + 1)
+                        } else {
+                            CycleSearchResult::UntouchedCStr(pstr.into(), max_steps)
+                        };
+                    }
+                }
+
+                if pstr_chars + 1 > max_steps {
+                    return CycleSearchResult::PStrLocation(max_steps, h_offset);
                 }
+
+                h_offset+1
             }
             (HeapCellValueTag::PStrOffset) => {
                 unreachable!()
@@ -379,11 +399,11 @@ impl MachineState {
                 }
             }
             (HeapCellValueTag::Atom, (name, arity)) => {
-                if name == atom!("[]") && arity == 0 {
-                    return CycleSearchResult::EmptyList;
+                return if name == atom!("[]") && arity == 0 {
+                    CycleSearchResult::EmptyList
                 } else {
-                    return CycleSearchResult::NotList;
-                }
+                    CycleSearchResult::NotList
+                };
             }
             _ => {
                 return CycleSearchResult::NotList;
@@ -393,7 +413,7 @@ impl MachineState {
         let mut brent_st = BrentAlgState::new(hare);
 
         brent_st.power += 1; // advance a step.
-        // brent_st.pstr_chars = pstr_chars;
+        brent_st.pstr_chars = pstr_chars;
 
         loop {
             if brent_st.num_steps() == max_steps {
@@ -406,41 +426,6 @@ impl MachineState {
         }
     }
 
-    fn term_variables_under_max_depth(
-        &mut self,
-        term: HeapCellValue,
-        max_depth: usize,
-        list_of_vars: HeapCellValue,
-    ) {
-        let mut seen_set = IndexSet::new();
-
-        {
-            let mut iter = stackful_post_order_iter(&mut self.heap, term);
-
-            while let Some(value) = iter.next() {
-                if iter.parent_stack_len() >= max_depth {
-                    iter.pop_stack();
-                    continue;
-                }
-
-                let value = unmark_cell_bits!(value);
-
-                if value.is_var() && !seen_set.contains(&value) {
-                    seen_set.insert(value);
-                }
-            }
-        }
-
-        let outcome = heap_loc_as_cell!(
-            iter_to_heap_list(
-                &mut self.heap,
-                seen_set.into_iter().rev(),
-            )
-        );
-
-        unify_fn!(*self, list_of_vars, outcome);
-    }
-
     fn finalize_skip_max_list(&mut self, n: usize, value: HeapCellValue) {
         let target_n = self.registers[1];
         self.unify_fixnum(Fixnum::build_with(n as i64), target_n);
@@ -541,18 +526,51 @@ impl MachineState {
 
         Ok(())
     }
-}
 
-impl MachineState {
+    fn term_variables_under_max_depth(
+        &mut self,
+        term: HeapCellValue,
+        max_depth: usize,
+        list_of_vars: HeapCellValue,
+    ) {
+        let mut seen_set = IndexSet::new();
+
+        {
+            let mut iter = stackful_post_order_iter(&mut self.heap, term);
+
+            while let Some(value) = iter.next() {
+                if iter.parent_stack_len() >= max_depth {
+                    iter.pop_stack();
+                    continue;
+                }
+
+                let value = unmark_cell_bits!(value);
+
+                if value.is_var() && !seen_set.contains(&value) {
+                    seen_set.insert(value);
+                }
+            }
+        }
+
+        let outcome = heap_loc_as_cell!(
+            iter_to_heap_list(
+                &mut self.heap,
+                seen_set.into_iter().rev(),
+            )
+        );
+
+        unify_fn!(*self, list_of_vars, outcome);
+    }
+
     #[inline]
-    fn install_new_block(&mut self, value: HeapCellValue) -> usize {
+    pub(crate) fn install_new_block(&mut self, value: HeapCellValue) -> usize {
         self.block = self.b;
         self.unify_fixnum(Fixnum::build_with(self.block as i64), value);
 
         self.block
     }
 
-    fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize {
+    pub(crate) fn copy_findall_solution(&mut self, lh_offset: usize, copy_target: HeapCellValue) -> usize {
         let threshold = self.lifted_heap.len() - lh_offset;
 
         let mut copy_ball_term =
@@ -567,18 +585,8 @@ impl MachineState {
         threshold + lh_offset + 2
     }
 
-    fn repl_redirect(&mut self, repl_code_ptr: REPLCodePtr) -> CallResult {
-        let p = if self.last_call {
-            self.cp
-        } else {
-            self.p.local() + 1
-        };
-
-        Ok(self.p = CodePtr::REPL(repl_code_ptr, p))
-    }
-
     #[inline(always)]
-    fn truncate_if_no_lifted_heap_diff(
+    pub(crate) fn truncate_if_no_lifted_heap_diff(
         &mut self,
         addr_constr: impl Fn(usize) -> HeapCellValue,
     ) {
@@ -599,7 +607,7 @@ impl MachineState {
         );
     }
 
-    fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option<DBRef> {
+    pub(crate) fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option<DBRef> {
         match db_ref {
             DBRef::NamedPred(name, arity) => {
                 let key = (*name, *arity);
@@ -612,10 +620,6 @@ impl MachineState {
                             return None;
                         }
 
-                        if SystemClauseType::from(*name, *arity).is_some() {
-                            continue;
-                        }
-
                         return Some(DBRef::NamedPred(*name, *arity));
                     }
                 }
@@ -634,7 +638,7 @@ impl MachineState {
         None
     }
 
-    fn parse_number_from_string(
+    pub(crate) fn parse_number_from_string(
         &mut self,
         mut string: String,
         indices: &IndexStore,
@@ -691,7 +695,7 @@ impl MachineState {
         Ok(())
     }
 
-    fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: LocalCodePtr) -> LocalCodePtr {
+    pub(crate) fn call_continuation_chunk(&mut self, chunk: HeapCellValue, return_p: usize) -> usize {
         let chunk = self.store(self.deref(chunk));
 
         let s = chunk.get_value();
@@ -709,7 +713,7 @@ impl MachineState {
         and_frame.prelude.e = prev_e;
         and_frame.prelude.cp = return_p;
 
-        self.p = CodePtr::Local(cp + 1);
+        self.p = cp + 1;
 
         // adjust cut point to occur after call_continuation.
         if num_cells > 0 {
@@ -725,7 +729,7 @@ impl MachineState {
         }
 
         self.e = e;
-        self.p.local()
+        self.p
     }
 
     pub fn value_to_str_like(&mut self, value: HeapCellValue) -> Option<AtomOrString> {
@@ -734,7 +738,7 @@ impl MachineState {
                 // avoid allocating a String if possible ...
                 Some(AtomOrString::Atom(cstr_atom))
             }
-            (HeapCellValueTag::Atom, (atom, arity)) => { // TODO: Char??
+            (HeapCellValueTag::Atom, (atom, arity)) => {
                 if arity == 0 {
                     // ... likewise.
                     Some(AtomOrString::Atom(atom))
@@ -742,6 +746,9 @@ impl MachineState {
                     None
                 }
             }
+            (HeapCellValueTag::Char, c) => {
+                Some(AtomOrString::Atom(self.atom_tbl.build_with(&c.to_string())))
+            }
             _ => {
                 if value.is_constant() {
                     return None;
@@ -768,7 +775,7 @@ impl MachineState {
         )
     }
 
-    fn codes_to_string(
+    pub(crate) fn codes_to_string(
         &mut self,
         addrs: impl Iterator<Item = HeapCellValue>,
         stub_gen: impl Fn() -> FunctorStub,
@@ -809,73 +816,76 @@ impl MachineState {
 }
 
 impl Machine {
-    pub(super) fn system_call(&mut self, ct: &SystemClauseType) -> CallResult {
-        match ct {
-            &SystemClauseType::BindFromRegister => {
-                let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
-                let n = match Number::try_from(reg) {
-                    Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
-                    Ok(Number::Integer(n)) => n.to_usize(),
-                    _ => {
-                        unreachable!()
-                    }
-                };
+    #[inline(always)]
+    pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool {
+        match &self.code[p] {
+            &Instruction::CallResetContinuationMarker(_) |
+            &Instruction::ExecuteResetContinuationMarker(_) => true,
+            _ => false
+        }
+    }
 
-                if let Some(n) = n {
-                    if n <= MAX_ARITY {
-                        let target = self.machine_st.registers[n];
-                        let addr = self.machine_st.registers[1];
+    #[inline(always)]
+    pub(crate) fn bind_from_register(&mut self) {
+        let reg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        let n = match Number::try_from(reg) {
+            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+            Ok(Number::Integer(n)) => n.to_usize(),
+            _ => {
+                unreachable!()
+            }
+        };
 
-                        unify_fn!(self.machine_st, addr, target);
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    }
-                }
+        if let Some(n) = n {
+            if n <= MAX_ARITY {
+                let target = self.machine_st.registers[n];
+                let addr = self.machine_st.registers[1];
 
-                self.machine_st.fail = true;
+                unify_fn!(self.machine_st, addr, target);
+                return;
             }
-            &SystemClauseType::CurrentHostname => {
-                match hostname::get().ok() {
-                    Some(host) => match host.to_str() {
-                        Some(host) => {
-                            let hostname = self.machine_st.atom_tbl.build_with(host);
+        }
 
-                            self.machine_st.unify_atom(
-                                hostname,
-                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
-                            );
+        self.machine_st.fail = true;
+    }
 
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                        None => {}
-                    },
-                    None => {}
+    #[inline(always)]
+    pub(crate) fn current_hostname(&mut self) {
+        match hostname::get().ok() {
+            Some(host) => match host.to_str() {
+                Some(host) => {
+                    let hostname = self.machine_st.atom_tbl.build_with(host);
+
+                    self.machine_st.unify_atom(
+                        hostname,
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+                    );
+
+                    return;
                 }
+                None => {}
+            },
+            None => {}
+        }
 
-                self.machine_st.fail = true;
-                return Ok(());
-            }
-            &SystemClauseType::CurrentInput => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let stream = self.user_input;
+        self.machine_st.fail = true;
+    }
 
-                if let Some(var) = addr.as_var() {
-                    self.machine_st.bind(var, stream_as_cell!(stream));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+    #[inline(always)]
+    pub(crate) fn current_input(&mut self) -> CallResult {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let stream = self.user_input;
 
-                read_heap_cell!(addr,
-                    (HeapCellValueTag::Cons, cons_ptr) => {
-                        match_untyped_arena_ptr!(cons_ptr,
-                             (ArenaHeaderTag::Stream, other_stream) => {
-                                 self.machine_st.fail = stream != other_stream;
-                             }
-                             _ => {
-                                 let stub = functor_stub(atom!("current_input"), 1);
-                                 let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
+        if let Some(var) = addr.as_var() {
+            self.machine_st.bind(var, stream_as_cell!(stream));
+            return Ok(());
+        }
 
-                                 return Err(self.machine_st.error_form(err, stub));
-                             }
-                        );
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Cons, cons_ptr) => {
+                match_untyped_arena_ptr!(cons_ptr,
+                    (ArenaHeaderTag::Stream, other_stream) => {
+                        self.machine_st.fail = stream != other_stream;
                     }
                     _ => {
                         let stub = functor_stub(atom!("current_input"), 1);
@@ -885,28 +895,32 @@ impl Machine {
                     }
                 );
             }
-            &SystemClauseType::CurrentOutput => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let stream = self.user_output;
+            _ => {
+                let stub = functor_stub(atom!("current_input"), 1);
+                let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
 
-                if let Some(var) = addr.as_var() {
-                    self.machine_st.bind(var, stream_as_cell!(stream));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+                return Err(self.machine_st.error_form(err, stub));
+            }
+        );
 
-                read_heap_cell!(addr,
-                    (HeapCellValueTag::Cons, cons_ptr) => {
-                        match_untyped_arena_ptr!(cons_ptr,
-                             (ArenaHeaderTag::Stream, other_stream) => {
-                                 self.machine_st.fail = stream != other_stream;
-                             }
-                             _ => {
-                                 let stub = functor_stub(atom!("current_output"), 1);
-                                 let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
+        Ok(())
+    }
 
-                                 return Err(self.machine_st.error_form(err, stub));
-                             }
-                        );
+    #[inline(always)]
+    pub(crate) fn current_output(&mut self) -> CallResult {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let stream = self.user_output;
+
+        if let Some(var) = addr.as_var() {
+            self.machine_st.bind(var, stream_as_cell!(stream));
+            return Ok(());
+        }
+
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Cons, cons_ptr) => {
+                match_untyped_arena_ptr!(cons_ptr,
+                    (ArenaHeaderTag::Stream, other_stream) => {
+                        self.machine_st.fail = stream != other_stream;
                     }
                     _ => {
                         let stub = functor_stub(atom!("current_output"), 1);
@@ -916,150 +930,245 @@ impl Machine {
                     }
                 );
             }
-            &SystemClauseType::DirectoryFiles => {
-                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let path = std::path::Path::new(dir.as_str());
-                    let mut files = Vec::new();
+            _ => {
+                let stub = functor_stub(atom!("current_output"), 1);
+                let err = self.machine_st.domain_error(DomainErrorType::Stream, addr);
 
-                    if let Ok(entries) = fs::read_dir(path) {
-                        for entry in entries {
-                            if let Ok(entry) = entry {
-                                if let Some(name) = entry.file_name().to_str() {
-                                    let name = self.machine_st.atom_tbl.build_with(name);
-                                    files.push(atom_as_cstr_cell!(name));
+                return Err(self.machine_st.error_form(err, stub));
+            }
+        );
 
-                                    continue;
-                                }
-                            }
+        Ok(())
+    }
 
-                            let stub = functor_stub(atom!("directory_files"), 2);
-                            let err = self.machine_st.representation_error(RepFlag::Character);
-                            let err = self.machine_st.error_form(err, stub);
+    #[inline(always)]
+    pub(crate) fn directory_files(&mut self) -> CallResult {
+        if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let path = std::path::Path::new(dir.as_str());
+            let mut files = Vec::new();
+
+            if let Ok(entries) = fs::read_dir(path) {
+                for entry in entries {
+                    if let Ok(entry) = entry {
+                        if let Some(name) = entry.file_name().to_str() {
+                            let name = self.machine_st.atom_tbl.build_with(name);
+                            files.push(atom_as_cstr_cell!(name));
 
-                            return Err(err);
+                            continue;
                         }
+                    }
 
-                        let files_list = heap_loc_as_cell!(
-                            iter_to_heap_list(&mut self.machine_st.heap, files.into_iter())
-                        );
+                    let stub = functor_stub(atom!("directory_files"), 2);
+                    let err = self.machine_st.representation_error(RepFlag::Character);
+                    let err = self.machine_st.error_form(err, stub);
 
-                        unify!(self.machine_st, self.machine_st.registers[2], files_list);
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    }
+                    return Err(err);
                 }
 
+                let files_list = heap_loc_as_cell!(
+                    iter_to_heap_list(&mut self.machine_st.heap, files.into_iter())
+                );
+
+                unify!(self.machine_st, self.machine_st.registers[2], files_list);
+                return Ok(());
+            }
+        }
+
+        self.machine_st.fail = true;
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn file_size(&mut self) {
+        if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let len = Number::arena_from(
+                fs::metadata(file.as_str()).unwrap().len(),
+                &mut self.machine_st.arena,
+            );
+
+            match len {
+                Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]),
+                Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]),
+                _ => unreachable!(),
+            }
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn file_exists(&mut self) {
+        if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let file_str = file.as_str();
+
+            if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() {
                 self.machine_st.fail = true;
             }
-            &SystemClauseType::FileSize => {
-                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let len = Number::arena_from(
-                        fs::metadata(file.as_str()).unwrap().len(),
-                        &mut self.machine_st.arena,
-                    );
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn directory_exists(&mut self) {
+        if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let dir_str = dir.as_str();
+
+            if !std::path::Path::new(dir_str).exists() || !fs::metadata(dir_str).unwrap().is_dir() {
+                self.machine_st.fail = true;
+            }
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
 
-                    match len {
-                        Number::Fixnum(n) => self.machine_st.unify_fixnum(n, self.machine_st.registers[2]),
-                        Number::Integer(n) => self.machine_st.unify_big_int(n, self.machine_st.registers[2]),
-                        _ => unreachable!(),
+    #[inline(always)]
+    pub(crate) fn file_time(&mut self) {
+        if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+                self.machine_st.registers[2]
+            )));
+
+            if let Ok(md) = fs::metadata(file.as_str()) {
+                if let Ok(time) = match which {
+                    atom!("modification") => md.modified(),
+                    atom!("access") => md.accessed(),
+                    atom!("creation") => md.created(),
+                    _ => {
+                        unreachable!()
                     }
-                } else {
-                    self.machine_st.fail = true;
+                } {
+                    let chars_atom = self.systemtime_to_timestamp(time);
+
+                    self.machine_st.unify_complete_string(
+                        chars_atom,
+                        self.machine_st.registers[3],
+                    );
+
+                    return;
                 }
             }
-            &SystemClauseType::FileExists => {
-                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let file_str = file.as_str();
+        }
 
-                    if !std::path::Path::new(file_str).exists() || !fs::metadata(file_str).unwrap().is_file() {
-                        self.machine_st.fail = true;
-                    }
-                } else {
+        self.machine_st.fail = true;
+    }
+
+    #[inline(always)]
+    pub(crate) fn directory_separator(&mut self) {
+        self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]);
+    }
+
+    #[inline(always)]
+    pub(crate) fn make_directory(&mut self) {
+        if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            match fs::create_dir(dir.as_str()) {
+                Ok(_) => {}
+                _ => {
                     self.machine_st.fail = true;
                 }
             }
-            &SystemClauseType::DirectoryExists => {
-                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let dir_str = dir.as_str();
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
 
-                    if !std::path::Path::new(dir_str).exists()
-                        || !fs::metadata(dir_str).unwrap().is_dir()
-                    {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                } else {
+    #[inline(always)]
+    pub(crate) fn make_directory_path(&mut self) {
+        if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+
+            match fs::create_dir_all(dir.as_str()) {
+                Ok(_) => {}
+                _ => {
                     self.machine_st.fail = true;
                 }
             }
-            &SystemClauseType::DirectorySeparator => {
-                self.machine_st.unify_char(std::path::MAIN_SEPARATOR, self.machine_st.registers[1]);
-            }
-            &SystemClauseType::MakeDirectory => {
-                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    match fs::create_dir(dir.as_str()) {
-                        Ok(_) => {}
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                } else {
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn delete_file(&mut self) {
+        if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            match fs::remove_file(file.as_str()) {
+                Ok(_) => {}
+                _ => {
                     self.machine_st.fail = true;
                 }
             }
-            &SystemClauseType::MakeDirectoryPath => {
-                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+        }
+    }
 
-                    match fs::create_dir_all(dir.as_str()) {
-                        Ok(_) => {}
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                } else {
-                    self.machine_st.fail = true;
+    #[inline(always)]
+    pub(crate) fn rename_file(&mut self) {
+        if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+                if fs::rename(file.as_str(), renamed.as_str()).is_ok() {
+                    return;
                 }
             }
-            &SystemClauseType::DeleteFile => {
-                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    match fs::remove_file(file.as_str()) {
-                        Ok(_) => {}
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
+        }
+
+        self.machine_st.fail = true;
+    }
+
+    #[inline(always)]
+    pub(crate) fn delete_directory(&mut self) {
+        if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            match fs::remove_dir(dir.as_str()) {
+                Ok(_) => {}
+                _ => {
+                    self.machine_st.fail = true;
                 }
             }
-            &SystemClauseType::RenameFile => {
-                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    if let Some(renamed) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
-                        if fs::rename(file.as_str(), renamed.as_str()).is_ok() {
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    }
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn working_directory(&mut self) -> CallResult {
+        if let Ok(dir) = env::current_dir() {
+            let current = match dir.to_str() {
+                Some(d) => d,
+                _ => {
+                    let stub = functor_stub(atom!("working_directory"), 2);
+                    let err = self.machine_st.representation_error(RepFlag::Character);
+                    let err = self.machine_st.error_form(err, stub);
+
+                    return Err(err);
                 }
+            };
 
-                self.machine_st.fail = true;
+            let current_atom = self.machine_st.atom_tbl.build_with(&current);
+
+            self.machine_st.unify_complete_string(
+                current_atom,
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+            );
+
+            if self.machine_st.fail {
+                return Ok(());
             }
-            &SystemClauseType::DeleteDirectory => {
-                if let Some(dir) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    match fs::remove_dir(dir.as_str()) {
-                        Ok(_) => {}
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
+
+            if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+                if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() {
+                    return Ok(());
                 }
             }
-            &SystemClauseType::WorkingDirectory => {
-                if let Ok(dir) = env::current_dir() {
-                    let current = match dir.to_str() {
-                        Some(d) => d,
+        }
+
+        self.machine_st.fail = true;
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn path_canonical(&mut self) -> CallResult {
+        if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            match fs::canonicalize(path.as_str()) {
+                Ok(canonical) => {
+                    let cs = match canonical.to_str() {
+                        Some(s) => s,
                         _ => {
-                            let stub = functor_stub(atom!("working_directory"), 2);
+                            let stub = functor_stub(atom!("path_canonical"), 2);
                             let err = self.machine_st.representation_error(RepFlag::Character);
                             let err = self.machine_st.error_form(err, stub);
 
@@ -1067,4379 +1176,4701 @@ impl Machine {
                         }
                     };
 
-                    let current_atom = self.machine_st.atom_tbl.build_with(&current);
+                    let canonical_atom = self.machine_st.atom_tbl.build_with(cs);
 
                     self.machine_st.unify_complete_string(
-                        current_atom,
-                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+                        canonical_atom,
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
                     );
 
-                    if self.machine_st.fail {
-                        return Ok(());
-                    }
-
-                    if let Some(next) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
-                        if env::set_current_dir(std::path::Path::new(next.as_str())).is_ok() {
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    }
+                    return Ok(());
+                }
+                _ => {
                 }
-
-                self.machine_st.fail = true;
             }
-            &SystemClauseType::PathCanonical => {
-                if let Some(path) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    match fs::canonicalize(path.as_str()) {
-                        Ok(canonical) => {
-                            let cs = match canonical.to_str() {
-                                Some(s) => s,
-                                _ => {
-                                    let stub = functor_stub(atom!("path_canonical"), 2);
-                                    let err = self.machine_st.representation_error(RepFlag::Character);
-                                    let err = self.machine_st.error_form(err, stub);
-
-                                    return Err(err);
-                                }
-                            };
+        }
+
+        self.machine_st.fail = true;
+        Ok(())
+    }
 
-                            let canonical_atom = self.machine_st.atom_tbl.build_with(cs);
+    #[inline(always)]
+    pub(crate) fn atom_chars(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                            self.machine_st.unify_complete_string(
-                                canonical_atom,
-                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
-                            );
+        read_heap_cell!(a1,
+            (HeapCellValueTag::Char) => {
+                let h = self.machine_st.heap.len();
+
+                self.machine_st.heap.push(a1);
+                self.machine_st.heap.push(empty_list_as_cell!());
+
+                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,
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+                    );
+                } else {
+                    self.machine_st.fail = true;
+                }
+            }
+            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                if let Some(str_like) = self.machine_st.value_to_str_like(a2) {
+                    let atom = match str_like {
+                        AtomOrString::Atom(atom) => {
+                            atom
                         }
-                        _ => {
+                        AtomOrString::String(string) => {
+                            self.machine_st.atom_tbl.build_with(&string)
                         }
-                    }
+                    };
+
+                    self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
+                    return;
                 }
 
                 self.machine_st.fail = true;
             }
-            &SystemClauseType::FileTime => {
-                if let Some(file) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let which = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+            _ => {
+                unreachable!();
+            }
+        );
+    }
 
-                    if let Ok(md) = fs::metadata(file.as_str()) {
-                        if let Ok(time) = match which {
-                            atom!("modification") => md.modified(),
-                            atom!("access") => md.accessed(),
-                            atom!("creation") => md.created(),
-                            _ => {
-                                unreachable!()
-                            }
-                        } {
-                            let chars_atom = self.systemtime_to_timestamp(time);
+    #[inline(always)]
+    pub(crate) fn atom_codes(&mut self) -> CallResult {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                            self.machine_st.unify_complete_string(
-                                chars_atom,
-                                self.machine_st.registers[3],
-                            );
+        read_heap_cell!(a1,
+            (HeapCellValueTag::Char, c) => {
+                let h = self.machine_st.heap.len();
 
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    }
-                }
+                self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
+                self.machine_st.heap.push(empty_list_as_cell!());
 
-                self.machine_st.fail = true;
+                unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
             }
-            &SystemClauseType::AtomChars => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                if arity == 0 {
+                    let iter = name.chars()
+                        .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
 
-                read_heap_cell!(a1,
-                    (HeapCellValueTag::Char) => {
-                        let h = self.machine_st.heap.len();
+                    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;
+                }
+            }
+            (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
+                let stub_gen = || functor_stub(atom!("atom_codes"), 2);
 
-                        self.machine_st.heap.push(a1);
-                        self.machine_st.heap.push(empty_list_as_cell!());
+                match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) {
+                    Ok(addrs) => {
+                        let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
+                        let atom = self.machine_st.atom_tbl.build_with(&string);
 
-                        unify!(self.machine_st, self.machine_st.registers[2], list_loc_as_cell!(h));
+                        self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
                     }
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        if arity == 0 {
-                            self.machine_st.unify_complete_string(
-                                name,
-                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
-                            );
-                        } else {
-                            self.machine_st.fail = true;
-                        }
+                    Err(e) => {
+                        return Err(e);
                     }
-                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                }
+            }
+            _ => {
+                unreachable!();
+            }
+        );
 
-                        if let Some(str_like) = self.machine_st.value_to_str_like(a2) {
-                            let atom = match str_like {
-                                AtomOrString::Atom(atom) => {
-                                    atom
-                                }
-                                AtomOrString::String(string) => {
-                                    self.machine_st.atom_tbl.build_with(&string)
-                                }
-                            };
+        Ok(())
+    }
 
-                            self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
+    #[inline(always)]
+    pub(crate) fn atom_length(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                        self.machine_st.fail = true;
-                    }
-                    _ => {
-                        unreachable!();
-                    }
-                );
+        let len: i64 = read_heap_cell!(a1,
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                if arity == 0 {
+                    name.chars().count() as i64
+                } else {
+                    self.machine_st.fail = true;
+                    return;
+                }
             }
-            &SystemClauseType::AtomCodes => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-
-                read_heap_cell!(a1,
-                    (HeapCellValueTag::Char, c) => {
-                        let h = self.machine_st.heap.len();
+            (HeapCellValueTag::Char) => {
+                1
+            }
+            _ => {
+                unreachable!()
+            }
+        );
 
-                        self.machine_st.heap.push(fixnum_as_cell!(Fixnum::build_with(c as i64)));
-                        self.machine_st.heap.push(empty_list_as_cell!());
+        self.machine_st.unify_fixnum(
+            Fixnum::build_with(len),
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+        );
+    }
 
-                        unify!(self.machine_st, list_loc_as_cell!(h), self.machine_st.registers[2]);
-                    }
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        if arity == 0 {
-                            let iter = name.chars()
-                                .map(|c| fixnum_as_cell!(Fixnum::build_with(c as i64)));
+    #[inline(always)]
+    pub(crate) fn call_continuation(&mut self, last_call: bool) -> CallResult {
+        let stub_gen = || functor_stub(atom!("call_continuation"), 1);
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        match self.machine_st.try_from_list(a1, stub_gen) {
+            Err(e) => Err(e),
+            Ok(cont_chunks) => {
+                let mut return_p = if last_call {
+                    self.machine_st.cp
+                } else {
+                    self.machine_st.p + 1
+                };
 
-                            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;
-                        }
-                    }
-                    (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
-                        let stub_gen = || functor_stub(atom!("atom_codes"), 2);
+                self.machine_st.p = return_p;
 
-                        match self.machine_st.try_from_list(self.machine_st.registers[2], stub_gen) {
-                            Ok(addrs) => {
-                                let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
-                                let atom = self.machine_st.atom_tbl.build_with(&string);
+                for chunk in cont_chunks.into_iter().rev() {
+                    return_p = self.machine_st.call_continuation_chunk(chunk, return_p);
+                }
 
-                                self.machine_st.bind(a1.as_var().unwrap(), atom_as_cell!(atom));
-                            }
-                            Err(e) => {
-                                return Err(e);
-                            }
-                        }
-                    }
-                    _ => {
-                        unreachable!();
-                    }
-                );
+                Ok(())
             }
-            &SystemClauseType::AtomLength => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        }
+    }
 
-                let len: i64 = read_heap_cell!(a1,
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        if arity == 0 {
-                            name.chars().count() as i64
-                        } else {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                    (HeapCellValueTag::Char) => {
-                        1
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                );
+    #[inline(always)]
+    pub(crate) fn chars_to_number(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("number_chars"), 2);
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) {
+            self.machine_st.parse_number_from_string(
+                atom_or_string.to_string(),
+                &self.indices,
+                stub_gen,
+            )?;
+        } else {
+            // a1 is a ground list at the call site within
+            // number_chars/2, so failure of value_to_str_like
+            // means the list contains a non-character.
+            let err = self.machine_st.type_error(ValidType::Character, a1);
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        }
 
-                self.machine_st.unify_fixnum(
-                    Fixnum::build_with(len),
-                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
-                );
-            }
-            &SystemClauseType::CallContinuation => {
-                let stub_gen = || functor_stub(atom!("call_continuation"), 1);
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        Ok(())
+    }
 
-                match self.machine_st.try_from_list(a1, stub_gen) {
-                    Err(e) => return Err(e),
-                    Ok(cont_chunks) => {
-                        let mut return_p = if self.machine_st.last_call {
-                            self.machine_st.cp
-                        } else {
-                            self.machine_st.p.local() + 1
-                        };
+    #[inline(always)]
+    pub(crate) fn create_partial_string(&mut self) {
+        let atom = cell_as_atom!(
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+        );
 
-                        self.machine_st.p = CodePtr::Local(return_p);
+        if atom == atom!("") {
+            self.machine_st.fail = true;
+            return;
+        }
 
-                        for chunk in cont_chunks.into_iter().rev() {
-                            return_p = self.machine_st.call_continuation_chunk(chunk, return_p);
-                        }
-                    }
-                }
+        let pstr_h = self.machine_st.heap.len();
 
-                return Ok(());
-            }
-            &SystemClauseType::CharsToNumber => {
-                let stub_gen = || functor_stub(atom!("number_chars"), 2);
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        self.machine_st.heap.push(pstr_as_cell!(atom));
+        self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1));
 
-                if let Some(atom_or_string) = self.machine_st.value_to_str_like(a1) {
-                    self.machine_st.parse_number_from_string(
-                        atom_or_string.to_string(),
-                        &self.indices,
-                        stub_gen,
-                    )?;
-                } else {
-                    // a1 is a ground list at the call site within
-                    // number_chars/2, so failure of value_to_str_like
-                    // means the list contains a non-character.
-                    let err = self.machine_st.type_error(ValidType::Character, a1);
-                    return Err(self.machine_st.error_form(err, stub_gen()));
-                }
-            }
-            &SystemClauseType::CreatePartialString => {
-                let atom = cell_as_atom!(
-                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
-                );
+        unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h));
 
-                if atom == atom!("") {
-                    self.machine_st.fail = true;
-                    return Ok(());
-                }
+        if !self.machine_st.fail {
+            self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]);
+        }
+    }
 
-                let pstr_h = self.machine_st.heap.len();
+    #[inline(always)]
+    pub(crate) fn is_partial_string(&mut self) {
+        let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                self.machine_st.heap.push(pstr_as_cell!(atom));
-                self.machine_st.heap.push(heap_loc_as_cell!(pstr_h+1));
+        let h = self.machine_st.heap.len();
+        self.machine_st.heap.push(value);
 
-                unify!(self.machine_st, self.machine_st.registers[2], pstr_loc_as_cell!(pstr_h));
+        let mut iter = HeapPStrIter::new(&self.machine_st.heap, h);
 
-                if !self.machine_st.fail {
-                    self.machine_st.bind(Ref::heap_cell(pstr_h+1), self.machine_st.registers[3]);
-                }
-            }
-            &SystemClauseType::IsPartialString => {
-                let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        while let Some(_) = iter.next() {}
 
-                let h = self.machine_st.heap.len();
-                self.machine_st.heap.push(value);
+        let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator();
+        self.machine_st.fail = !at_end_of_pstr;
 
-                let mut iter = HeapPStrIter::new(&self.machine_st.heap, h);
+        self.machine_st.heap.pop();
+    }
 
-                while let Some(_) = iter.next() {}
+    #[inline(always)]
+    pub(crate) fn partial_string_tail(&mut self) {
+        let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                let at_end_of_pstr = iter.focus.is_var() || iter.at_string_terminator();
-                self.machine_st.fail = !at_end_of_pstr;
+        read_heap_cell!(pstr,
+            (HeapCellValueTag::PStrLoc, h) => {
+                let (h, _) = pstr_loc_and_offset(&self.machine_st.heap, h);
 
-                self.machine_st.heap.pop();
+                if HeapCellValueTag::CStr == self.machine_st.heap[h].get_tag() {
+                    self.machine_st.unify_atom(
+                        atom!("[]"),
+                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+                    );
+                } else {
+                    unify_fn!(
+                        self.machine_st,
+                        heap_loc_as_cell!(h+1),
+                        self.machine_st.registers[2]
+                    );
+                }
             }
-            &SystemClauseType::PartialStringTail => {
-                let pstr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-
-                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!("[]"),
-                                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
-                            );
-                        } else {
-                            unify_fn!(
-                                self.machine_st,
-                                heap_loc_as_cell!(h+1),
-                                self.machine_st.registers[2]
-                            );
-                        }
-                    }
-                    (HeapCellValueTag::CStr) => {
-                        self.machine_st.unify_atom(
-                            atom!("[]"),
-                            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
-                        );
-                    }
-                    (HeapCellValueTag::Lis, h) => {
-                        unify_fn!(
-                            self.machine_st,
-                            heap_loc_as_cell!(h+1),
-                            self.machine_st.registers[2]
-                        );
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                    }
+            (HeapCellValueTag::CStr) => {
+                self.machine_st.unify_atom(
+                    atom!("[]"),
+                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
                 );
             }
-            &SystemClauseType::PeekByte => {
-                let stub_gen = || functor_stub(atom!("peek_byte"), 2);
-
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("peek_byte"),
-                    2,
-                )?;
-
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Binary,
-                    Some(self.machine_st.registers[2]),
-                    atom!("peek_byte"),
-                    2,
-                )?;
-
-                if stream.past_end_of_stream() {
-                    if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    } else if self.machine_st.fail {
-                        return Ok(());
-                    }
-                }
+            (HeapCellValueTag::Lis, h) => {
+                unify_fn!(
+                    self.machine_st,
+                    heap_loc_as_cell!(h+1),
+                    self.machine_st.registers[2]
+                );
+            }
+            _ => {
+                self.machine_st.fail = true;
+            }
+        );
+    }
 
-                if stream.at_end_of_stream() {
-                    stream.set_past_end_of_stream(true);
+    #[inline(always)]
+    pub(crate) fn peek_byte(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("peek_byte"), 2);
+
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("peek_byte"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Binary,
+            Some(self.machine_st.registers[2]),
+            atom!("peek_byte"),
+            2,
+        )?;
+
+        if stream.past_end_of_stream() {
+            if EOFAction::Reset != stream.options().eof_action() {
+                return Ok(());
+            } else if self.machine_st.fail {
+                return Ok(());
+            }
+        }
 
-                    self.machine_st.unify_fixnum(
-                        Fixnum::build_with(-1),
-                        self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
-                    );
+        if stream.at_end_of_stream() {
+            stream.set_past_end_of_stream(true);
 
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+            self.machine_st.unify_fixnum(
+                Fixnum::build_with(-1),
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+            );
 
-                let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) {
-                    addr if addr.is_var() => addr,
-                    addr => match Number::try_from(addr) {
-                        Ok(Number::Integer(n)) => {
-                            if let Some(nb) = n.to_u8() {
-                                fixnum_as_cell!(Fixnum::build_with(nb as i64))
-                            } else {
-                                let err = self.machine_st.type_error(ValidType::InByte, addr);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                        Ok(Number::Fixnum(n)) => {
-                            if let Ok(nb) = u8::try_from(n.get_num()) {
-                                fixnum_as_cell!(Fixnum::build_with(nb as i64))
-                            } else {
-                                let err = self.machine_st.type_error(ValidType::InByte, addr);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                        _ => {
-                            let err = self.machine_st.type_error(ValidType::InByte, addr);
-                            return Err(self.machine_st.error_form(err, stub_gen()));
-                        }
-                    },
-                };
+            return Ok(());
+        }
 
-                loop {
-                    match stream.peek_byte().map_err(|e| e.kind()) {
-                        Ok(b) => {
-                            self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr);
-                        }
-                        Err(ErrorKind::PermissionDenied) => {
-                            self.machine_st.fail = true;
-                            break;
-                        }
-                        _ => {
-                            self.machine_st.eof_action(
-                                self.machine_st.registers[2],
-                                stream,
-                                atom!("peek_byte"),
-                                2,
-                            )?;
-
-                            if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            } else if self.machine_st.fail {
-                                return Ok(());
-                            }
-                        }
+        let addr = match self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])) {
+            addr if addr.is_var() => addr,
+            addr => match Number::try_from(addr) {
+                Ok(Number::Integer(n)) => {
+                    if let Some(nb) = n.to_u8() {
+                        fixnum_as_cell!(Fixnum::build_with(nb as i64))
+                    } else {
+                        let err = self.machine_st.type_error(ValidType::InByte, addr);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
                     }
                 }
-            }
-            &SystemClauseType::PeekChar => {
-                let stub_gen = || functor_stub(atom!("peek_char"), 2);
-
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("peek_char"),
-                    2,
-                )?;
+                Ok(Number::Fixnum(n)) => {
+                    if let Ok(nb) = u8::try_from(n.get_num()) {
+                        fixnum_as_cell!(Fixnum::build_with(nb as i64))
+                    } else {
+                        let err = self.machine_st.type_error(ValidType::InByte, addr);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                }
+                _ => {
+                    let err = self.machine_st.type_error(ValidType::InByte, addr);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
+                }
+            },
+        };
 
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    Some(self.machine_st.registers[2]),
-                    atom!("peek_char"),
-                    2,
-                )?;
+        loop {
+            match stream.peek_byte().map_err(|e| e.kind()) {
+                Ok(b) => {
+                    self.machine_st.unify_fixnum(Fixnum::build_with(b as i64), addr);
+                }
+                Err(ErrorKind::PermissionDenied) => {
+                    self.machine_st.fail = true;
+                    break;
+                }
+                _ => {
+                    self.machine_st.eof_action(
+                        self.machine_st.registers[2],
+                        stream,
+                        atom!("peek_byte"),
+                        2,
+                    )?;
 
-                if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                        break;
                     } else if self.machine_st.fail {
-                        return Ok(());
+                        break;
                     }
                 }
+            }
+        }
 
-                if stream.at_end_of_stream() {
-                    let end_of_file = atom!("end_of_file");
-                    stream.set_past_end_of_stream(true);
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn peek_char(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("peek_char"), 2);
+
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("peek_char"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            Some(self.machine_st.registers[2]),
+            atom!("peek_char"),
+            2,
+        )?;
+
+        if stream.past_end_of_stream() {
+            if EOFAction::Reset != stream.options().eof_action() {
+                return Ok(());
+            } else if self.machine_st.fail {
+                return Ok(());
+            }
+        }
+
+        if stream.at_end_of_stream() {
+            let end_of_file = atom!("end_of_file");
+            stream.set_past_end_of_stream(true);
+
+            self.machine_st.unify_atom(
+                end_of_file,
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+            );
 
-                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
+            return Ok(());
+        }
+
+        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let a2 = read_heap_cell!(a2,
+            (HeapCellValueTag::Char) => {
+                a2
+            }
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                if arity == 0 {
+                    if let Some(c) = name.as_char() {
+                        char_as_cell!(c)
+                    } else {
+                        let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                } else {
+                    let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
                 }
+            }
+            (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
+                a2
+            }
+            _ => {
+                let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                return Err(self.machine_st.error_form(err, stub_gen()));
+            }
+        );
 
-                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        loop {
+            match stream.peek_char().map(|result| result.map_err(|e| e.kind())) {
+                Some(Ok(d)) => {
+                    self.machine_st.unify_char(d, a2);
+                    break;
+                }
+                Some(Err(ErrorKind::PermissionDenied)) => {
+                    self.machine_st.fail = true;
+                    break;
+                }
+                _ => {
+                    self.machine_st.eof_action(
+                        self.machine_st.registers[2],
+                        stream,
+                        atom!("peek_char"),
+                        2,
+                    )?;
 
-                let a2 = read_heap_cell!(a2,
-                    (HeapCellValueTag::Char) => {
-                        a2
+                    if EOFAction::Reset != stream.options().eof_action() {
+                        break;
+                    } else if self.machine_st.fail {
+                        break;
                     }
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        if arity == 0 {
-                            if let Some(c) = name.as_char() {
-                                char_as_cell!(c)
-                            } else {
-                                let err = self.machine_st.type_error(ValidType::InCharacter, a2);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn peek_code(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("peek_code"), 2);
+
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("peek_code"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            Some(self.machine_st.registers[2]),
+            atom!("peek_code"),
+            2,
+        )?;
+
+        if stream.past_end_of_stream() {
+            if EOFAction::Reset != stream.options().eof_action() {
+                return Ok(());
+            } else if self.machine_st.fail {
+                return Ok(());
+            }
+        }
+
+        if stream.at_end_of_stream() {
+            let end_of_file = atom!("end_of_file");
+            stream.set_past_end_of_stream(true);
+
+            self.machine_st.unify_atom(
+                end_of_file,
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+            );
+
+            return Ok(());
+        }
+
+        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let addr = read_heap_cell!(a2,
+            (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
+                a2
+            }
+            _ => {
+                match Number::try_from(a2) {
+                    Ok(Number::Integer(n)) => {
+                        let n = n
+                            .to_u32()
+                            .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
+
+                        if let Some(n) = n {
+                            fixnum_as_cell!(Fixnum::build_with(n as i64))
                         } else {
-                            let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                            let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
                             return Err(self.machine_st.error_form(err, stub_gen()));
                         }
                     }
-                    (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
-                        a2
+                    Ok(Number::Fixnum(n)) => {
+                        let n = u32::try_from(n.get_num())
+                            .ok()
+                            .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
+
+                        if let Some(n) = n {
+                            fixnum_as_cell!(Fixnum::build_with(n as i64))
+                        } else {
+                            let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                            return Err(self.machine_st.error_form(err, stub_gen()));
+                        }
                     }
                     _ => {
-                        let err = self.machine_st.type_error(ValidType::InCharacter, a2);
+                        let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
                         return Err(self.machine_st.error_form(err, stub_gen()));
                     }
-                );
-
-                loop {
-                    match stream.peek_char().map(|result| result.map_err(|e| e.kind())) {
-                        Some(Ok(d)) => {
-                            self.machine_st.unify_char(d, a2);
-                            break;
-                        }
-                        Some(Err(ErrorKind::PermissionDenied)) => {
-                            self.machine_st.fail = true;
-                            break;
-                        }
-                        _ => {
-                            self.machine_st.eof_action(
-                                self.machine_st.registers[2],
-                                stream,
-                                atom!("peek_char"),
-                                2,
-                            )?;
-
-                            if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            } else if self.machine_st.fail {
-                                return Ok(());
-                            }
-                        }
-                    }
                 }
             }
-            &SystemClauseType::PeekCode => {
-                let stub_gen = || functor_stub(atom!("peek_code"), 2);
+        );
 
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("peek_code"),
-                    2,
-                )?;
+        loop {
+            let result = stream.peek_char();
 
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    Some(self.machine_st.registers[2]),
-                    atom!("peek_code"),
-                    2,
-                )?;
+            match result.map(|result| result.map_err(|e| e.kind())) {
+                Some(Ok(c)) => {
+                    self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
+                    break;
+                }
+                Some(Err(ErrorKind::PermissionDenied)) => {
+                    self.machine_st.fail = true;
+                    break;
+                }
+                _ => {
+                    self.machine_st.eof_action(
+                        self.machine_st.registers[2],
+                        stream,
+                        atom!("peek_code"),
+                        2,
+                    )?;
 
-                if stream.past_end_of_stream() {
                     if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                        break;
                     } else if self.machine_st.fail {
-                        return Ok(());
+                        break;
                     }
                 }
+            }
+        }
 
-                if stream.at_end_of_stream() {
-                    let end_of_file = atom!("end_of_file");
-                    stream.set_past_end_of_stream(true);
+        return Ok(());
+    }
 
-                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+    #[inline(always)]
+    pub(crate) fn number_to_chars(&mut self) {
+        let n = self.machine_st.registers[1];
+        let chs = self.machine_st.registers[2];
+
+        let n = self.machine_st.store(self.machine_st.deref(n));
+
+        let string = match Number::try_from(n) {
+            Ok(Number::Float(OrderedFloat(n))) => {
+                format!("{0:<20?}", n)
+            }
+            Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+            Ok(Number::Integer(n)) => n.to_string(),
+            Ok(Number::Rational(r)) => {
+                // n has already been confirmed as an integer, and
+                // internally, Rational is assumed reduced, so its denominator
+                // must be 1.
+                r.numer().to_string()
+            }
+            _ => {
+                unreachable!()
+            }
+        };
+
+        let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim());
+        self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs)));
+    }
+
+    #[inline(always)]
+    pub(crate) fn number_to_codes(&mut self) {
+        let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let chs = self.machine_st.registers[2];
+
+        let string = match Number::try_from(n) {
+            Ok(Number::Float(OrderedFloat(n))) => {
+                format!("{0:<20?}", n)
+            }
+            Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+            Ok(Number::Integer(n)) => n.to_string(),
+            Ok(Number::Rational(r)) => {
+                // n has already been confirmed as an integer, and
+                // internally, Rational is assumed reduced, so its
+                // denominator must be 1.
+                r.numer().to_string()
+            }
+            _ => {
+                unreachable!()
+            }
+        };
+
+        let codes = string.trim().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);
+    }
+
+    #[inline(always)]
+    pub(crate) fn codes_to_number(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("number_codes"), 2);
+
+        match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) {
+            Err(e) => {
+                return Err(e);
+            }
+            Ok(addrs) => {
+                let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
+                self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?;
+            }
+        }
+
+        Ok(())
+    }
+
+    #[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);
+
+        self.machine_st.unify_fixnum(lh_len, a1);
+    }
+
+    #[inline(always)]
+    pub(crate) fn char_code(&mut self) -> CallResult {
+        let stub_gen = || functor_stub(atom!("char_code"), 2);
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
+        let c = read_heap_cell!(a1,
+            (HeapCellValueTag::Atom, (name, _arity)) => {
+                name.as_char().unwrap()
+            }
+            (HeapCellValueTag::Char, c) => {
+                c
+            }
+            _ => {
                 let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                let addr = read_heap_cell!(a2,
-                    (HeapCellValueTag::Var | HeapCellValueTag::StackVar | HeapCellValueTag::AttrVar) => {
-                        a2
-                    }
-                    _ => {
-                        match Number::try_from(a2) {
-                            Ok(Number::Integer(n)) => {
-                                let n = n
-                                    .to_u32()
-                                    .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
-
-                                if let Some(n) = n {
-                                    fixnum_as_cell!(Fixnum::build_with(n as i64))
-                                } else {
-                                    let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
-                                    return Err(self.machine_st.error_form(err, stub_gen()));
-                                }
-                            }
-                            Ok(Number::Fixnum(n)) => {
-                                let n = u32::try_from(n.get_num())
-                                    .ok()
-                                    .and_then(|n| std::char::from_u32(n).and_then(|_| Some(n)));
-
-                                if let Some(n) = n {
-                                    fixnum_as_cell!(Fixnum::build_with(n as i64))
-                                } else {
-                                    let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
-                                    return Err(self.machine_st.error_form(err, stub_gen()));
-                                }
-                            }
+                match Number::try_from(a2) {
+                    Ok(Number::Integer(n)) => {
+                        let c = match n.to_u32().and_then(std::char::from_u32) {
+                            Some(c) => c,
                             _ => {
-                                let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
+                                let err = self.machine_st.representation_error(RepFlag::CharacterCode);
                                 return Err(self.machine_st.error_form(err, stub_gen()));
                             }
-                        }
-                    }
-                );
-
-                loop {
-                    let result = stream.peek_char();
+                        };
 
-                    match result.map(|result| result.map_err(|e| e.kind())) {
-                        Some(Ok(c)) => {
-                            self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
-                            break;
-                        }
-                        Some(Err(ErrorKind::PermissionDenied)) => {
-                            self.machine_st.fail = true;
-                            break;
-                        }
-                        _ => {
-                            self.machine_st.eof_action(
-                                self.machine_st.registers[2],
-                                stream,
-                                atom!("peek_code"),
-                                2,
-                            )?;
-
-                            if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            } else if self.machine_st.fail {
-                                return Ok(());
+                        self.machine_st.unify_char(c, a2);
+                        return Ok(());
+                    }
+                    Ok(Number::Fixnum(n)) => {
+                        match u32::try_from(n.get_num()) {
+                            Ok(n) => {
+                                if let Some(c) = std::char::from_u32(n) {
+                                    self.machine_st.unify_char(c, a1);
+                                    return Ok(());
+                                }
                             }
+                            _ => {}
                         }
+
+                        let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                    _ => {
+                        self.machine_st.fail = true;
+                        return Ok(());
                     }
                 }
             }
-            &SystemClauseType::NumberToChars => {
-                let n = self.machine_st.registers[1];
-                let chs = self.machine_st.registers[2];
+        );
+
+        self.machine_st.unify_fixnum(
+            Fixnum::build_with(c as i64),
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+        );
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn char_type(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let c = read_heap_cell!(a1,
+            (HeapCellValueTag::Char, c) => {
+                c
+            }
+            (HeapCellValueTag::Atom, (name, _arity)) => {
+                name.as_char().unwrap()
+            }
+            _ => {
+                unreachable!()
+            }
+        );
+
+        let chars = cell_as_atom!(a2);
+        self.machine_st.fail = true; // This predicate fails by default.
+
+        macro_rules! macro_check {
+            ($id:ident, $name:expr) => {
+                if $id!(c) && chars == $name {
+                    self.machine_st.fail = false;
+                    return;
+                }
+            };
+        }
+
+        macro_rules! method_check {
+            ($id:ident, $name:expr) => {
+                if c.$id() && chars == $name {
+                    self.machine_st.fail = false;
+                    return;
+                }
+            };
+        }
+
+        macro_check!(alpha_char, atom!("alpha"));
+        method_check!(is_alphabetic, atom!("alphabetic"));
+        method_check!(is_alphanumeric, atom!("alphanumeric"));
+        macro_check!(alpha_numeric_char, atom!("alnum"));
+        method_check!(is_ascii, atom!("ascii"));
+        method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction"));
+        method_check!(is_ascii_graphic, atom!("ascii_graphic"));
+        // macro_check!(backslash_char, atom!("backslash"));
+        // macro_check!(back_quote_char, atom!("back_quote"));
+        macro_check!(binary_digit_char, atom!("binary_digit"));
+        // macro_check!(capital_letter_char, atom!("upper"));
+        // macro_check!(comment_1_char, "comment_1");
+        // macro_check!(comment_2_char, "comment_2");
+        method_check!(is_control, atom!("control"));
+        // macro_check!(cut_char, atom!("cut"));
+        macro_check!(decimal_digit_char, atom!("decimal_digit"));
+        // macro_check!(decimal_point_char, atom!("decimal_point"));
+        // macro_check!(double_quote_char, atom!("double_quote"));
+        macro_check!(exponent_char, atom!("exponent"));
+        macro_check!(graphic_char, atom!("graphic"));
+        macro_check!(graphic_token_char, atom!("graphic_token"));
+        macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit"));
+        macro_check!(layout_char, atom!("layout"));
+        method_check!(is_lowercase, atom!("lower"));
+        macro_check!(meta_char, atom!("meta"));
+        // macro_check!(new_line_char, atom!("new_line"));
+        method_check!(is_numeric, atom!("numeric"));
+        macro_check!(octal_digit_char, atom!("octal_digit"));
+        macro_check!(octet_char, atom!("octet"));
+        macro_check!(prolog_char, atom!("prolog"));
+        // macro_check!(semicolon_char, atom!("semicolon"));
+        macro_check!(sign_char, atom!("sign"));
+        // macro_check!(single_quote_char, atom!("single_quote"));
+        // macro_check!(small_letter_char, atom!("lower"));
+        macro_check!(solo_char, atom!("solo"));
+        // macro_check!(space_char, atom!("space"));
+        macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal"));
+        macro_check!(symbolic_control_char, atom!("symbolic_control"));
+        method_check!(is_uppercase, atom!("upper"));
+        // macro_check!(variable_indicator_char, atom!("variable_indicator"));
+        method_check!(is_whitespace, atom!("whitespace"));
+    }
+
+    #[inline(always)]
+    pub(crate) fn check_cut_point(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let old_b = cell_as_fixnum!(addr).get_num() as usize;
+
+        let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
+        let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b;
+
+        if prev_b > old_b {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn copy_term_without_attr_vars(&mut self) {
+        self.machine_st.copy_term(AttrVarPolicy::StripAttributes);
+    }
+
+    #[inline(always)]
+    pub(crate) fn fetch_global_var(&mut self) {
+        let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+        let addr = self.machine_st.registers[2];
+
+        match self.indices.global_variables.get_mut(&key) {
+            Some((ref ball, ref mut loc)) => match loc {
+                Some(value_loc) => {
+                    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.into_iter());
+
+                    unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h));
+
+                    if !self.machine_st.fail {
+                        *loc = Some(heap_loc_as_cell!(h));
+                        self.machine_st.trail(TrailRef::BlackboardEntry(key));
+                    }
+                }
+                _ => self.machine_st.fail = true,
+            },
+            None => self.machine_st.fail = true,
+        };
+    }
+
+    #[inline(always)]
+    pub(crate) fn put_code(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("put_code"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            None,
+            atom!("put_code"),
+            2,
+        )?;
+
+        let stub_gen = || functor_stub(atom!("put_code"), 2);
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        if addr.is_var() {
+            let err = self.machine_st.instantiation_error();
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        } else {
+            match Number::try_from(addr) {
+                Ok(Number::Integer(n)) => {
+                    if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) {
+                        write!(&mut stream, "{}", c).unwrap();
+                        return Ok(());
+                    }
+                }
+                Ok(Number::Fixnum(n)) => {
+                    let n = n.get_num();
+
+                    if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) {
+                        write!(&mut stream, "{}", c).unwrap();
+                        return Ok(());
+                    }
+                }
+                _ => {
+                    let err = self.machine_st.type_error(ValidType::Integer, addr);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
+                }
+            }
+
+            let err = self.machine_st.representation_error(RepFlag::CharacterCode);
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn put_char(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("put_char"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            None,
+            atom!("put_char"),
+            2,
+        )?;
+
+        let stub_gen = || functor_stub(atom!("put_char"), 2);
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        if addr.is_var() {
+            let err = self.machine_st.instantiation_error();
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        } else {
+            read_heap_cell!(addr,
+                (HeapCellValueTag::Atom, (name, _arity)) => {
+                    let c = name.as_char().unwrap();
+                    write!(&mut stream, "{}", c).unwrap();
+                    return Ok(());
+                }
+                (HeapCellValueTag::Char, c) => {
+                    write!(&mut stream, "{}", c).unwrap();
+                    return Ok(());
+                }
+                _ => {
+                }
+            );
+
+            let err = self.machine_st.type_error(ValidType::Character, addr);
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn put_chars(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("$put_chars"),
+            2,
+        )?;
+
+        let mut bytes = Vec::new();
+        let stub_gen = || functor_stub(atom!("$put_chars"), 2);
+
+        if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+            if stream.options().stream_type() == StreamType::Binary {
+                for c in string.as_str().chars() {
+                    if c as u32 > 255 {
+                        let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c));
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+
+                    bytes.push(c as u8);
+                }
+            } else {
+                bytes = string.as_str().bytes().collect();
+            }
+
+            match stream.write_all(&bytes) {
+                Ok(_) => {
+                }
+                _ => {
+                    let addr = stream_as_cell!(stream);
+                    let err = self.machine_st.existence_error(ExistenceError::Stream(addr));
+
+                    return Err(self.machine_st.error_form(err, stub_gen()));
+                }
+            }
+        } else {
+            self.machine_st.fail = true;
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn put_byte(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("put_byte"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Binary,
+            None,
+            atom!("put_byte"),
+            2,
+        )?;
+
+        let stub_gen = || functor_stub(atom!("put_byte"), 2);
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        if addr.is_var() {
+            let err = self.machine_st.instantiation_error();
+            return Err(self.machine_st.error_form(err, stub_gen()));
+        } else {
+            match Number::try_from(addr) {
+                Ok(Number::Integer(n)) => {
+                    if let Some(nb) = n.to_u8() {
+                        match stream.write(&mut [nb]) {
+                            Ok(1) => {
+                                return Ok(());
+                            }
+                            _ => {
+                                let err = self.machine_st.existence_error(
+                                    ExistenceError::Stream(stream_as_cell!(stream))
+                                );
+
+                                return Err(self.machine_st.error_form(err, stub_gen()));
+                            }
+                        }
+                    }
+                }
+                Ok(Number::Fixnum(n)) => {
+                    if let Ok(nb) = u8::try_from(n.get_num()) {
+                        match stream.write(&mut [nb]) {
+                            Ok(1) => {
+                                return Ok(());
+                            }
+                            _ => {
+                                let err = self.machine_st.existence_error(
+                                    ExistenceError::Stream(stream_as_cell!(stream))
+                                );
+
+                                return Err(self.machine_st.error_form(err, stub_gen()));
+                            }
+                        }
+                    }
+                }
+                _ => {
+                }
+            }
+        }
+
+        let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]);
+        Err(self.machine_st.error_form(err, stub_gen()))
+    }
+
+    #[inline(always)]
+    pub(crate) fn get_byte(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("get_byte"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Binary,
+            Some(self.machine_st.registers[2]),
+            atom!("get_byte"),
+            2,
+        )?;
+
+        if stream.past_end_of_stream() {
+            self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?;
+
+            if EOFAction::Reset != stream.options().eof_action() {
+                return Ok(());
+            } else if self.machine_st.fail {
+                return Ok(());
+            }
+        }
+
+        let stub_gen = || functor_stub(atom!("get_byte"), 2);
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let addr = if addr.is_var() {
+            addr
+        } else {
+            match Number::try_from(addr) {
+                Ok(Number::Integer(n)) => {
+                    if let Some(nb) = n.to_u8() {
+                        fixnum_as_cell!(Fixnum::build_with(nb as i64))
+                    } else {
+                        let err = self.machine_st.type_error(ValidType::InByte, addr);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                }
+                Ok(Number::Fixnum(n)) => {
+                    if let Ok(nb) = u8::try_from(n.get_num()) {
+                        fixnum_as_cell!(Fixnum::build_with(nb as i64))
+                    } else {
+                        let err = self.machine_st.type_error(ValidType::InByte, addr);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                }
+                _ => {
+                    let err = self.machine_st.type_error(ValidType::InByte, addr);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
+                }
+            }
+        };
+
+        loop {
+            let mut b = [0u8; 1];
+
+            match stream.read(&mut b) {
+                Ok(1) => {
+                    self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
+                    break;
+                }
+                _ => {
+                    stream.set_past_end_of_stream(true);
+                    self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]);
+                    break;
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn get_char(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("get_char"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            Some(self.machine_st.registers[2]),
+            atom!("get_char"),
+            2,
+        )?;
+
+        if stream.past_end_of_stream() {
+            if EOFAction::Reset != stream.options().eof_action() {
+                return Ok(());
+            } else if self.machine_st.fail {
+                return Ok(());
+            }
+        }
+
+        if stream.at_end_of_stream() {
+            let end_of_file = atom!("end_of_file");
+            stream.set_past_end_of_stream(true);
+
+            self.machine_st.unify_atom(
+                end_of_file,
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+            );
+
+            return Ok(());
+        }
+
+        let stub_gen = || functor_stub(atom!("get_char"), 2);
+        let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?;
+
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let addr = if addr.is_var() {
+            addr
+        } else {
+            read_heap_cell!(addr,
+                (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()));
+                }
+            )
+        };
+
+        loop {
+            let result = iter.read_char();
+
+            match result {
+                Some(Ok(c)) => {
+                    self.machine_st.unify_char(c, addr);
+                    break;
+                }
+                _ => {
+                    self.machine_st.eof_action(
+                        self.machine_st.registers[2],
+                        stream,
+                        atom!("get_char"),
+                        2,
+                    )?;
+
+                    if EOFAction::Reset != stream.options().eof_action() {
+                        break;
+                    } else if self.machine_st.fail {
+                        break;
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn get_n_chars(&mut self) -> CallResult {
+        let stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("get_n_chars"),
+            3,
+        )?;
+
+        let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) {
+            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
+            Ok(Number::Integer(n)) => match n.to_usize() {
+                Some(u) => u,
+                _ => {
+                    self.machine_st.fail = true;
+                    return Ok(());
+                }
+            },
+            _ => {
+                unreachable!()
+            }
+        };
+
+        let mut string = String::new();
+
+        if stream.options().stream_type() == StreamType::Binary {
+            let mut buf = vec![];
+            let mut chunk = stream.take(num as u64);
+
+            chunk.read_to_end(&mut buf).ok();
+
+            for c in buf {
+                string.push(c as char);
+            }
+        } else {
+            let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?;
+
+            for _ in 0..num {
+                let result = iter.read_char();
+
+                match result {
+                    Some(Ok(c)) => {
+                        string.push(c);
+                    }
+                    _ => {
+                        break;
+                    }
+                }
+            }
+        };
+
+        let atom = self.machine_st.atom_tbl.build_with(&string);
+        self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn get_code(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("get_code"),
+            2,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            Some(self.machine_st.registers[2]),
+            atom!("get_code"),
+            2,
+        )?;
+
+        if stream.past_end_of_stream() {
+            if EOFAction::Reset != stream.options().eof_action() {
+                return Ok(());
+            } else if self.machine_st.fail {
+                return Ok(());
+            }
+        }
+
+        if stream.at_end_of_stream() {
+            let end_of_file = atom!("end_of_file");
+            stream.set_past_end_of_stream(true);
+
+            self.machine_st.unify_atom(
+                end_of_file,
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+            );
+
+            return Ok(());
+        }
+
+        let stub_gen = || functor_stub(atom!("get_code"), 2);
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let addr = if addr.is_var() {
+            addr
+        } else {
+            match Number::try_from(addr) {
+                Ok(Number::Integer(n)) => {
+                    let n = n
+                        .to_u32()
+                        .and_then(|n| std::char::from_u32(n));
+
+                    if let Some(n) = n {
+                        fixnum_as_cell!(Fixnum::build_with(n as i64))
+                    } else {
+                        let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                }
+                Ok(Number::Fixnum(n)) => {
+                    let nf = u32::try_from(n.get_num())
+                        .ok()
+                        .and_then(|n| std::char::from_u32(n));
+
+                    if nf.is_some() {
+                        fixnum_as_cell!(n)
+                    } else {
+                        let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
+                        return Err(self.machine_st.error_form(err, stub_gen()));
+                    }
+                }
+                _ => {
+                    let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
+                    return Err(self.machine_st.error_form(err, stub_gen()));
+                }
+            }
+        };
+
+        let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?;
+
+        loop {
+            let result = iter.read_char();
+
+            match result {
+                Some(Ok(c)) => {
+                    self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
+                    break;
+                }
+                _ => {
+                    self.machine_st.eof_action(
+                        self.machine_st.registers[2],
+                        stream,
+                        atom!("get_code"),
+                        2,
+                    )?;
+
+                    if EOFAction::Reset != stream.options().eof_action() {
+                        break;
+                    } else if self.machine_st.fail {
+                        break;
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn first_stream(&mut self) {
+        let mut first_stream = None;
+        let mut null_streams = BTreeSet::new();
+
+        for stream in self.indices.streams.iter().cloned() {
+            if !stream.is_null_stream() {
+                first_stream = Some(stream);
+                break;
+            } else {
+                null_streams.insert(stream);
+            }
+        }
+
+        self.indices.streams = self.indices.streams.sub(&null_streams);
+
+        if let Some(first_stream) = first_stream {
+            let stream = stream_as_cell!(first_stream);
+
+            let var = self.machine_st.store(self.machine_st.deref(
+                self.machine_st.registers[1]
+            )).as_var().unwrap();
+
+            self.machine_st.bind(var, stream);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn next_stream(&mut self) {
+        let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1]
+        )));
+
+        let mut next_stream = None;
+        let mut null_streams = BTreeSet::new();
+
+        for stream in self.indices
+            .streams
+            .range(prev_stream..)
+            .skip(1)
+            .cloned()
+        {
+            if !stream.is_null_stream() {
+                next_stream = Some(stream);
+                break;
+            } else {
+                null_streams.insert(stream);
+            }
+        }
+
+        self.indices.streams = self.indices.streams.sub(&null_streams);
+
+        if let Some(next_stream) = next_stream {
+            let var = self.machine_st.store(self.machine_st.deref(
+                self.machine_st.registers[2]
+            )).as_var().unwrap();
+
+            let next_stream = stream_as_cell!(next_stream);
+            self.machine_st.bind(var, next_stream);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn flush_output(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("flush_output"),
+            1,
+        )?;
+
+        if !stream.is_output_stream() {
+            let stub = functor_stub(atom!("flush_output"), 1);
+            let addr = stream_as_cell!(stream);
+
+            let err = self.machine_st.permission_error(
+                Permission::OutputStream,
+                atom!("stream"),
+                addr,
+            );
+
+            return Err(self.machine_st.error_form(err, stub));
+        }
+
+        stream.flush().unwrap();
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn get_single_char(&mut self) -> CallResult {
+        let ctrl_c = KeyEvent {
+            code: KeyCode::Char('c'),
+            modifiers: KeyModifiers::CONTROL,
+        };
+
+        let key = get_key();
+
+        if key == ctrl_c {
+            let stub = functor_stub(atom!("get_single_char"), 1);
+            let err = self.machine_st.interrupt_error();
+            let err = self.machine_st.error_form(err, stub);
+
+            return Err(err);
+        }
+
+        let c = match key.code {
+            KeyCode::Enter => '\n',
+            KeyCode::Tab => '\t',
+            KeyCode::Char(c) => c,
+            _ => unreachable!(),
+        };
+
+        self.machine_st.unify_char(
+            c,
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+        );
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn head_is_dynamic(&mut self) {
+        let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1])
+        ));
+
+        let (name, arity) = read_heap_cell!(
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+            (HeapCellValueTag::Str, s) => {
+                cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity()
+            }
+            (HeapCellValueTag::Atom, (name, _arity)) => {
+                (name, 0)
+            }
+            _ => {
+                unreachable!()
+            }
+        );
+
+        self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity));
+    }
+
+    #[inline(always)]
+    pub(crate) fn close(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("close"),
+            2,
+        )?;
+
+        if !stream.is_input_stream() {
+            stream.flush().unwrap(); // 8.11.6.1b)
+        }
 
-                let n = self.machine_st.store(self.machine_st.deref(n));
+        self.indices.streams.remove(&stream);
 
-                let string = match Number::try_from(n) {
-                    Ok(Number::Float(OrderedFloat(n))) => {
-                        format!("{0:<20?}", n)
-                    }
-                    Ok(Number::Fixnum(n)) => n.get_num().to_string(),
-                    Ok(Number::Integer(n)) => n.to_string(),
-                    Ok(Number::Rational(r)) => {
-                        // n has already been confirmed as an integer, and
-                        // internally, Rational is assumed reduced, so its denominator
-                        // must be 1.
-                        r.numer().to_string()
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                };
+        if stream == self.user_input {
+            self.user_input = self.indices
+                .stream_aliases
+                .get(&atom!("user_input"))
+                .cloned()
+                .unwrap();
 
-                let chars_atom = self.machine_st.atom_tbl.build_with(&string.trim());
-                self.machine_st.unify_complete_string(chars_atom, self.machine_st.store(self.machine_st.deref(chs)));
-            }
-            &SystemClauseType::NumberToCodes => {
-                let n = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let chs = self.machine_st.registers[2];
+            self.indices.streams.insert(self.user_input);
+        } else if stream == self.user_output {
+            self.user_output = self.indices
+                .stream_aliases
+                .get(&atom!("user_output"))
+                .cloned()
+                .unwrap();
 
-                let string = match Number::try_from(n) {
-                    Ok(Number::Float(OrderedFloat(n))) => {
-                        format!("{0:<20?}", n)
-                    }
-                    Ok(Number::Fixnum(n)) => n.get_num().to_string(),
-                    Ok(Number::Integer(n)) => n.to_string(),
-                    Ok(Number::Rational(r)) => {
-                        // n has already been confirmed as an integer, and
-                        // internally, Rational is assumed reduced, so its
-                        // denominator must be 1.
-                        r.numer().to_string()
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                };
+            self.indices.streams.insert(self.user_output);
+        }
 
-                let codes = string.trim().chars().map(|c| {
-                    fixnum_as_cell!(Fixnum::build_with(c as i64))
-                });
+        if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() {
+            let close_result = stream.close();
 
-                let h = iter_to_heap_list(&mut self.machine_st.heap, codes);
-                unify!(self.machine_st, heap_loc_as_cell!(h), chs);
+            if let Some(alias) = stream.options().get_alias() {
+                self.indices.stream_aliases.remove(&alias);
             }
-            &SystemClauseType::CodesToNumber => {
-                let stub_gen = || functor_stub(atom!("number_codes"), 2);
 
-                match self.machine_st.try_from_list(self.machine_st.registers[1], stub_gen) {
-                    Err(e) => {
-                        return Err(e);
-                    }
-                    Ok(addrs) => {
-                        let string = self.machine_st.codes_to_string(addrs.into_iter(), stub_gen)?;
-                        self.machine_st.parse_number_from_string(string, &self.indices, stub_gen)?;
-                    }
-                }
-            }
-            &SystemClauseType::LiftedHeapLength => {
-                let a1 = self.machine_st.registers[1];
-                let lh_len = Fixnum::build_with(self.machine_st.lifted_heap.len() as i64);
+            if let Err(_) = close_result {
+                let stub = functor_stub(atom!("close"), 1);
+                let addr = stream_as_cell!(stream);
+                let err  = self.machine_st.existence_error(ExistenceError::Stream(addr));
 
-                self.machine_st.unify_fixnum(lh_len, a1);
+                return Err(self.machine_st.error_form(err, stub));
             }
-            &SystemClauseType::CharCode => {
-                let stub_gen = || functor_stub(atom!("char_code"), 2);
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        }
 
-                let c = read_heap_cell!(a1,
-                    (HeapCellValueTag::Atom, (name, _arity)) => {
-                        name.as_char().unwrap()
-                    }
-                    (HeapCellValueTag::Char, c) => {
-                        c
-                    }
-                    _ => {
-                        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
-
-                        match Number::try_from(a2) {
-                            Ok(Number::Integer(n)) => {
-                                let c = match n.to_u32().and_then(std::char::from_u32) {
-                                    Some(c) => c,
-                                    _ => {
-                                        let err = self.machine_st.representation_error(RepFlag::CharacterCode);
-                                        return Err(self.machine_st.error_form(err, stub_gen()));
-                                    }
-                                };
+        Ok(())
+    }
 
-                                self.machine_st.unify_char(c, a2);
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            }
-                            Ok(Number::Fixnum(n)) => {
-                                match u32::try_from(n.get_num()) {
-                                    Ok(n) => {
-                                        if let Some(c) = std::char::from_u32(n) {
-                                            self.machine_st.unify_char(c, a1);
-                                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                                        }
-                                    }
-                                    _ => {}
-                                }
+    #[inline(always)]
+    pub(crate) fn copy_to_lifted_heap(&mut self) {
+        let lh_offset = cell_as_fixnum!(
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+        ).get_num() as usize;
 
-                                let err = self.machine_st.representation_error(RepFlag::CharacterCode);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                            _ => {
-                                self.machine_st.fail = true;
-                                return Ok(());
-                            }
-                        }
-                    }
-                );
+        let copy_target = self.machine_st.registers[2];
 
-                self.machine_st.unify_fixnum(
-                    Fixnum::build_with(c as i64),
-                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
-                );
-            }
-            &SystemClauseType::CharType => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target);
+        let new_threshold = self.machine_st.lifted_heap.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;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn delete_attribute(&mut self) {
+        let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        if let HeapCellValueTag::Lis = ls0.get_tag() {
+            let l1 = ls0.get_value();
+            let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
+
+            if let HeapCellValueTag::Lis = ls1.get_tag() {
+                let l2 = ls1.get_value();
+
+                let old_addr = self.machine_st.heap[l1+1];
+                let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
+
+                let tail = if tail.is_var() {
+                    heap_loc_as_cell!(l1 + 1)
+                } else {
+                    tail
+                };
 
-                let c = read_heap_cell!(a1,
-                    (HeapCellValueTag::Char, c) => {
-                        c
+                let trail_ref = read_heap_cell!(old_addr,
+                    (HeapCellValueTag::Var, h) => {
+                        TrailRef::AttrVarHeapLink(h)
                     }
-                    (HeapCellValueTag::Atom, (name, _arity)) => {
-                        name.as_char().unwrap()
+                    (HeapCellValueTag::Lis, l) => {
+                        TrailRef::AttrVarListLink(l1 + 1, l)
                     }
                     _ => {
                         unreachable!()
                     }
                 );
 
-                let chars = cell_as_atom!(a2);
-                self.machine_st.fail = true; // This predicate fails by default.
-
-                macro_rules! macro_check {
-                    ($id:ident, $name:expr) => {
-                        if $id!(c) && chars == $name {
-                            self.machine_st.fail = false;
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    };
-                }
+                self.machine_st.heap[l1 + 1] = tail;
+                self.machine_st.trail(trail_ref);
+            }
+        }
+    }
 
-                macro_rules! method_check {
-                    ($id:ident, $name:expr) => {
-                        if c.$id() && chars == $name {
-                            self.machine_st.fail = false;
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    };
-                }
+    #[inline(always)]
+    pub(crate) fn delete_head_attribute(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                macro_check!(alpha_char, atom!("alpha"));
-                method_check!(is_alphabetic, atom!("alphabetic"));
-                method_check!(is_alphanumeric, atom!("alphanumeric"));
-                macro_check!(alpha_numeric_char, atom!("alnum"));
-                method_check!(is_ascii, atom!("ascii"));
-                method_check!(is_ascii_punctuation, atom!("ascii_ponctuaction"));
-                method_check!(is_ascii_graphic, atom!("ascii_graphic"));
-                // macro_check!(backslash_char, atom!("backslash"));
-                // macro_check!(back_quote_char, atom!("back_quote"));
-                macro_check!(binary_digit_char, atom!("binary_digit"));
-                // macro_check!(capital_letter_char, atom!("upper"));
-                // macro_check!(comment_1_char, "comment_1");
-                // macro_check!(comment_2_char, "comment_2");
-                method_check!(is_control, atom!("control"));
-                // macro_check!(cut_char, atom!("cut"));
-                macro_check!(decimal_digit_char, atom!("decimal_digit"));
-                // macro_check!(decimal_point_char, atom!("decimal_point"));
-                // macro_check!(double_quote_char, atom!("double_quote"));
-                macro_check!(exponent_char, atom!("exponent"));
-                macro_check!(graphic_char, atom!("graphic"));
-                macro_check!(graphic_token_char, atom!("graphic_token"));
-                macro_check!(hexadecimal_digit_char, atom!("hexadecimal_digit"));
-                macro_check!(layout_char, atom!("layout"));
-                method_check!(is_lowercase, atom!("lower"));
-                macro_check!(meta_char, atom!("meta"));
-                // macro_check!(new_line_char, atom!("new_line"));
-                method_check!(is_numeric, atom!("numeric"));
-                macro_check!(octal_digit_char, atom!("octal_digit"));
-                macro_check!(octet_char, atom!("octet"));
-                macro_check!(prolog_char, atom!("prolog"));
-                // macro_check!(semicolon_char, atom!("semicolon"));
-                macro_check!(sign_char, atom!("sign"));
-                // macro_check!(single_quote_char, atom!("single_quote"));
-                // macro_check!(small_letter_char, atom!("lower"));
-                macro_check!(solo_char, atom!("solo"));
-                // macro_check!(space_char, atom!("space"));
-                macro_check!(symbolic_hexadecimal_char, atom!("symbolic_hexadecimal"));
-                macro_check!(symbolic_control_char, atom!("symbolic_control"));
-                method_check!(is_uppercase, atom!("upper"));
-                // macro_check!(variable_indicator_char, atom!("variable_indicator"));
-                method_check!(is_whitespace, atom!("whitespace"));
-            }
-            &SystemClauseType::CheckCutPoint => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let old_b = cell_as_fixnum!(addr).get_num() as usize;
-
-                let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
-                let prev_b = self.machine_st.stack.index_or_frame(prev_b).prelude.b;
-
-                if prev_b > old_b {
-                    self.machine_st.fail = true;
-                }
-            }
-            &SystemClauseType::CopyTermWithoutAttrVars => {
-                self.machine_st.copy_term(AttrVarPolicy::StripAttributes);
-            }
-            &SystemClauseType::FetchGlobalVar => {
-                let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
-                let addr = self.machine_st.registers[2];
+        debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
 
-                match self.indices.global_variables.get_mut(&key) {
-                    Some((ref ball, ref mut loc)) => match loc {
-                        Some(value_loc) => {
-                            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);
+        let h = addr.get_value();
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
 
-                            self.machine_st.heap.extend(stub.into_iter());
+        debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
 
-                            unify_fn!(self.machine_st, addr, heap_loc_as_cell!(h));
+        let l = addr.get_value();
+        let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1)));
 
-                            if !self.machine_st.fail {
-                                *loc = Some(heap_loc_as_cell!(h));
-                                self.machine_st.trail(TrailRef::BlackboardEntry(key));
-                            }
-                        }
-                        _ => self.machine_st.fail = true,
-                    },
-                    None => self.machine_st.fail = true,
-                };
-            }
-            &SystemClauseType::PutCode => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("put_code"),
-                    2,
-                )?;
+        let tail = if tail.is_var() {
+            self.machine_st.heap[h] = heap_loc_as_cell!(h);
+            self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
 
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    None,
-                    atom!("put_code"),
-                    2,
-                )?;
+            heap_loc_as_cell!(h + 1)
+        } else {
+            tail
+        };
 
-                let stub_gen = || functor_stub(atom!("put_code"), 2);
+        self.machine_st.heap[h + 1] = tail;
+        self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
+    }
 
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+    #[inline(always)]
+    pub(crate) fn dynamic_module_resolution(
+        &mut self,
+        narity: usize,
+    ) -> Result<(Atom, PredicateKey), MachineStub> {
+        let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1 + narity]
+        )));
+
+        let addr = self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[2 + narity]
+        ));
+
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Str, a) => {
+                let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a])
+                    .get_name_and_arity();
 
-                if addr.is_var() {
-                    let err = self.machine_st.instantiation_error();
-                    return Err(self.machine_st.error_form(err, stub_gen()));
-                } else {
-                    match Number::try_from(addr) {
-                        Ok(Number::Integer(n)) => {
-                            if let Some(c) = n.to_u32().and_then(|c| char::try_from(c).ok()) {
-                                write!(&mut stream, "{}", c).unwrap();
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            }
-                        }
-                        Ok(Number::Fixnum(n)) => {
-                            let n = n.get_num();
 
-                            if let Some(c) = u32::try_from(n).ok().and_then(|c| char::from_u32(c)) {
-                                write!(&mut stream, "{}", c).unwrap();
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            }
-                        }
-                        _ => {
-                            let err = self.machine_st.type_error(ValidType::Integer, addr);
-                            return Err(self.machine_st.error_form(err, stub_gen()));
-                        }
-                    }
+                for i in (arity + 1..arity + narity + 1).rev() {
+                    self.machine_st.registers[i] = self.machine_st.registers[i - arity];
+                }
 
-                    let err = self.machine_st.representation_error(RepFlag::CharacterCode);
-                    return Err(self.machine_st.error_form(err, stub_gen()));
+                for i in 1..arity + 1 {
+                    self.machine_st.registers[i] = self.machine_st.heap[a + i];
                 }
-            }
-            &SystemClauseType::PutChar => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("put_char"),
-                    2,
-                )?;
 
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    None,
-                    atom!("put_char"),
-                    2,
-                )?;
+                Ok((module_name, (name, arity + narity)))
+            }
+            (HeapCellValueTag::Atom, (name, _arity)) => {
+                Ok((module_name, (name, narity)))
+            }
+            (HeapCellValueTag::Char, c) => {
+                let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity);
+                Ok((module_name, key))
+            }
+            _ => {
+                let stub = functor_stub(atom!("(:)"), 2);
+                let err = self.machine_st.type_error(ValidType::Callable, addr);
 
-                let stub_gen = || functor_stub(atom!("put_char"), 2);
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                Err(self.machine_st.error_form(err, stub))
+            }
+        )
+    }
 
-                if addr.is_var() {
-                    let err = self.machine_st.instantiation_error();
-                    return Err(self.machine_st.error_form(err, stub_gen()));
-                } else {
-                    read_heap_cell!(addr,
-                        (HeapCellValueTag::Atom, (name, _arity)) => {
-                            let c = name.as_char().unwrap();
-                            write!(&mut stream, "{}", c).unwrap();
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                        (HeapCellValueTag::Char, c) => {
-                            write!(&mut stream, "{}", c).unwrap();
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                        _ => {
-                        }
-                    );
+    #[inline(always)]
+    pub(crate) fn enqueue_attributed_var(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                    let err = self.machine_st.type_error(ValidType::Character, addr);
-                    return Err(self.machine_st.error_form(err, stub_gen()));
-                }
+        read_heap_cell!(addr,
+            (HeapCellValueTag::AttrVar, h) => {
+                self.machine_st.attr_var_init.attr_var_queue.push(h);
+            }
+            _ => {
             }
-            &SystemClauseType::PutChars => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("$put_chars"),
-                    2,
-                )?;
+        );
+    }
 
-                let mut bytes = Vec::new();
-                let stub_gen = || functor_stub(atom!("$put_chars"), 2);
+    #[inline(always)]
+    pub(crate) fn get_next_db_ref(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
-                    if stream.options().stream_type() == StreamType::Binary {
-                        for c in string.as_str().chars() {
-                            if c as u32 > 255 {
-                                let err = self.machine_st.type_error(ValidType::Byte, char_as_cell!(c));
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
+        if let Some(name_var) = a1.as_var() {
+            let mut iter = self.indices.code_dir.iter();
 
-                            bytes.push(c as u8);
-                        }
-                    } else {
-                        bytes = string.as_str().bytes().collect();
-                    }
+            while let Some(((name, arity), _)) = iter.next() {
+                let arity_var = self.machine_st.deref(self.machine_st.registers[2])
+                    .as_var().unwrap();
 
-                    match stream.write_all(&bytes) {
-                        Ok(_) => {
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                        _ => {
-                            let addr = stream_as_cell!(stream);
-                            let err = self.machine_st.existence_error(ExistenceError::Stream(addr));
+                self.machine_st.bind(name_var, atom_as_cell!(name));
+                self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64)));
 
-                            return Err(self.machine_st.error_form(err, stub_gen()));
-                        }
-                    }
-                } else {
+                return;
+            }
+
+            self.machine_st.fail = true;
+        } else if a1.get_tag() == HeapCellValueTag::Atom {
+            let name = cell_as_atom!(a1);
+            let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
+                self.machine_st.registers[2])
+            )).get_num() as usize;
+
+            match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) {
+                Some(DBRef::NamedPred(name, arity)) => {
+                    let atom_var = self.machine_st.deref(self.machine_st.registers[3])
+                        .as_var().unwrap();
+
+                    let arity_var = self.machine_st.deref(self.machine_st.registers[4])
+                        .as_var().unwrap();
+
+                    self.machine_st.bind(atom_var, atom_as_cell!(name));
+                    self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64)));
+                }
+                Some(DBRef::Op(..)) | None => {
                     self.machine_st.fail = true;
                 }
             }
-            &SystemClauseType::PutByte => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("put_byte"),
-                    2,
-                )?;
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
 
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Binary,
-                    None,
-                    atom!("put_byte"),
-                    2,
-                )?;
+    #[inline(always)]
+    pub(crate) fn get_next_op_db_ref(&mut self) {
+        let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        if let Some(prec_var) = prec.as_var() {
+            let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+            let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+            let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7]));
+
+            let spec_num = if spec.get_tag() == HeapCellValueTag::Atom {
+                (match cell_as_atom!(spec) {
+                    atom!("xfx") => XFX,
+                    atom!("xfy") => XFY,
+                    atom!("yfx") => YFX,
+                    atom!("fx") => FX,
+                    atom!("fy") => FY,
+                    atom!("xf") => XF,
+                    _ => unreachable!(),
+                }) as u8
+            } else {
+                0
+            };
 
-                let stub_gen = || functor_stub(atom!("put_byte"), 2);
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+            let unossified_op_dir = if !orig_op.is_var() {
+                let orig_op = cell_as_atom!(orig_op);
 
-                if addr.is_var() {
-                    let err = self.machine_st.instantiation_error();
-                    return Err(self.machine_st.error_form(err, stub_gen()));
-                } else {
-                    match Number::try_from(addr) {
-                        Ok(Number::Integer(n)) => {
-                            if let Some(nb) = n.to_u8() {
-                                match stream.write(&mut [nb]) {
-                                    Ok(1) => {
-                                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                                    }
-                                    _ => {
-                                        let err = self.machine_st.existence_error(
-                                            ExistenceError::Stream(stream_as_cell!(stream))
-                                        );
+                let op_descs = [
+                    self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)),
+                    self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)),
+                    self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)),
+                ];
 
-                                        return Err(self.machine_st.error_form(err, stub_gen()));
-                                    }
-                                }
-                            }
-                        }
-                        Ok(Number::Fixnum(n)) => {
-                            if let Ok(nb) = u8::try_from(n.get_num()) {
-                                match stream.write(&mut [nb]) {
-                                    Ok(1) => {
-                                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                                    }
-                                    _ => {
-                                        let err = self.machine_st.existence_error(
-                                            ExistenceError::Stream(stream_as_cell!(stream))
-                                        );
+                let number_of_keys = op_descs[0].is_some() as usize +
+                    op_descs[1].is_some() as usize +
+                    op_descs[2].is_some() as usize;
 
-                                        return Err(self.machine_st.error_form(err, stub_gen()));
-                                    }
-                                }
+                match number_of_keys {
+                    0 => {
+                        self.machine_st.fail = true;
+                        return;
+                    }
+                    1 => {
+                        for op_desc in op_descs {
+                            if let Some((_, op_desc)) = op_desc {
+                                let (op_prec, op_spec) =
+                                    (op_desc.get_prec(), op_desc.get_spec());
+
+                                let op_spec = match op_spec as u32 {
+                                    XFX => atom!("xfx"),
+                                    XFY => atom!("xfy"),
+                                    YFX => atom!("yfx"),
+                                    FX => atom!("fx"),
+                                    FY => atom!("fy"),
+                                    XF => atom!("xf"),
+                                    YF => atom!("yf"),
+                                    _ => unreachable!(),
+                                };
+
+                                let op_prec = Fixnum::build_with(op_prec as i64);
+
+                                self.machine_st.unify_fixnum(op_prec, prec);
+                                self.machine_st.unify_atom(op_spec, spec);
                             }
                         }
-                        _ => {
-                        }
-                    }
-                }
 
-                let err = self.machine_st.type_error(ValidType::Byte, self.machine_st.registers[2]);
-                return Err(self.machine_st.error_form(err, stub_gen()));
-            }
-            &SystemClauseType::GetByte => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("get_byte"),
-                    2,
-                )?;
-
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Binary,
-                    Some(self.machine_st.registers[2]),
-                    atom!("get_byte"),
-                    2,
-                )?;
-
-                if stream.past_end_of_stream() {
-                    self.machine_st.eof_action(self.machine_st.registers[2], stream, atom!("get_byte"), 2)?;
-
-                    if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    } else if self.machine_st.fail {
-                        return Ok(());
+                        return;
                     }
-                }
-
-                let stub_gen = || functor_stub(atom!("get_byte"), 2);
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                    _ => {
+                        let mut unossified_op_dir = OssifiedOpDir::new();
 
-                let addr = if addr.is_var() {
-                    addr
-                } else {
-                    match Number::try_from(addr) {
-                        Ok(Number::Integer(n)) => {
-                            if let Some(nb) = n.to_u8() {
-                                fixnum_as_cell!(Fixnum::build_with(nb as i64))
-                            } else {
-                                let err = self.machine_st.type_error(ValidType::InByte, addr);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                        Ok(Number::Fixnum(n)) => {
-                            if let Ok(nb) = u8::try_from(n.get_num()) {
-                                fixnum_as_cell!(Fixnum::build_with(nb as i64))
-                            } else {
-                                let err = self.machine_st.type_error(ValidType::InByte, addr);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
+                        for op_desc in op_descs {
+                            if let Some((key, op_desc)) = op_desc {
+                                let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec());
+                                unossified_op_dir.insert(*key, (prec as usize, spec as Specifier));
                             }
                         }
-                        _ => {
-                            let err = self.machine_st.type_error(ValidType::InByte, addr);
-                            return Err(self.machine_st.error_form(err, stub_gen()));
-                        }
+
+                        unossified_op_dir
                     }
-                };
+                }
+            } else {
+                let mut unossified_op_dir = OssifiedOpDir::new();
 
-                loop {
-                    let mut b = [0u8; 1];
+                unossified_op_dir.extend(self.indices.op_dir.iter().filter_map(
+                    |(key, op_desc)| {
+                        let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec());
+                        let name = key.0;
 
-                    match stream.read(&mut b) {
-                        Ok(1) => {
-                            self.machine_st.unify_fixnum(Fixnum::build_with(b[0] as i64), addr);
-                            break;
-                        }
-                        _ => {
-                            stream.set_past_end_of_stream(true);
-                            self.machine_st.unify_fixnum(Fixnum::build_with(-1), self.machine_st.registers[2]);
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                        if other_prec == 0 {
+                            return None;
                         }
-                    }
-                }
-            }
-            &SystemClauseType::GetChar => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("get_char"),
-                    2,
-                )?;
 
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    Some(self.machine_st.registers[2]),
-                    atom!("get_char"),
-                    2,
-                )?;
+                        if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) ||
+                            (!spec.is_var() && other_spec != spec_num) {
+                                return None;
+                            }
 
-                if stream.past_end_of_stream() {
-                    if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    } else if self.machine_st.fail {
-                        return Ok(());
+                        Some((*key, (other_prec as usize, other_spec as Specifier)))
                     }
-                }
-
-                if stream.at_end_of_stream() {
-                    let end_of_file = atom!("end_of_file");
-                    stream.set_past_end_of_stream(true);
+                ));
 
-                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+                unossified_op_dir
+            };
 
-                let stub_gen = || functor_stub(atom!("get_char"), 2);
-                let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_char"), 2)?;
+            let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena);
 
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+            match ossified_op_dir.iter().next() {
+                Some(((op_atom, _), (op_prec, op_spec))) => {
+                    let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref(
+                        self.machine_st.registers[4]
+                    )).as_var().unwrap();
 
-                let addr = if addr.is_var() {
-                    addr
-                } else {
-                    read_heap_cell!(addr,
-                        (HeapCellValueTag::Atom, (atom, _arity)) => {
-                            char_as_cell!(atom.as_char().unwrap())
-                        }
-                        (HeapCellValueTag::Char) => {
-                            addr
-                        }
+                    let spec_atom = match *op_spec {
+                        FX => atom!("fx"),
+                        FY => atom!("fy"),
+                        XF => atom!("xf"),
+                        YF => atom!("yf"),
+                        XFX => atom!("xfx"),
+                        XFY => atom!("xfy"),
+                        YFX => atom!("yfx"),
                         _ => {
-                            let err = self.machine_st.type_error(ValidType::InCharacter, addr);
-                            return Err(self.machine_st.error_form(err, stub_gen()));
+                            self.machine_st.fail = true;
+                            return;
                         }
-                    )
-                };
+                    };
+
+                    let spec_var = spec.as_var().unwrap();
+                    let op_var = op.as_var().unwrap();
 
-                loop {
-                    let result = iter.read_char();
+                    self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64)));
+                    self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
+                    self.machine_st.bind(op_var, atom_as_cell!(op_atom));
+                    self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir));
+                }
+                None => {
+                    self.machine_st.fail = true;
+                    return;
+                }
+            }
+        } else {
+            let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+            let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
+            let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
 
-                    match result {
-                        Some(Ok(c)) => {
-                            self.machine_st.unify_char(c, addr);
+            if ossified_op_dir_cell.is_var() {
+                self.machine_st.fail = true;
+                return;
+            }
 
-                            if self.machine_st.fail {
-                                return Ok(());
-                            }
+            let ossified_op_dir = cell_as_ossified_op_dir!(
+                ossified_op_dir_cell
+            );
 
-                            break;
-                        }
+            let fixity = match spec {
+                atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In,
+                atom!("xf") | atom!("yf") => Fixity::Post,
+                atom!("fx") | atom!("fy") => Fixity::Pre,
+                _ => {
+                    self.machine_st.fail = true;
+                    return;
+                }
+            };
+
+            match self.machine_st.get_next_db_ref(
+                &self.indices,
+                &DBRef::Op(op_atom, fixity, ossified_op_dir),
+            ) {
+                Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => {
+                    let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap();
+
+                    let prec_var = self.machine_st.deref(self.machine_st.registers[5])
+                        .as_var().unwrap();
+
+                    let spec_var = self.machine_st.deref(self.machine_st.registers[6])
+                        .as_var().unwrap();
+
+                    let op_var = self.machine_st.deref(self.machine_st.registers[7])
+                        .as_var().unwrap();
+
+                    let spec_atom = match *spec {
+                        FX => atom!("fx"),
+                        FY => atom!("fy"),
+                        XF => atom!("xf"),
+                        YF => atom!("yf"),
+                        XFX => atom!("xfx"),
+                        XFY => atom!("xfy"),
+                        YFX => atom!("yfx"),
                         _ => {
-                            self.machine_st.eof_action(
-                                self.machine_st.registers[2],
-                                stream,
-                                atom!("get_char"),
-                                2,
-                            )?;
-
-                            if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            } else if self.machine_st.fail {
-                                return Ok(());
-                            }
+                            self.machine_st.fail = true;
+                            return;
                         }
-                    }
+                    };
+
+                    self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64)));
+                    self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
+                    self.machine_st.bind(op_var, atom_as_cell!(op_atom));
+                }
+                Some(DBRef::NamedPred(..)) | None => {
+                    self.machine_st.fail = true;
                 }
             }
-            &SystemClauseType::GetNChars => {
-                let stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("get_n_chars"),
-                    3,
-                )?;
+        }
+    }
 
-                let num = match Number::try_from(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))) {
-                    Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
-                    Ok(Number::Integer(n)) => match n.to_usize() {
-                        Some(u) => u,
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    },
-                    _ => {
-                        unreachable!()
-                    }
-                };
+    #[inline(always)]
+    pub(crate) fn maybe(&mut self) {
+        let result = {
+            let mut rand = RANDOM_STATE.borrow_mut();
+            rand.bits(1) == 0
+        };
 
-                let mut string = String::new();
+        self.machine_st.fail = result;
+    }
 
-                if stream.options().stream_type() == StreamType::Binary {
-                    let mut buf = vec![];
-                    let mut chunk = stream.take(num as u64);
+    #[inline(always)]
+    pub(crate) fn cpu_now(&mut self) {
+        let secs = ProcessTime::now().as_duration().as_secs_f64();
+        let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena);
 
-                    chunk.read_to_end(&mut buf).ok();
+        self.machine_st.unify_f64(secs, self.machine_st.registers[1]);
+    }
 
-                    for c in buf {
-                        string.push(c as char);
-                    }
-                } else {
-                    let mut iter = self.machine_st.open_parsing_stream(stream, atom!("get_n_chars"), 2)?;
+    #[inline(always)]
+    pub(crate) fn current_time(&mut self) {
+        let timestamp = self.systemtime_to_timestamp(SystemTime::now());
+        self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]);
+    }
 
-                    for _ in 0..num {
-                        let result = iter.read_char();
+    #[inline(always)]
+    pub(crate) fn open(&mut self) -> CallResult {
+        let alias = self.machine_st.registers[4];
+        let eof_action = self.machine_st.registers[5];
+        let reposition = self.machine_st.registers[6];
+        let stream_type = self.machine_st.registers[7];
 
-                        match result {
-                            Some(Ok(c)) => {
-                                string.push(c);
-                            }
-                            _ => {
-                                break;
-                            }
-                        }
-                    }
-                };
+        let options  = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+        let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                let atom = self.machine_st.atom_tbl.build_with(&string);
-                self.machine_st.unify_complete_string(atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
-            }
-            &SystemClauseType::GetCode => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("get_code"),
-                    2,
-                )?;
-
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    Some(self.machine_st.registers[2]),
-                    atom!("get_code"),
-                    2,
-                )?;
-
-                if stream.past_end_of_stream() {
-                    if EOFAction::Reset != stream.options().eof_action() {
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    } else if self.machine_st.fail {
-                        return Ok(());
-                    }
+        if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) {
+            let file_spec = match str_like {
+                AtomOrString::Atom(atom) => {
+                    atom
                 }
-
-                if stream.at_end_of_stream() {
-                    let end_of_file = atom!("end_of_file");
-
-                    stream.set_past_end_of_stream(true);
-
-                    self.machine_st.unify_atom(end_of_file, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
+                AtomOrString::String(string) => {
+                    self.machine_st.atom_tbl.build_with(&string)
                 }
+            };
 
-                let stub_gen = || functor_stub(atom!("get_code"), 2);
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+            let mut stream = self.machine_st.stream_from_file_spec(
+                file_spec,
+                &mut self.indices,
+                &options,
+            )?;
 
-                let addr = if addr.is_var() {
-                    addr
-                } else {
-                    match Number::try_from(addr) {
-                        Ok(Number::Integer(n)) => {
-                            let n = n
-                                .to_u32()
-                                .and_then(|n| std::char::from_u32(n));
-
-                            if let Some(n) = n {
-                                fixnum_as_cell!(Fixnum::build_with(n as i64))
-                            } else {
-                                let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                        Ok(Number::Fixnum(n)) => {
-                            let nf = u32::try_from(n.get_num())
-                                .ok()
-                                .and_then(|n| std::char::from_u32(n));
-
-                            if nf.is_some() {
-                                fixnum_as_cell!(n)
-                            } else {
-                                let err = self.machine_st.representation_error(RepFlag::InCharacterCode);
-                                return Err(self.machine_st.error_form(err, stub_gen()));
-                            }
-                        }
-                        _ => {
-                            let err = self.machine_st.type_error(ValidType::Integer, self.machine_st.registers[2]);
-                            return Err(self.machine_st.error_form(err, stub_gen()));
-                        }
-                    }
-                };
+            *stream.options_mut() = options;
+            self.indices.streams.insert(stream);
 
-                let mut iter = self.machine_st.open_parsing_stream(stream.clone(), atom!("get_code"), 2)?;
+            if let Some(alias) = stream.options().get_alias() {
+                self.indices.stream_aliases.insert(alias, stream);
+            }
 
-                loop {
-                    let result = iter.read_char();
+            let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+            self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream));
+        } else {
+            let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink);
+            let stub = functor_stub(atom!("open"), 4);
 
-                    match result {
-                        Some(Ok(c)) => {
-                            self.machine_st.unify_fixnum(Fixnum::build_with(c as i64), addr);
+            return Err(self.machine_st.error_form(err, stub));
+        }
 
-                            if self.machine_st.fail {
-                                return Ok(());
-                            }
+        Ok(())
+    }
 
-                            break;
-                        }
-                        _ => {
-                            self.machine_st.eof_action(
-                                self.machine_st.registers[2],
-                                stream,
-                                atom!("get_code"),
-                                2,
-                            )?;
-
-                            if EOFAction::Reset != stream.options().eof_action() {
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            } else if self.machine_st.fail {
-                                return Ok(());
-                            }
-                        }
-                    }
-                }
-            }
-            &SystemClauseType::FirstStream => {
-                let mut first_stream = None;
-                let mut null_streams = BTreeSet::new();
+    #[inline(always)]
+    pub(crate) fn op_declaration(&mut self) -> CallResult {
+        let priority = self.machine_st.registers[1];
+        let specifier = self.machine_st.registers[2];
+        let op = self.machine_st.registers[3];
 
-                for stream in self.indices.streams.iter().cloned() {
-                    if !stream.is_null_stream() {
-                        first_stream = Some(stream);
-                        break;
-                    } else {
-                        null_streams.insert(stream);
-                    }
-                }
+        let priority = self.machine_st.store(self.machine_st.deref(priority));
 
-                self.indices.streams = self.indices.streams.sub(&null_streams);
+        let priority = match Number::try_from(priority) {
+            Ok(Number::Integer(n)) => n.to_u16().unwrap(),
+            Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(),
+            _ => {
+                unreachable!();
+            }
+        };
 
-                if let Some(first_stream) = first_stream {
-                    let stream = stream_as_cell!(first_stream);
+        let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier)))
+            .get_name();
 
-                    let var = self.machine_st.store(self.machine_st.deref(
-                        self.machine_st.registers[1]
-                    )).as_var().unwrap();
+        let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)),
+            (HeapCellValueTag::Char) => {
+                self.machine_st.atom_tbl.build_with(&op.to_string())
+            }
+            (HeapCellValueTag::Atom, (name, _arity)) => {
+                name
+            }
+            _ => {
+                unreachable!()
+            }
+        );
 
-                    self.machine_st.bind(var, stream);
+        let result = to_op_decl(priority, specifier, op)
+            .map_err(SessionError::from)
+            .and_then(|mut op_decl| {
+                if op_decl.op_desc.get_prec() == 0 {
+                    Ok(op_decl.remove(&mut self.indices.op_dir))
                 } else {
-                    self.machine_st.fail = true;
-                    return Ok(());
+                    let spec = get_op_desc(
+                        op_decl.name,
+                        &CompositeOpDir::new(&self.indices.op_dir, None),
+                    );
+
+                    op_decl.submit(spec, &mut self.indices.op_dir)
                 }
+            });
+
+        match result {
+            Ok(()) => Ok(()),
+            Err(e) => {
+                // 8.14.3.3 l)
+                let err = self.machine_st.session_error(e);
+                let stub = functor_stub(atom!("op"), 3);
+
+                Err(self.machine_st.error_form(err, stub))
             }
-            &SystemClauseType::NextStream => {
-                let prev_stream = cell_as_stream!(self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[1]
-                )));
+        }
+    }
 
-                let mut next_stream = None;
-                let mut null_streams = BTreeSet::new();
+    #[inline(always)]
+    pub(crate) fn set_stream_options(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("open"),
+            4,
+        )?;
+
+        let alias = self.machine_st.registers[2];
+        let eof_action = self.machine_st.registers[3];
+        let reposition = self.machine_st.registers[4];
+        let stream_type = self.machine_st.registers[5];
+
+        let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+        *stream.options_mut() = options;
 
-                for stream in self.indices
-                    .streams
-                    .range(prev_stream..)
-                    .skip(1)
-                    .cloned()
-                {
-                    if !stream.is_null_stream() {
-                        next_stream = Some(stream);
-                        break;
-                    } else {
-                        null_streams.insert(stream);
-                    }
-                }
+        Ok(())
+    }
 
-                self.indices.streams = self.indices.streams.sub(&null_streams);
+    #[inline(always)]
+    pub(crate) fn truncate_if_no_lifted_heap_growth_diff(&mut self) {
+        self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
+    }
 
-                if let Some(next_stream) = next_stream {
-                    let var = self.machine_st.store(self.machine_st.deref(
-                        self.machine_st.registers[2]
-                    )).as_var().unwrap();
+    #[inline(always)]
+    pub(crate) fn truncate_if_no_lifted_heap_growth(&mut self) {
+        self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
+    }
+
+    #[inline(always)]
+    pub(crate) fn get_attributed_variable_list(&mut self) {
+        let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let attr_var_list = read_heap_cell!(attr_var,
+            (HeapCellValueTag::AttrVar, h) => {
+                h + 1
+            }
+            (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+                // create an AttrVar in the heap.
+                let h = self.machine_st.heap.len();
 
-                    let next_stream = stream_as_cell!(next_stream);
+                self.machine_st.heap.push(attr_var_as_cell!(h));
+                self.machine_st.heap.push(heap_loc_as_cell!(h+1));
 
-                    self.machine_st.bind(var, next_stream);
-                } else {
-                    self.machine_st.fail = true;
-                    return Ok(());
-                }
+                self.machine_st.bind(Ref::attr_var(h), attr_var);
+                h + 1
+            }
+            _ => {
+                self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::FlushOutput => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("flush_output"),
-                    1,
-                )?;
+        );
 
-                if !stream.is_output_stream() {
-                    let stub = functor_stub(atom!("flush_output"), 1);
-                    let addr = stream_as_cell!(stream); // vec![HeapCellValue::Stream(stream)];
+        let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr);
+    }
 
-                    let err = self.machine_st.permission_error(
-                        Permission::OutputStream,
-                        atom!("stream"),
-                        addr,
-                    );
+    #[inline(always)]
+    pub(crate) fn get_attr_var_queue_delimiter(&mut self) {
+        let addr = self.machine_st.registers[1];
+        let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64);
 
-                    return Err(self.machine_st.error_form(err, stub));
-                }
+        self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr)));
+    }
 
-                stream.flush().unwrap();
+    #[inline(always)]
+    pub(crate) fn get_attr_var_queue_beyond(&mut self) {
+        let addr = self.machine_st.registers[1];
+        let addr = self.machine_st.store(self.machine_st.deref(addr));
+
+        let b = match Number::try_from(addr) {
+            Ok(Number::Integer(n)) => n.to_usize(),
+            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+            _ => {
+                self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::GetSingleChar => {
-                let ctrl_c = KeyEvent {
-                    code: KeyCode::Char('c'),
-                    modifiers: KeyModifiers::CONTROL,
-                };
+        };
 
-                let key = get_key();
+        if let Some(b) = b {
+            let iter = self.machine_st.gather_attr_vars_created_since(b);
 
-                if key == ctrl_c {
-                    let stub = functor_stub(atom!("get_single_char"), 1);
-                    let err = self.machine_st.interrupt_error();
-                    let err = self.machine_st.error_form(err, stub);
+            let var_list_addr = heap_loc_as_cell!(
+                iter_to_heap_list(&mut self.machine_st.heap, iter)
+            );
 
-                    return Err(err);
-                }
+            let list_addr = self.machine_st.registers[2];
+            unify!(self.machine_st, var_list_addr, list_addr);
+        }
+    }
 
-                let c = match key.code {
-                    KeyCode::Enter => '\n',
-                    KeyCode::Tab => '\t',
-                    KeyCode::Char(c) => c,
-                    _ => unreachable!(),
-                };
+    #[inline(always)]
+    pub(crate) fn get_continuation_chunk(&mut self) {
+        let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let e = cell_as_fixnum!(e).get_num() as usize;
 
-                self.machine_st.unify_char(c, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
-            }
-            &SystemClauseType::HeadIsDynamic => {
-                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+        let p_functor = self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[2]
+        ));
 
-                let (name, arity) = read_heap_cell!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
-                    (HeapCellValueTag::Str, s) => {
-                        cell_as_atom_cell!(self.machine_st.heap[s]).get_name_and_arity()
-                    }
-                    (HeapCellValueTag::Atom, (name, _arity)) => {
-                        (name, 0)
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                );
+        let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap();
 
-                self.machine_st.fail = !self.indices.is_dynamic_predicate(module_name, (name, arity));
-            }
-            &SystemClauseType::Close => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("close"),
-                    2,
-                )?;
+        let num_cells = *self.code[p].perm_vars_mut().unwrap();
+        let mut addrs = vec![];
 
-                if !stream.is_input_stream() {
-                    stream.flush().unwrap(); // 8.11.6.1b)
-                }
+        for idx in 1..num_cells + 1 {
+            addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]);
+        }
 
-                self.indices.streams.remove(&stream);
+        let chunk = str_loc_as_cell!(self.machine_st.heap.len());
 
-                if stream == self.user_input {
-                    self.user_input = self.indices
-                        .stream_aliases
-                        .get(&atom!("user_input"))
-                        .cloned()
-                        .unwrap();
+        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.extend(addrs);
 
-                    self.indices.streams.insert(self.user_input);
-                } else if stream == self.user_output {
-                    self.user_output = self.indices
-                        .stream_aliases
-                        .get(&atom!("user_output"))
-                        .cloned()
-                        .unwrap();
+        unify!(self.machine_st, self.machine_st.registers[3], chunk);
+    }
 
-                    self.indices.streams.insert(self.user_output);
-                }
+    #[inline(always)]
+    pub(crate) fn get_lifted_heap_from_offset_diff(&mut self) {
+        let lh_offset = self.machine_st.registers[1];
+        let lh_offset = cell_as_fixnum!(
+            self.machine_st.store(self.machine_st.deref(lh_offset))
+        ).get_num() as usize;
 
-                if !stream.is_stdin() && !stream.is_stdout() && !stream.is_stderr() {
-                    let close_result = stream.close();
+        if lh_offset >= self.machine_st.lifted_heap.len() {
+            let solutions = self.machine_st.registers[2];
+            let diff = self.machine_st.registers[3];
 
-                    if let Some(alias) = stream.options().get_alias() {
-                        self.indices.stream_aliases.remove(&alias);
-                    }
-                    if let Err(_) = close_result {
-                        let stub = functor_stub(atom!("close"), 1);
-                        let addr = stream_as_cell!(stream);
-                        let err  = self.machine_st.existence_error(ExistenceError::Stream(addr));
+            unify_fn!(self.machine_st, solutions, diff);
+        } else {
+            let h = self.machine_st.heap.len();
+            let mut last_index = h;
 
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
-                }
+            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);
             }
-            &SystemClauseType::CopyToLiftedHeap => {
-                let lh_offset = cell_as_fixnum!(
-                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
-                ).get_num() as usize;
 
-                let copy_target = self.machine_st.registers[2];
+            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]);
+            }
 
-                let old_threshold = self.machine_st.copy_findall_solution(lh_offset, copy_target);
-                let new_threshold = self.machine_st.lifted_heap.len() - lh_offset;
+            self.machine_st.lifted_heap.truncate(lh_offset);
 
-                self.machine_st.lifted_heap[old_threshold] = heap_loc_as_cell!(new_threshold);
+            let solutions = self.machine_st.registers[2];
+            unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
+        }
+    }
 
-                for addr in self.machine_st.lifted_heap[old_threshold + 1 ..].iter_mut() {
-                    *addr -= self.machine_st.heap.len() + lh_offset;
-                }
-            },
-            &SystemClauseType::DeleteAttribute => {
-                let ls0 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+    #[inline(always)]
+    pub(crate) fn get_lifted_heap_from_offset(&mut self) {
+        let lh_offset = self.machine_st.registers[1];
+        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() {
+            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();
 
-                if let HeapCellValueTag::Lis = ls0.get_tag() {
-                    let l1 = ls0.get_value();
-                    let ls1 = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l1 + 1)));
+            for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() {
+                self.machine_st.heap.push(addr + h);
+            }
 
-                    if let HeapCellValueTag::Lis = ls1.get_tag() {
-                        let l2 = ls1.get_value();
+            self.machine_st.lifted_heap.truncate(lh_offset);
 
-                        let old_addr = self.machine_st.heap[l1+1];
-                        let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l2 + 1)));
+            let solutions = self.machine_st.registers[2];
+            unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
+        }
+    }
 
-                        let tail = if tail.is_var() {
-                            heap_loc_as_cell!(l1 + 1)
-                        } else {
-                            tail
-                        };
+    #[inline(always)]
+    pub(crate) fn get_double_quotes(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        self.machine_st.unify_atom(
+            match self.machine_st.flags.double_quotes {
+                DoubleQuotes::Chars => atom!("chars"),
+                DoubleQuotes::Atom => atom!("atom"),
+                DoubleQuotes::Codes => atom!("codes"),
+            },
+            a1,
+        );
+    }
 
-                        let trail_ref = read_heap_cell!(old_addr,
-                            (HeapCellValueTag::Var, h) => {
-                                TrailRef::AttrVarHeapLink(h)
-                            }
-                            (HeapCellValueTag::Lis, l) => {
-                                TrailRef::AttrVarListLink(l1 + 1, l)
-                            }
-                            _ => {
-                                unreachable!()
-                            }
-                        );
+    #[inline(always)]
+    pub(crate) fn get_scc_cleaner(&mut self) {
+        let dest = self.machine_st.registers[1];
 
-                        self.machine_st.heap[l1 + 1] = tail;
-                        self.machine_st.trail(trail_ref);
-                    }
+        if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() {
+            let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
+
+            if b <= b_cutoff {
+                self.machine_st.block = prev_b;
+
+                if let Some(r) = dest.as_var() {
+                    self.machine_st.bind(r, addr);
+                    return;
                 }
+            } else {
+                self.machine_st.cont_pts.push((addr, b_cutoff, prev_b));
             }
-            &SystemClauseType::DeleteHeadAttribute => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        }
 
-                debug_assert_eq!(addr.get_tag(), HeapCellValueTag::AttrVar);
+        self.machine_st.fail = true;
+    }
 
-                let h = addr.get_value();
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.heap[h + 1]));
+    #[inline(always)]
+    pub(crate) fn halt(&mut self) {
+        let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        let code = match Number::try_from(code) {
+            Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(),
+            Ok(Number::Integer(n)) => n.to_i32().unwrap(),
+            Ok(Number::Rational(r)) => {
+                // n has already been confirmed as an integer, and
+                // internally, Rational is assumed reduced, so its
+                // denominator must be 1.
+                r.numer().to_i32().unwrap()
+            }
+            _ => {
+                unreachable!()
+            }
+        };
 
-                debug_assert_eq!(addr.get_tag(), HeapCellValueTag::Lis);
+        std::process::exit(code);
+    }
 
-                let l = addr.get_value();
-                let tail = self.machine_st.store(self.machine_st.deref(heap_loc_as_cell!(l + 1)));
+    #[inline(always)]
+    pub(crate) fn install_scc_cleaner(&mut self) {
+        let addr = self.machine_st.registers[1];
+        let b = self.machine_st.b;
+        let prev_block = self.machine_st.block;
 
-                let tail = if tail.is_var() {
-                    self.machine_st.heap[h] = heap_loc_as_cell!(h);
-                    self.machine_st.trail(TrailRef::Ref(Ref::attr_var(h)));
+        self.machine_st.run_cleaners_fn = Machine::run_cleaners;
 
-                    heap_loc_as_cell!(h + 1)
-                } else {
-                    tail
-                };
+        self.machine_st.install_new_block(self.machine_st.registers[2]);
+        self.machine_st.cont_pts.push((addr, b, prev_block));
+    }
+
+    #[inline(always)]
+    pub(crate) fn install_inference_counter(&mut self) -> CallResult {
+        // A1 = B, A2 = L
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let n = match Number::try_from(a2) {
+            Ok(Number::Fixnum(bp)) => bp.get_num() as usize,
+            Ok(Number::Integer(n)) => n.to_usize().unwrap(),
+            _ => {
+                let stub = functor_stub(
+                    atom!("call_with_inference_limit"),
+                    3,
+                );
 
-                self.machine_st.heap[h + 1] = tail;
-                self.machine_st.trail(TrailRef::AttrVarListLink(h + 1, l));
+                let err = self.machine_st.type_error(ValidType::Integer, a2);
+                return Err(self.machine_st.error_form(err, stub));
             }
-            &SystemClauseType::DynamicModuleResolution(narity) => {
-                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[1 + narity]
-                )));
+        };
 
-                let addr = self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[2 + narity]
-                ));
+        let bp = cell_as_fixnum!(a1).get_num() as usize;
+        let count = self.machine_st.cwil.add_limit(n, bp);
+        let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
 
-                read_heap_cell!(addr,
-                    (HeapCellValueTag::Str, a) => {
-                        let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[a])
-                            .get_name_and_arity();
+        self.machine_st.increment_call_count_fn = MachineState::increment_call_count;
 
-                        for i in (arity + 1..arity + narity + 1).rev() {
-                            self.machine_st.registers[i] = self.machine_st.registers[i - arity];
-                        }
+        let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+        self.machine_st.unify_big_int(count, a3);
 
-                        for i in 1..arity + 1 {
-                            self.machine_st.registers[i] = self.machine_st.heap[a + i];
-                        }
+        Ok(())
+    }
 
-                        return self.call_clause_type(module_name, (name, arity + narity));
-                    }
-                    (HeapCellValueTag::Atom, (name, _arity)) => {
-                        return self.call_clause_type(module_name, (name, narity));
-                    }
-                    (HeapCellValueTag::Char, c) => {
-                        let key = (self.machine_st.atom_tbl.build_with(&c.to_string()), narity);
-                        return self.call_clause_type(module_name, key);
-                    }
-                    _ => {
-                        let stub = functor_stub(atom!("(:)"), 2);
-                        let err = self.machine_st.type_error(ValidType::Callable, addr);
+    #[inline(always)]
+    pub(crate) fn module_exists(&mut self) {
+        let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let module_name = cell_as_atom!(module);
 
-                        return Err(self.machine_st.error_form(err, stub));
+        self.machine_st.fail = !self.indices.modules.contains_key(&module_name);
+    }
+
+    #[inline(always)]
+    pub(crate) fn no_such_predicate(&mut self) -> CallResult {
+        let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1]
+        )));
+
+        let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        self.machine_st.fail = read_heap_cell!(head,
+            (HeapCellValueTag::Str, s) => {
+                let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+                    .get_name_and_arity();
+
+                let ct = ClauseType::from(name, arity);
+
+                if ct.is_inlined() || ct.is_builtin() {
+                    true
+                } else {
+                    let index = self.indices.get_predicate_code_index(
+                        name,
+                        arity,
+                        module_name,
+                    )
+                        .map(|index| index.get())
+                        .unwrap_or(IndexPtr::DynamicUndefined);
+
+                    match index {
+                        IndexPtr::DynamicUndefined | IndexPtr::Undefined => false,
+                        _ => true,
                     }
-                );
+                }
             }
-            &SystemClauseType::EnqueueAttributedVar => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                debug_assert_eq!(arity, 0);
 
-                read_heap_cell!(addr,
-                    (HeapCellValueTag::AttrVar, h) => {
-                        self.machine_st.attr_var_init.attr_var_queue.push(h);
-                    }
-                    _ => {
+                let ct = ClauseType::from(name, 0);
+
+                if ct.is_inlined() || ct.is_builtin() {
+                    true
+                } else {
+                    let index = self.indices.get_predicate_code_index(
+                        name,
+                        0,
+                        module_name,
+                    )
+                        .map(|index| index.get())
+                        .unwrap_or(IndexPtr::DynamicUndefined);
+
+                    match index {
+                        IndexPtr::DynamicUndefined => false,
+                        _ => true,
                     }
-                );
+                }
             }
-            &SystemClauseType::GetNextDBRef => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+            _ => {
+                let err = self.machine_st.type_error(ValidType::Callable, head);
+                let stub = functor_stub(atom!("clause"), 2);
 
-                if let Some(name_var) = a1.as_var() {
-                    let mut iter = self.indices.code_dir.iter();
+                return Err(self.machine_st.error_form(err, stub));
+            }
+        );
 
-                    while let Some(((name, arity), _)) = iter.next() {
-                        if SystemClauseType::from(*name, *arity).is_some() {
-                            continue;
-                        }
+        Ok(())
+    }
+    #[inline(always)]
+    pub(crate) fn redo_attr_var_binding(&mut self) {
+        let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                        let arity_var = self.machine_st.deref(self.machine_st.registers[2])
-                            .as_var().unwrap();
+        debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag());
+        self.machine_st.heap[var.get_value()] = value;
+    }
 
-                        self.machine_st.bind(name_var, atom_as_cell!(name));
-                        self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(*arity as i64)));
+    #[inline(always)]
+    pub(super) fn restore_instr_at_verify_attr_interrupt(&mut self) {
+        match &self.code[VERIFY_ATTR_INTERRUPT_LOC] {
+            &Instruction::VerifyAttrInterrupt => {}
+            _ => {
+                let instr = mem::replace(
+                    &mut self.code[VERIFY_ATTR_INTERRUPT_LOC],
+                    Instruction::VerifyAttrInterrupt,
+                );
 
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    }
+                self.code[self.machine_st.attr_var_init.cp] = instr;
+            }
+        }
+    }
 
-                    self.machine_st.fail = true;
-                } else if a1.get_tag() == HeapCellValueTag::Atom {
-                    let name = cell_as_atom!(a1);
-                    let arity = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])))
-                        .get_num() as usize;
+    #[inline(always)]
+    pub(crate) fn reset_attr_var_state(&mut self) { // 1344! That's the value of self.b we need to pop this.
+        self.restore_instr_at_verify_attr_interrupt();
+        self.machine_st.attr_var_init.reset();
+    }
+
+    #[inline(always)]
+    pub(crate) fn remove_call_policy_check(&mut self) {
+        let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1]
+        ))).get_num() as usize;
+
+        if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
+            self.machine_st.cwil.reset();
+            self.machine_st.increment_call_count_fn = |_| { Ok(()) };
+        }
+    }
 
-                    match self.machine_st.get_next_db_ref(&self.indices, &DBRef::NamedPred(name, arity)) {
-                        Some(DBRef::NamedPred(name, arity)) => {
-                            let atom_var = self.machine_st.deref(self.machine_st.registers[3])
-                                .as_var().unwrap();
+    #[inline(always)]
+    pub(crate) fn remove_inference_counter(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let bp = cell_as_fixnum!(a1).get_num() as usize;
 
-                            let arity_var = self.machine_st.deref(self.machine_st.registers[4])
-                                .as_var().unwrap();
+        let count = self.machine_st.cwil.remove_limit(bp).clone();
+        let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
 
-                            self.machine_st.bind(atom_var, atom_as_cell!(name));
-                            self.machine_st.bind(arity_var, fixnum_as_cell!(Fixnum::build_with(arity as i64)));
-                        }
-                        Some(DBRef::Op(..)) | None => {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                } else {
-                    self.machine_st.fail = true;
-                    return Ok(());
-                }
-            }
-            &SystemClauseType::GetNextOpDBRef => {
-                let prec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-
-                if let Some(prec_var) = prec.as_var() {
-                    let spec = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
-                    let op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
-                    let orig_op = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[7]));
-
-                    let spec_num = if spec.get_tag() == HeapCellValueTag::Atom {
-                        (match cell_as_atom!(spec) {
-                            atom!("xfx") => XFX,
-                            atom!("xfy") => XFY,
-                            atom!("yfx") => YFX,
-                            atom!("fx") => FX,
-                            atom!("fy") => FY,
-                            atom!("xf") => XF,
-                            _ => unreachable!(),
-                        }) as u8
-                    } else {
-                        0
-                    };
+        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        self.machine_st.unify_big_int(count, a2);
+    }
 
-                    let unossified_op_dir = if !orig_op.is_var() {
-                        let orig_op = cell_as_atom!(orig_op);
+    #[inline(always)]
+    pub(crate) fn return_from_verify_attr(&mut self) {
+        let e = self.machine_st.e;
+        let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
 
-                        let op_descs = [
-                            self.indices.op_dir.get_key_value(&(orig_op, Fixity::In)),
-                            self.indices.op_dir.get_key_value(&(orig_op, Fixity::Pre)),
-                            self.indices.op_dir.get_key_value(&(orig_op, Fixity::Post)),
-                        ];
+        for i in 1..frame_len - 2 {
+            self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)];
+        }
 
-                        let number_of_keys = op_descs[0].is_some() as usize +
-                            op_descs[1].is_some() as usize +
-                            op_descs[2].is_some() as usize;
+        self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 2)])
+            .get_num() as usize;
 
-                        match number_of_keys {
-                            0 => {
-                                self.machine_st.fail = true;
-                                return Ok(());
-                            }
-                            1 => {
-                                for op_desc in op_descs {
-                                    if let Some((_, op_desc)) = op_desc {
-                                        let (op_prec, op_spec) =
-                                            (op_desc.get_prec(), op_desc.get_spec());
-
-                                        let op_spec = match op_spec as u32 {
-                                            XFX => atom!("xfx"),
-                                            XFY => atom!("xfy"),
-                                            YFX => atom!("yfx"),
-                                            FX => atom!("fx"),
-                                            FY => atom!("fy"),
-                                            XF => atom!("xf"),
-                                            YF => atom!("yf"),
-                                            _ => unreachable!(),
-                                        };
-
-                                        let op_prec = Fixnum::build_with(op_prec as i64);
-
-                                        self.machine_st.unify_fixnum(op_prec, prec);
-                                        self.machine_st.unify_atom(op_spec, spec);
-                                    }
-                                }
+        self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)])
+            .get_num() as usize;
 
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            }
-                            _ => {
-                                let mut unossified_op_dir = OssifiedOpDir::new();
+        let p = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)]).get_num() as usize;
 
-                                for op_desc in op_descs {
-                                    if let Some((key, op_desc)) = op_desc {
-                                        let (prec, spec) = (op_desc.get_prec(), op_desc.get_spec());
-                                        unossified_op_dir.insert(*key, (prec as usize, spec as Specifier));
-                                    }
-                                }
+        self.machine_st.deallocate();
+        self.machine_st.p = p;
+    }
 
-                                unossified_op_dir
-                            }
-                        }
-                    } else {
-                        let mut unossified_op_dir = OssifiedOpDir::new();
+    #[inline(always)]
+    pub(crate) fn restore_cut_policy(&mut self) {
+        if self.machine_st.cont_pts.is_empty() {
+            self.machine_st.run_cleaners_fn = |_| { false };
+        }
+    }
 
-                        unossified_op_dir.extend(self.indices.op_dir.iter().filter_map(
-                            |(key, op_desc)| {
-                                let (other_prec, other_spec) = (op_desc.get_prec(), op_desc.get_spec());
-                                let name = key.0;
+    #[inline(always)]
+    pub(crate) fn set_cut_point(&mut self, r: RegType) -> bool {
+        let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+        self.machine_st.cut_body(cp);
 
-                                if other_prec == 0 {
-                                    return None;
-                                }
+        (self.machine_st.run_cleaners_fn)(self)
+    }
 
-                                if (!orig_op.is_var() && atom_as_cell!(name) != orig_op) ||
-                                    (!spec.is_var() && other_spec != spec_num) {
-                                        return None;
-                                    }
+    #[inline(always)]
+    pub(crate) fn set_cut_point_by_default(&mut self, r: RegType) {
+        let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
+        self.machine_st.cut_body(cp);
+    }
 
-                                Some((*key, (other_prec as usize, other_spec as Specifier)))
-                            }
-                        ));
+    #[inline(always)]
+    pub(crate) fn set_input(&mut self) -> CallResult {
+        let addr = self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1]
+        ));
+
+        let stream = self.machine_st.get_stream_or_alias(
+            addr,
+            &self.indices.stream_aliases,
+            atom!("set_input"),
+            1,
+        )?;
+
+        if !stream.is_input_stream() {
+            let stub = functor_stub(atom!("set_input"), 1);
+            let user_alias = atom_as_cell!(atom!("user"));
+
+            let err = self.machine_st.permission_error(
+                Permission::InputStream,
+                atom!("stream"),
+                user_alias,
+            );
 
-                        unossified_op_dir
-                    };
+            return Err(self.machine_st.error_form(err, stub));
+        }
 
-                    let ossified_op_dir = arena_alloc!(unossified_op_dir, &mut self.machine_st.arena);
-
-                    match ossified_op_dir.iter().next() {
-                        Some(((op_atom, _), (op_prec, op_spec))) => {
-                            let ossified_op_dir_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]))
-                                .as_var().unwrap();
-
-                            let spec_atom = match *op_spec {
-                                FX => atom!("fx"),
-                                FY => atom!("fy"),
-                                XF => atom!("xf"),
-                                YF => atom!("yf"),
-                                XFX => atom!("xfx"),
-                                XFY => atom!("xfy"),
-                                YFX => atom!("yfx"),
-                                _ => {
-                                    self.machine_st.fail = true;
-                                    return Ok(());
-                                }
-                            };
+        self.user_input = stream;
+        Ok(())
+    }
 
-                            let spec_var = spec.as_var().unwrap();
-                            let op_var = op.as_var().unwrap();
+    #[inline(always)]
+    pub(crate) fn set_output(&mut self) -> CallResult {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let stream = self.machine_st.get_stream_or_alias(
+            addr,
+            &self.indices.stream_aliases,
+            atom!("set_output"),
+            1,
+        )?;
+
+        if !stream.is_output_stream() {
+            let stub = functor_stub(atom!("set_input"), 1);
+
+            let user_alias = atom_as_cell!(atom!("user"));
+            let err = self.machine_st.permission_error(
+                Permission::OutputStream,
+                atom!("stream"),
+                user_alias,
+            );
 
-                            self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*op_prec as i64)));
-                            self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
-                            self.machine_st.bind(op_var, atom_as_cell!(op_atom));
-                            self.machine_st.bind(ossified_op_dir_var, typed_arena_ptr_as_cell!(ossified_op_dir));
-                        }
-                        None => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                } else {
-                    let spec = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
-                    let op_atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3])));
-                    let ossified_op_dir_cell = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
+            return Err(self.machine_st.error_form(err, stub));
+        }
 
-                    if ossified_op_dir_cell.is_var() {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
+        self.user_output = stream;
+        Ok(())
+    }
 
-                    let ossified_op_dir = cell_as_ossified_op_dir!(
-                        ossified_op_dir_cell
-                    );
+    #[inline(always)]
+    pub(crate) fn set_double_quotes(&mut self) {
+        let atom = cell_as_atom!(self.machine_st.registers[1]);
 
-                    let fixity = match spec {
-                        atom!("xfy") | atom!("yfx") | atom!("xfx") => Fixity::In,
-                        atom!("xf") | atom!("yf") => Fixity::Post,
-                        atom!("fx") | atom!("fy") => Fixity::Pre,
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    };
+        self.machine_st.flags.double_quotes = match atom {
+            atom!("atom") => DoubleQuotes::Atom,
+            atom!("chars") => DoubleQuotes::Chars,
+            atom!("codes") => DoubleQuotes::Codes,
+            _ => {
+                self.machine_st.fail = true;
+                return;
+            }
+        };
+    }
 
-                    match self.machine_st.get_next_db_ref(
-                        &self.indices,
-                        &DBRef::Op(op_atom, fixity, ossified_op_dir),
-                    ) {
-                        Some(DBRef::Op(op_atom, fixity, ossified_op_dir)) => {
-                            let (prec, spec) = ossified_op_dir.get(&(op_atom, fixity)).unwrap();
-
-                            let prec_var = self.machine_st.deref(self.machine_st.registers[5])
-                                .as_var().unwrap();
-
-                            let spec_var = self.machine_st.deref(self.machine_st.registers[6])
-                                .as_var().unwrap();
-
-                            let op_var = self.machine_st.deref(self.machine_st.registers[7])
-                                .as_var().unwrap();
-
-                            let spec_atom = match *spec {
-                                FX => atom!("fx"),
-                                FY => atom!("fy"),
-                                XF => atom!("xf"),
-                                YF => atom!("yf"),
-                                XFX => atom!("xfx"),
-                                XFY => atom!("xfy"),
-                                YFX => atom!("yfx"),
-                                _ => {
-                                    self.machine_st.fail = true;
-                                    return Ok(());
-                                }
-                            };
+    #[inline(always)]
+    pub(crate) fn inference_level(&mut self) {
+        let a1 = self.machine_st.registers[1];
+        let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                            self.machine_st.bind(prec_var, fixnum_as_cell!(Fixnum::build_with(*prec as i64)));
-                            self.machine_st.bind(spec_var, atom_as_cell!(spec_atom));
-                            self.machine_st.bind(op_var, atom_as_cell!(op_atom));
-                        }
-                        Some(DBRef::NamedPred(..)) | None => {
-                            self.machine_st.fail = true;
-                        }
-                    }
-                }
-            }
-            &SystemClauseType::Maybe => {
-                let result = {
-                    let mut rand = RANDOM_STATE.borrow_mut();
-                    rand.bits(1) == 0
-                };
+        let bp = cell_as_fixnum!(a2).get_num() as usize;
+        let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
 
-                self.machine_st.fail = result;
-            }
-            &SystemClauseType::CpuNow => {
-                let secs = ProcessTime::now().as_duration().as_secs_f64();
-                let secs = arena_alloc!(OrderedFloat(secs), &mut self.machine_st.arena);
+        if prev_b <= bp {
+            self.machine_st.unify_atom(atom!("!"), a1)
+        } else {
+            self.machine_st.unify_atom(atom!("true"), a1);
+        }
+    }
 
-                self.machine_st.unify_f64(secs, self.machine_st.registers[1]);
-            }
-            &SystemClauseType::CurrentTime => {
-                let timestamp = self.systemtime_to_timestamp(SystemTime::now());
-                self.machine_st.unify_atom(timestamp, self.machine_st.registers[1]);
-            }
-            &SystemClauseType::Open => {
-                let alias = self.machine_st.registers[4];
-                let eof_action = self.machine_st.registers[5];
-                let reposition = self.machine_st.registers[6];
-                let stream_type = self.machine_st.registers[7];
+    #[inline(always)]
+    pub(crate) fn clean_up_block(&mut self) {
+        let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let nb = cell_as_fixnum!(nb).get_num() as usize;
 
-                let options  = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
-                let src_sink = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let b = self.machine_st.b;
 
-                if let Some(str_like) = self.machine_st.value_to_str_like(src_sink) {
-                    let file_spec = match str_like {
-                        AtomOrString::Atom(atom) => {
-                            atom
-                        }
-                        AtomOrString::String(string) => {
-                            self.machine_st.atom_tbl.build_with(&string)
-                        }
-                    };
+        if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb {
+            self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b;
+        }
+    }
 
-                    let mut stream = self.machine_st.stream_from_file_spec(
-                        file_spec,
-                        &mut self.indices,
-                        &options,
-                    )?;
+    #[inline(always)]
+    pub(crate) fn erase_ball(&mut self) {
+        self.machine_st.ball.reset();
+    }
 
-                    *stream.options_mut() = options;
-                    self.indices.streams.insert(stream);
+    #[inline(always)]
+    pub(crate) fn get_ball(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let h = self.machine_st.heap.len();
 
-                    if let Some(alias) = stream.options().get_alias() {
-                        self.indices.stream_aliases.insert(alias, stream);
-                    }
+        if self.machine_st.ball.stub.len() > 0 {
+            let stub = self.machine_st.ball.copy_and_align(h);
+            self.machine_st.heap.extend(stub.into_iter());
+        } else {
+            self.machine_st.fail = true;
+            return;
+        }
 
-                    let stream_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
-                    self.machine_st.bind(stream_var.as_var().unwrap(), stream_as_cell!(stream));
-                } else {
-                    let err = self.machine_st.domain_error(DomainErrorType::SourceSink, src_sink);
-                    let stub = functor_stub(atom!("open"), 4);
+        match addr.as_var() {
+            Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]),
+            _ => self.machine_st.fail = true,
+        };
+    }
 
-                    return Err(self.machine_st.error_form(err, stub));
-                }
-            }
-            &SystemClauseType::OpDeclaration => {
-                let priority = self.machine_st.registers[1];
-                let specifier = self.machine_st.registers[2];
-                let op = self.machine_st.registers[3];
+    #[inline(always)]
+    pub(crate) fn get_current_block(&mut self) {
+        let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap());
+        self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
+    }
 
-                let priority = self.machine_st.store(self.machine_st.deref(priority));
+    #[inline(always)]
+    pub(crate) fn get_b_value(&mut self) {
+        let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap());
+        self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
+    }
 
-                let priority = match Number::try_from(priority) {
-                    Ok(Number::Integer(n)) => n.to_u16().unwrap(),
-                    Ok(Number::Fixnum(n)) => u16::try_from(n.get_num()).unwrap(),
-                    _ => {
-                        unreachable!();
-                    }
-                };
+    #[inline(always)]
+    pub(crate) fn get_cut_point(&mut self) {
+        let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap());
+        self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
+    }
 
-                let specifier = cell_as_atom_cell!(self.machine_st.store(self.machine_st.deref(specifier)))
-                    .get_name();
+    #[inline(always)]
+    pub(crate) fn get_staggered_cut_point(&mut self) {
+        use std::sync::Once;
 
-                let op = read_heap_cell!(self.machine_st.store(self.machine_st.deref(op)),
-                    (HeapCellValueTag::Char) => {
-                        self.machine_st.atom_tbl.build_with(&op.to_string())
-                    }
-                    (HeapCellValueTag::Atom, (name, _arity)) => {
-                        name
+        let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0;
+        static LOC_INIT: Once = Once::new();
+
+        let semicolon_second_clause_p = unsafe {
+            LOC_INIT.call_once(|| {
+                match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) {
+                    Some(IndexPtr::Index(p)) => {
+                        match &self.code[p] {
+                            &Instruction::TryMeElse(o) => {
+                                SEMICOLON_SECOND_BRANCH_LOC = p + o;
+                            }
+                            _ => {
+                                unreachable!();
+                            }
+                        }
                     }
                     _ => {
-                        unreachable!()
+                        unreachable!();
                     }
-                );
+                }
+            });
 
-                let result = to_op_decl(priority, specifier, op)
-                    .map_err(SessionError::from)
-                    .and_then(|mut op_decl| {
-                        if op_decl.op_desc.get_prec() == 0 {
-                            Ok(op_decl.remove(&mut self.indices.op_dir))
-                        } else {
-                            let spec = get_op_desc(
-                                op_decl.name,
-                                &CompositeOpDir::new(&self.indices.op_dir, None),
-                            );
+            SEMICOLON_SECOND_BRANCH_LOC
+        };
 
-                            op_decl.submit(spec, &mut self.indices.op_dir)
-                        }
-                    });
+        let staggered_b0 = if self.machine_st.b > 0 {
+            let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b);
 
-                match result {
-                    Ok(()) => {}
-                    Err(e) => {
-                        // 8.14.3.3 l)
-                        let err = self.machine_st.session_error(e);
-                        let stub = functor_stub(atom!("op"), 3);
+            if or_frame.prelude.bp == semicolon_second_clause_p {
+                or_frame.prelude.b0
+            } else {
+                self.machine_st.b0
+            }
+        } else {
+            self.machine_st.b0
+        };
 
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
+        let staggered_b0 = integer_as_cell!(
+            Number::arena_from(staggered_b0, &mut self.machine_st.arena)
+        );
+
+        self.machine_st.bind(b.as_var().unwrap(), staggered_b0);
+    }
+
+    #[inline(always)]
+    pub(crate) fn next_ep(&mut self) {
+        let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        read_heap_cell!(first_arg,
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                debug_assert_eq!(name, atom!("first"));
+                debug_assert_eq!(arity, 0);
+
+                if self.machine_st.e == 0 {
+                    self.machine_st.fail = true;
+                    return;
                 }
-            }
-            &SystemClauseType::SetStreamOptions => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("open"),
-                    4,
-                )?;
 
-                let alias = self.machine_st.registers[2];
-                let eof_action = self.machine_st.registers[3];
-                let reposition = self.machine_st.registers[4];
-                let stream_type = self.machine_st.registers[5];
+                let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e);
+                let cp = and_frame.prelude.cp - 1;
 
-                let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
-                *stream.options_mut() = options;
-            }
-            &SystemClauseType::TruncateIfNoLiftedHeapGrowthDiff => {
-                self.machine_st.truncate_if_no_lifted_heap_diff(|h| heap_loc_as_cell!(h))
-            }
-            &SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
-                self.machine_st.truncate_if_no_lifted_heap_diff(|_| empty_list_as_cell!())
-            }
-            &SystemClauseType::GetAttributedVariableList => {
-                let attr_var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let attr_var_list = read_heap_cell!(attr_var,
-                    (HeapCellValueTag::AttrVar, h) => {
-                        h + 1
-                    }
-                    (HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
-                        // create an AttrVar in the heap.
-                        let h = self.machine_st.heap.len();
+                let e = and_frame.prelude.e;
+                let e = Fixnum::build_with(i64::try_from(e).unwrap());
 
-                        self.machine_st.heap.push(attr_var_as_cell!(h));
-                        self.machine_st.heap.push(heap_loc_as_cell!(h+1));
+                let p = str_loc_as_cell!(self.machine_st.heap.len());
 
-                        self.machine_st.bind(Ref::attr_var(h), attr_var);
-                        h + 1
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                );
+                self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
+                self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
 
-                let list_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
-                self.machine_st.bind(Ref::heap_cell(attr_var_list), list_addr);
+                if !self.machine_st.fail {
+                    unify!(self.machine_st, p, self.machine_st.registers[3]);
+                }
             }
-            &SystemClauseType::GetAttrVarQueueDelimiter => {
-                let addr = self.machine_st.registers[1];
-                let value = Fixnum::build_with(self.machine_st.attr_var_init.attr_var_queue.len() as i64);
+            (HeapCellValueTag::Fixnum, n) => {
+                let e = n.get_num() as usize;
 
-                self.machine_st.unify_fixnum(value, self.machine_st.store(self.machine_st.deref(addr)));
-            }
-            &SystemClauseType::GetAttrVarQueueBeyond => {
-                let addr = self.machine_st.registers[1];
-                let addr = self.machine_st.store(self.machine_st.deref(addr));
+                if e == 0 {
+                    self.machine_st.fail = true;
+                    return;
+                }
 
-                let b = match Number::try_from(addr) {
-                    Ok(Number::Integer(n)) => n.to_usize(),
-                    Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                };
+                // get the call site so that the number of
+                // active permanent variables can be read from
+                // it later.
+                let and_frame = self.machine_st.stack.index_and_frame(e);
+                let cp = and_frame.prelude.cp - 1;
 
-                if let Some(b) = b {
-                    let iter = self.machine_st.gather_attr_vars_created_since(b);
+                let p = str_loc_as_cell!(self.machine_st.heap.len());
+                self.machine_st.heap.extend(functor!(atom!("dir_entry"), [fixnum(cp)]));
 
-                    let var_list_addr = heap_loc_as_cell!(
-                        iter_to_heap_list(&mut self.machine_st.heap, iter)
-                    );
+                let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap());
+                self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
 
-                    let list_addr = self.machine_st.registers[2];
-                    unify!(self.machine_st, var_list_addr, list_addr);
+                if !self.machine_st.fail {
+                    unify!(self.machine_st, p, self.machine_st.registers[3]);
                 }
             }
-            &SystemClauseType::GetContinuationChunk => {
-                let e = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let e = cell_as_fixnum!(e).get_num() as usize;
+            _ => {
+                unreachable!();
+            }
+        );
+    }
 
-                let p_functor = self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[2]
-                ));
-                let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap();
+    #[inline(always)]
+    pub(crate) fn points_to_continuation_reset_marker(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                let num_cells = match self.code_repo.lookup_instr(&self.machine_st, &CodePtr::Local(p)) {
-                    Some(line) => {
-                        let perm_vars = match line.as_ref(&self.code_repo.code) {
-                            Line::Control(ref ctrl_instr) => ctrl_instr.perm_vars(),
-                            _ => None,
-                        };
+        let p = match to_local_code_ptr(&self.machine_st.heap, addr) {
+            Some(p) => p + 1,
+            None => {
+                self.machine_st.fail = true;
+                return;
+            }
+        };
 
-                        perm_vars.unwrap()
-                    }
-                    _ => unreachable!(),
-                };
+        if !self.is_reset_cont_marker(p) {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn quoted_token(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                let mut addrs = vec![];
+        read_heap_cell!(addr,
+            (HeapCellValueTag::Fixnum, n) => {
+                let n = u32::try_from(n.get_num()).ok();
+                let n = n.and_then(std::char::from_u32);
 
-                for idx in 1..num_cells + 1 {
-                    addrs.push(self.machine_st.stack[stack_loc!(AndFrame, e, idx)]);
-                }
+                self.machine_st.fail = match n {
+                    Some(c) => non_quoted_token(once(c)),
+                    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());
+            }
+            _ => {
+                self.machine_st.fail = true;
+            }
+        );
+    }
 
-                let chunk = str_loc_as_cell!(self.machine_st.heap.len());
+    #[inline(always)]
+    pub(crate) fn read_query_term(&mut self) -> CallResult {
+        self.user_input.reset();
 
-                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.extend(addrs);
+        set_prompt(true);
+        let result = self.machine_st.read_term(self.user_input, &mut self.indices);
+        set_prompt(false);
 
-                unify!(self.machine_st, self.machine_st.registers[3], chunk);
+        match result {
+            Ok(()) => Ok(()),
+            Err(e) => {
+                self.user_input = input_stream(&mut self.machine_st.arena);
+                return Err(e);
             }
-            &SystemClauseType::GetLiftedHeapFromOffsetDiff => {
-                let lh_offset = self.machine_st.registers[1];
-                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() {
-                    let solutions = self.machine_st.registers[2];
-                    let diff = self.machine_st.registers[3];
+    #[inline(always)]
+    pub(crate) fn read_term(&mut self) -> CallResult {
+        set_prompt(false);
 
-                    unify_fn!(self.machine_st, solutions, diff);
-                } else {
-                    let h = self.machine_st.heap.len();
-                    let mut last_index = h;
+        let stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("read_term"),
+            3,
+        )?;
 
-                    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);
-                    }
+        self.machine_st.read_term(stream, &mut self.indices)
+    }
 
-                    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]);
-                    }
+    #[inline(always)]
+    pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
+        if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let chars = atom_or_string.to_string();
+            let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena);
 
-                    self.machine_st.lifted_heap.truncate(lh_offset);
+            let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) {
+                Ok(term_write_result) => term_write_result,
+                Err(e) => {
+                    let stub = functor_stub(atom!("read_term_from_chars"), 2);
+                    let e = self.machine_st.session_error(SessionError::from(e));
 
-                    let solutions = self.machine_st.registers[2];
-                    unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
+                    return Err(self.machine_st.error_form(e, stub));
                 }
-            }
-            &SystemClauseType::GetLiftedHeapFromOffset => {
-                let lh_offset = self.machine_st.registers[1];
-                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() {
-                    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 result = heap_loc_as_cell!(term_write_result.heap_loc);
+            let var = self.machine_st.store(self.machine_st.deref(
+                self.machine_st.registers[2]
+            )).as_var().unwrap();
 
-                    for addr in self.machine_st.lifted_heap[lh_offset..].iter().cloned() {
-                        self.machine_st.heap.push(addr + h);
-                    }
+            self.machine_st.bind(var, result);
+        } else {
+            unreachable!()
+        }
 
-                    self.machine_st.lifted_heap.truncate(lh_offset);
+        Ok(())
+    }
 
-                    let solutions = self.machine_st.registers[2];
-                    unify_fn!(self.machine_st, heap_loc_as_cell!(h), solutions);
-                }
-            }
-            &SystemClauseType::GetDoubleQuotes => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+    #[inline(always)]
+    pub(crate) fn reset_block(&mut self) {
+        let addr = self.machine_st.deref(self.machine_st.registers[1]);
+        self.machine_st.reset_block(addr);
+    }
 
-                self.machine_st.unify_atom(
-                    match self.machine_st.flags.double_quotes {
-                        DoubleQuotes::Chars => atom!("chars"),
-                        DoubleQuotes::Atom => atom!("atom"),
-                        DoubleQuotes::Codes => atom!("codes"),
-                    },
-                    a1,
-                );
-            }
-            &SystemClauseType::GetSCCCleaner => {
-                let dest = self.machine_st.registers[1];
+    #[inline(always)]
+    pub(crate) fn reset_continuation_marker(&mut self) {
+        let h = self.machine_st.heap.len();
 
-                if let Some((addr, b_cutoff, prev_b)) = self.machine_st.cont_pts.pop() {
-                    let b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
+        self.machine_st.registers[3] = atom_as_cell!(atom!("none"));
+        self.machine_st.registers[4] = heap_loc_as_cell!(h);
 
-                    if b <= b_cutoff {
-                        self.machine_st.block = prev_b;
+        self.machine_st.heap.push(heap_loc_as_cell!(h));
+    }
 
-                        if let Some(r) = dest.as_var() {
-                            self.machine_st.bind(r, addr);
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    } else {
-                        self.machine_st.cont_pts.push((addr, b_cutoff, prev_b));
-                    }
-                }
+    #[inline(always)]
+    pub(crate) fn set_ball(&mut self) {
+        self.machine_st.set_ball();
+    }
 
+    #[inline(always)]
+    pub(crate) fn set_seed(&mut self) {
+        let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let mut rand = RANDOM_STATE.borrow_mut();
+
+        match Number::try_from(seed) {
+            Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)),
+            Ok(Number::Integer(n)) => rand.seed(&*n),
+            Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()),
+            _ => {
                 self.machine_st.fail = true;
             }
-            &SystemClauseType::Halt => {
-                let code = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-
-                let code = match Number::try_from(code) {
-                    Ok(Number::Fixnum(n)) => i32::try_from(n.get_num()).unwrap(),
-                    Ok(Number::Integer(n)) => n.to_i32().unwrap(),
-                    Ok(Number::Rational(r)) => {
-                        // n has already been confirmed as an integer, and
-                        // internally, Rational is assumed reduced, so its
-                        // denominator must be 1.
-                        r.numer().to_i32().unwrap()
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                };
+        }
+    }
 
-                std::process::exit(code);
+    #[inline(always)]
+    pub(crate) fn sleep(&mut self) {
+        let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        let time = match Number::try_from(time) {
+            Ok(Number::Float(n)) => n.into_inner(),
+            Ok(Number::Fixnum(n)) => n.get_num() as f64,
+            Ok(Number::Integer(n)) => n.to_f64(),
+            _ => {
+                unreachable!()
             }
-            &SystemClauseType::InstallSCCCleaner => {
-                let addr = self.machine_st.registers[1];
-                let b = self.machine_st.b;
-                let prev_block = self.machine_st.block;
+        };
 
-                self.machine_st.run_cleaners_fn = Machine::run_cleaners;
+        let duration = Duration::new(1, 0);
+        let duration = duration.mul_f64(time);
 
-                self.machine_st.install_new_block(self.machine_st.registers[2]);
-                self.machine_st.cont_pts.push((addr, b, prev_block));
-            }
-            &SystemClauseType::InstallInferenceCounter => {
-                // A1 = B, A2 = L
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        std::thread::sleep(duration);
+    }
+
+    #[inline(always)]
+    pub(crate) fn socket_client_open(&mut self) -> CallResult {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+
+        let socket_atom = cell_as_atom!(addr);
 
-                let n = match Number::try_from(a2) {
-                    Ok(Number::Fixnum(bp)) => bp.get_num() as usize,
-                    Ok(Number::Integer(n)) => n.to_usize().unwrap(),
+        let _port = read_heap_cell!(port,
+            (HeapCellValueTag::Atom, (name, arity)) => {
+                debug_assert_eq!(arity, 0);
+                name
+            }
+            _ => {
+                self.machine_st.atom_tbl.build_with(&match Number::try_from(port) {
+                    Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+                    Ok(Number::Integer(n)) => n.to_string(),
                     _ => {
-                        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));
+                        unreachable!()
                     }
-                };
+                })
+            }
+        );
 
-                let bp = cell_as_fixnum!(a1).get_num() as usize;
-                let count = self.machine_st.cwil.add_limit(n, bp);
-                let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
+        let socket_addr = if socket_atom == atom!("") {
+            atom!("127.0.0.1")
+        } else {
+            socket_atom
+        };
 
-                self.machine_st.increment_call_count_fn = MachineState::increment_call_count;
+        let alias = self.machine_st.registers[4];
+        let eof_action = self.machine_st.registers[5];
+        let reposition = self.machine_st.registers[6];
+        let stream_type = self.machine_st.registers[7];
 
-                let a3 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
-                self.machine_st.unify_big_int(count, a3);
-            }
-            &SystemClauseType::ModuleExists => {
-                let module = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let module_name = cell_as_atom!(module);
+        let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+
+        if options.reposition() {
+            return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3));
+        }
 
-                self.machine_st.fail = !self.indices.modules.contains_key(&module_name);
+        if let Some(alias) = options.get_alias() {
+            if self.indices.stream_aliases.contains_key(&alias) {
+                return Err(self.machine_st.occupied_alias_permission_error(
+                    alias,
+                    atom!("socket_client_open"),
+                    3,
+                ));
             }
-            &SystemClauseType::NoSuchPredicate => {
-                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
-                let head = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        }
 
-                self.machine_st.fail = read_heap_cell!(head,
-                    (HeapCellValueTag::Str, s) => {
-                        let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
-                            .get_name_and_arity();
+        let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) {
+            Ok(tcp_stream) => {
+                let mut stream = {
+                    let tls = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+                        self.machine_st.registers[8]
+                    )));
 
-                        if clause_type_form(name, arity).is_some() {
-                            true
-                        } else {
-                            let index = self.indices.get_predicate_code_index(
-                                name,
-                                arity,
-                                module_name,
-                            )
-                            .map(|index| index.get())
-                            .unwrap_or(IndexPtr::DynamicUndefined);
-
-                            match index {
-                                IndexPtr::DynamicUndefined | IndexPtr::Undefined => false,
-                                _ => true,
-                            }
+                    match tls {
+                        atom!("false") => {
+                            Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.machine_st.arena)
                         }
-                    }
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        debug_assert_eq!(arity, 0);
+                        atom!("true") => {
+                            let connector = TlsConnector::new().unwrap();
+                            let stream = Stream::from_tcp_stream(
+                                socket_addr,
+                                tcp_stream,
+                                &mut self.machine_st.arena,
+                            );
 
-                        if clause_type_form(name, 0).is_some() {
-                            true
-                        } else {
-                            let index = self.indices.get_predicate_code_index(
-                                name,
-                                0,
-                                module_name,
-                            )
-                            .map(|index| index.get())
-                            .unwrap_or(IndexPtr::DynamicUndefined);
-
-                            match index {
-                                IndexPtr::DynamicUndefined => false,
-                                _ => true,
-                            }
-                        }
-                    }
-                    _ => {
-                        let err = self.machine_st.type_error(ValidType::Callable, head);
-                        let stub = functor_stub(atom!("clause"), 2);
+                            let stream =
+                                match connector.connect(socket_atom.as_str(), stream) {
+                                    Ok(tls_stream) => tls_stream,
+                                    Err(_) => {
+                                        return Err(self.machine_st.open_permission_error(
+                                            addr,
+                                            atom!("socket_client_open"),
+                                            3,
+                                        ));
+                                    }
+                                };
 
-                        return Err(self.machine_st.error_form(err, stub));
+                            Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena)
+                        }
+                        _ => {
+                            unreachable!()
+                        }
                     }
-                );
-            }
-            &SystemClauseType::RedoAttrVarBinding => {
-                let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                };
 
-                debug_assert_eq!(HeapCellValueTag::AttrVar, var.get_tag());
-                self.machine_st.heap[var.get_value()] = value;
-            }
-            &SystemClauseType::ResetAttrVarState => {
-                self.machine_st.attr_var_init.reset();
-            }
-            &SystemClauseType::RemoveCallPolicyCheck => {
-                let bp = cell_as_fixnum!(self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[1]
-                ))).get_num() as usize;
+                *stream.options_mut() = options;
 
-                if bp == self.machine_st.b && self.machine_st.cwil.is_empty() {
-                    self.machine_st.cwil.reset();
-                    self.machine_st.increment_call_count_fn = |_| { Ok(()) };
+                if let Some(alias) = stream.options().get_alias() {
+                    self.indices.stream_aliases.insert(alias, stream);
                 }
-            }
-            &SystemClauseType::RemoveInferenceCounter => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let bp = cell_as_fixnum!(a1).get_num() as usize;
-
-                let count = self.machine_st.cwil.remove_limit(bp).clone();
-                let count = arena_alloc!(count.clone(), &mut self.machine_st.arena);
 
-                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+                self.indices.streams.insert(stream);
 
-                self.machine_st.unify_big_int(count, a2);
+                stream_as_cell!(stream)
             }
-            &SystemClauseType::REPL(repl_code_ptr) => {
-                return self.machine_st.repl_redirect(repl_code_ptr);
+            Err(ErrorKind::PermissionDenied) => {
+                return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3));
             }
-            &SystemClauseType::ReturnFromVerifyAttr => {
-                let e = self.machine_st.e;
-                let frame_len = self.machine_st.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
+            Err(ErrorKind::NotFound) => {
+                let stub = functor_stub(atom!("socket_client_open"), 3);
+                let err = self.machine_st.existence_error(
+                    ExistenceError::SourceSink(addr),
+                );
 
-                for i in 1..frame_len - 1 {
-                    self.machine_st.registers[i] = self.machine_st.stack[stack_loc!(AndFrame, e, i)];
-                }
+                return Err(self.machine_st.error_form(err, stub));
+            }
+            Err(_) => {
+                // for now, just fail. expand to meaningful error messages later.
+                self.machine_st.fail = true;
+                return Ok(());
+            }
+        };
 
-                self.machine_st.b0 = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len - 1)])
-                    .get_num() as usize;
+        let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+        self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
 
-                self.machine_st.num_of_args = cell_as_fixnum!(self.machine_st.stack[stack_loc!(AndFrame, e, frame_len)])
-                    .get_num() as usize;
+        Ok(())
+    }
 
-                self.machine_st.deallocate();
-                self.machine_st.p = CodePtr::Local(self.machine_st.stack.index_and_frame(e).prelude.interrupt_cp);
+    #[inline(always)]
+    pub(crate) fn socket_server_open(&mut self) -> CallResult {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let socket_atom = cell_as_atom_cell!(addr).get_name();
 
-                return Ok(());
-            }
-            &SystemClauseType::RestoreCutPolicy => {
-                if self.machine_st.cont_pts.is_empty() {
-                    self.machine_st.run_cleaners_fn = |_| { false };
-                }
-            }
-            &SystemClauseType::SetCutPoint(r) => {
-                let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
-                self.machine_st.cut_body(cp);
+        let socket_atom = if socket_atom == atom!("[]") {
+            atom!("127.0.0.1")
+        } else {
+            socket_atom
+        };
 
-                if (self.machine_st.run_cleaners_fn)(self) {
-                    return Ok(());
-                }
-            }
-            &SystemClauseType::SetCutPointByDefault(r) => {
-                let cp = self.machine_st.store(self.machine_st.deref(self.machine_st[r]));
-                self.machine_st.cut_body(cp);
-            }
-            &SystemClauseType::SetInput => {
-                let addr = self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[1]
-                ));
-                let stream = self.machine_st.get_stream_or_alias(
-                    addr,
-                    &self.indices.stream_aliases,
-                    atom!("set_input"),
-                    1,
-                )?;
-
-                if !stream.is_input_stream() {
-                    let stub = functor_stub(atom!("set_input"), 1);
-                    let user_alias = atom_as_cell!(atom!("user"));
-
-                    let err = self.machine_st.permission_error(
-                        Permission::InputStream,
-                        atom!("stream"),
-                        user_alias,
-                    );
+        let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                    return Err(self.machine_st.error_form(err, stub));
+        let port = if port.is_var() {
+            String::from("0")
+        } else {
+            match Number::try_from(port) {
+                Ok(Number::Fixnum(n)) => n.get_num().to_string(),
+                Ok(Number::Integer(n)) => n.to_string(),
+                _ => {
+                    unreachable!()
                 }
-
-                self.user_input = stream;
             }
-            &SystemClauseType::SetOutput => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let stream = self.machine_st.get_stream_or_alias(
-                    addr,
-                    &self.indices.stream_aliases,
-                    atom!("set_output"),
-                    1,
-                )?;
-
-                if !stream.is_output_stream() {
-                    let stub = functor_stub(atom!("set_input"), 1);
+        };
 
-                    let user_alias = atom_as_cell!(atom!("user"));
-                    let err = self.machine_st.permission_error(
-                        Permission::OutputStream,
-                        atom!("stream"),
-                        user_alias,
-                    );
+        let had_zero_port = &port == "0";
 
-                    return Err(self.machine_st.error_form(err, stub));
-                }
+        let server_addr = if socket_atom == atom!("") {
+            port
+        } else {
+            format!("{}:{}", socket_atom.as_str(), port)
+        };
 
-                self.user_output = stream;
-            }
-            &SystemClauseType::SetDoubleQuotes => {
-                let atom = cell_as_atom!(self.machine_st.registers[1]);
+        let (tcp_listener, port) =
+            match TcpListener::bind(server_addr).map_err(|e| e.kind()) {
+                Ok(tcp_listener) => {
+                    let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
 
-                self.machine_st.flags.double_quotes = match atom {
-                    atom!("atom") => DoubleQuotes::Atom,
-                    atom!("chars") => DoubleQuotes::Chars,
-                    atom!("codes") => DoubleQuotes::Codes,
-                    _ => {
+                    if let Some(port) = port {
+                        (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize)
+                    } else {
                         self.machine_st.fail = true;
                         return Ok(());
                     }
-                };
-            }
-            &SystemClauseType::InferenceLevel => {
-                let a1 = self.machine_st.registers[1];
-                let a2 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
-
-                let bp = cell_as_fixnum!(a2).get_num() as usize;
-                let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
-
-                if prev_b <= bp {
-                    self.machine_st.unify_atom(atom!("!"), a1)
-                } else {
-                    self.machine_st.unify_atom(atom!("true"), a1);
                 }
-            }
-            &SystemClauseType::CleanUpBlock => {
-                let nb = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let nb = cell_as_fixnum!(nb).get_num() as usize;
-
-                let b = self.machine_st.b;
-
-                if nb > 0 && self.machine_st.stack.index_or_frame(b).prelude.b == nb {
-                    self.machine_st.b = self.machine_st.stack.index_or_frame(nb).prelude.b;
+                Err(ErrorKind::PermissionDenied) => {
+                    return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2));
                 }
-            }
-            &SystemClauseType::EraseBall => {
-                self.machine_st.ball.reset();
-            }
-            &SystemClauseType::Fail => {
-                self.machine_st.fail = true;
-            }
-            &SystemClauseType::GetBall => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let h = self.machine_st.heap.len();
-
-                if self.machine_st.ball.stub.len() > 0 {
-                    let stub = self.machine_st.ball.copy_and_align(h);
-                    self.machine_st.heap.extend(stub.into_iter());
-                } else {
+                _ => {
                     self.machine_st.fail = true;
                     return Ok(());
                 }
+            };
 
-                match addr.as_var() {
-                    Some(r) => self.machine_st.bind(r, self.machine_st.heap[h]),
-                    _ => self.machine_st.fail = true,
-                };
-            }
-            &SystemClauseType::GetCurrentBlock => {
-                let n = Fixnum::build_with(i64::try_from(self.machine_st.block).unwrap());
-                self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
-            }
-            &SystemClauseType::GetBValue => {
-                let n = Fixnum::build_with(i64::try_from(self.machine_st.b).unwrap());
-                self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
-            }
-            &SystemClauseType::GetCutPoint => {
-                let n = Fixnum::build_with(i64::try_from(self.machine_st.b0).unwrap());
-                self.machine_st.unify_fixnum(n, self.machine_st.registers[1]);
-            }
-            &SystemClauseType::GetStaggeredCutPoint => {
-                use std::sync::Once;
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+        self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener));
 
-                let b = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        if had_zero_port {
+            self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]);
+        }
 
-                static mut SEMICOLON_SECOND_BRANCH_LOC: usize = 0;
-                static LOC_INIT: Once = Once::new();
+        Ok(())
+    }
 
-                let semicolon_second_clause_p = unsafe {
-                    LOC_INIT.call_once(|| {
-                        match self.indices.code_dir.get(&(atom!(";"), 2)).map(|cell| cell.get()) {
-                            Some(IndexPtr::Index(p)) => {
-                                match self.code_repo.code[p] {
-                                    Line::Choice(ChoiceInstruction::TryMeElse(o)) => {
-                                        SEMICOLON_SECOND_BRANCH_LOC = p + o;
-                                    }
-                                    _ => {
-                                        unreachable!();
-                                    }
-                                }
-                            }
-                            _ => {
-                                unreachable!();
-                            }
-                        }
-                    });
+    #[inline(always)]
+    pub(crate) fn socket_server_accept(&mut self) -> CallResult {
+        let alias = self.machine_st.registers[4];
+        let eof_action = self.machine_st.registers[5];
+        let reposition = self.machine_st.registers[6];
+        let stream_type = self.machine_st.registers[7];
 
-                    LocalCodePtr::DirEntry(SEMICOLON_SECOND_BRANCH_LOC)
-                };
+        let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
 
-                let staggered_b0 = if self.machine_st.b > 0 {
-                    let or_frame = self.machine_st.stack.index_or_frame(self.machine_st.b);
+        if options.reposition() {
+            return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4));
+        }
 
-                    if or_frame.prelude.bp == semicolon_second_clause_p {
-                        or_frame.prelude.b0
-                    } else {
-                        self.machine_st.b0
-                    }
-                } else {
-                    self.machine_st.b0
-                };
+        if let Some(alias) = options.get_alias() {
+            if self.indices.stream_aliases.contains_key(&alias) {
+                return Err(self.machine_st.occupied_alias_permission_error(
+                    alias,
+                    atom!("socket_server_accept"),
+                    4,
+                ));
+            }
+        }
 
-                let staggered_b0 = integer_as_cell!(
-                    Number::arena_from(staggered_b0, &mut self.machine_st.arena)
-                );
+        let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                self.machine_st.bind(b.as_var().unwrap(), staggered_b0);
-            }
-            &SystemClauseType::InstallNewBlock => {
-                self.machine_st.install_new_block(self.machine_st.registers[1]);
-            }
-            &SystemClauseType::NextEP => {
-                let first_arg = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        read_heap_cell!(culprit,
+            (HeapCellValueTag::Cons, cons_ptr) => {
+                match_untyped_arena_ptr!(cons_ptr,
+                     (ArenaHeaderTag::TcpListener, tcp_listener) => {
+                         match tcp_listener.accept().ok() {
+                             Some((tcp_stream, socket_addr)) => {
+                                 let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string());
 
-                read_heap_cell!(first_arg,
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        debug_assert_eq!(name, atom!("first"));
-                        debug_assert_eq!(arity, 0);
+                                 let mut tcp_stream = Stream::from_tcp_stream(
+                                     client,
+                                     tcp_stream,
+                                     &mut self.machine_st.arena,
+                                 );
 
-                        if self.machine_st.e == 0 {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
+                                 *tcp_stream.options_mut() = options;
 
-                        let and_frame = self.machine_st.stack.index_and_frame(self.machine_st.e);
-                        let cp = (and_frame.prelude.cp - 1).unwrap();
+                                 if let Some(alias) = &tcp_stream.options().get_alias() {
+                                     self.indices.stream_aliases.insert(*alias, tcp_stream);
+                                 }
 
-                        let e = and_frame.prelude.e;
-                        let e = Fixnum::build_with(i64::try_from(e).unwrap());
+                                 self.indices.streams.insert(tcp_stream);
 
-                        let p = str_loc_as_cell!(self.machine_st.heap.len());
+                                 let tcp_stream = stream_as_cell!(tcp_stream);
+                                 let client = atom_as_cell!(client);
 
-                        self.machine_st.heap.extend(cp.as_functor());
-                        self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
+                                 let client_addr = self.machine_st.store(self.machine_st.deref(
+                                     self.machine_st.registers[2],
+                                 ));
+                                 let stream_addr = self.machine_st.store(self.machine_st.deref(
+                                     self.machine_st.registers[3],
+                                 ));
 
-                        if !self.machine_st.fail {
-                            unify!(self.machine_st, p, self.machine_st.registers[3]);
-                        }
+                                 self.machine_st.bind(client_addr.as_var().unwrap(), client);
+                                 self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream);
+                             }
+                             None => {
+                                 self.machine_st.fail = true;
+                             }
+                         }
+                     }
+                     _ => {
+                     }
+                );
+            }
+            _ => {
+            }
+        );
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn tls_client_connect(&mut self) -> CallResult {
+        if let Some(hostname) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let stream0 = self.machine_st.get_stream_or_alias(
+                self.machine_st.registers[2],
+                &self.indices.stream_aliases,
+                atom!("tls_client_negotiate"),
+                3,
+            )?;
+
+            let connector = TlsConnector::new().unwrap();
+            let stream =
+                match connector.connect(hostname.as_str(), stream0) {
+                    Ok(tls_stream) => tls_stream,
+                    Err(_) => {
+                        return Err(self.machine_st.open_permission_error(
+                            self.machine_st.registers[1],
+                            atom!("tls_client_negotiate"),
+                            3,
+                        ));
                     }
-                    (HeapCellValueTag::Fixnum, n) => {
-                        let e = n.get_num() as usize;
+                };
 
-                        if e == 0 {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
+            let addr = atom!("TLS");
+            let stream = Stream::from_tls_stream(addr, stream, &mut self.machine_st.arena);
+            self.indices.streams.insert(stream);
 
-                        // get the call site so that the number of
-                        // active permanent variables can be read from
-                        // it later.
-                        let and_frame = self.machine_st.stack.index_and_frame(e);
-                        let cp = (and_frame.prelude.cp - 1).unwrap();
+            self.machine_st.heap.push(stream_as_cell!(stream));
+            let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+            self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
 
-                        let p = str_loc_as_cell!(self.machine_st.heap.len());
-                        self.machine_st.heap.extend(cp.as_functor());
+            Ok(())
+        } else {
+            unreachable!();
+        }
+    }
 
-                        let e = Fixnum::build_with(i64::try_from(and_frame.prelude.e).unwrap());
-                        self.machine_st.unify_fixnum(e, self.machine_st.registers[2]);
+    #[inline(always)]
+    pub(crate) fn tls_accept_client(&mut self) -> CallResult {
+        let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
 
-                        if !self.machine_st.fail {
-                            unify!(self.machine_st, p, self.machine_st.registers[3]);
-                        }
-                    }
-                    _ => {
-                        unreachable!();
+        if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
+            let identity =
+                match Identity::from_pkcs12(&pkcs12, password.as_str()) {
+                    Ok(identity) => identity,
+                    Err(_) => {
+                        return Err(self.machine_st.open_permission_error(
+                            self.machine_st.registers[1],
+                            atom!("tls_server_negotiate"),
+                            3,
+                        ));
                     }
-                );
-            }
-            &SystemClauseType::PointsToContinuationResetMarker => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+                };
 
-                let p = match to_local_code_ptr(&self.machine_st.heap, addr) {
-                    Some(p) => p + 1,
-                    None => {
-                        self.machine_st.fail = true;
-                        return Ok(());
+            let stream0 = self.machine_st.get_stream_or_alias(
+                self.machine_st.registers[3],
+                &self.indices.stream_aliases,
+                atom!("tls_server_negotiate"),
+                3,
+            )?;
+
+            let acceptor = TlsAcceptor::new(identity).unwrap();
+
+            let stream =
+                match acceptor.accept(stream0) {
+                    Ok(tls_stream) => tls_stream,
+                    Err(_) => {
+                        return Err(self.machine_st.open_permission_error(
+                            self.machine_st.registers[3],
+                            atom!("tls_server_negotiate"),
+                            3,
+                        ));
                     }
                 };
 
-                if self.is_reset_cont_marker(p) {
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+            let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena);
+            self.indices.streams.insert(stream);
 
-                self.machine_st.fail = true;
-                return Ok(());
-            }
-            &SystemClauseType::QuotedToken => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+            let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
+            self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
+        } else {
+            unreachable!();
+        }
 
-                read_heap_cell!(addr,
-                    (HeapCellValueTag::Fixnum, n) => {
-                        let n = u32::try_from(n.get_num()).ok();
-                        let n = n.and_then(std::char::from_u32);
+        Ok(())
+    }
 
-                        self.machine_st.fail = match n {
-                            Some(c) => non_quoted_token(once(c)),
-                            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());
+    #[inline(always)]
+    pub(crate) fn socket_server_close(&mut self) -> CallResult {
+        let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        read_heap_cell!(culprit,
+            (HeapCellValueTag::Cons, cons_ptr) => {
+                match_untyped_arena_ptr!(cons_ptr,
+                    (ArenaHeaderTag::TcpListener, tcp_listener) => {
+                        unsafe {
+                            // dropping closes the instance.
+                            std::ptr::drop_in_place(&mut tcp_listener as *mut _);
+                        }
+
+                        tcp_listener.set_tag(ArenaHeaderTag::Dropped);
+                        return Ok(());
                     }
                     _ => {
-                        self.machine_st.fail = true;
                     }
                 );
             }
-            &SystemClauseType::ReadQueryTerm => {
-                self.user_input.reset();
-
-                set_prompt(true);
-                let result = self.machine_st.read_term(self.user_input, &mut self.indices);
-                set_prompt(false);
-
-                match result {
-                    Ok(()) => {}
-                    Err(e) => {
-                        self.user_input = input_stream(&mut self.machine_st.arena);
-                        return Err(e);
-                    }
-                }
+            _ => {
             }
-            &SystemClauseType::ReadTerm => {
-                set_prompt(false);
+        );
 
-                let stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("read_term"),
-                    3,
-                )?;
+        let err = self.machine_st.type_error(ValidType::TcpListener, culprit);
+        let stub = functor_stub(atom!("socket_server_close"), 1);
 
-                self.machine_st.read_term(stream, &mut self.indices)?;
-            }
-            &SystemClauseType::ReadTermFromChars => {
-                if let Some(atom_or_string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let chars = atom_or_string.to_string();
-                    let stream = Stream::from_owned_string(chars, &mut self.machine_st.arena);
+        return Err(self.machine_st.error_form(err, stub));
+    }
 
-                    let term_write_result = match self.machine_st.read(stream, &self.indices.op_dir) {
-                        Ok(term_write_result) => term_write_result,
-                        Err(e) => {
-                            let stub = functor_stub(atom!("read_term_from_chars"), 2);
-                            let e = self.machine_st.session_error(SessionError::from(e));
+    #[inline(always)]
+    pub(crate) fn set_stream_position(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("set_stream_position"),
+            2,
+        )?;
+
+        if !stream.options().reposition() {
+            let stub = functor_stub(atom!("set_stream_position"), 2);
+
+            let err = self.machine_st.permission_error(
+                Permission::Reposition,
+                atom!("stream"),
+                vec![stream_as_cell!(stream)],
+            );
 
-                            return Err(self.machine_st.error_form(e, stub));
-                        }
-                    };
+            return Err(self.machine_st.error_form(err, stub));
+        }
 
-                    let result = heap_loc_as_cell!(term_write_result.heap_loc);
-                    let var = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])).as_var().unwrap();
+        let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                    self.machine_st.bind(var, result);
+        let position = match Number::try_from(position) {
+            Ok(Number::Fixnum(n)) => n.get_num() as u64,
+            Ok(Number::Integer(n)) => {
+                if let Some(n) = n.to_u64() {
+                    n
                 } else {
-                    unreachable!()
+                    self.machine_st.fail = true;
+                    return Ok(());
                 }
             }
-            &SystemClauseType::ResetBlock => {
-                let addr = self.machine_st.deref(self.machine_st.registers[1]);
-                self.machine_st.reset_block(addr);
+            _ => {
+                unreachable!()
             }
-            &SystemClauseType::ResetContinuationMarker => {
-                let h = self.machine_st.heap.len();
+        };
 
-                self.machine_st.registers[3] = atom_as_cell!(atom!("none"));
-                self.machine_st.registers[4] = heap_loc_as_cell!(h);
+        stream.set_position(position);
+        Ok(())
+    }
 
-                self.machine_st.heap.push(heap_loc_as_cell!(h));
-            }
-            &SystemClauseType::SetBall => {
-                self.machine_st.set_ball();
+    #[inline(always)]
+    pub(crate) fn stream_property(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("stream_property"),
+            2,
+        )?;
+
+        let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[2]
+        )));
+
+        let property = match atom {
+            atom!("file_name") => {
+                atom_as_cell!(if let Some(file_name) = stream.file_name() {
+                    file_name
+                } else {
+                    self.machine_st.fail = true;
+                    return Ok(());
+                })
+            }
+            atom!("mode") => atom_as_cell!(stream.mode()),
+            atom!("direction") =>
+                atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() {
+                    atom!("input_output")
+                } else if stream.is_input_stream() {
+                    atom!("input")
+                } else {
+                    atom!("output")
+                }),
+            atom!("alias") => {
+                atom_as_cell!(if let Some(alias) = stream.options().get_alias() {
+                    alias
+                } else {
+                    self.machine_st.fail = true;
+                    return Ok(());
+                })
             }
-            &SystemClauseType::SetSeed => {
-                let seed = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let mut rand = RANDOM_STATE.borrow_mut();
+            atom!("position") => {
+                if let Some((position, lines_read)) = stream.position() {
+                    let h = self.machine_st.heap.len();
 
-                match Number::try_from(seed) {
-                    Ok(Number::Fixnum(n)) => rand.seed(&Integer::from(n)),
-                    Ok(Number::Integer(n)) => rand.seed(&*n),
-                    Ok(Number::Rational(n)) if n.denom() == &1 => rand.seed(n.numer()),
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
+                    let position_term = functor!(
+                        atom!("position_and_lines_read"),
+                        [integer(position, &mut self.machine_st.arena),
+                         integer(lines_read, &mut self.machine_st.arena)]
+                    );
+
+                    self.machine_st.heap.extend(position_term.into_iter());
+                    str_loc_as_cell!(h)
+                } else {
+                    self.machine_st.fail = true;
+                    return Ok(());
                 }
             }
-            &SystemClauseType::SkipMaxList => {
-                if let Err(err) = self.machine_st.skip_max_list() {
-                    return Err(err);
-                }
+            atom!("end_of_stream") => {
+                let end_of_stream_pos = stream.position_relative_to_end();
+                atom_as_cell!(end_of_stream_pos.as_atom())
             }
-            &SystemClauseType::Sleep => {
-                let time = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-
-                let time = match Number::try_from(time) {
-                    Ok(Number::Float(n)) => n.into_inner(),
-                    Ok(Number::Fixnum(n)) => n.get_num() as f64,
-                    Ok(Number::Integer(n)) => n.to_f64(),
-                    _ => {
-                        unreachable!()
-                    }
-                };
-
-                let duration = Duration::new(1, 0);
-                let duration = duration.mul_f64(time);
-
-                std::thread::sleep(duration);
+            atom!("eof_action") => {
+                atom_as_cell!(stream.options().eof_action().as_atom())
             }
-            &SystemClauseType::SocketClientOpen => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
-
-                let socket_atom = cell_as_atom!(addr);
-
-                let _port = read_heap_cell!(port,
-                    (HeapCellValueTag::Atom, (name, arity)) => {
-                        debug_assert_eq!(arity, 0);
-                        name
-                    }
-                    _ => {
-                        self.machine_st.atom_tbl.build_with(&match Number::try_from(port) {
-                            Ok(Number::Fixnum(n)) => n.get_num().to_string(),
-                            Ok(Number::Integer(n)) => n.to_string(),
-                            _ => {
-                                unreachable!()
-                            }
-                        })
-                    }
-                );
-
-                let socket_addr = if socket_atom == atom!("") {
-                    atom!("127.0.0.1")
-                } else {
-                    socket_atom
-                };
-
-                let alias = self.machine_st.registers[4];
-                let eof_action = self.machine_st.registers[5];
-                let reposition = self.machine_st.registers[6];
-                let stream_type = self.machine_st.registers[7];
+            atom!("reposition") =>
+                atom_as_cell!(if stream.options().reposition() {
+                    atom!("true")
+                } else {
+                    atom!("false")
+                }),
+            atom!("type") => {
+                atom_as_cell!(stream.options().stream_type().as_property_atom())
+            }
+            _ => {
+                unreachable!()
+            }
+        };
 
-                let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+        unify!(self.machine_st, property, self.machine_st.registers[3]);
+        Ok(())
+    }
 
-                if options.reposition() {
-                    return Err(self.machine_st.reposition_error(atom!("socket_client_open"), 3));
-                }
+    #[inline(always)]
+    pub(crate) fn store_global_var(&mut self) {
+        let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
 
-                if let Some(alias) = options.get_alias() {
-                    if self.indices.stream_aliases.contains_key(&alias) {
-                        return Err(self.machine_st.occupied_alias_permission_error(
-                            alias,
-                            atom!("socket_client_open"),
-                            3,
-                        ));
-                    }
-                }
+        let value = self.machine_st.registers[2];
+        let mut ball = Ball::new();
 
-                let stream = match TcpStream::connect(socket_addr.as_str()).map_err(|e| e.kind()) {
-                    Ok(tcp_stream) => {
-                        let mut stream = Stream::from_tcp_stream(socket_addr, tcp_stream, &mut self.arena);
+        ball.boundary = self.machine_st.heap.len();
 
-                        *stream.options_mut() = options;
+        copy_term(
+            CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub),
+            value,
+            AttrVarPolicy::DeepCopy,
+        );
 
-                        if let Some(alias) = stream.options().get_alias() {
-                            self.indices.stream_aliases.insert(alias, stream);
-                        }
+        self.indices.global_variables.insert(key, (ball, None));
+    }
 
-                        self.indices.streams.insert(stream);
+    #[inline(always)]
+    pub(crate) fn store_backtrackable_global_var(&mut self) {
+        let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+        let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                        stream_as_cell!(stream)
-                    }
-                    Err(ErrorKind::PermissionDenied) => {
-                        return Err(self.machine_st.open_permission_error(addr, atom!("socket_client_open"), 3));
-                    }
-                    Err(ErrorKind::NotFound) => {
-                        let stub = functor_stub(atom!("socket_client_open"), 3);
-                        let err = self.machine_st.existence_error(
-                            ExistenceError::SourceSink(addr),
-                        );
+        match self.indices.global_variables.get_mut(&key) {
+            Some((_, ref mut loc)) => match loc {
+                Some(ref mut value) => {
+                    self.machine_st.trail(TrailRef::BlackboardOffset(key, *value));
+                    *value = new_value;
+                }
+                loc @ None => {
+                    self.machine_st.trail(TrailRef::BlackboardEntry(key));
+                    *loc = Some(new_value);
+                }
+            },
+            None => {
+                self.machine_st.trail(TrailRef::BlackboardEntry(key));
+                self.indices
+                    .global_variables
+                    .insert(key, (Ball::new(), Some(new_value)));
+            }
+        }
+    }
 
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
-                    Err(_) => {
-                        // for now, just fail. expand to meaningful error messages later.
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                };
+    #[inline(always)]
+    pub(crate) fn term_attributed_variables(&mut self) {
+        if self.machine_st.registers[1].is_constant() {
+            self.machine_st.unify_atom(
+                atom!("[]"),
+                self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])),
+            );
 
-                let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
-                self.machine_st.bind(stream_addr.as_var().unwrap(), stream);
-            }
-            &SystemClauseType::SocketServerOpen => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let socket_atom = cell_as_atom_cell!(addr).get_name();
+            return;
+        }
 
-                let socket_atom = if socket_atom == atom!("[]") {
-                    atom!("127.0.0.1")
-                } else {
-                    socket_atom
-                };
+        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 port = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        unify_fn!(self.machine_st, self.machine_st.registers[2], outcome);
+    }
 
-                let port = if port.is_var() {
-                    String::from("0")
-                } else {
-                    match Number::try_from(port) {
-                        Ok(Number::Fixnum(n)) => n.get_num().to_string(),
-                        Ok(Number::Integer(n)) => n.to_string(),
-                        _ => {
-                            unreachable!()
-                        }
-                    }
-                };
+    #[inline(always)]
+    pub(crate) fn term_variables(&mut self) {
+        let a1 = self.machine_st.registers[1];
+        let a2 = self.machine_st.registers[2];
 
-                let had_zero_port = &port == "0";
+        let stored_v = self.machine_st.store(self.machine_st.deref(a1));
 
-                let server_addr = if socket_atom == atom!("") {
-                    port
-                } else {
-                    format!("{}:{}", socket_atom.as_str(), port)
-                };
+        if stored_v.is_constant() {
+            self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2)));
+            return;
+        }
 
-                let (tcp_listener, port) =
-                    match TcpListener::bind(server_addr).map_err(|e| e.kind()) {
-                        Ok(tcp_listener) => {
-                            let port = tcp_listener.local_addr().map(|addr| addr.port()).ok();
+        let mut seen_set = IndexSet::new();
 
-                            if let Some(port) = port {
-                                (arena_alloc!(tcp_listener, &mut self.machine_st.arena), port as usize)
-                            } else {
-                                self.machine_st.fail = true;
-                                return Ok(());
-                            }
-                        }
-                        Err(ErrorKind::PermissionDenied) => {
-                            return Err(self.machine_st.open_permission_error(addr, atom!("socket_server_open"), 2));
-                        }
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    };
+        {
+            let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v);
 
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
-                self.machine_st.bind(addr.as_var().unwrap(), typed_arena_ptr_as_cell!(tcp_listener));
+            while let Some(addr) = iter.next() {
+                let addr = unmark_cell_bits!(addr);
 
-                if had_zero_port {
-                    self.machine_st.unify_fixnum(Fixnum::build_with(port as i64), self.machine_st.registers[2]);
+                if addr.is_var() {
+                    seen_set.insert(addr);
                 }
             }
-            &SystemClauseType::SocketServerAccept => {
-                let alias = self.machine_st.registers[4];
-                let eof_action = self.machine_st.registers[5];
-                let reposition = self.machine_st.registers[6];
-                let stream_type = self.machine_st.registers[7];
+        }
 
-                let options = self.machine_st.to_stream_options(alias, eof_action, reposition, stream_type);
+        let outcome = heap_loc_as_cell!(
+            filtered_iter_to_heap_list(
+                &mut self.machine_st.heap,
+                seen_set.into_iter().rev(),
+                |heap, value| {
+                    heap_bound_store(
+                        heap,
+                        heap_bound_deref(heap, value),
+                    ).is_var()
+                },
+            )
+        );
 
-                if options.reposition() {
-                    return Err(self.machine_st.reposition_error(atom!("socket_server_accept"), 4));
-                }
+        unify_fn!(self.machine_st, a2, outcome);
+    }
 
-                if let Some(alias) = options.get_alias() {
-                    if self.indices.stream_aliases.contains_key(&alias) {
-                        return Err(self.machine_st.occupied_alias_permission_error(
-                            alias,
-                            atom!("socket_server_accept"),
-                            4,
-                        ));
-                    }
-                }
+    #[inline(always)]
+    pub(crate) fn term_variables_under_max_depth(&mut self) {
+        // Term, MaxDepth, VarList
+        let max_depth = cell_as_fixnum!(
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
+        ).get_num() as usize;
+
+        self.machine_st.term_variables_under_max_depth(
+            self.machine_st.registers[1],
+            max_depth,
+            self.machine_st.registers[3],
+        );
+    }
 
-                let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+    #[inline(always)]
+    pub(crate) fn truncate_lifted_heap_to(&mut self) {
+        let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let lh_offset = cell_as_fixnum!(a1).get_num() as usize;
 
-                read_heap_cell!(culprit,
-                    (HeapCellValueTag::Cons, cons_ptr) => {
-                        match_untyped_arena_ptr!(cons_ptr,
-                             (ArenaHeaderTag::TcpListener, tcp_listener) => {
-                                 match tcp_listener.accept().ok() {
-                                     Some((tcp_stream, socket_addr)) => {
-                                         let client = self.machine_st.atom_tbl.build_with(&socket_addr.to_string());
+        self.machine_st.lifted_heap.truncate(lh_offset);
+    }
 
-                                         let mut tcp_stream = Stream::from_tcp_stream(
-                                             client,
-                                             tcp_stream,
-                                             &mut self.machine_st.arena,
-                                         );
+    #[inline(always)]
+    pub(crate) fn unify_with_occurs_check(&mut self) {
+        let a1 = self.machine_st.registers[1];
+        let a2 = self.machine_st.registers[2];
 
-                                         *tcp_stream.options_mut() = options;
+        unify_with_occurs_check!(&mut self.machine_st, a1, a2);
+    }
 
-                                         if let Some(alias) = &tcp_stream.options().get_alias() {
-                                             self.indices.stream_aliases.insert(*alias, tcp_stream);
-                                         }
+    #[inline(always)]
+    pub(crate) fn unwind_environments(&mut self) -> bool {
+        let mut e = self.machine_st.e;
+        let mut cp = self.machine_st.cp;
 
-                                         self.indices.streams.insert(tcp_stream);
+        while e > 0 {
+            if self.is_reset_cont_marker(cp) {
+                self.machine_st.e = e;
+                self.machine_st.p = cp + 1; // skip the reset marker.
 
-                                         let tcp_stream = stream_as_cell!(tcp_stream);
-                                         let client = atom_as_cell!(client);
+                return true;
+            }
 
-                                         let client_addr = self.machine_st.store(self.machine_st.deref(
-                                             self.machine_st.registers[2],
-                                         ));
-                                         let stream_addr = self.machine_st.store(self.machine_st.deref(
-                                             self.machine_st.registers[3],
-                                         ));
+            let and_frame = self.machine_st.stack.index_and_frame(e);
 
-                                         self.machine_st.bind(client_addr.as_var().unwrap(), client);
-                                         self.machine_st.bind(stream_addr.as_var().unwrap(), tcp_stream);
+            cp = and_frame.prelude.cp;
+            e = and_frame.prelude.e;
+        }
 
-                                         return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                                     }
-                                     None => {
-                                         self.machine_st.fail = true;
-                                         return Ok(());
-                                     }
-                                 }
-                             }
-                             _ => {
-                             }
-                        );
-                    }
-                    _ => {
-                    }
-                );
-            }
-            &SystemClauseType::TLSClientConnect => {
-                if let Some(hostname) = self.value_to_str_like(self.registers[1]) {
-                    let stream0 = self.get_stream_or_alias(
-                        self.registers[2],
-                        &indices.stream_aliases,
-                        atom!("tls_client_negotiate"),
-                        3,
-                    )?;
+        false
+    }
 
-                    let connector = TlsConnector::new().unwrap();
-                    let stream =
-                        match connector.connect(hostname.as_str(), stream0) {
-                            Ok(tls_stream) => tls_stream,
-                            Err(_) => {
-                                return Err(self.open_permission_error(
-                                    self[temp_v!(1)],
-                                    atom!("tls_client_negotiate"),
-                                    3,
-                                ));
-                            }
-                        };
+    #[inline(always)]
+    pub(crate) fn wam_instructions(&mut self) -> CallResult {
+        let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1])
+        ));
 
-                    let addr = atom!("TLS");
-                    let stream = Stream::from_tls_stream(addr, stream, &mut self.arena);
-                    indices.streams.insert(stream);
+        let name = self.machine_st.registers[2];
+        let arity = self.machine_st.registers[3];
 
-                    self.heap.push(stream_as_cell!(stream));
-                    let stream_addr = self.store(self.deref(self.registers[3]));
-                    self.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
-                } else {
-                    unreachable!();
-                }
-            }
-            &SystemClauseType::TLSAcceptClient => {
-                let pkcs12 = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
-
-                if let Some(password) = self.machine_st.value_to_str_like(self.machine_st.registers[2]) {
-                    let identity =
-                        match Identity::from_pkcs12(&pkcs12, password.as_str()) {
-                            Ok(identity) => identity,
-                            Err(_) => {
-                                return Err(self.machine_st.open_permission_error(
-                                    self.machine_st.registers[1],
-                                    atom!("tls_server_negotiate"),
-                                    3,
-                                ));
-                            }
-                        };
+        let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name)));
+        let arity = self.machine_st.store(self.machine_st.deref(arity));
 
-                    let stream0 = self.machine_st.get_stream_or_alias(
-                        self.machine_st.registers[3],
-                        &self.indices.stream_aliases,
-                        atom!("tls_server_negotiate"),
-                        3,
-                    )?;
+        let arity = match Number::try_from(arity) {
+            Ok(Number::Fixnum(n)) => n.get_num() as usize,
+            Ok(Number::Integer(n)) => n.to_usize().unwrap(),
+            _ => {
+                unreachable!()
+            }
+        };
 
-                    let acceptor = TlsAcceptor::new(identity).unwrap();
-
-                    let stream =
-                        match acceptor.accept(stream0) {
-                            Ok(tls_stream) => tls_stream,
-                            Err(_) => {
-                                return Err(self.machine_st.open_permission_error(
-                                    self.machine_st.registers[3],
-                                    atom!("tls_server_negotiate"),
-                                    3,
-                                ));
-                            }
-                        };
+        let key = (name, arity);
+
+        let first_idx = match module_name {
+            atom!("user") => self.indices.code_dir.get(&key),
+            _ => match self.indices.modules.get(&module_name) {
+                Some(module) => module.code_dir.get(&key),
+                None => {
+                    let stub = functor_stub(key.0, key.1);
+                    let err = self.machine_st.session_error(
+                        SessionError::from(CompilationError::InvalidModuleResolution(
+                            module_name,
+                        )),
+                    );
 
-                    let stream = Stream::from_tls_stream(atom!("TLS"), stream, &mut self.machine_st.arena);
-                    self.indices.streams.insert(stream);
+                    return Err(self.machine_st.error_form(err, stub));
+                }
+            },
+        };
 
-                    let stream_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[4]));
-                    self.machine_st.bind(stream_addr.as_var().unwrap(), stream_as_cell!(stream));
+        let first_idx = match first_idx {
+            Some(ref idx) if idx.local().is_some() => {
+                if let Some(idx) = idx.local() {
+                    idx
                 } else {
-                    unreachable!();
+                    unreachable!()
                 }
             }
-            &SystemClauseType::SocketServerClose => {
-                let culprit = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-
-                read_heap_cell!(culprit,
-                    (HeapCellValueTag::Cons, cons_ptr) => {
-                        match_untyped_arena_ptr!(cons_ptr,
-                            (ArenaHeaderTag::TcpListener, tcp_listener) => {
-                                unsafe {
-                                    // dropping closes the instance.
-                                    std::ptr::drop_in_place(&mut tcp_listener as *mut _);
-                                }
-
-                                tcp_listener.set_tag(ArenaHeaderTag::Dropped);
-                                return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                            }
-                            _ => {
-                            }
-                        );
-                    }
-                    _ => {
-                    }
+            _ => {
+                let stub = functor_stub(name, arity);
+                let err = self.machine_st.existence_error(
+                    ExistenceError::Procedure(name, arity),
                 );
 
-                let err = self.machine_st.type_error(ValidType::TcpListener, culprit);
-                let stub = functor_stub(atom!("socket_server_close"), 1);
-
                 return Err(self.machine_st.error_form(err, stub));
             }
-            &SystemClauseType::SetStreamPosition => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("set_stream_position"),
-                    2,
-                )?;
-
-                if !stream.options().reposition() {
-                    let stub = functor_stub(atom!("set_stream_position"), 2);
-
-                    let err = self.machine_st.permission_error(
-                        Permission::Reposition,
-                        atom!("stream"),
-                        vec![stream_as_cell!(stream)],
-                    );
+        };
 
-                    return Err(self.machine_st.error_form(err, stub));
-                }
+        let mut h = self.machine_st.heap.len();
 
-                let position = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        let mut functors = vec![];
+        let mut functor_list = vec![];
 
-                let position = match Number::try_from(position) {
-                    Ok(Number::Fixnum(n)) => n.get_num() as u64,
-                    Ok(Number::Integer(n)) => {
-                        if let Some(n) = n.to_u64() {
-                            n
-                        } else {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
+        walk_code(&self.code, first_idx, |instr| {
+            let old_len = functors.len();
+            instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors);
+            let new_len = functors.len();
+
+            for index in old_len..new_len {
+                let functor_len = functors[index].len();
+
+                match functor_len {
+                    0 => {}
+                    1 => {
+                        functor_list.push(heap_loc_as_cell!(h));
+                        h += functor_len;
                     }
                     _ => {
-                        unreachable!()
+                        functor_list.push(str_loc_as_cell!(h));
+                        h += functor_len;
                     }
-                };
-
-                stream.set_position(position);
+                }
             }
-            &SystemClauseType::StreamProperty => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("stream_property"),
-                    2,
-                )?;
+        });
 
-                let atom = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
+        for functor in functors {
+            self.machine_st.heap.extend(functor.into_iter());
+        }
 
-                let property = match atom {
-                    atom!("file_name") => {
-                        atom_as_cell!(if let Some(file_name) = stream.file_name() {
-                            file_name
-                        } else {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        })
-                    }
-                    atom!("mode") => atom_as_cell!(stream.mode()),
-                    atom!("direction") =>
-                        atom_as_cell!(if stream.is_input_stream() && stream.is_output_stream() {
-                            atom!("input_output")
-                        } else if stream.is_input_stream() {
-                            atom!("input")
-                        } else {
-                            atom!("output")
-                        }),
-                    atom!("alias") => {
-                        atom_as_cell!(if let Some(alias) = stream.options().get_alias() {
-                            alias
-                        } else {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        })
-                    }
-                    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)]
-                            );
+        let listing = heap_loc_as_cell!(
+            iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter())
+        );
 
-                            self.machine_st.heap.extend(position_term.into_iter());
-                            str_loc_as_cell!(h)
-                        } else {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                    atom!("end_of_stream") => {
-                        let end_of_stream_pos = stream.position_relative_to_end();
-                        atom_as_cell!(end_of_stream_pos.as_atom())
-                    }
-                    atom!("eof_action") => {
-                        atom_as_cell!(stream.options().eof_action().as_atom())
-                    }
-                    atom!("reposition") =>
-                        atom_as_cell!(if stream.options().reposition() {
-                            atom!("true")
-                        } else {
-                            atom!("false")
-                        }),
-                    atom!("type") => {
-                        atom_as_cell!(stream.options().stream_type().as_property_atom())
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                };
+        let listing_var = self.machine_st.registers[4];
 
-                unify!(self.machine_st, property, self.machine_st.registers[3]);
-            }
-            &SystemClauseType::StoreGlobalVar => {
-                let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+        unify!(self.machine_st, listing, listing_var);
+        Ok(())
+    }
 
-                let value = self.machine_st.registers[2];
-                let mut ball = Ball::new();
+    #[inline(always)]
+    pub(crate) fn write_term(&mut self) -> CallResult {
+        let mut stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("write_term"),
+            3,
+        )?;
+
+        self.machine_st.check_stream_properties(
+            stream,
+            StreamType::Text,
+            None, // input
+            atom!("write_term"),
+            3,
+        )?;
+
+        let opt_err = if !stream.is_output_stream() {
+            Some(atom!("stream")) // 8.14.2.3 g)
+        } else if stream.options().stream_type() == StreamType::Binary {
+            Some(atom!("binary_stream")) // 8.14.2.3 h)
+        } else {
+            None
+        };
 
-                ball.boundary = self.machine_st.heap.len();
+        if let Some(err_atom) = opt_err {
+            return Err(self.machine_st.stream_permission_error(
+                Permission::OutputStream,
+                err_atom,
+                stream,
+                atom!("write_term"),
+                3,
+            ));
+        }
 
-                copy_term(
-                    CopyBallTerm::new(&mut self.machine_st.stack, &mut self.machine_st.heap, &mut ball.stub),
-                    value,
-                    AttrVarPolicy::DeepCopy,
-                );
+        let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
+            Some(printer) => printer,
+            None => {
+                // this next line is executed by
+                // MachineState::write_term in this case. it's
+                // commented here because rustc can't prove
+                // that it's no longer borrowed.
 
-                self.indices.global_variables.insert(key, (ball, None));
+                // self.machine_st.fail = true;
+                return Ok(());
             }
-            &SystemClauseType::StoreBacktrackableGlobalVar => {
-                let key = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
-                let new_value = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        };
 
-                match self.indices.global_variables.get_mut(&key) {
-                    Some((_, ref mut loc)) => match loc {
-                        Some(ref mut value) => {
-                            self.machine_st.trail(TrailRef::BlackboardOffset(key, *value));
-                            *value = new_value;
-                        }
-                        loc @ None => {
-                            self.machine_st.trail(TrailRef::BlackboardEntry(key));
-                            *loc = Some(new_value);
-                        }
-                    },
-                    None => {
-                        self.machine_st.trail(TrailRef::BlackboardEntry(key));
-                        self.indices
-                            .global_variables
-                            .insert(key, (Ball::new(), Some(new_value)));
-                    }
-                }
-            }
-            &SystemClauseType::TermAttributedVariables => {
-                if self.machine_st.registers[1].is_constant() {
-                    self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2])));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+        let output = printer.print();
 
-                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())
+        match write!(&mut stream, "{}", output.result()) {
+            Ok(_) => {}
+            Err(_) => {
+                let stub = functor_stub(atom!("open"), 4);
+                let err = self.machine_st.existence_error(
+                    ExistenceError::Stream(self.machine_st.registers[1]),
                 );
 
-                unify_fn!(self.machine_st, self.machine_st.registers[2], outcome);
+                return Err(self.machine_st.error_form(err, stub));
             }
-            &SystemClauseType::Succeed => {}
-            &SystemClauseType::TermVariables => {
-                let a1 = self.machine_st.registers[1];
-                let a2 = self.machine_st.registers[2];
+        }
 
-                let stored_v = self.machine_st.store(self.machine_st.deref(a1));
+        stream.flush().unwrap();
+        Ok(())
+    }
 
-                if stored_v.is_constant() {
-                    self.machine_st.unify_atom(atom!("[]"), self.machine_st.store(self.machine_st.deref(a2)));
-                    return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                }
+    #[inline(always)]
+    pub(crate) fn write_term_to_chars(&mut self) -> CallResult {
+        let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
+            None => {
+                // this next line is executed by
+                // MachineState::write_term in this case. it's
+                // commented here because rustc can't prove
+                // that it's no longer borrowed.
 
-                let mut seen_set = IndexSet::new();
+                // self.machine_st.fail = true;
+                return Ok(());
+            }
+            Some(printer) => printer,
+        };
 
-                {
-                    let mut iter = stackless_preorder_iter(&mut self.machine_st.heap, stored_v);
+        let result = printer.print().result();
+        let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl);
 
-                    while let Some(addr) = iter.next() {
-                        let addr = unmark_cell_bits!(addr);
+        let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
 
-                        if addr.is_var() {
-                            seen_set.insert(addr);
-                        }
-                    }
-                }
+        if let Some(var) = result_addr.as_var() {
+            self.machine_st.bind(var, chars);
+        } else {
+            unreachable!()
+        }
 
-                let outcome = heap_loc_as_cell!(
-                    filtered_iter_to_heap_list(
-                        &mut self.machine_st.heap,
-                        seen_set.into_iter().rev(),
-                        |heap, value| {
-                            heap_bound_store(
-                                heap,
-                                heap_bound_deref(heap, value),
-                            ).is_var()
-                        },
-                    )
-                );
+        Ok(())
+    }
 
-                unify_fn!(self.machine_st, a2, outcome);
-            }
-            &SystemClauseType::TermVariablesUnderMaxDepth => {
-                // Term, MaxDepth, VarList
-                let max_depth = cell_as_fixnum!(
-                    self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]))
-                ).get_num() as usize;
+    #[inline(always)]
+    pub(crate) fn scryer_prolog_version(&mut self) {
+        use git_version::git_version;
 
-                self.machine_st.term_variables_under_max_depth(
-                    self.machine_st.registers[1],
-                    max_depth,
-                    self.machine_st.registers[3],
-                );
-            }
-            &SystemClauseType::TruncateLiftedHeapTo => {
-                let a1 = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let lh_offset = cell_as_fixnum!(a1).get_num() as usize;
+        let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
+        let buffer_atom = self.machine_st.atom_tbl.build_with(buffer);
 
-                self.machine_st.lifted_heap.truncate(lh_offset);
-            }
-            &SystemClauseType::UnifyWithOccursCheck => {
-                let a1 = self.machine_st.registers[1];
-                let a2 = self.machine_st.registers[2];
+        self.machine_st.unify_complete_string(
+            buffer_atom,
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])),
+        );
+    }
 
-                unify_with_occurs_check!(&mut self.machine_st, a1, a2);
+    #[inline(always)]
+    pub(crate) fn crypto_random_byte(&mut self) {
+        let arg = self.machine_st.registers[1];
+        let mut bytes: [u8; 1] = [0];
+
+        match rng().fill(&mut bytes) {
+            Ok(()) => {}
+            Err(_) => {
+                // the error payload here is of type 'Unspecified',
+                // which contains no information whatsoever. So, for now,
+                // just fail.
+                self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::UnwindEnvironments => {
-                let mut e = self.machine_st.e;
-                let mut cp = self.machine_st.cp;
+        }
 
-                while e > 0 {
-                    if self.is_reset_cont_marker(cp) {
-                        self.machine_st.e = e;
-                        self.machine_st.p = CodePtr::Local(cp + 1); // skip the reset marker.
+        let byte = Fixnum::build_with(bytes[0] as i64);
+        self.machine_st.unify_fixnum(byte, arg);
+    }
 
-                        return Ok(());
-                    }
+    #[inline(always)]
+    pub(crate) fn crypto_data_hash(&mut self) {
+        let encoding = cell_as_atom!(self.machine_st.registers[2]);
+        let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
 
-                    let and_frame = self.machine_st.stack.index_and_frame(e);
+        let algorithm = cell_as_atom!(self.machine_st.registers[4]);
 
-                    cp = and_frame.prelude.cp;
-                    e = and_frame.prelude.e;
-                }
+        let ints_list = match algorithm {
+            atom!("sha3_224") => {
+                let mut context = Sha3_224::new();
+                context.input(&bytes);
+
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
             }
-            &SystemClauseType::UnwindStack => {
-                self.machine_st.unwind_stack();
+            atom!("sha3_256") => {
+                let mut context = Sha3_256::new();
+                context.input(&bytes);
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
             }
-            &SystemClauseType::WAMInstructions => {
-                let module_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
-                    self.machine_st.registers[1])
-                ));
-
-                let name = self.machine_st.registers[2];
-                let arity = self.machine_st.registers[3];
-
-                let name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(name)));
-                let arity = self.machine_st.store(self.machine_st.deref(arity));
-
-                let arity = match Number::try_from(arity) {
-                    Ok(Number::Fixnum(n)) => n.get_num() as usize,
-                    Ok(Number::Integer(n)) => n.to_usize().unwrap(),
-                    _ => {
-                        unreachable!()
-                    }
-                };
-
-                let key = (name, arity);
-
-                let first_idx = match module_name {
-                    atom!("user") => self.indices.code_dir.get(&key),
-                    _ => match self.indices.modules.get(&module_name) {
-                        Some(module) => module.code_dir.get(&key),
-                        None => {
-                            let stub = functor_stub(key.0, key.1);
-                            let err = self.machine_st.session_error(
-                                SessionError::from(CompilationError::InvalidModuleResolution(
-                                    module_name,
-                                )),
-                            );
+            atom!("sha3_384") => {
+                let mut context = Sha3_384::new();
+                context.input(&bytes);
 
-                            return Err(self.machine_st.error_form(err, stub));
-                        }
-                    },
-                };
-
-                let first_idx = match first_idx {
-                    Some(ref idx) if idx.local().is_some() => {
-                        if let Some(idx) = idx.local() {
-                            idx
-                        } else {
-                            unreachable!()
-                        }
-                    }
-                    _ => {
-                        let stub = functor_stub(name, arity);
-                        let err = self.machine_st.existence_error(
-                            ExistenceError::Procedure(name, arity),
-                        );
-
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
-                };
-
-                let mut h = self.machine_st.heap.len();
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
+            }
+            atom!("sha3_512") => {
+                let mut context = Sha3_512::new();
+                context.input(&bytes);
 
-                let mut functors = vec![];
-                let mut functor_list = vec![];
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
+            }
+            atom!("blake2s256") => {
+                let mut context = Blake2s::new();
+                context.input(&bytes);
 
-                walk_code(&self.code_repo.code, first_idx, |instr| {
-                    let old_len = functors.len();
-                    instr.enqueue_functors(h, &mut self.machine_st.arena, &mut functors);
-                    let new_len = functors.len();
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
+            }
+            atom!("blake2b512") => {
+                let mut context = Blake2b::new();
+                context.input(&bytes);
 
-                    for index in old_len..new_len {
-                        let functor_len = functors[index].len();
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
+            }
+            atom!("ripemd160") => {
+                let mut context = Ripemd160::new();
+                context.input(&bytes);
 
-                        match functor_len {
-                            0 => {}
-                            1 => {
-                                functor_list.push(heap_loc_as_cell!(h));
-                                h += functor_len;
-                            }
-                            _ => {
-                                functor_list.push(str_loc_as_cell!(h));
-                                h += functor_len;
-                            }
+                heap_loc_as_cell!(
+                    iter_to_heap_list(
+                        &mut self.machine_st.heap,
+                        context
+                            .result()
+                            .as_ref()
+                            .iter()
+                            .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
+                    )
+                )
+            }
+            _ => {
+                let ints = digest::digest(
+                    match algorithm {
+                        atom!("sha256") => &digest::SHA256,
+                        atom!("sha384") => &digest::SHA384,
+                        atom!("sha512") => &digest::SHA512,
+                        atom!("sha512_256") => &digest::SHA512_256,
+                        _ => {
+                            unreachable!()
                         }
-                    }
-                });
-
-                for functor in functors {
-                    self.machine_st.heap.extend(functor.into_iter());
-                }
-
-                let listing = heap_loc_as_cell!(
-                    iter_to_heap_list(&mut self.machine_st.heap, functor_list.into_iter())
+                    },
+                    &bytes,
                 );
 
-                let listing_var = self.machine_st.registers[4];
-
-                unify!(self.machine_st, listing, listing_var);
+                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))),
+                    )
+                )
             }
-            &SystemClauseType::WriteTerm => {
-                let mut stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("write_term"),
-                    3,
-                )?;
-
-                self.machine_st.check_stream_properties(
-                    stream,
-                    StreamType::Text,
-                    None, // input
-                    atom!("write_term"),
-                    3,
-                )?;
+        };
 
-                let opt_err = if !stream.is_output_stream() {
-                    Some(atom!("stream")) // 8.14.2.3 g)
-                } else if stream.options().stream_type() == StreamType::Binary {
-                    Some(atom!("binary_stream")) // 8.14.2.3 h)
-                } else {
-                    None
-                };
+        unify!(self.machine_st, self.machine_st.registers[3], ints_list);
+    }
 
-                if let Some(err_atom) = opt_err {
-                    return Err(self.machine_st.stream_permission_error(
-                        Permission::OutputStream,
-                        err_atom,
-                        stream,
-                        atom!("write_term"),
-                        3,
-                    ));
-                }
+    #[inline(always)]
+    pub(crate) fn crypto_data_hkdf(&mut self) {
+        let encoding = cell_as_atom!(self.machine_st.registers[2]);
+        let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
 
-                let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
-                    Some(printer) => printer,
-                    None => {
-                        // this next line is executed by
-                        // MachineState::write_term in this case. it's
-                        // commented here because rustc can't prove
-                        // that it's no longer borrowed.
+        let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
+        let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
 
-                        // self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                };
+        let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
+        let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
 
-                let output = printer.print();
+        let algorithm = cell_as_atom!(self.machine_st.registers[5]);
 
-                match write!(&mut stream, "{}", output.result()) {
-                    Ok(_) => {}
-                    Err(_) => {
-                        let stub = functor_stub(atom!("open"), 4);
-                        let err = self.machine_st.existence_error(
-                            ExistenceError::Stream(self.machine_st.registers[1]),
-                        );
+        let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6]));
 
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
+        let length = match Number::try_from(length) {
+            Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
+            Ok(Number::Integer(n)) => match n.to_usize() {
+                Some(u) => u,
+                _ => {
+                    self.machine_st.fail = true;
+                    return;
                 }
-
-                stream.flush().unwrap();
+            },
+            _ => {
+                unreachable!()
             }
-            &SystemClauseType::WriteTermToChars => {
-                let printer = match self.machine_st.write_term(&self.indices.op_dir)? {
-                    None => {
-                        // this next line is executed by
-                        // MachineState::write_term in this case. it's
-                        // commented here because rustc can't prove
-                        // that it's no longer borrowed.
-
-                        // self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                    Some(printer) => printer,
-                };
-
-                let result = printer.print().result();
-                let chars = put_complete_string(&mut self.machine_st.heap, &result, &mut self.machine_st.atom_tbl);
-
-                let result_addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        };
 
-                if let Some(var) = result_addr.as_var() {
-                    self.machine_st.bind(var, chars);
-                } else {
-                    unreachable!()
+        let ints_list = {
+            let digest_alg = match algorithm {
+                atom!("sha256") => hkdf::HKDF_SHA256,
+                atom!("sha384") => hkdf::HKDF_SHA384,
+                atom!("sha512") => hkdf::HKDF_SHA512,
+                _ => {
+                    self.machine_st.fail = true;
+                    return;
                 }
-            }
-            &SystemClauseType::ScryerPrologVersion => {
-                use git_version::git_version;
+            };
 
-                let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
-                let buffer_atom = self.machine_st.atom_tbl.build_with(buffer);
+            let salt = hkdf::Salt::new(digest_alg, &salt);
+            let mut bytes: Vec<u8> = Vec::new();
 
-                self.machine_st.unify_complete_string(buffer_atom, self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
-            }
-            &SystemClauseType::CryptoRandomByte => {
-                let arg = self.machine_st.registers[1];
-                let mut bytes: [u8; 1] = [0];
+            bytes.resize(length, 0);
 
-                match rng().fill(&mut bytes) {
-                    Ok(()) => {}
-                    Err(_) => {
-                        // the error payload here is of type 'Unspecified',
-                        // which contains no information whatsoever. So, for now,
-                        // just fail.
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
+            match salt.extract(&data).expand(&[&info[..]], MyKey(length)) {
+                Ok(r) => {
+                    r.fill(&mut bytes).unwrap();
+                }
+                _ => {
+                    self.machine_st.fail = true;
+                    return;
                 }
-
-                let byte = Fixnum::build_with(bytes[0] as i64);
-                self.machine_st.unify_fixnum(byte, arg);
             }
-            &SystemClauseType::CryptoDataHash => {
-                let encoding = cell_as_atom!(self.machine_st.registers[2]);
-                let bytes = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
 
-                let algorithm = cell_as_atom!(self.machine_st.registers[4]);
-
-                let ints_list = match algorithm {
-                    atom!("sha3_224") => {
-                        let mut context = Sha3_224::new();
-                        context.input(&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))),
+                )
+            )
+        };
 
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    atom!("sha3_256") => {
-                        let mut context = Sha3_256::new();
-                        context.input(&bytes);
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    atom!("sha3_384") => {
-                        let mut context = Sha3_384::new();
-                        context.input(&bytes);
-
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    atom!("sha3_512") => {
-                        let mut context = Sha3_512::new();
-                        context.input(&bytes);
-
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    atom!("blake2s256") => {
-                        let mut context = Blake2s::new();
-                        context.input(&bytes);
-
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    atom!("blake2b512") => {
-                        let mut context = Blake2b::new();
-                        context.input(&bytes);
-
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    atom!("ripemd160") => {
-                        let mut context = Ripemd160::new();
-                        context.input(&bytes);
-
-                        heap_loc_as_cell!(
-                            iter_to_heap_list(
-                                &mut self.machine_st.heap,
-                                context
-                                    .result()
-                                    .as_ref()
-                                    .iter()
-                                    .map(|b| fixnum_as_cell!(Fixnum::build_with(*b as i64))),
-                            )
-                        )
-                    }
-                    _ => {
-                        let ints = digest::digest(
-                            match algorithm {
-                                atom!("sha256") => &digest::SHA256,
-                                atom!("sha384") => &digest::SHA384,
-                                atom!("sha512") => &digest::SHA512,
-                                atom!("sha512_256") => &digest::SHA512_256,
-                                _ => {
-                                    unreachable!()
-                                }
-                            },
-                            &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))),
-                            )
-                        )
-                    }
-                };
+        unify!(self.machine_st, self.machine_st.registers[7], ints_list);
+    }
 
-                unify!(self.machine_st, self.machine_st.registers[3], ints_list);
+    #[inline(always)]
+    pub(crate) fn crypto_password_hash(&mut self) {
+        let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3);
+        let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
+        let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3);
+        let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
+
+        let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
+
+        let iterations = match Number::try_from(iterations) {
+            Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(),
+            Ok(Number::Integer(n)) => match n.to_u64() {
+                Some(i) => i,
+                None => {
+                    self.machine_st.fail = true;
+                    return;
+                }
+            },
+            _ => {
+                unreachable!()
             }
-            &SystemClauseType::CryptoDataHKDF => {
-                let encoding = cell_as_atom!(self.machine_st.registers[2]);
-                let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
+        };
 
-                let stub1_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
-                let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
+        let ints_list = {
+            let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN];
 
-                let stub2_gen = || functor_stub(atom!("crypto_data_hkdf"), 4);
-                let info = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
+            pbkdf2::derive(
+                pbkdf2::PBKDF2_HMAC_SHA512,
+                NonZeroU32::new(iterations as u32).unwrap(),
+                &salt,
+                &data,
+                &mut bytes,
+            );
 
-                let algorithm = cell_as_atom!(self.machine_st.registers[5]);
+            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))),
+                )
+            )
+        };
 
-                let length = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[6]));
+        unify!(self.machine_st, self.machine_st.registers[4], ints_list);
+    }
 
-                let length = match Number::try_from(length) {
-                    Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).unwrap(),
-                    Ok(Number::Integer(n)) => match n.to_usize() {
-                        Some(u) => u,
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    },
-                    _ => {
-                        unreachable!()
-                    }
-                };
+    #[inline(always)]
+    pub(crate) fn crypto_data_encrypt(&mut self) {
+        let encoding = cell_as_atom!(self.machine_st.registers[3]);
 
-                let ints_list = {
-                    let digest_alg = match algorithm {
-                        atom!("sha256") => hkdf::HKDF_SHA256,
-                        atom!("sha384") => hkdf::HKDF_SHA384,
-                        atom!("sha512") => hkdf::HKDF_SHA512,
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    };
+        let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
+        let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
 
-                    let salt = hkdf::Salt::new(digest_alg, &salt);
-                    let mut bytes: Vec<u8> = Vec::new();
+        let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
+        let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
 
-                    bytes.resize(length, 0);
+        let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
+        let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen);
 
-                    match salt.extract(&data).expand(&[&info[..]], MyKey(length)) {
-                        Ok(r) => {
-                            r.fill(&mut bytes).unwrap();
-                        }
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
+        let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
+        let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
+        let key = aead::LessSafeKey::new(unbound_key);
 
-                    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))),
-                        )
-                    )
-                };
+        let mut in_out = data;
 
-                unify!(self.machine_st, self.machine_st.registers[7], ints_list);
+        let tag = match key.seal_in_place_separate_tag(
+            nonce,
+            aead::Aad::from(aad),
+            &mut in_out,
+        ) {
+            Ok(d) => d,
+            _ => {
+                self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::CryptoPasswordHash => {
-                let stub1_gen = || functor_stub(atom!("crypto_password_hash"), 3);
-                let data = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
-                let stub2_gen = || functor_stub(atom!("crypto_password_hash"), 3);
-                let salt = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
-
-                let iterations = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[3]));
-
-                let iterations = match Number::try_from(iterations) {
-                    Ok(Number::Fixnum(n)) => u64::try_from(n.get_num()).unwrap(),
-                    Ok(Number::Integer(n)) => match n.to_u64() {
-                        Some(i) => i,
-                        None => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    },
-                    _ => {
-                        unreachable!()
-                    }
-                };
-
-                let ints_list = {
-                    let mut bytes = [0u8; digest::SHA512_OUTPUT_LEN];
+        };
 
-                    pbkdf2::derive(
-                        pbkdf2::PBKDF2_HMAC_SHA512,
-                        NonZeroU32::new(iterations as u32).unwrap(),
-                        &salt,
-                        &data,
-                        &mut bytes,
-                    );
+        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))),
+            )
+        );
 
-                    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))),
-                        )
-                    )
-                };
+        let complete_string = {
+            let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
+            put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl)
+        };
 
-                unify!(self.machine_st, self.machine_st.registers[4], ints_list);
-            }
-            &SystemClauseType::CryptoDataEncrypt => {
-                let encoding = cell_as_atom!(self.machine_st.registers[3]);
+        unify!(self.machine_st, self.machine_st.registers[6], tag_list);
+        unify!(self.machine_st, self.machine_st.registers[7], complete_string);
+    }
 
-                let data = self.string_encoding_bytes(self.machine_st.registers[1], encoding);
-                let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+    #[inline(always)]
+    pub(crate) fn crypto_data_decrypt(&mut self) {
+        let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+        let encoding = cell_as_atom!(self.machine_st.registers[5]);
 
-                let stub2_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
-                let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
+        let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+        let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
 
-                let stub3_gen = || functor_stub(atom!("crypto_data_encrypt"), 7);
-                let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[5], stub3_gen);
+        let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
+        let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
+        let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
 
-                let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
-                let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
-                let key = aead::LessSafeKey::new(unbound_key);
+        let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
+        let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
+        let key = aead::LessSafeKey::new(unbound_key);
 
-                let mut in_out = data;
+        let mut in_out = data;
 
-                let tag = match key.seal_in_place_separate_tag(
-                    nonce,
-                    aead::Aad::from(aad),
-                    &mut in_out,
-                ) {
+        let complete_string = {
+            let decrypted_data =
+                match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) {
                     Ok(d) => d,
                     _ => {
                         self.machine_st.fail = true;
-                        return Ok(());
+                        return;
                     }
                 };
 
-                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 complete_string = {
-                    let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
-                    put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl)
-                };
-
-                unify!(self.machine_st, self.machine_st.registers[6], tag_list);
-                unify!(self.machine_st, self.machine_st.registers[7], complete_string);
-            }
-            &SystemClauseType::CryptoDataDecrypt => {
-                let data = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
-                let encoding = cell_as_atom!(self.machine_st.registers[5]);
-
-                let aad = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
-                let stub1_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
-
-                let key = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub1_gen);
-                let stub2_gen = || functor_stub(atom!("crypto_data_decrypt"), 7);
-                let iv = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub2_gen);
+            let buffer = match encoding {
+                atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)),
+                atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) {
+                    Ok(str) => str,
+                    _ => {
+                        self.machine_st.fail = true;
+                        return;
+                    }
+                },
+                _ => {
+                    unreachable!()
+                }
+            };
 
-                let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
-                let nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
-                let key = aead::LessSafeKey::new(unbound_key);
+            put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl)
+        };
 
-                let mut in_out = data;
+        unify!(self.machine_st, self.machine_st.registers[6], complete_string);
+    }
 
-                let complete_string = {
-                    let decrypted_data =
-                        match key.open_in_place(nonce, aead::Aad::from(aad), &mut in_out) {
-                            Ok(d) => d,
-                            _ => {
-                                self.machine_st.fail = true;
-                                return Ok(());
-                            }
-                        };
+    #[inline(always)]
+    pub(crate) fn crypto_curve_scalar_mult(&mut self) {
+        let curve = cell_as_atom!(self.machine_st.registers[1]);
 
-                    let buffer = match encoding {
-                        atom!("octet") => String::from_iter(decrypted_data.iter().map(|b| *b as char)),
-                        atom!("utf8") => match String::from_utf8(decrypted_data.to_vec()) {
-                            Ok(str) => str,
-                            _ => {
-                                self.machine_st.fail = true;
-                                return Ok(());
-                            }
-                        },
-                        _ => {
-                            unreachable!()
-                        }
-                    };
+        let curve_id = match curve {
+            atom!("secp112r1") => Nid::SECP112R1,
+            atom!("secp256k1") => Nid::SECP256K1,
+            _ => {
+                unreachable!()
+            }
+        };
 
-                    put_complete_string(&mut self.machine_st.heap, &buffer, &mut self.machine_st.atom_tbl)
-                };
+        let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
 
-                unify!(self.machine_st, self.machine_st.registers[6], complete_string);
+        let scalar = match Number::try_from(scalar) {
+            Ok(Number::Fixnum(n)) => Integer::from(n.get_num()),
+            Ok(Number::Integer(n)) => Integer::from(&*n),
+            _ => {
+                unreachable!()
             }
-            &SystemClauseType::CryptoCurveScalarMult => {
-                let curve = cell_as_atom!(self.machine_st.registers[1]);
+        };
 
-                let curve_id = match curve {
-                    atom!("secp112r1") => Nid::SECP112R1,
-                    atom!("secp256k1") => Nid::SECP256K1,
-                    _ => {
-                        unreachable!()
-                    }
-                };
+        let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5);
+        let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
 
-                let scalar = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[2]));
+        let mut bnctx = BigNumContext::new().unwrap();
+        let group = EcGroup::from_curve_name(curve_id).unwrap();
+        let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap();
+        let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap();
+        let mut result = EcPoint::new(&group).unwrap();
 
-                let scalar = match Number::try_from(scalar) {
-                    Ok(Number::Fixnum(n)) => Integer::from(n.get_num()),
-                    Ok(Number::Integer(n)) => Integer::from(&*n),
-                    _ => {
-                        unreachable!()
-                    }
-                };
+        result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok();
 
-                let stub_gen = || functor_stub(atom!("crypto_curve_scalar_mult"), 5);
-                let qbytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[3], stub_gen);
+        let mut rx = BigNum::new().unwrap();
+        let mut ry = BigNum::new().unwrap();
 
-                let mut bnctx = BigNumContext::new().unwrap();
-                let group = EcGroup::from_curve_name(curve_id).unwrap();
-                let mut point = EcPoint::from_bytes(&group, &qbytes, &mut bnctx).unwrap();
-                let scalar_bn = BigNum::from_dec_str(&scalar.to_string()).unwrap();
-                let mut result = EcPoint::new(&group).unwrap();
+        result
+            .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx)
+            .ok();
 
-                result.mul(&group, &mut point, &scalar_bn, &mut bnctx).ok();
+        let sx = put_complete_string(
+            &mut self.machine_st.heap,
+            &rx.to_dec_str().unwrap(),
+            &mut self.machine_st.atom_tbl,
+        );
 
-                let mut rx = BigNum::new().unwrap();
-                let mut ry = BigNum::new().unwrap();
+        let sy = put_complete_string(
+            &mut self.machine_st.heap,
+            &ry.to_dec_str().unwrap(),
+            &mut self.machine_st.atom_tbl,
+        );
 
-                result
-                    .affine_coordinates_gfp(&group, &mut rx, &mut ry, &mut bnctx)
-                    .ok();
+        unify!(self.machine_st, self.machine_st.registers[4], sx);
+        unify!(self.machine_st, self.machine_st.registers[5], sy);
+    }
 
-                let sx = put_complete_string(
-                    &mut self.machine_st.heap,
-                    &rx.to_dec_str().unwrap(),
-                    &mut self.machine_st.atom_tbl,
-                );
+    #[inline(always)]
+    pub(crate) fn ed25519_new_key_pair(&mut self) {
+        let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
+        let complete_string = {
+            let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char));
+            put_complete_string(
+                &mut self.machine_st.heap,
+                &buffer,
+                &mut self.machine_st.atom_tbl,
+            )
+        };
 
-                let sy = put_complete_string(
-                    &mut self.machine_st.heap,
-                    &ry.to_dec_str().unwrap(),
-                    &mut self.machine_st.atom_tbl,
-                );
+        unify!(self.machine_st, self.machine_st.registers[1], complete_string)
+    }
 
-                unify!(self.machine_st, self.machine_st.registers[4], sx);
-                unify!(self.machine_st, self.machine_st.registers[5], sy);
-            }
-            &SystemClauseType::Ed25519NewKeyPair => {
-                let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
-                let complete_string = {
-                    let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char));
-                    put_complete_string(
-                        &mut self.machine_st.heap,
-                        &buffer,
-                        &mut self.machine_st.atom_tbl,
-                    )
-                };
+    #[inline(always)]
+    pub(crate) fn ed25519_key_pair_public_key(&mut self) {
+        let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
 
-                unify!(self.machine_st, self.machine_st.registers[1], complete_string)
+        let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
+            Ok(kp) => kp,
+            _ => {
+                self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::Ed25519KeyPairPublicKey => {
-                let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+        };
 
-                let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
-                    Ok(kp) => kp,
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                };
+        let complete_string = {
+            let buffer = String::from_iter(
+                key_pair.public_key().as_ref().iter().map(|b| *b as char),
+            );
+
+            put_complete_string(
+                &mut self.machine_st.heap,
+                &buffer,
+                &mut self.machine_st.atom_tbl,
+            )
+        };
 
-                let complete_string = {
-                    let buffer = String::from_iter(
-                        key_pair.public_key().as_ref().iter().map(|b| *b as char),
-                    );
+        unify!(self.machine_st, self.machine_st.registers[2], complete_string);
+    }
 
-                    put_complete_string(
-                        &mut self.machine_st.heap,
-                        &buffer,
-                        &mut self.machine_st.atom_tbl,
-                    )
-                };
+    #[inline(always)]
+    pub(crate) fn ed25519_sign(&mut self) {
+        let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+        let encoding = cell_as_atom!(self.machine_st.registers[3]);
+        let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
 
-                unify!(self.machine_st, self.machine_st.registers[2], complete_string);
+        let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
+            Ok(kp) => kp,
+            _ => {
+                self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::Ed25519Sign => {
-                let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
-                let encoding = cell_as_atom!(self.machine_st.registers[3]);
-                let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+        };
 
-                let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
-                    Ok(kp) => kp,
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                };
+        let sig = key_pair.sign(&data);
 
-                let sig = key_pair.sign(&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 = 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))),
-                    )
-                );
+        unify!(self.machine_st, self.machine_st.registers[4], sig_list);
+    }
 
-                unify!(self.machine_st, self.machine_st.registers[4], sig_list);
-            }
-            &SystemClauseType::Ed25519Verify => {
-                let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
-                let encoding = cell_as_atom!(self.machine_st.registers[3]);
-                let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
-                let stub_gen = || functor_stub(atom!("ed25519_verify"), 5);
-                let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
+    #[inline(always)]
+    pub(crate) fn ed25519_verify(&mut self) {
+        let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+        let encoding = cell_as_atom!(self.machine_st.registers[3]);
+        let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
+        let stub_gen = || functor_stub(atom!("ed25519_verify"), 5);
+        let signature = self.machine_st.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
 
-                let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
+        let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
 
-                match peer_public_key.verify(&data, &signature) {
-                    Ok(_) => {}
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                }
+        match peer_public_key.verify(&data, &signature) {
+            Ok(_) => {}
+            _ => {
+                self.machine_st.fail = true;
             }
-            &SystemClauseType::Curve25519ScalarMult => {
-                let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
-                let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
-                let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
+        }
+    }
 
-                let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
-                let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
-                let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
+    #[inline(always)]
+    pub(crate) fn curve25519_scalar_mult(&mut self) {
+        let stub1_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
+        let scalar_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[1], stub1_gen);
+        let scalar = Scalar(<[u8; 32]>::try_from(&scalar_bytes[..]).unwrap());
 
-                let result = scalarmult(&scalar, &point).unwrap();
+        let stub2_gen = || functor_stub(atom!("curve25519_scalar_mult"), 3);
+        let point_bytes = self.machine_st.integers_to_bytevec(self.machine_st.registers[2], stub2_gen);
+        let point = GroupElement(<[u8; 32]>::try_from(&point_bytes[..]).unwrap());
 
-                let string = String::from_iter(result[..].iter().map(|b| *b as char));
-                let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl);
+        let result = scalarmult(&scalar, &point).unwrap();
 
-                unify!(self.machine_st, self.machine_st.registers[3], cstr);
-            }
-            &SystemClauseType::FirstNonOctet => {
-                let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let string = String::from_iter(result[..].iter().map(|b| *b as char));
+        let cstr = put_complete_string(&mut self.machine_st.heap, &string, &mut self.machine_st.atom_tbl);
 
-                if let Some(string) = self.machine_st.value_to_str_like(addr) {
-                    for c in string.as_str().chars() {
-                        if c as u32 > 255 {
-                            let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string());
-                            self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]);
-                            return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                        }
-                    }
-                }
+        unify!(self.machine_st, self.machine_st.registers[3], cstr);
+    }
 
-                self.machine_st.fail = true;
-                return Ok(());
+    #[inline(always)]
+    pub(crate) fn first_non_octet(&mut self) {
+        let addr = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+
+        if let Some(string) = self.machine_st.value_to_str_like(addr) {
+            for c in string.as_str().chars() {
+                if c as u32 > 255 {
+                    let non_octet = self.machine_st.atom_tbl.build_with(&c.to_string());
+                    self.machine_st.unify_atom(non_octet, self.machine_st.registers[2]);
+                    return;
+                }
             }
-            &SystemClauseType::LoadHTML => {
-                if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap();
-                    let result = self.html_node_to_term(doc.nth(0).unwrap());
+        }
+
+        self.machine_st.fail = true;
+    }
+
+    #[inline(always)]
+    pub(crate) fn load_html(&mut self) {
+        if let Some(string) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            let doc = select::document::Document::from_read(string.as_str().as_bytes()).unwrap();
+            let result = self.html_node_to_term(doc.nth(0).unwrap());
+
+            unify!(self.machine_st, self.machine_st.registers[2], result);
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
 
+    #[inline(always)]
+    pub(crate) fn load_xml(&mut self) {
+        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());
                     unify!(self.machine_st, self.machine_st.registers[2], result);
-                } else {
-                    self.machine_st.fail = true;
-                    return Ok(());
                 }
-            }
-            &SystemClauseType::LoadXML => {
-                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());
-                            unify!(self.machine_st, self.machine_st.registers[2], result);
-                        }
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                } else {
+                _ => {
                     self.machine_st.fail = true;
-                    return Ok(());
                 }
             }
-            &SystemClauseType::GetEnv => {
-                if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
-                    match env::var(key.as_str()) {
-                        Ok(value) => {
-                            let cstr = put_complete_string(
-                                &mut self.machine_st.heap,
-                                &value,
-                                &mut self.machine_st.atom_tbl,
-                            );
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
 
-                            unify!(self.machine_st, self.machine_st.registers[2], cstr);
-                        }
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                } else {
+    #[inline(always)]
+    pub(crate) fn get_env(&mut self) {
+        if let Some(key) = self.machine_st.value_to_str_like(self.machine_st.registers[1]) {
+            match env::var(key.as_str()) {
+                Ok(value) => {
+                    let cstr = put_complete_string(
+                        &mut self.machine_st.heap,
+                        &value,
+                        &mut self.machine_st.atom_tbl,
+                    );
+
+                    unify!(self.machine_st, self.machine_st.registers[2], cstr);
+                }
+                _ => {
                     self.machine_st.fail = true;
-                    return Ok(());
                 }
             }
-            &SystemClauseType::SetEnv => {
-                let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
-                let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
+        } else {
+            self.machine_st.fail = true;
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn set_env(&mut self) {
+        let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
+        let value = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
 
-                env::set_var(key.as_str(), value.as_str());
+        env::set_var(key.as_str(), value.as_str());
+    }
+
+    #[inline(always)]
+    pub(crate) fn unset_env(&mut self) {
+        let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
+        env::remove_var(key.as_str());
+    }
+
+    #[inline(always)]
+    pub(crate) fn pid(&mut self) {
+        let pid = process::id();
+
+        match fixnum!(Number, pid as i64, &mut self.machine_st.arena) {
+            Number::Fixnum(pid) => {
+                self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]);
             }
-            &SystemClauseType::UnsetEnv => {
-                let key = self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap();
-                env::remove_var(key.as_str());
+            Number::Integer(pid) => {
+                self.machine_st.unify_big_int(pid, self.machine_st.registers[1]);
             }
-            &SystemClauseType::PID => {
-                let pid = process::id();
-
-                match fixnum!(Number, pid as i64, &mut self.machine_st.arena) {
-                    Number::Fixnum(pid) => {
-                        self.machine_st.unify_fixnum(pid, self.machine_st.registers[1]);
-                    }
-                    Number::Integer(pid) => {
-                        self.machine_st.unify_big_int(pid, self.machine_st.registers[1]);
-                    }
-                    _ => {
-                        unreachable!();
-                    }
-                }
+            _ => {
+                unreachable!();
             }
-            &SystemClauseType::Shell => {
-                // shell executes a command in a system shell
-                // the code looks for a SHELL env var to do it in a UNIX-style
-                // if not found, the code looks for COMSPEC env var to do it in a DOS-style
-                // the output is printed directly to stdout
-                // the output status code is returned after finishing
-                fn command_result(machine: &mut MachineState, command: std::io::Result<process::ExitStatus>) {
-                    match command {
-                        Ok(status) => {
-                            match status.code() {
-                                Some(code) => {
-                                    let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena));
-                                    unify!(machine, code, machine.registers[2]);
-                                }
-                                _ => {
-                                    machine.fail = true;
-                                }
-                            }
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn shell(&mut self) {
+        // shell executes a command in a system shell
+        // the code looks for a SHELL env var to do it in a UNIX-style
+        // if not found, the code looks for COMSPEC env var to do it in a DOS-style
+        // the output is printed directly to stdout
+        // the output status code is returned after finishing
+        fn command_result(machine: &mut MachineState, command: std::io::Result<process::ExitStatus>) {
+            match command {
+                Ok(status) => {
+                    match status.code() {
+                        Some(code) => {
+                            let code = integer_as_cell!(Number::arena_from(code, &mut machine.arena));
+                            unify!(machine, code, machine.registers[2]);
                         }
                         _ => {
                             machine.fail = true;
                         }
                     }
                 }
+                _ => {
+                    machine.fail = true;
+                }
+            }
+        }
 
-                let command = self.machine_st.value_to_str_like(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))).unwrap();
+        let command = self.machine_st.value_to_str_like(
+            self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]))
+        ).unwrap();
 
-                match env::var("SHELL") {
+        match env::var("SHELL") {
+            Ok(value) => {
+                let command = process::Command::new(&value)
+                    .arg("-c")
+                    .arg(command.as_str())
+                    .status();
+                command_result(&mut self.machine_st, command);
+            }
+            _ => {
+                match env::var("COMSPEC") {
                     Ok(value) => {
                         let command = process::Command::new(&value)
-                            .arg("-c")
+                            .arg("/C")
                             .arg(command.as_str())
                             .status();
                         command_result(&mut self.machine_st, command);
                     }
                     _ => {
-                        match env::var("COMSPEC") {
-                            Ok(value) => {
-                                let command = process::Command::new(&value)
-                                    .arg("/C")
-                                    .arg(command.as_str())
-                                    .status();
-                                command_result(&mut self.machine_st, command);
-                            }
-                            _ => {
-                                self.machine_st.fail = true;
-                            }
-                        }
+                        self.machine_st.fail = true;
                     }
-                };
+                }
             }
-            &SystemClauseType::CharsBase64 => {
-                let padding = cell_as_atom!(self.machine_st.registers[3]);
-                let charset = cell_as_atom!(self.machine_st.registers[4]);
-
-                let config = if padding == atom!("true") {
-                    if charset == atom!("standard") {
-                        base64::STANDARD
-                    } else {
-                        base64::URL_SAFE
-                    }
-                } else {
-                    if charset == atom!("standard") {
-                        base64::STANDARD_NO_PAD
-                    } else {
-                        base64::URL_SAFE_NO_PAD
-                    }
-                };
-
-                if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() {
-                    let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
-                    let bytes = base64::decode_config(b64.as_str(), config);
-
-                    match bytes {
-                        Ok(bs) => {
-                            let string = String::from_iter(bs.iter().map(|b| *b as char));
-                            let cstr = put_complete_string(
-                                &mut self.machine_st.heap,
-                                &string,
-                                &mut self.machine_st.atom_tbl,
-                            );
+        };
+    }
 
-                            unify!(self.machine_st, self.machine_st.registers[1], cstr);
-                        }
-                        _ => {
-                            self.machine_st.fail = true;
-                            return Ok(());
-                        }
-                    }
-                } else {
-                    let mut bytes = vec![];
-                    for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() {
-                        if c as u32 > 255 {
-                            let stub = functor_stub(atom!("chars_base64"), 3);
-
-                            let err = self.machine_st.type_error(
-                                ValidType::Byte,
-                                char_as_cell!(c),
-                            );
+    #[inline(always)]
+    pub(crate) fn chars_base64(&mut self) -> CallResult {
+        let padding = cell_as_atom!(self.machine_st.registers[3]);
+        let charset = cell_as_atom!(self.machine_st.registers[4]);
 
-                            return Err(self.machine_st.error_form(err, stub));
-                        }
+        let config = if padding == atom!("true") {
+            if charset == atom!("standard") {
+                base64::STANDARD
+            } else {
+                base64::URL_SAFE
+            }
+        } else {
+            if charset == atom!("standard") {
+                base64::STANDARD_NO_PAD
+            } else {
+                base64::URL_SAFE_NO_PAD
+            }
+        };
 
-                        bytes.push(c as u8);
-                    }
+        if self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])).is_var() {
+            let b64 = self.machine_st.value_to_str_like(self.machine_st.registers[2]).unwrap();
+            let bytes = base64::decode_config(b64.as_str(), config);
 
-                    let b64 = base64::encode_config(bytes, config);
+            match bytes {
+                Ok(bs) => {
+                    let string = String::from_iter(bs.iter().map(|b| *b as char));
                     let cstr = put_complete_string(
                         &mut self.machine_st.heap,
-                        &b64,
+                        &string,
                         &mut self.machine_st.atom_tbl,
                     );
 
-                    unify!(self.machine_st, self.machine_st.registers[2], cstr);
+                    unify!(self.machine_st, self.machine_st.registers[1], cstr);
+                }
+                _ => {
+                    self.machine_st.fail = true;
+                    return Ok(());
                 }
             }
-            &SystemClauseType::LoadLibraryAsStream => {
-                let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1])));
+        } else {
+            let mut bytes = vec![];
+            for c in self.machine_st.value_to_str_like(self.machine_st.registers[1]).unwrap().as_str().chars() {
+                if c as u32 > 255 {
+                    let stub = functor_stub(atom!("chars_base64"), 3);
+
+                    let err = self.machine_st.type_error(
+                        ValidType::Byte,
+                        char_as_cell!(c),
+                    );
 
-                use crate::machine::LIBRARIES;
+                    return Err(self.machine_st.error_form(err, stub));
+                }
 
-                match LIBRARIES.borrow().get(library_name.as_str()) {
-                    Some(library) => {
-                        let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena);
-                        unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]);
+                bytes.push(c as u8);
+            }
 
-                        let mut path_buf = machine::current_dir();
+            let b64 = base64::encode_config(bytes, config);
+            let cstr = put_complete_string(
+                &mut self.machine_st.heap,
+                &b64,
+                &mut self.machine_st.atom_tbl,
+            );
 
-                        path_buf.push("/lib");
-                        path_buf.push(library_name.as_str());
+            unify!(self.machine_st, self.machine_st.registers[2], cstr);
+        }
 
-                        let library_path_str = path_buf.to_str().unwrap();
-                        let library_path = self.machine_st.atom_tbl.build_with(library_path_str);
+        Ok(())
+    }
 
-                        self.machine_st.unify_atom(library_path, self.machine_st.registers[3]);
-                    }
-                    None => {
-                        let stub = functor_stub(atom!("load"), 1);
-                        let err = self.machine_st.existence_error(
-                            ExistenceError::ModuleSource(ModuleSource::Library(library_name))
-                        );
+    #[inline(always)]
+    pub(crate) fn load_library_as_stream(&mut self) -> CallResult {
+        let library_name = cell_as_atom!(self.machine_st.store(self.machine_st.deref(
+            self.machine_st.registers[1]
+        )));
 
-                        return Err(self.machine_st.error_form(err, stub));
-                    }
-                }
-            }
-            &SystemClauseType::DevourWhitespace => {
-                let stream = self.machine_st.get_stream_or_alias(
-                    self.machine_st.registers[1],
-                    &self.indices.stream_aliases,
-                    atom!("$devour_whitespace"),
-                    1,
-                )?;
+        use crate::machine::LIBRARIES;
 
-                match self.machine_st.devour_whitespace(stream) {
-                    Ok(false) => { // not at EOF.
-                    }
-                    _ => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                }
-            }
-            &SystemClauseType::IsSTOEnabled => {
-                if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
-                    self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]);
-                } else if self.machine_st.unify_fn as usize
-                    == MachineState::unify_with_occurs_check_with_error as usize
-                {
-                    self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]);
-                } else {
-                    self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]);
-                }
+        match LIBRARIES.borrow().get(library_name.as_str()) {
+            Some(library) => {
+                let lib_stream = Stream::from_static_string(library, &mut self.machine_st.arena);
+                unify!(self.machine_st, stream_as_cell!(lib_stream), self.machine_st.registers[2]);
+
+                let mut path_buf = machine::current_dir();
+
+                path_buf.push("/lib");
+                path_buf.push(library_name.as_str());
+
+                let library_path_str = path_buf.to_str().unwrap();
+                let library_path = self.machine_st.atom_tbl.build_with(library_path_str);
+
+                self.machine_st.unify_atom(library_path, self.machine_st.registers[3]);
             }
-            &SystemClauseType::SetSTOAsUnify => {
-                self.machine_st.unify_fn = MachineState::unify_with_occurs_check;
-                self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper;
+            None => {
+                let stub = functor_stub(atom!("load"), 1);
+                let err = self.machine_st.existence_error(
+                    ExistenceError::ModuleSource(ModuleSource::Library(library_name))
+                );
+
+                return Err(self.machine_st.error_form(err, stub));
             }
-            &SystemClauseType::SetNSTOAsUnify => {
-                self.machine_st.unify_fn = MachineState::unify;
-                self.machine_st.bind_fn = MachineState::bind;
+        }
+
+        Ok(())
+    }
+
+    #[inline(always)]
+    pub(crate) fn devour_whitespace(&mut self) -> CallResult {
+        let stream = self.machine_st.get_stream_or_alias(
+            self.machine_st.registers[1],
+            &self.indices.stream_aliases,
+            atom!("$devour_whitespace"),
+            1,
+        )?;
+
+        match self.machine_st.devour_whitespace(stream) {
+            Ok(false) => { // not at EOF.
             }
-            &SystemClauseType::SetSTOWithErrorAsUnify => {
-                self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error;
-                self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
+            _ => {
+                self.machine_st.fail = true;
             }
-            &SystemClauseType::HomeDirectory => {
-                let path = match dirs_next::home_dir() {
-                    Some(path) => path,
-                    None => {
-                        self.machine_st.fail = true;
-                        return Ok(());
-                    }
-                };
+        }
 
-                if path.is_dir() {
-                    if let Some(path) = path.to_str() {
-                        let path_string = put_complete_string(
-                            &mut self.machine_st.heap,
-                            path,
-                            &mut self.machine_st.atom_tbl,
-                        );
+        Ok(())
+    }
 
-                        unify!(self.machine_st, self.machine_st.registers[1], path_string);
-                        return return_from_clause!(self.machine_st.last_call, self.machine_st);
-                    }
-                }
+    #[inline(always)]
+    pub(crate) fn is_sto_enabled(&mut self) {
+        if self.machine_st.unify_fn as usize == MachineState::unify_with_occurs_check as usize {
+            self.machine_st.unify_atom(atom!("true"), self.machine_st.registers[1]);
+        } else if self.machine_st.unify_fn as usize
+            == MachineState::unify_with_occurs_check_with_error as usize
+        {
+            self.machine_st.unify_atom(atom!("error"), self.machine_st.registers[1]);
+        } else {
+            self.machine_st.unify_atom(atom!("false"), self.machine_st.registers[1]);
+        }
+    }
+
+    #[inline(always)]
+    pub(crate) fn set_sto_as_unify(&mut self) {
+        self.machine_st.unify_fn = MachineState::unify_with_occurs_check;
+        self.machine_st.bind_fn = MachineState::bind_with_occurs_check_wrapper;
+    }
+
+    #[inline(always)]
+    pub(crate) fn set_nsto_as_unify(&mut self) {
+        self.machine_st.unify_fn = MachineState::unify;
+        self.machine_st.bind_fn = MachineState::bind;
+    }
+
+    #[inline(always)]
+    pub(crate) fn set_sto_with_error_as_unify(&mut self) {
+        self.machine_st.unify_fn = MachineState::unify_with_occurs_check_with_error;
+        self.machine_st.bind_fn = MachineState::bind_with_occurs_check_with_error_wrapper;
+    }
 
+    #[inline(always)]
+    pub(crate) fn home_directory(&mut self) {
+        let path = match dirs_next::home_dir() {
+            Some(path) => path,
+            None => {
                 self.machine_st.fail = true;
+                return;
             }
-            &SystemClauseType::DebugHook => {
-                self.machine_st.fail = false;
+        };
+
+        if path.is_dir() {
+            if let Some(path) = path.to_str() {
+                let path_string = put_complete_string(
+                    &mut self.machine_st.heap,
+                    path,
+                    &mut self.machine_st.atom_tbl,
+                );
+
+                unify!(self.machine_st, self.machine_st.registers[1], path_string);
+                return;
             }
-            &SystemClauseType::PopCount => {
-                let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
-                let pop_count = integer_as_cell!(match Number::try_from(number) {
-                    Ok(Number::Fixnum(n)) => {
-                        Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64))
-                    }
-                    Ok(Number::Integer(n)) => {
-                        Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena)
-                    }
-                    _ => {
-                        unreachable!()
-                    }
-                });
+        }
+
+        self.machine_st.fail = true;
+    }
 
-                unify!(self.machine_st, self.machine_st.registers[2], pop_count);
+    pub(crate) fn debug_hook(&mut self) {
+    }
+
+    #[inline(always)]
+    pub(crate) fn pop_count(&mut self) {
+        let number = self.machine_st.store(self.machine_st.deref(self.machine_st.registers[1]));
+        let pop_count = integer_as_cell!(match Number::try_from(number) {
+            Ok(Number::Fixnum(n)) => {
+                Number::Fixnum(Fixnum::build_with(n.get_num().count_ones() as i64))
             }
-        };
+            Ok(Number::Integer(n)) => {
+                Number::arena_from(n.count_ones().unwrap(), &mut self.machine_st.arena)
+            }
+            _ => {
+                unreachable!()
+            }
+        });
 
-        return_from_clause!(self.machine_st.last_call, self.machine_st)
+        unify!(self.machine_st, self.machine_st.registers[2], pop_count);
     }
 
     pub(super) fn systemtime_to_timestamp(&mut self, system_time: SystemTime) -> Atom {
         let datetime: DateTime<Local> = system_time.into();
 
         let mut fstr = "[".to_string();
-        const SPECIFIERS: [&'static str; 19] = [
-            "Y", "m", "d", "H", "M", "S", "y", "b", "B", "a", "A", "w", "u", "U", "W", "j", "D",
-            "x", "v",
+        const SPECIFIERS: [char; 19] = [
+            'Y', 'm', 'd', 'H', 'M', 'S', 'y', 'b', 'B', 'a', 'A', 'w', 'u', 'U', 'W', 'j', 'D',
+            'x', 'v',
         ];
 
         for spec in SPECIFIERS {
index 90fed1109d055f3c053288285d0c4e1ab351c21a..0b83bbb7444a9a1d1606542aadf420fee84ef681 100644 (file)
@@ -1,9 +1,3 @@
-macro_rules! interm {
-    ($n: expr) => {
-        ArithmeticTerm::Interm($n)
-    };
-}
-
 /* A simple macro to count the arguments in a variadic list
  * of token trees.
  */
@@ -524,6 +518,35 @@ macro_rules! functor_term {
     );
 }
 
+macro_rules! compare_number_instr {
+    ($cmp: expr, $at_1: expr, $at_2: expr) => {{
+        $cmp.set_terms($at_1, $at_2);
+        call_clause!(ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp)), 0)
+    }};
+}
+
+macro_rules! call_clause {
+    ($clause_type:expr, $pvs:expr) => {{
+        let mut instr = $clause_type.to_instr();
+        instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
+        instr
+    }};
+}
+
+macro_rules! call_clause_by_default {
+    ($clause_type:expr, $pvs:expr) => {{
+        let mut instr = $clause_type.to_instr().to_default();
+        instr.perm_vars_mut().map(|pvs| *pvs = $pvs);
+        instr
+    }};
+}
+
+macro_rules! interm {
+    ($n: expr) => {
+        ArithmeticTerm::Interm($n)
+    };
+}
+
 macro_rules! ar_reg {
     ($r: expr) => {
         ArithmeticTerm::Reg($r)
@@ -545,228 +568,17 @@ macro_rules! index_store {
     ($code_dir:expr, $op_dir:expr, $modules:expr) => {
         IndexStore {
             code_dir: $code_dir,
-            extensible_predicates: ExtensiblePredicates::new(),
-            local_extensible_predicates: LocalExtensiblePredicates::new(),
-            global_variables: GlobalVarDir::new(),
-            meta_predicates: MetaPredicateDir::new(),
+            extensible_predicates: ExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+            local_extensible_predicates: LocalExtensiblePredicates::with_hasher(FxBuildHasher::default()),
+            global_variables: GlobalVarDir::with_hasher(FxBuildHasher::default()),
+            meta_predicates: MetaPredicateDir::with_hasher(FxBuildHasher::default()),
             modules: $modules,
             op_dir: $op_dir,
             streams: StreamDir::new(),
-            stream_aliases: StreamAliasDir::new(),
-        }
-    };
-}
-
-macro_rules! is_atom {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtom($r)), 1, 0)
-    };
-}
-
-macro_rules! is_atomic {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsAtomic($r)), 1, 0)
-    };
-}
-
-macro_rules! is_integer {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsInteger($r)), 1, 0)
-    };
-}
-
-macro_rules! is_compound {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsCompound($r)), 1, 0)
-    };
-}
-
-macro_rules! is_float {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsFloat($r)), 1, 0)
-    };
-}
-
-macro_rules! is_rational {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsRational($r)), 1, 0)
-    };
-}
-
-macro_rules! is_number {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsNumber($r)), 1, 0)
-    };
-}
-
-macro_rules! is_nonvar {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsNonVar($r)), 1, 0)
-    };
-}
-
-macro_rules! is_var {
-    ($r:expr) => {
-        call_clause!(ClauseType::Inlined(InlinedClauseType::IsVar($r)), 1, 0)
-    };
-}
-
-macro_rules! call_clause {
-    ($ct:expr, $arity:expr, $pvs:expr) => {
-        Line::Control(ControlInstruction::CallClause(
-            $ct, $arity, $pvs, false, false,
-        ))
-    };
-    ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
-        Line::Control(ControlInstruction::CallClause(
-            $ct, $arity, $pvs, $lco, false,
-        ))
-    };
-}
-
-macro_rules! call_clause_by_default {
-    ($ct:expr, $arity:expr, $pvs:expr) => {
-        Line::Control(ControlInstruction::CallClause(
-            $ct, $arity, $pvs, false, true,
-        ))
-    };
-    ($ct:expr, $arity:expr, $pvs:expr, $lco:expr) => {
-        Line::Control(ControlInstruction::CallClause(
-            $ct, $arity, $pvs, $lco, true,
-        ))
-    };
-}
-
-macro_rules! proceed {
-    () => {
-        Line::Control(ControlInstruction::Proceed)
-    };
-}
-
-macro_rules! is_call {
-    ($r:expr, $at:expr) => {
-        call_clause!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
-    };
-}
-
-macro_rules! is_call_by_default {
-    ($r:expr, $at:expr) => {
-        call_clause_by_default!(ClauseType::BuiltIn(BuiltInClauseType::Is($r, $at)), 2, 0)
-    };
-}
-
-macro_rules! set_cp {
-    ($r:expr) => {
-        call_clause!(ClauseType::System(SystemClauseType::SetCutPoint($r)), 1, 0)
-    };
-}
-
-macro_rules! succeed {
-    () => {
-        call_clause!(ClauseType::System(SystemClauseType::Succeed), 0, 0)
-    };
-}
-
-macro_rules! fail {
-    () => {
-        call_clause!(ClauseType::System(SystemClauseType::Fail), 0, 0)
-    };
-}
-
-macro_rules! compare_number_instr {
-    ($cmp: expr, $at_1: expr, $at_2: expr) => {{
-        let ct = ClauseType::Inlined(InlinedClauseType::CompareNumber($cmp, $at_1, $at_2));
-        call_clause!(ct, 2, 0)
-    }};
-}
-
-macro_rules! jmp_call {
-    ($arity:expr, $offset:expr, $pvs:expr) => {
-        Line::Control(ControlInstruction::JmpBy($arity, $offset, $pvs, false))
-    };
-}
-
-macro_rules! return_from_clause {
-    ($lco:expr, $machine_st:expr) => {{
-        if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
-            return Ok(());
-        }
-
-        if $lco {
-            $machine_st.p = CodePtr::Local($machine_st.cp);
-        } else {
-            $machine_st.p += 1;
-        }
-
-        Ok(())
-    }};
-}
-
-macro_rules! dir_entry {
-    ($idx:expr) => {
-        LocalCodePtr::DirEntry($idx)
-    };
-}
-
-macro_rules! put_constant {
-    ($lvl:expr, $cons:expr, $r:expr) => {
-        QueryInstruction::PutConstant($lvl, $cons, $r)
-    };
-}
-
-macro_rules! get_level_and_unify {
-    ($r: expr) => {
-        Line::Cut(CutInstruction::GetLevelAndUnify($r))
-    };
-}
-
-/*
-macro_rules! unwind_protect {
-    ($e: expr, $protected: expr) => {
-        match $e {
-            Err(e) => {
-                $protected;
-                return Err(e);
-            }
-            _ => {}
-        }
-    };
-}
-*/
-/*
-macro_rules! discard_result {
-    ($f: expr) => {
-        match $f {
-            _ => (),
+            stream_aliases: StreamAliasDir::with_hasher(FxBuildHasher::default()),
         }
     };
 }
-*/
-
-macro_rules! try_or_fail {
-    ($s:expr, $e:expr) => {{
-        match $e {
-            Ok(val) => val,
-            Err(msg) => {
-                $s.throw_exception(msg);
-                return;
-            }
-        }
-    }};
-}
-
-macro_rules! try_or_fail_gen {
-    ($s:expr, $e:expr) => {{
-        match $e {
-            Ok(val) => val,
-            Err(msg_fn) => {
-                let e = msg_fn($s);
-                $s.throw_exception(e);
-                return;
-            }
-        }
-    }};
-}
 
 macro_rules! unify {
     ($machine_st:expr, $($value:expr),*) => {{
index 1bbde9c291b5c79c248b0d7a9b232781bca7ae6b..3db3ca0eb3d81f2d26f5dc2bdaf9f38aa8a5da82 100644 (file)
@@ -13,6 +13,7 @@ use std::vec::Vec;
 
 use rug::{Integer, Rational};
 
+use fxhash::FxBuildHasher;
 use indexmap::IndexMap;
 use modular_bitfield::error::OutOfBounds;
 use modular_bitfield::prelude::*;
@@ -286,7 +287,7 @@ impl OpDesc {
 }
 
 // name and fixity -> operator type and precedence.
-pub type OpDir = IndexMap<(Atom, Fixity), OpDesc>;
+pub type OpDir = IndexMap<(Atom, Fixity), OpDesc, FxBuildHasher>;
 
 #[derive(Debug, Clone, Copy)]
 pub struct MachineFlags {
@@ -329,7 +330,7 @@ impl Default for DoubleQuotes {
 }
 
 pub fn default_op_dir() -> OpDir {
-    let mut op_dir = OpDir::new();
+    let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
 
     op_dir.insert(
         (atom!(":-"), Fixity::In),
index eced1d72b96a5a9d874306ef34f915b46721a650..def66b10630560fff214733fd13bf3be3d586b7f 100644 (file)
@@ -12,6 +12,8 @@ use crate::machine::streams::*;
 use crate::parser::char_reader::*;
 use crate::types::*;
 
+use fxhash::FxBuildHasher;
+
 use rustyline::error::ReadlineError;
 use rustyline::{Cmd, Config, Editor, KeyEvent};
 
@@ -257,7 +259,7 @@ impl<'a, 'b> TermWriter<'a, 'b> {
             heap,
             atom_tbl,
             queue: SubtermDeque::new(),
-            var_dict: HeapVarDict::new(),
+            var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
         }
     }
 
index 0d4ac6d6ec66cb4b8cf53aac372d8461c5a56488..cbb469f9d26446890283c0fd9775e841988d9bd9 100644 (file)
@@ -1,39 +1,41 @@
 use crate::parser::ast::*;
 
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::iterators::*;
 use crate::types::*;
 
+pub(crate) struct FactInstruction;
+pub(crate) struct QueryInstruction;
+
 pub(crate) trait CompilationTarget<'a> {
     type Iterator: Iterator<Item = TermRef<'a>>;
 
     fn iter(term: &'a Term) -> Self::Iterator;
 
-    fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Self;
-    fn to_list(lvl: Level, r: RegType) -> Self;
-    fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self;
+    fn to_constant(lvl: Level, literal: Literal, r: RegType) -> Instruction;
+    fn to_list(lvl: Level, r: RegType) -> Instruction;
+    fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction;
 
-    fn to_void(num_subterms: usize) -> Self;
-    fn is_void_instr(&self) -> bool;
+    fn to_void(num_subterms: usize) -> Instruction;
+    fn is_void_instr(instr: &Instruction) -> bool;
 
-    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self;
+    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction;
 
-    fn incr_void_instr(&mut self);
+    fn incr_void_instr(instr: &mut Instruction);
 
-    fn constant_subterm(literal: Literal) -> Self;
+    fn constant_subterm(literal: Literal) -> Instruction;
 
-    fn argument_to_variable(r: RegType, r: usize) -> Self;
-    fn argument_to_value(r: RegType, val: usize) -> Self;
+    fn argument_to_variable(r: RegType, r: usize) -> Instruction;
+    fn argument_to_value(r: RegType, val: usize) -> Instruction;
 
-    fn move_to_register(r: RegType, val: usize) -> Self;
+    fn move_to_register(r: RegType, val: usize) -> Instruction;
 
-    fn subterm_to_variable(r: RegType) -> Self;
-    fn subterm_to_value(r: RegType) -> Self;
+    fn subterm_to_variable(r: RegType) -> Instruction;
+    fn subterm_to_value(r: RegType) -> Instruction;
 
-    fn clause_arg_to_instr(r: RegType) -> Self;
+    fn clause_arg_to_instr(r: RegType) -> Instruction;
 }
 
 impl<'a> CompilationTarget<'a> for FactInstruction {
@@ -43,66 +45,66 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
         breadth_first_iter(term, false) // do not iterate over the root clause if one exists.
     }
 
-    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self {
-        FactInstruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
+    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+        Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
     }
 
-    fn to_structure(ct: ClauseType, arity: usize, reg: RegType) -> Self {
-        FactInstruction::GetStructure(ct, arity, reg)
+    fn to_structure(name: Atom, arity: usize, reg: RegType) -> Instruction {
+        Instruction::GetStructure(name, arity, reg)
     }
 
-    fn to_list(lvl: Level, reg: RegType) -> Self {
-        FactInstruction::GetList(lvl, reg)
+    fn to_list(lvl: Level, reg: RegType) -> Instruction {
+        Instruction::GetList(lvl, reg)
     }
 
-    fn to_void(num_subterms: usize) -> Self {
-        FactInstruction::UnifyVoid(num_subterms)
+    fn to_void(num_subterms: usize) -> Instruction {
+        Instruction::UnifyVoid(num_subterms)
     }
 
-    fn is_void_instr(&self) -> bool {
-        match self {
-            &FactInstruction::UnifyVoid(_) => true,
+    fn is_void_instr(instr: &Instruction) -> bool {
+        match instr {
+            &Instruction::UnifyVoid(_) => true,
             _ => false,
         }
     }
 
-    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self {
-        FactInstruction::GetPartialString(lvl, string, r, has_tail)
+    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
+        Instruction::GetPartialString(lvl, string, r, has_tail)
     }
 
-    fn incr_void_instr(&mut self) {
-        match self {
-            &mut FactInstruction::UnifyVoid(ref mut incr) => *incr += 1,
+    fn incr_void_instr(instr: &mut Instruction) {
+        match instr {
+            &mut Instruction::UnifyVoid(ref mut incr) => *incr += 1,
             _ => {}
         }
     }
 
-    fn constant_subterm(constant: Literal) -> Self {
-        FactInstruction::UnifyConstant(HeapCellValue::from(constant))
+    fn constant_subterm(constant: Literal) -> Instruction {
+        Instruction::UnifyConstant(HeapCellValue::from(constant))
     }
 
-    fn argument_to_variable(arg: RegType, val: usize) -> Self {
-        FactInstruction::GetVariable(arg, val)
+    fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
+        Instruction::GetVariable(arg, val)
     }
 
-    fn move_to_register(arg: RegType, val: usize) -> Self {
-        FactInstruction::GetVariable(arg, val)
+    fn move_to_register(arg: RegType, val: usize) -> Instruction {
+        Instruction::GetVariable(arg, val)
     }
 
-    fn argument_to_value(arg: RegType, val: usize) -> Self {
-        FactInstruction::GetValue(arg, val)
+    fn argument_to_value(arg: RegType, val: usize) -> Instruction {
+        Instruction::GetValue(arg, val)
     }
 
-    fn subterm_to_variable(val: RegType) -> Self {
-        FactInstruction::UnifyVariable(val)
+    fn subterm_to_variable(val: RegType) -> Instruction {
+        Instruction::UnifyVariable(val)
     }
 
-    fn subterm_to_value(val: RegType) -> Self {
-        FactInstruction::UnifyValue(val)
+    fn subterm_to_value(val: RegType) -> Instruction {
+        Instruction::UnifyValue(val)
     }
 
-    fn clause_arg_to_instr(val: RegType) -> Self {
-        FactInstruction::UnifyVariable(val)
+    fn clause_arg_to_instr(val: RegType) -> Instruction {
+        Instruction::UnifyVariable(val)
     }
 }
 
@@ -113,65 +115,65 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
         post_order_iter(term)
     }
 
-    fn to_structure(ct: ClauseType, arity: usize, r: RegType) -> Self {
-        QueryInstruction::PutStructure(ct, arity, r)
+    fn to_structure(name: Atom, arity: usize, r: RegType) -> Instruction {
+        Instruction::PutStructure(name, arity, r)
     }
 
-    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Self {
-        QueryInstruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
+    fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+        Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
     }
 
-    fn to_list(lvl: Level, reg: RegType) -> Self {
-        QueryInstruction::PutList(lvl, reg)
+    fn to_list(lvl: Level, reg: RegType) -> Instruction {
+        Instruction::PutList(lvl, reg)
     }
 
-    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Self {
-        QueryInstruction::PutPartialString(lvl, string, r, has_tail)
+    fn to_pstr(lvl: Level, string: Atom, r: RegType, has_tail: bool) -> Instruction {
+        Instruction::PutPartialString(lvl, string, r, has_tail)
     }
 
-    fn to_void(subterms: usize) -> Self {
-        QueryInstruction::SetVoid(subterms)
+    fn to_void(subterms: usize) -> Instruction {
+        Instruction::SetVoid(subterms)
     }
 
-    fn is_void_instr(&self) -> bool {
-        match self {
-            &QueryInstruction::SetVoid(_) => true,
+    fn is_void_instr(instr: &Instruction) -> bool {
+        match instr {
+            &Instruction::SetVoid(_) => true,
             _ => false,
         }
     }
 
-    fn incr_void_instr(&mut self) {
-        match self {
-            &mut QueryInstruction::SetVoid(ref mut incr) => *incr += 1,
+    fn incr_void_instr(instr: &mut Instruction) {
+        match instr {
+            &mut Instruction::SetVoid(ref mut incr) => *incr += 1,
             _ => {}
         }
     }
 
-    fn constant_subterm(constant: Literal) -> Self {
-        QueryInstruction::SetConstant(HeapCellValue::from(constant))
+    fn constant_subterm(constant: Literal) -> Instruction {
+        Instruction::SetConstant(HeapCellValue::from(constant))
     }
 
-    fn argument_to_variable(arg: RegType, val: usize) -> Self {
-        QueryInstruction::PutVariable(arg, val)
+    fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
+        Instruction::PutVariable(arg, val)
     }
 
-    fn move_to_register(arg: RegType, val: usize) -> Self {
-        QueryInstruction::GetVariable(arg, val)
+    fn move_to_register(arg: RegType, val: usize) -> Instruction {
+        Instruction::GetVariable(arg, val)
     }
 
-    fn argument_to_value(arg: RegType, val: usize) -> Self {
-        QueryInstruction::PutValue(arg, val)
+    fn argument_to_value(arg: RegType, val: usize) -> Instruction {
+        Instruction::PutValue(arg, val)
     }
 
-    fn subterm_to_variable(val: RegType) -> Self {
-        QueryInstruction::SetVariable(val)
+    fn subterm_to_variable(val: RegType) -> Instruction {
+        Instruction::SetVariable(val)
     }
 
-    fn subterm_to_value(val: RegType) -> Self {
-        QueryInstruction::SetValue(val)
+    fn subterm_to_value(val: RegType) -> Instruction {
+        Instruction::SetValue(val)
     }
 
-    fn clause_arg_to_instr(val: RegType) -> Self {
-        QueryInstruction::SetValue(val)
+    fn clause_arg_to_instr(val: RegType) -> Instruction {
+        Instruction::SetValue(val)
     }
 }
index 18a6f3e8f26204f2606308ea3791ac13bb0e3300..b72e0ed1b0e611756d0f14e59bd34c4956815ab6 100644 (file)
@@ -158,7 +158,7 @@ instruction_match(Term, VarList) :-
           (  Item == user ->
              catch(load(user_input), E, print_exception_with_check(E))
           ;
-          submit_query_and_print_results(consult(Item), [])
+             submit_query_and_print_results(consult(Item), [])
           )
        ;  catch(type_error(atom, Item, repl/0),
                 E,
@@ -184,7 +184,7 @@ submit_query_and_print_results_(_, _) :-
 submit_query_and_print_results(Term0, VarList) :-
     (  functor(Term0, call, _) ->
        Term = Term0 % prevent pre-mature expansion of incomplete goal
-    % in the first argument, which is done by call/N
+                    % in the first argument, which is done by call/N
     ;  expand_goal(Term0, user, Term)
     ),
     setup_call_cleanup(bb_put('$first_answer', true),
index 455cc72bdcaaf99376c2c845116a515eb88d33dc..38f8b139de238c005b3345705f21cf77fedc9945 100644 (file)
@@ -1,6 +1,5 @@
 use crate::arena::*;
 use crate::atom_table::*;
-use crate::clause_types::*;
 use crate::forms::*;
 use crate::instructions::*;
 use crate::machine::loader::CompilationTarget;
@@ -15,18 +14,7 @@ use ordered_float::OrderedFloat;
 
 use std::fmt;
 
-impl fmt::Display for LocalCodePtr {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
-            LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
-            // LocalCodePtr::IndexingBuf(p, o, i) => {
-            //     write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i)
-            // }
-        }
-    }
-}
-
+/*
 impl fmt::Display for REPLCodePtr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -77,6 +65,7 @@ impl fmt::Display for REPLCodePtr {
         }
     }
 }
+*/
 
 impl fmt::Display for IndexPtr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -97,6 +86,7 @@ impl fmt::Display for CompilationTarget {
     }
 }
 
+/*
 impl fmt::Display for FactInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -221,6 +211,7 @@ impl fmt::Display for ClauseType {
         }
     }
 }
+*/
 
 impl fmt::Display for HeapCellValue {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -269,82 +260,10 @@ impl fmt::Display for HeapCellValue {
                 unreachable!()
             }
         )
-        /*
-        match self {
-            &HeapCellValue::Addr(ref addr) => write!(f, "{}", addr),
-            &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
-            &HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
-            &HeapCellValue::Integer(ref n) => write!(f, "{}", n),
-            &HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
-            &HeapCellValue::Rational(ref n) => write!(f, "{}", n),
-            &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
-                f,
-                "{}/{} (op, priority: {}, spec: {})",
-                name.as_str(),
-                arity,
-                cell.prec(),
-                cell.assoc()
-            ),
-            &HeapCellValue::NamedStr(arity, ref name, None) => {
-                write!(f, "{}/{}", name.as_str(), arity)
-            }
-            &HeapCellValue::PartialString(ref pstr, has_tail) => {
-                write!(
-                    f,
-                    "pstr ( buf: \"{}\", has_tail({}) )",
-                    pstr.as_str_from(0),
-                    has_tail,
-                )
-            }
-            &HeapCellValue::Stream(ref stream) => {
-                write!(f, "$stream({})", stream.as_ptr() as usize)
-            }
-            &HeapCellValue::TcpListener(ref tcp_listener) => {
-                write!(f, "$tcp_listener({})", tcp_listener.local_addr().unwrap())
-            }
-        }
-        */
     }
 }
 
 /*
-impl fmt::Display for DBRef {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            &DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity),
-            &DBRef::Op(priority, spec, ref name, ..) => {
-                write!(f, "db_ref:op({}, {}, {})", priority, spec, name)
-            }
-        }
-    }
-}
-*/
-
-/*
-impl fmt::Display for Addr {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            &Addr::Char(c) => write!(f, "Addr::Char({})", c),
-            &Addr::EmptyList => write!(f, "Addr::EmptyList"),
-            &Addr::Fixnum(n) => write!(f, "Addr::Fixnum({})", n),
-            &Addr::Float(fl) => write!(f, "Addr::Float({})", fl),
-            &Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
-            &Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
-            &Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
-            &Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s),
-            &Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
-            &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
-            &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
-            &Addr::Str(s) => write!(f, "Addr::Str({})", s),
-            &Addr::PStrLocation(h, n) => write!(f, "Addr::PStrLocation({}, {})", h, n),
-            &Addr::Stream(stream) => write!(f, "Addr::Stream({})", stream),
-            &Addr::TcpListener(tcp_listener) => write!(f, "Addr::TcpListener({})", tcp_listener),
-            &Addr::Usize(cp) => write!(f, "Addr::Usize({})", cp),
-        }
-    }
-}
-*/
-
 impl fmt::Display for ControlInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -375,6 +294,7 @@ impl fmt::Display for ControlInstruction {
         }
     }
 }
+*/
 
 impl fmt::Display for IndexedChoiceInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -386,6 +306,7 @@ impl fmt::Display for IndexedChoiceInstruction {
     }
 }
 
+/*
 impl fmt::Display for ChoiceInstruction {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -443,6 +364,7 @@ impl fmt::Display for ChoiceInstruction {
         }
     }
 }
+*/
 
 impl fmt::Display for IndexingCodePtr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -602,6 +524,7 @@ impl fmt::Display for IndexingLine {
     }
 }
 
+/*
 impl fmt::Display for Line {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -625,17 +548,8 @@ impl fmt::Display for Line {
         }
     }
 }
-
-impl fmt::Display for Number {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Number::Float(fl) => write!(f, "{}", fl),
-            Number::Integer(n) => write!(f, "{}", n),
-            Number::Rational(r) => write!(f, "{}", r),
-            Number::Fixnum(n) => write!(f, "{}", n.get_num()),
-        }
-    }
-}
+*/
+/*
 
 impl fmt::Display for ArithmeticTerm {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -745,7 +659,8 @@ impl fmt::Display for CutInstruction {
         }
     }
 }
-
+*/
+/*
 impl fmt::Display for Level {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
@@ -754,3 +669,4 @@ impl fmt::Display for Level {
         }
     }
 }
+*/