From 955e1799c8e8b58d3fcce9cf4d1a61741e57e8e8 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sun, 19 Dec 2021 18:57:57 -0700 Subject: [PATCH] flatten the instruction dispatch loop --- Cargo.lock | 76 + Cargo.toml | 9 +- build.rs | 15 + crates/instructions-template/Cargo.lock | 129 + crates/instructions-template/Cargo.toml | 14 + crates/instructions-template/src/lib.rs | 3286 +++++++++ crates/prolog_parser/Cargo.toml | 26 - crates/static-string-indexing/Cargo.toml | 2 +- crates/to-syn-value/Cargo.toml | 10 + crates/to-syn-value/src/lib.rs | 3 + crates/to-syn-value_derive/Cargo.toml | 14 + crates/to-syn-value_derive/src/lib.rs | 20 + src/allocator.rs | 9 +- src/arithmetic.rs | 112 +- src/clause_types.rs | 952 --- src/codegen.rs | 319 +- src/debray_allocator.rs | 54 +- src/fixtures.rs | 22 +- src/forms.rs | 61 +- src/heap_print.rs | 2 +- src/instructions.rs | 919 --- src/iterators.rs | 15 +- src/lib.rs | 6 +- src/lib/between.pl | 14 +- src/lib/builtins.pl | 4 +- src/lib/lists.pl | 9 +- src/loader.pl | 11 +- src/machine/arithmetic_ops.rs | 3 +- src/machine/attributed_variables.rs | 38 +- src/machine/code_repo.rs | 197 - src/machine/code_walker.rs | 26 +- src/machine/compile.rs | 315 +- src/machine/dispatch.rs | 5853 ++++++++++++--- src/machine/gc.rs | 1 - src/machine/heap.rs | 184 +- src/machine/load_state.rs | 20 +- src/machine/loader.rs | 210 +- src/machine/machine_errors.rs | 7 +- src/machine/machine_indices.rs | 207 +- src/machine/machine_state.rs | 42 +- src/machine/machine_state_impl.rs | 114 +- src/machine/mock_wam.rs | 8 +- src/machine/mod.rs | 975 +-- src/machine/preprocessor.rs | 32 +- src/machine/stack.rs | 11 +- src/machine/system_calls.rs | 8269 ++++++++++++---------- src/macros.rs | 256 +- src/parser/ast.rs | 5 +- src/read.rs | 4 +- src/targets.rs | 152 +- src/toplevel.pl | 4 +- src/write.rs | 110 +- 52 files changed, 13691 insertions(+), 9465 deletions(-) create mode 100644 crates/instructions-template/Cargo.lock create mode 100644 crates/instructions-template/Cargo.toml create mode 100644 crates/instructions-template/src/lib.rs delete mode 100644 crates/prolog_parser/Cargo.toml create mode 100644 crates/to-syn-value/Cargo.toml create mode 100644 crates/to-syn-value/src/lib.rs create mode 100644 crates/to-syn-value_derive/Cargo.toml create mode 100644 crates/to-syn-value_derive/src/lib.rs delete mode 100644 src/clause_types.rs delete mode 100644 src/instructions.rs delete mode 100644 src/machine/code_repo.rs diff --git a/Cargo.lock b/Cargo.lock index 7818a0a4..4d699f11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index d0a332fb..8e81a947 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/build.rs b/build.rs index 88267cdc..6c315769 100644 --- 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 index 00000000..08be8ba3 --- /dev/null +++ b/crates/instructions-template/Cargo.lock @@ -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 index 00000000..92f130ed --- /dev/null +++ b/crates/instructions-template/Cargo.toml @@ -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 index 00000000..386bafd5 --- /dev/null +++ b/crates/instructions-template/src/lib.rs @@ -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), + // 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 { + 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( + 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::(&variant.ident, "Name"); + let arity = Arity::from(prop_from_ident::(&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), + 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), + DynamicIndexedChoice(SliceDeque), + } + + impl From for IndexingLine { + #[inline] + fn from(instr: IndexingInstruction) -> Self { + IndexingLine::Indexing(instr) + } + } + + impl From> for IndexingLine { + #[inline] + fn from(instrs: SliceDeque) -> 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; + + impl Instruction { + #[inline] + pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec> { + match self { + Instruction::IndexingCode(ref mut indexing_code) => Some(indexing_code), + _ => None, + } + } + + #[inline] + pub fn to_indexing_line(&self) -> Option<&Vec> { + 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, + ) { + 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() -> Vec { + 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::(); + let builtin_type_variants = attributeless_enum::(); + let inlined_type_variants = attributeless_enum::(); + let system_clause_type_variants = attributeless_enum::(); + let repl_code_ptr_variants = attributeless_enum::(); + let compare_number_variants = attributeless_enum::(); + let compare_term_variants = attributeless_enum::(); + + 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::() { + 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::() { + 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(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::( + &variant, + prefix, + &mut self.compare_number_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "CompareTerm" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.compare_term_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "BuiltInClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.builtin_type_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "InlinedClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.inlined_type_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "REPLCodePtr" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.repl_code_ptr_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "SystemClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.system_clause_type_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "InstructionTemplate" { + ( prop_from_ident::(&variant.ident, "Name"), + Arity::from(prop_from_ident::(&variant.ident, "Arity")), + CountableInference::NotCounted + ) + } else if id == "ClauseType" { + let (name, arity) = add_discriminant_data::( + &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 index dc19afbd..00000000 --- a/crates/prolog_parser/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "prolog_parser" -version = "0.8.68" -authors = ["Mark Thom "] -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"] diff --git a/crates/static-string-indexing/Cargo.toml b/crates/static-string-indexing/Cargo.toml index a6da96b9..1432ae68 100644 --- a/crates/static-string-indexing/Cargo.toml +++ b/crates/static-string-indexing/Cargo.toml @@ -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 index 00000000..3fa4953d --- /dev/null +++ b/crates/to-syn-value/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "to-syn-value" +version = "0.1.0" +authors = ["Mark Thom "] +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 index 00000000..753c44a9 --- /dev/null +++ b/crates/to-syn-value/src/lib.rs @@ -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 index 00000000..9dc0e8ac --- /dev/null +++ b/crates/to-syn-value_derive/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "to-syn-value_derive" +version = "0.1.0" +authors = ["Mark Thom "] +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 index 00000000..13845ac4 --- /dev/null +++ b/crates/to-syn-value_derive/src/lib.rs @@ -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() +} diff --git a/src/allocator.rs b/src/allocator.rs index c29adc92..7a3b43a0 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -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(&mut self, _: Level, _: GenContext, _: &mut Vec) + fn mark_anon_var(&mut self, _: Level, _: GenContext, _: &mut Code) where Target: crate::targets::CompilationTarget<'a>; fn mark_non_var( @@ -19,7 +20,7 @@ pub(crate) trait Allocator<'a> { _: Level, _: GenContext, _: &'a Cell, - _: &mut Vec, + _: &mut Code, ) where Target: crate::targets::CompilationTarget<'a>; fn mark_reserved_var( @@ -28,7 +29,7 @@ pub(crate) trait Allocator<'a> { _: Level, _: &'a Cell, _: GenContext, - _: &mut Vec, + _: &mut Code, _: RegType, _: bool, ) where @@ -39,7 +40,7 @@ pub(crate) trait Allocator<'a> { _: Level, _: &'a Cell, _: GenContext, - _: &mut Vec, + _: &mut Code, ) where Target: crate::targets::CompilationTarget<'a>; diff --git a/src/arithmetic.rs b/src/arithmetic.rs index d09187f8..6396336d 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -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>, @@ -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 { + ) -> Result { 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 { + ) -> Result { 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 { + ) -> Result { 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 index 8083775a..00000000 --- a/src/clause_types.rs +++ /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 { - 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 { - 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 for ClauseType { - fn from(inlined_ct: InlinedClauseType) -> Self { - ClauseType::Inlined(inlined_ct) - } -} diff --git a/src/codegen.rs b/src/codegen.rs index ca344558..a8094841 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -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, 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::(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: &mut Vec) + fn add_or_increment_void_instr(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, term_loc: GenContext, is_exposed: bool, - target: &mut Vec, + 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::(var.clone(), Level::Deep, cell, term_loc, target); } else { - Self::add_or_increment_void_instr(target); + Self::add_or_increment_void_instr::(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: &mut Code, ) { match subterm { &Term::AnonVar if is_exposed => { - self.marker.mark_anon_var(Level::Deep, term_loc, target); + self.marker.mark_anon_var::(Level::Deep, term_loc, target); } &Term::AnonVar => { - Self::add_or_increment_void_instr(target); + Self::add_or_increment_void_instr::(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::(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::(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 + ) -> Code where Target: crate::targets::CompilationTarget<'a>, Iter: Iterator>, { - 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::(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::(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::(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::(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::(head, term_loc, is_exposed, &mut target); + self.subterm_to_instr::(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::(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::(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::(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::(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::( 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::(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::(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::( + 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) { 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, 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::(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::(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::( + 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::(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 += diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 2b67c56d..9c688858 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -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, VarData>, + bindings: IndexMap, VarData, FxBuildHasher>, arg_c: usize, temp_lb: usize, arity: usize, // 0 if not at head. - contents: IndexMap>, + contents: IndexMap, FxBuildHasher>, in_use: BTreeSet, } @@ -123,7 +126,7 @@ impl DebrayAllocator { } } - fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec) + fn evacuate_arg<'a, Target>(&mut self, chunk_num: usize, target: &mut Vec) where Target: CompilationTarget<'a>, { @@ -152,7 +155,7 @@ impl DebrayAllocator { var: &String, lvl: Level, term_loc: GenContext, - target: &mut Vec, + target: &mut Vec, ) -> 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::(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::(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(&mut self, lvl: Level, term_loc: GenContext, target: &mut Vec) + fn mark_anon_var( + &mut self, + lvl: Level, + term_loc: GenContext, + target: &mut Vec, + ) 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::(chunk_num, target); } self.arg_c += 1; @@ -243,7 +251,7 @@ impl<'a> Allocator<'a> for DebrayAllocator { lvl: Level, term_loc: GenContext, cell: &Cell, - target: &mut Vec, + target: &mut Vec, ) 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::(chunk_num, target); } self.arg_c += 1; @@ -270,20 +278,18 @@ impl<'a> Allocator<'a> for DebrayAllocator { cell.set(r); } - fn mark_var( + fn mark_var>( &mut self, var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, - target: &mut Vec, - ) where - Target: CompilationTarget<'a>, - { + target: &mut Vec, + ) { 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::(&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::(var, lvl, cell, term_loc, target, r, is_new_var); } - fn mark_reserved_var( + fn mark_reserved_var>( &mut self, var: Rc, lvl: Level, cell: &'a Cell, term_loc: GenContext, - target: &mut Vec, + target: &mut Vec, 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::(term_loc.chunk_num(), target); } self.arg_c += 1; diff --git a/src/fixtures.rs b/src/fixtures.rs index d6a1eea9..43c3ace8 100644 --- a/src/fixtures.rs +++ b/src/fixtures.rs @@ -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); diff --git a/src/forms.rs b/src/forms.rs index b8042820..ce517a5f 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -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; @@ -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, @@ -431,7 +433,7 @@ pub(crate) fn fetch_op_spec(name: Atom, arity: usize, op_dir: &OpDir) -> Option< } } -pub(crate) type ModuleDir = IndexMap; +pub(crate) type ModuleDir = IndexMap; #[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 { 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. -} - diff --git a/src/heap_print.rs b/src/heap_print.rs index f9421788..e1c4e214 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -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 index efaf4d5a..00000000 --- a/src/instructions.rs +++ /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), - DynamicIndexedChoice(SliceDeque), -} - -impl From for IndexingLine { - #[inline] - fn from(instr: IndexingInstruction) -> Self { - IndexingLine::Indexing(instr) - } -} - -impl From> for IndexingLine { - #[inline] - fn from(instrs: SliceDeque) -> Self { - IndexingLine::IndexedChoice(instrs) - } -} - -#[derive(Debug)] -pub(crate) enum Line { - Arithmetic(ArithmeticInstruction), - Choice(ChoiceInstruction), - Control(ControlInstruction), - Cut(CutInstruction), - Fact(FactInstruction), - IndexingCode(Vec), - 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, - ) { - 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> { - match line { - Line::IndexingCode(ref mut indexing_code) => Some(indexing_code), - _ => None, - } -} - -#[inline] -pub(crate) fn to_indexing_line(line: &Line) -> Option<&Vec> { - 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 { - 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), - 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; - -pub(crate) type Code = Vec; diff --git a/src/iterators.rs b/src/iterators.rs index 3c6e955c..4f255584 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -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, _, )) => { diff --git a/src/lib.rs b/src/lib.rs index 458ad485..a4aff98c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/lib/between.pl b/src/lib/between.pl index b162e023..3e023c8c 100644 --- a/src/lib/between.pl +++ b/src/lib/between.pl @@ -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, diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index f1b2f2d9..32527df9 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -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) diff --git a/src/lib/lists.pl b/src/lib/lists.pl index a64c3ad3..752e8271 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -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). diff --git a/src/loader.pl b/src/loader.pl index a9e8f8d7..dd26bbb8 100644 --- a/src/loader.pl +++ b/src/loader.pl @@ -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). diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 85b6cbc3..5cc64098 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -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 { 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), diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index 568978d8..a158d3af 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -15,8 +15,9 @@ pub(super) type Bindings = Vec<(usize, HeapCellValue)>; pub(super) struct AttrVarInitializer { pub(super) attr_var_queue: Vec, 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 { diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs deleted file mode 100644 index f6fb6aa0..00000000 --- a/src/machine/code_repo.rs +++ /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 { - 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() } - } -} diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs index fe63347f..fcda8710 100644 --- a/src/machine/code_walker.rs +++ b/src/machine/code_walker.rs @@ -2,45 +2,47 @@ use crate::instructions::*; use indexmap::IndexSet; -fn capture_offset(line: &Line, index: usize, stack: &mut Vec) -> bool { +fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec) -> 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) -> 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(); diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 8b69ced8..fa1f7250 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -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 { 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 { 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 { 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 { 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, diff --git a/src/machine/dispatch.rs b/src/machine/dispatch.rs index 9b02d191..6f5d9d02 100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@ -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!(), + } } } } diff --git a/src/machine/gc.rs b/src/machine/gc.rs index 1b7f83fe..1f9c80dc 100644 --- a/src/machine/gc.rs +++ b/src/machine/gc.rs @@ -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); diff --git a/src/machine/heap.rs b/src/machine/heap.rs index cb166b69..6a5e14ef 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -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 { +pub(crate) fn to_local_code_ptr(heap: &Heap, addr: HeapCellValue) -> Option { let extract_integer = |s: usize| -> Option { 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 Option HeapTemplate { - #[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::()); - 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::(); - 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::() - } - - pub(crate) fn append(&mut self, vals: Vec) { - 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 Index for HeapTemplate { - 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::(); - &*(ptr as *const HeapCellValue) - } - } -} - -impl Index for HeapTemplate { - type Output = HeapCellValue; - - #[inline] - fn index(&self, index: usize) -> &Self::Output { - unsafe { - let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); - &*(ptr as *const HeapCellValue) - } - } -} - -impl IndexMut for HeapTemplate { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - unsafe { - let ptr = self.buf.top as usize - (index + 1) * mem::size_of::(); - &mut *(ptr as *mut HeapCellValue) - } - } -} -*/ diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs index 036c31d7..1ad94f15 100644 --- a/src/machine/load_state.rs +++ b/src/machine/load_state.rs @@ -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, } }; diff --git a/src/machine/loader.rs b/src/machine/loader.rs index 061452ab..e4a40a20 100644 --- a/src/machine/loader.rs +++ b/src/machine/loader.rs @@ -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: >::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, 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; diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index cae977e5..37910002 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -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(); diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 3f8d47e8..5f9d08d5 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -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 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 for LocalCodePtr { - type Output = Option; - - #[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 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 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 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 for CodePtr { } } -pub(crate) type HeapVarDict = IndexMap, HeapCellValue>; -pub(crate) type AllocVarDict = IndexMap, VarData>; +impl Default for CodePtr { + #[inline] + fn default() -> Self { + CodePtr::Local(0) + } +} +*/ + +pub(crate) type HeapVarDict = IndexMap, HeapCellValue, FxBuildHasher>; +pub(crate) type AllocVarDict = IndexMap, VarData, FxBuildHasher>; -pub(crate) type GlobalVarDir = IndexMap)>; +pub(crate) type GlobalVarDir = IndexMap), FxBuildHasher>; -pub(crate) type StreamAliasDir = IndexMap; +pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; -pub(crate) type MetaPredicateDir = IndexMap>; +pub(crate) type MetaPredicateDir = IndexMap, FxBuildHasher>; -pub(crate) type ExtensiblePredicates = IndexMap; +pub(crate) type ExtensiblePredicates = IndexMap; pub(crate) type LocalExtensiblePredicates = - IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton>; + IndexMap<(CompilationTarget, PredicateKey), LocalPredicateSkeleton, FxBuildHasher>; + +pub(crate) type CodeDir = IndexMap; #[derive(Debug)] pub struct IndexStore { @@ -504,14 +381,14 @@ impl IndexStore { ) -> Option { 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; diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index 6bd29da2..6da9674b 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -55,14 +55,14 @@ pub struct MachineState { pub arena: Arena, pub(super) pdl: Vec, 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; diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index ee04d645..6461f7f0 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -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 { + pub(super) fn setup_call_n(&mut self, arity: usize) -> Result { 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; diff --git a/src/machine/mock_wam.rs b/src/machine/mock_wam.rs index 7f73755a..0b4923da 100644 --- a/src/machine/mock_wam.rs +++ b/src/machine/mock_wam.rs @@ -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!() } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index b33df9d4..7c2be32d 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -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, } +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; diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs index c3711db0..50a46947 100644 --- a/src/machine/preprocessor.rs +++ b/src/machine/preprocessor.rs @@ -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) -> Result>) -> Result { - 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); 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, )), diff --git a/src/machine/stack.rs b/src/machine/stack.rs index b175917b..388c3008 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -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 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, diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index d84c2ea9..08a99f30 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -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 { + pub(crate) fn get_next_db_ref(&self, indices: &IndexStore, db_ref: &DBRef) -> Option { 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 { @@ -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, 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(¤t); + + 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(¤t); + 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 = 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 = 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) { - 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) { + 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 = 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 { diff --git a/src/macros.rs b/src/macros.rs index 90fed110..0b83bbb7 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,9 +1,3 @@ -macro_rules! interm { - ($n: expr) => { - ArithmeticTerm::Interm($n) - }; -} - /* A simple macro to count the arguments in a variadic list * of token trees. */ @@ -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),*) => {{ diff --git a/src/parser/ast.rs b/src/parser/ast.rs index 1bbde9c2..3db3ca0e 100644 --- a/src/parser/ast.rs +++ b/src/parser/ast.rs @@ -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), diff --git a/src/read.rs b/src/read.rs index eced1d72..def66b10 100644 --- a/src/read.rs +++ b/src/read.rs @@ -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()), } } diff --git a/src/targets.rs b/src/targets.rs index 0d4ac6d6..cbb469f9 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -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>; 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) } } diff --git a/src/toplevel.pl b/src/toplevel.pl index 18a6f3e8..b72e0ed1 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -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), diff --git a/src/write.rs b/src/write.rs index 455cc72b..38f8b139 100644 --- a/src/write.rs +++ b/src/write.rs @@ -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 { } } } +*/ -- 2.54.0