--- /dev/null
+// 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 = "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 = "3", Name = "$asserta")))]
+ Asserta,
+ #[strum_discriminants(strum(props(Arity = "3", 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 = "$file_copy")))]
+ FileCopy,
+ #[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 = "arity", Name = "$module_call")))]
+ DynamicModuleResolution(usize),
+ #[strum_discriminants(strum(props(Arity = "arity", Name = "$prepare_call_clause")))]
+ PrepareCallClause(usize),
+ #[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 = "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 = "7", Name = "$get_next_op_db_ref")))]
+ GetNextOpDBRef,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$lookup_db_ref")))]
+ LookupDBRef,
+ #[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 = "1", 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 = "$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_current_scc_block")))]
+ GetCurrentSCCBlock,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_cp")))]
+ GetCutPoint,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_double_quotes")))]
+ GetDoubleQuotes,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$get_unknown")))]
+ GetUnknown,
+ #[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_from_chars")))]
+ ReadFromChars,
+ #[strum_discriminants(strum(props(Arity = "5", Name = "$read_term_from_chars")))]
+ ReadTermFromChars,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$reset_block")))]
+ ResetBlock,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$reset_scc_block")))]
+ ResetSCCBlock,
+ #[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 = "0", Name = "$push_ball_stack")))]
+ PushBallStack,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$pop_ball_stack")))]
+ PopBallStack,
+ #[strum_discriminants(strum(props(Arity = "0", Name = "$pop_from_ball_stack")))]
+ PopFromBallStack,
+ #[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_unknown")))]
+ SetUnknown,
+ #[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 = "7", 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 = "2", Name = "$inlined_instructions")))]
+ InlinedInstructions,
+ #[strum_discriminants(strum(props(Arity = "8", Name = "$write_term")))]
+ WriteTerm,
+ #[strum_discriminants(strum(props(Arity = "8", 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 = "4", 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,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$det_length_rundown")))]
+ DeterministicLengthRundown,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$http_open")))]
+ HttpOpen,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$http_listen")))]
+ HttpListen,
+ #[strum_discriminants(strum(props(Arity = "7", Name = "$http_accept")))]
+ HttpAccept,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$http_answer")))]
+ HttpAnswer,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$load_foreign_lib")))]
+ LoadForeignLib,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$foreign_call")))]
+ ForeignCall,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$define_foreign_struct")))]
+ DefineForeignStruct,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$predicate_defined")))]
+ PredicateDefined,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$strip_module")))]
+ StripModule,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$compile_inline_or_expanded_goal")))]
+ CompileInlineOrExpandedGoal,
+ #[strum_discriminants(strum(props(Arity = "arity", Name = "$fast_call")))]
+ FastCallN(usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$is_expanded_or_inlined")))]
+ IsExpandedOrInlined,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$get_clause_p")))]
+ GetClauseP,
+ #[strum_discriminants(strum(props(Arity = "6", Name = "$invoke_clause_at_p")))]
+ InvokeClauseAtP,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$get_from_attr_list")))]
+ GetFromAttributedVarList,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$put_to_attr_list")))]
+ PutToAttributedVarList,
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$del_from_attr_list")))]
+ DeleteFromAttributedVarList,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$delete_all_attributes_from_var")))]
+ DeleteAllAttributesFromVar,
+ #[strum_discriminants(strum(props(Arity = "1", Name = "$unattributed_var")))]
+ UnattributedVar,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$get_db_refs")))]
+ GetDBRefs,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$keysort_with_constant_var_ordering")))]
+ KeySortWithConstantVarOrdering,
+ 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(Level, 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_prev_level")))]
+ GetPrevLevel(RegType),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "get_cut_point")))]
+ GetCutPoint(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 = "2", Name = "add")))]
+ Add(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "sub")))]
+ Sub(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "mul")))]
+ Mul(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "pow")))]
+ Pow(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "int_pow")))]
+ IntPow(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "i_div")))]
+ IDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "max")))]
+ Max(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "min")))]
+ Min(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "int_floor_div")))]
+ IntFloorDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "r_div")))]
+ RDiv(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "div")))]
+ Div(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "shl")))]
+ Shl(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "shr")))]
+ Shr(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "xor")))]
+ Xor(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "and")))]
+ And(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "or")))]
+ Or(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "mod")))]
+ Mod(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "rem")))]
+ Rem(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "2", Name = "gcd")))]
+ Gcd(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sign")))]
+ Sign(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "cos")))]
+ Cos(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sin")))]
+ Sin(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "tan")))]
+ Tan(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "log")))]
+ Log(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "exp")))]
+ Exp(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "acos")))]
+ ACos(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "asin")))]
+ ASin(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atan")))]
+ ATan(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atan2")))]
+ ATan2(ArithmeticTerm, ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sqrt")))]
+ Sqrt(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "abs")))]
+ Abs(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "float")))]
+ Float(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "truncate")))]
+ Truncate(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "round")))]
+ Round(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "ceiling")))]
+ Ceiling(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "floor")))]
+ Floor(ArithmeticTerm, usize),
++ #[strum_discriminants(strum(props(Arity = "1", Name = "float_fractional_part")))]
++ FloatFractionalPart(ArithmeticTerm, usize),
++ #[strum_discriminants(strum(props(Arity = "1", Name = "float_integer_part")))]
++ FloatIntegerPart(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "neg")))]
+ Neg(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "plus")))]
+ Plus(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "acosh")))]
+ ACosh(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "asinh")))]
+ ASinh(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "atanh")))]
+ ATanh(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "cosh")))]
+ Cosh(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "sinh")))]
+ Sinh(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "tanh")))]
+ Tanh(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", Name = "log10")))]
+ Log10(ArithmeticTerm, usize),
+ #[strum_discriminants(strum(props(Arity = "1", 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 = "1", Name = "jmp_by_call")))]
+ JmpByCall(usize), // relative offset.
+ #[strum_discriminants(strum(props(Arity = "1", Name = "rev_jmp_by")))]
+ RevJmpBy(usize),
+ #[strum_discriminants(strum(props(Arity = "0", Name = "proceed")))]
+ Proceed,
+ // indexing.
+ #[strum_discriminants(strum(props(Arity = "1", Name = "indexing_code")))]
+ IndexingCode(Vec<IndexingLine>),
+ // break from loop instruction.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "break_from_dispatch")))]
+ BreakFromDispatchLoop,
+ // swap the verify attr interrupt instruction with the next control instruction.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))]
+ InstallVerifyAttr,
+ // call verify_attrs.
+ #[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))]
+ VerifyAttrInterrupt,
+ // procedures
+ CallClause(ClauseType, usize, usize, bool, bool), // ClauseType,
+ // arity,
+ // perm_vars,
+ // last_call,
+ // use_default_call_policy.
+}
+
+fn derive_input(ty: &Type) -> Option<DeriveInput> {
+ let clause_type: Type = parse_quote!{ ClauseType };
+ let built_in_clause_type: Type = parse_quote! { BuiltInClauseType };
+ let inlined_clause_type: Type = parse_quote! { InlinedClauseType };
+ let system_clause_type: Type = parse_quote! { SystemClauseType };
+ let compare_term_type: Type = parse_quote! { CompareTerm };
+ let compare_number_type: Type = parse_quote! { CompareNumber };
+ let repl_code_ptr_type: Type = parse_quote! { REPLCodePtr };
+
+ if ty == &clause_type {
+ Some(ClauseType::to_derive_input())
+ } else if ty == &built_in_clause_type {
+ Some(BuiltInClauseType::to_derive_input())
+ } else if ty == &inlined_clause_type {
+ Some(InlinedClauseType::to_derive_input())
+ } else if ty == &system_clause_type {
+ Some(SystemClauseType::to_derive_input())
+ } else if ty == &compare_number_type {
+ Some(CompareNumber::to_derive_input())
+ } else if ty == &compare_term_type {
+ Some(CompareTerm::to_derive_input())
+ } else if ty == &repl_code_ptr_type {
+ Some(REPLCodePtr::to_derive_input())
+ } else {
+ None
+ }
+}
+
+impl ToTokens for Arity {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ Arity::Static(arity) => {
+ arity.to_tokens(tokens);
+ }
+ Arity::Ident(arity) => {
+ let ident = format_ident!("{}", arity);
+ tokens.append(ident);
+ }
+ }
+ }
+}
+
+fn add_discriminant_data<DiscriminantT>(
+ variant: &Variant,
+ prefix: &'static str,
+ variant_data: &mut Vec<(&'static str, Arity, Variant)>,
+) -> (&'static str, Arity)
+ where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug
+{
+ let name = prop_from_ident::<DiscriminantT>(&variant.ident, "Name");
+ let arity = Arity::from(prop_from_ident::<DiscriminantT>(&variant.ident, "Arity"));
+
+ if prefix == "Call" {
+ let mut variant = variant.clone();
+ variant.attrs.clear();
+
+ variant_data.push((name, arity, variant));
+ }
+
+ (name, arity)
+}
+
+fn generate_instruction_preface() -> TokenStream {
+ quote! {
+ use crate::arena::*;
+ use crate::arithmetic::*;
+ use crate::atom_table::*;
+ use crate::forms::*;
+ use crate::machine::heap::*;
+ use crate::machine::machine_errors::MachineStub;
+ use crate::machine::machine_indices::CodeIndex;
+ use crate::parser::ast::*;
+ use crate::types::*;
+
+ use fxhash::FxBuildHasher;
+ use indexmap::IndexMap;
+
+ use std::collections::VecDeque;
+
+ fn reg_type_into_functor(r: RegType) -> MachineStub {
+ match r {
+ RegType::Temp(r) => functor!(atom!("x"), [fixnum(r)]),
+ RegType::Perm(r) => functor!(atom!("y"), [fixnum(r)]),
+ }
+ }
+
+ impl Level {
+ fn into_functor(self) -> MachineStub {
+ match self {
+ Level::Root => functor!(atom!("level"), [atom(atom!("root"))]),
+ Level::Shallow => functor!(atom!("level"), [atom(atom!("shallow"))]),
+ Level::Deep => functor!(atom!("level"), [atom(atom!("deep"))]),
+ }
+ }
+ }
+
+ impl ArithmeticTerm {
+ fn into_functor(&self, arena: &mut Arena) -> MachineStub {
+ match self {
+ &ArithmeticTerm::Reg(r) => reg_type_into_functor(r),
+ &ArithmeticTerm::Interm(i) => {
+ functor!(atom!("intermediate"), [fixnum(i)])
+ }
+ &ArithmeticTerm::Number(n) => {
+ vec![HeapCellValue::from((n, arena))]
+ }
+ }
+ }
+ }
+
+ #[derive(Debug, Clone, Copy)]
+ pub enum NextOrFail {
+ Next(usize),
+ Fail(usize),
+ }
+
+ impl Default for NextOrFail {
+ fn default() -> Self {
+ NextOrFail::Fail(0)
+ }
+ }
+
+ impl NextOrFail {
+ #[inline]
+ pub fn is_next(&self) -> bool {
+ if let NextOrFail::Next(_) = self {
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+ pub enum Death {
+ Finite(usize),
+ Infinity,
+ }
+
+ impl Default for Death {
+ fn default() -> Self {
+ Death::Infinity
+ }
+ }
+
+ #[derive(Clone, Copy, Debug)]
+ pub enum IndexedChoiceInstruction {
+ Retry(usize),
+ Trust(usize),
+ Try(usize),
+ }
+
+ impl IndexedChoiceInstruction {
+ pub(crate) fn offset(&self) -> usize {
+ match self {
+ &IndexedChoiceInstruction::Retry(offset) => offset,
+ &IndexedChoiceInstruction::Trust(offset) => offset,
+ &IndexedChoiceInstruction::Try(offset) => offset,
+ }
+ }
+
+ pub(crate) fn to_functor(&self) -> MachineStub {
+ match self {
+ &IndexedChoiceInstruction::Try(offset) => {
+ functor!(atom!("try"), [fixnum(offset)])
+ }
+ &IndexedChoiceInstruction::Trust(offset) => {
+ functor!(atom!("trust"), [fixnum(offset)])
+ }
+ &IndexedChoiceInstruction::Retry(offset) => {
+ functor!(atom!("retry"), [fixnum(offset)])
+ }
+ }
+ }
+ }
+
+ /// `IndexingInstruction` cf. page 110 of wambook.
+ #[derive(Clone, Debug)]
+ pub enum IndexingInstruction {
+ // The first index is the optimal argument being indexed.
+ SwitchOnTerm(
+ usize,
+ IndexingCodePtr,
+ IndexingCodePtr,
+ IndexingCodePtr,
+ IndexingCodePtr,
+ ),
+ SwitchOnConstant(IndexMap<Literal, IndexingCodePtr, FxBuildHasher>),
+ SwitchOnStructure(IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>),
+ }
+
+ #[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(VecDeque<IndexedChoiceInstruction>),
+ DynamicIndexedChoice(VecDeque<usize>),
+ }
+
+ impl From<IndexingInstruction> for IndexingLine {
+ #[inline]
+ fn from(instr: IndexingInstruction) -> Self {
+ IndexingLine::Indexing(instr)
+ }
+ }
+
+ impl From<VecDeque<IndexedChoiceInstruction>> for IndexingLine {
+ #[inline]
+ fn from(instrs: VecDeque<IndexedChoiceInstruction>) -> Self {
+ IndexingLine::IndexedChoice(instrs.into_iter().collect())
+ }
+ }
+
+ fn arith_instr_unary_functor(
+ h: usize,
+ name: Atom,
+ arena: &mut Arena,
+ at: &ArithmeticTerm,
+ t: usize,
+ ) -> MachineStub {
+ let at_stub = at.into_functor(arena);
+ functor!(name, [str(h, 0), fixnum(t)], [at_stub])
+ }
+
+ fn arith_instr_bin_functor(
+ h: usize,
+ name: Atom,
+ arena: &mut Arena,
+ at_1: &ArithmeticTerm,
+ at_2: &ArithmeticTerm,
+ t: usize,
+ ) -> MachineStub {
+ let at_1_stub = at_1.into_functor(arena);
+ let at_2_stub = at_2.into_functor(arena);
+
+ functor!(
+ name,
+ [str(h, 0), str(h, 1), fixnum(t)],
+ [at_1_stub, at_2_stub]
+ )
+ }
+
+ pub type Code = Vec<Instruction>;
+ pub type CodeDeque = VecDeque<Instruction>;
+
+ impl Instruction {
+ #[inline]
+ pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec<IndexingLine>> {
+ match self {
+ Instruction::IndexingCode(ref mut indexing_code) => Some(indexing_code),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_indexing_line(&self) -> Option<&Vec<IndexingLine>> {
+ match self {
+ Instruction::IndexingCode(ref indexing_code) => Some(indexing_code),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn is_head_instr(&self) -> bool {
+ match self {
+ Instruction::Deallocate |
+ Instruction::GetConstant(..) |
+ Instruction::GetList(..) |
+ Instruction::GetPartialString(..) |
+ Instruction::GetStructure(..) |
+ Instruction::GetValue(..) |
+ Instruction::UnifyConstant(..) |
+ Instruction::UnifyLocalValue(..) |
+ Instruction::UnifyVariable(..) |
+ Instruction::UnifyValue(..) |
+ Instruction::UnifyVoid(..) |
+ Instruction::GetVariable(..) |
+ Instruction::PutConstant(..) |
+ Instruction::PutList(..) |
+ Instruction::PutPartialString(..) |
+ Instruction::PutStructure(..) |
+ Instruction::PutUnsafeValue(..) |
+ Instruction::PutValue(..) |
+ Instruction::PutVariable(..) |
+ Instruction::SetConstant(..) |
+ Instruction::SetLocalValue(..) |
+ Instruction::SetVariable(..) |
+ Instruction::SetValue(..) |
+ Instruction::SetVoid(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn enqueue_functors(
+ &self,
+ mut h: usize,
+ arena: &mut Arena,
+ functors: &mut Vec<MachineStub>,
+ ) {
+ match self {
+ &Instruction::IndexingCode(ref indexing_instrs) => {
+ for indexing_instr in indexing_instrs {
+ match indexing_instr {
+ IndexingLine::Indexing(indexing_instr) => {
+ let section = indexing_instr.to_functor(h);
+ h += section.len();
+ functors.push(section);
+ }
+ IndexingLine::IndexedChoice(indexed_choice_instrs) => {
+ for indexed_choice_instr in indexed_choice_instrs {
+ let section = indexed_choice_instr.to_functor();
+ h += section.len();
+ functors.push(section);
+ }
+ }
+ IndexingLine::DynamicIndexedChoice(indexed_choice_instrs) => {
+ for indexed_choice_instr in indexed_choice_instrs {
+ let section = functor!(atom!("dynamic"), [fixnum(*indexed_choice_instr)]);
+
+ h += section.len();
+ functors.push(section);
+ }
+ }
+ }
+ }
+ }
+ instr => functors.push(instr.to_functor(h, arena)),
+ }
+ }
+
+ fn to_functor(&self, h: usize, arena: &mut Arena) -> MachineStub {
+ match self {
+ &Instruction::InstallVerifyAttr => {
+ functor!(atom!("install_verify_attr"))
+ }
+ &Instruction::VerifyAttrInterrupt => {
+ functor!(atom!("verify_attr_interrupt"))
+ }
+ &Instruction::DynamicElse(birth, death, next_or_fail) => {
+ match (death, next_or_fail) {
+ (Death::Infinity, NextOrFail::Next(i)) => {
+ functor!(
+ atom!("dynamic_else"),
+ [fixnum(birth), atom(atom!("inf")), fixnum(i)]
+ )
+ }
+ (Death::Infinity, NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_else"),
+ [fixnum(birth), atom(atom!("inf")), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_else"),
+ [fixnum(birth), fixnum(d), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Next(i)) => {
+ functor!(atom!("dynamic_else"), [fixnum(birth), fixnum(d), fixnum(i)])
+ }
+ }
+ }
+ &Instruction::DynamicInternalElse(birth, death, next_or_fail) => {
+ match (death, next_or_fail) {
+ (Death::Infinity, NextOrFail::Next(i)) => {
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), atom(atom!("inf")), fixnum(i)]
+ )
+ }
+ (Death::Infinity, NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), atom(atom!("inf")), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Fail(i)) => {
+ let next_functor = functor!(atom!("fail"), [fixnum(i)]);
+
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), fixnum(d), str(h, 0)],
+ [next_functor]
+ )
+ }
+ (Death::Finite(d), NextOrFail::Next(i)) => {
+ functor!(
+ atom!("dynamic_internal_else"),
+ [fixnum(birth), fixnum(d), fixnum(i)]
+ )
+ }
+ }
+ }
+ &Instruction::TryMeElse(offset) => {
+ functor!(atom!("try_me_else"), [fixnum(offset)])
+ }
+ &Instruction::RetryMeElse(offset) => {
+ functor!(atom!("retry_me_else"), [fixnum(offset)])
+ }
+ &Instruction::TrustMe(offset) => {
+ functor!(atom!("trust_me"), [fixnum(offset)])
+ }
+ &Instruction::DefaultRetryMeElse(offset) => {
+ functor!(atom!("default_retry_me_else"), [fixnum(offset)])
+ }
+ &Instruction::DefaultTrustMe(offset) => {
+ functor!(atom!("default_trust_me"), [fixnum(offset)])
+ }
+ &Instruction::Cut(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("cut"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::GetLevel(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_level"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::GetPrevLevel(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_prev_level"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::GetCutPoint(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_cut_point"), [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::ACosh(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("acosh"), arena, at, t)
+ }
+ &Instruction::ASinh(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("asinh"), arena, at, t)
+ }
+ &Instruction::ATanh(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("atanh"), arena, at, t)
+ }
+ &Instruction::Cosh(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("cosh"), arena, at, t)
+ }
+ &Instruction::Sinh(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("sinh"), arena, at, t)
+ }
+ &Instruction::Tanh(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("tanh"), arena, at, t)
+ }
+ &Instruction::Sqrt(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("sqrt"), arena, at, t)
+ }
+ &Instruction::Log10(ref at, t) => {
+ arith_instr_unary_functor(h, atom!("log10"), 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::FloatFractionalPart(ref at, t) => {
++ arith_instr_unary_functor(h, atom!("float_fractional_part"), arena, at, t)
++ }
++ &Instruction::FloatIntegerPart(ref at, t) => {
++ arith_instr_unary_functor(h, atom!("float_integer_part"), arena, at, t)
++ }
+ &Instruction::Neg(ref at, t) => arith_instr_unary_functor(
+ h,
+ atom!("-"),
+ arena,
+ at,
+ t,
+ ),
+ &Instruction::Plus(ref at, t) => arith_instr_unary_functor(
+ h,
+ atom!("+"),
+ arena,
+ at,
+ t,
+ ),
+ &Instruction::BitwiseComplement(ref at, t) => arith_instr_unary_functor(
+ h,
+ atom!("\\"),
+ arena,
+ at,
+ 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::CallFastCallN(arity) => {
+ functor!(atom!("call_fast_call_n"), [fixnum(arity)])
+ }
+ &Instruction::ExecuteFastCallN(arity) => {
+ functor!(atom!("execute_fast_call_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::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::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::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::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::CallFileCopy |
+ &Instruction::CallWorkingDirectory |
+ &Instruction::CallDeleteDirectory |
+ &Instruction::CallPathCanonical |
+ &Instruction::CallFileTime |
+ &Instruction::CallDynamicModuleResolution(..) |
+ &Instruction::CallPrepareCallClause(..) |
+ &Instruction::CallCompileInlineOrExpandedGoal |
+ &Instruction::CallIsExpandedOrInlined |
+ &Instruction::CallGetClauseP |
+ &Instruction::CallInvokeClauseAtP |
+ &Instruction::CallGetFromAttributedVarList |
+ &Instruction::CallPutToAttributedVarList |
+ &Instruction::CallDeleteFromAttributedVarList |
+ &Instruction::CallDeleteAllAttributesFromVar |
+ &Instruction::CallUnattributedVar |
+ &Instruction::CallGetDBRefs |
+ &Instruction::CallKeySortWithConstantVarOrdering |
+ &Instruction::CallFetchGlobalVar |
+ &Instruction::CallFirstStream |
+ &Instruction::CallFlushOutput |
+ &Instruction::CallGetByte |
+ &Instruction::CallGetChar |
+ &Instruction::CallGetNChars |
+ &Instruction::CallGetCode |
+ &Instruction::CallGetSingleChar |
+ &Instruction::CallTruncateIfNoLiftedHeapGrowthDiff |
+ &Instruction::CallTruncateIfNoLiftedHeapGrowth |
+ &Instruction::CallGetAttributedVariableList |
+ &Instruction::CallGetAttrVarQueueDelimiter |
+ &Instruction::CallGetAttrVarQueueBeyond |
+ &Instruction::CallGetBValue |
+ &Instruction::CallGetContinuationChunk |
+ &Instruction::CallGetNextOpDBRef |
+ &Instruction::CallLookupDBRef |
+ &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::CallFail |
+ &Instruction::CallGetBall |
+ &Instruction::CallGetCurrentBlock |
+ &Instruction::CallGetCurrentSCCBlock |
+ &Instruction::CallGetCutPoint |
+ &Instruction::CallGetDoubleQuotes |
+ &Instruction::CallGetUnknown |
+ &Instruction::CallInstallNewBlock |
+ &Instruction::CallMaybe |
+ &Instruction::CallCpuNow |
+ &Instruction::CallDeterministicLengthRundown |
+ &Instruction::CallHttpOpen |
+ &Instruction::CallHttpListen |
+ &Instruction::CallHttpAccept |
+ &Instruction::CallHttpAnswer |
+ &Instruction::CallLoadForeignLib |
+ &Instruction::CallForeignCall |
+ &Instruction::CallDefineForeignStruct |
+ &Instruction::CallPredicateDefined |
+ &Instruction::CallStripModule |
+ &Instruction::CallCurrentTime |
+ &Instruction::CallQuotedToken |
+ &Instruction::CallReadFromChars |
+ &Instruction::CallReadTermFromChars |
+ &Instruction::CallResetBlock |
+ &Instruction::CallResetSCCBlock |
+ &Instruction::CallReturnFromVerifyAttr |
+ &Instruction::CallSetBall |
+ &Instruction::CallPushBallStack |
+ &Instruction::CallPopBallStack |
+ &Instruction::CallPopFromBallStack |
+ &Instruction::CallSetCutPointByDefault(..) |
+ &Instruction::CallSetDoubleQuotes |
+ &Instruction::CallSetUnknown |
+ &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::CallInlinedInstructions |
+ &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::ExecuteFileCopy |
+ &Instruction::ExecuteWorkingDirectory |
+ &Instruction::ExecuteDeleteDirectory |
+ &Instruction::ExecutePathCanonical |
+ &Instruction::ExecuteFileTime |
+ &Instruction::ExecuteDynamicModuleResolution(..) |
+ &Instruction::ExecutePrepareCallClause(..) |
+ &Instruction::ExecuteCompileInlineOrExpandedGoal |
+ &Instruction::ExecuteIsExpandedOrInlined |
+ &Instruction::ExecuteGetClauseP |
+ &Instruction::ExecuteInvokeClauseAtP |
+ &Instruction::ExecuteGetFromAttributedVarList |
+ &Instruction::ExecutePutToAttributedVarList |
+ &Instruction::ExecuteDeleteFromAttributedVarList |
+ &Instruction::ExecuteDeleteAllAttributesFromVar |
+ &Instruction::ExecuteUnattributedVar |
+ &Instruction::ExecuteGetDBRefs |
+ &Instruction::ExecuteKeySortWithConstantVarOrdering |
+ &Instruction::ExecuteFetchGlobalVar |
+ &Instruction::ExecuteFirstStream |
+ &Instruction::ExecuteFlushOutput |
+ &Instruction::ExecuteGetByte |
+ &Instruction::ExecuteGetChar |
+ &Instruction::ExecuteGetNChars |
+ &Instruction::ExecuteGetCode |
+ &Instruction::ExecuteGetSingleChar |
+ &Instruction::ExecuteTruncateIfNoLiftedHeapGrowthDiff |
+ &Instruction::ExecuteTruncateIfNoLiftedHeapGrowth |
+ &Instruction::ExecuteGetAttributedVariableList |
+ &Instruction::ExecuteGetAttrVarQueueDelimiter |
+ &Instruction::ExecuteGetAttrVarQueueBeyond |
+ &Instruction::ExecuteGetBValue |
+ &Instruction::ExecuteGetContinuationChunk |
+ &Instruction::ExecuteGetNextOpDBRef |
+ &Instruction::ExecuteLookupDBRef |
+ &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::ExecuteFail |
+ &Instruction::ExecuteGetBall |
+ &Instruction::ExecuteGetCurrentBlock |
+ &Instruction::ExecuteGetCurrentSCCBlock |
+ &Instruction::ExecuteGetCutPoint |
+ &Instruction::ExecuteGetDoubleQuotes |
+ &Instruction::ExecuteGetUnknown |
+ &Instruction::ExecuteInstallNewBlock |
+ &Instruction::ExecuteMaybe |
+ &Instruction::ExecuteCpuNow |
+ &Instruction::ExecuteDeterministicLengthRundown |
+ &Instruction::ExecuteHttpOpen |
+ &Instruction::ExecuteHttpListen |
+ &Instruction::ExecuteHttpAccept |
+ &Instruction::ExecuteHttpAnswer |
+ &Instruction::ExecuteLoadForeignLib |
+ &Instruction::ExecuteForeignCall |
+ &Instruction::ExecuteDefineForeignStruct |
+ &Instruction::ExecutePredicateDefined |
+ &Instruction::ExecuteStripModule |
+ &Instruction::ExecuteCurrentTime |
+ &Instruction::ExecuteQuotedToken |
+ &Instruction::ExecuteReadFromChars |
+ &Instruction::ExecuteReadTermFromChars |
+ &Instruction::ExecuteResetBlock |
+ &Instruction::ExecuteResetSCCBlock |
+ &Instruction::ExecuteReturnFromVerifyAttr |
+ &Instruction::ExecuteSetBall |
+ &Instruction::ExecutePushBallStack |
+ &Instruction::ExecutePopBallStack |
+ &Instruction::ExecutePopFromBallStack |
+ &Instruction::ExecuteSetCutPointByDefault(_) |
+ &Instruction::ExecuteSetDoubleQuotes |
+ &Instruction::ExecuteSetUnknown |
+ &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::ExecuteInlinedInstructions |
+ &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::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(lvl, name, arity, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("get_structure"),
+ [str(h, 0), atom(name), fixnum(arity), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::GetValue(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_value"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::GetVariable(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("get_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::UnifyConstant(c) => {
+ functor!(atom!("unify_constant"), [cell(c)])
+ }
+ &Instruction::UnifyLocalValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("unify_local_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::UnifyVariable(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("unify_variable"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::UnifyValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("unify_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::UnifyVoid(vars) => {
+ functor!(atom!("unify_void"), [fixnum(vars)])
+ }
+ &Instruction::PutUnsafeValue(norm, arg) => {
+ functor!(atom!("put_unsafe_value"), [fixnum(norm), fixnum(arg)])
+ }
+ &Instruction::PutConstant(lvl, c, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_constant"),
+ [str(h, 0), cell(c), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::PutList(lvl, r) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_list"),
+ [str(h, 0), str(h, 1)],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::PutPartialString(lvl, s, r, has_tail) => {
+ let lvl_stub = lvl.into_functor();
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_partial_string"),
+ [
+ str(h, 0),
+ string(h, s),
+ str(h, 1),
+ boolean(has_tail)
+ ],
+ [lvl_stub, rt_stub]
+ )
+ }
+ &Instruction::PutStructure(name, arity, r) => {
+ let rt_stub = reg_type_into_functor(r);
+
+ functor!(
+ atom!("put_structure"),
+ [atom(name), fixnum(arity), str(h, 0)],
+ [rt_stub]
+ )
+ }
+ &Instruction::PutValue(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("put_value"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::PutVariable(r, arg) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("put_variable"), [str(h, 0), fixnum(arg)], [rt_stub])
+ }
+ &Instruction::SetConstant(c) => {
+ functor!(atom!("set_constant"), [cell(c)])
+ }
+ &Instruction::SetLocalValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("set_local_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::SetVariable(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("set_variable"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::SetValue(r) => {
+ let rt_stub = reg_type_into_functor(r);
+ functor!(atom!("set_value"), [str(h, 0)], [rt_stub])
+ }
+ &Instruction::SetVoid(vars) => {
+ functor!(atom!("set_void"), [fixnum(vars)])
+ }
+ &Instruction::BreakFromDispatchLoop => {
+ functor!(atom!("$break_from_dispatch_loop"))
+ }
+ }
+ }
+ }
+ }
+}
+
+pub fn generate_instructions_rs() -> TokenStream {
+ let input = InstructionTemplate::to_derive_input();
+ let mut instr_data = InstructionData::new();
+
+ instr_data.generate_instruction_enum_loop(input);
+
+ let instr_variants: Vec<_> = instr_data.instr_variants
+ .iter()
+ .cloned()
+ .map(|(_, _, _, variant)| variant)
+ .collect();
+
+ fn attributeless_enum<T: ToDeriveInput>() -> Vec<Variant> {
+ if let Data::Enum(DataEnum { mut variants, .. }) = T::to_derive_input().data {
+ for variant in &mut variants {
+ variant.attrs.clear();
+ }
+
+ variants.into_iter().collect()
+ } else {
+ unreachable!()
+ }
+ }
+
+ let clause_type_variants = attributeless_enum::<ClauseType>();
+ let builtin_type_variants = attributeless_enum::<BuiltInClauseType>();
+ let inlined_type_variants = attributeless_enum::<InlinedClauseType>();
+ let system_clause_type_variants = attributeless_enum::<SystemClauseType>();
+ let repl_code_ptr_variants = attributeless_enum::<REPLCodePtr>();
+ let compare_number_variants = attributeless_enum::<CompareNumber>();
+ let compare_term_variants = attributeless_enum::<CompareTerm>();
+
+ let mut clause_type_from_name_and_arity_arms = vec![];
+ let mut clause_type_to_instr_arms = vec![];
+ let mut clause_type_name_arms = vec![];
+ let mut is_inbuilt_arms = vec![];
+ let mut is_inlined_arms = vec![];
+
+ is_inbuilt_arms.push(quote! {
+ (atom!(":-"), 1 | 2) => true
+ });
+
+ 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),*)
+ }
+ );
+
+ is_inbuilt_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+
+ is_inlined_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+ }
+
+ 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
+ }
+ );
+
+ is_inbuilt_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+ }
+
+ 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),*)
+ }
+ } else {
+ quote! {
+ ClauseType::BuiltIn(
+ BuiltInClauseType::#ident
+ ) => Instruction::#instr_ident
+ }
+ });
+
+ is_inbuilt_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+ }
+
+ for (name, arity, variant) in instr_data.inlined_type_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ if field.ty.type_id() == TypeId::of::<usize>() {
+ quote! { #arity }
+ } else {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::Inlined(
+ InlinedClauseType::#ident(#(#variant_fields),*)
+ )
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::Inlined(
+ InlinedClauseType::#ident
+ )
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::#ident(..)
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::#ident
+ ) => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(
+ quote! {
+ ClauseType::Inlined(
+ InlinedClauseType::#ident(#(#placeholder_ids),*)
+ ) => Instruction::#instr_ident(*#(#placeholder_ids),*)
+ }
+ );
+
+ is_inbuilt_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+
+ is_inlined_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+ }
+
+ 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 if ident.to_string() == "InlineCallN" {
+ quote! {
+ (atom!(#name), arity) => ClauseType::System(
+ SystemClauseType::#ident(arity)
+ )
+ }
+ } 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),*)
+ }
+ } else {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::#ident
+ ) => Instruction::#instr_ident
+ }
+ });
+
+ is_inbuilt_arms.push(
+ if let Arity::Ident("arity") = &arity {
+ quote! {
+ (atom!(#name), _arity) => true
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ }
+ );
+ }
+
+ for (name, arity, variant) in instr_data.repl_code_ptr_variants {
+ let ident = variant.ident.clone();
+
+ let variant_fields: Vec<_> = variant.fields
+ .into_iter()
+ .map(|field| {
+ if field.ty.type_id() == TypeId::of::<usize>() {
+ quote! { #arity }
+ } else {
+ let ty = field.ty;
+ quote! { #ty::default() }
+ }
+ })
+ .collect();
+
+ clause_type_from_name_and_arity_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident(#(#variant_fields),*)
+ ))
+ }
+ } else {
+ quote! {
+ (atom!(#name), #arity) => ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident
+ ))
+ }
+ });
+
+ clause_type_name_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::REPL(REPLCodePtr::#ident(..))
+ ) => atom!(#name)
+ }
+ } else {
+ quote! {
+ ClauseType::System(
+ SystemClauseType::REPL(REPLCodePtr::#ident)
+ ) => atom!(#name)
+ }
+ });
+
+ let ident = variant.ident;
+ let instr_ident = format_ident!("Call{}", ident);
+
+ let placeholder_ids: Vec<_> = (0 .. variant_fields.len())
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ clause_type_to_instr_arms.push(if !variant_fields.is_empty() {
+ quote! {
+ ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident(#(#placeholder_ids),*)
+ )) => Instruction::#instr_ident(#(*#placeholder_ids),*)
+ }
+ } else {
+ quote! {
+ ClauseType::System(SystemClauseType::REPL(
+ REPLCodePtr::#ident
+ )) => Instruction::#instr_ident
+ }
+ });
+
+ is_inbuilt_arms.push(
+ quote! {
+ (atom!(#name), #arity) => true
+ }
+ );
+ }
+
+ 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(arena))
+ });
+
+ clause_type_to_instr_arms.push(quote! {
+ ClauseType::Named(arity, name, idx) => Instruction::CallNamed(*arity, *name, *idx)
+ });
+
+ 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),*)
+ }
+ } else {
+ quote! {
+ ClauseType::#ident => Instruction::#ident
+ }
+ });
+
+ is_inbuilt_arms.push(
+ quote! {
+ (atom!(#name), _arity) => true
+ }
+ );
+ }
+
+ 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 {
+ 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 {
+ 0
+ };
+
+ let placeholder_ids: Vec<_> = (0 .. enum_arity)
+ .map(|n| format_ident!("f_{}", n))
+ .collect();
+
+ Some(if enum_arity == 0 {
+ quote! {
+ Instruction::#variant_ident =>
+ Instruction::#def_variant_ident
+ }
+ } else {
+ quote! {
+ Instruction::#variant_ident(#(#placeholder_ids),*) =>
+ Instruction::#def_variant_ident(#(#placeholder_ids),*)
+ }
+ })
+ } else {
+ None
+ }
+ })
+ .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 enum_arity = if let Fields::Unnamed(fields) = &variant.fields {
+ fields.unnamed.len()
+ } else {
+ 0
+ };
+
+ let variant_ident = variant.ident.clone();
+
+ Some(if enum_arity == 0 {
+ quote! {
+ Instruction::#variant_ident => true
+ }
+ } else {
+ 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") {
+ if arity == 0 {
+ quote! {
+ (#name, execute) => {
+ Instruction::#variant_ident
+ }
+ }
+ } else {
+ quote! {
+ (#name, execute, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ }
+ } else if variant_string.starts_with("Call") {
+ if arity == 0 {
+ quote! {
+ (#name) => {
+ Instruction::#variant_ident
+ }
+ }
+ } else {
+ quote! {
+ (#name, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ }
+ } else if variant_string.starts_with("DefaultExecute") {
+ if arity == 0 {
+ quote! {
+ (#name, execute, default) => {
+ Instruction::#variant_ident
+ }
+ }
+ } else {
+ quote! {
+ (#name, execute, default, $($args:expr),*) => {
+ Instruction::#variant_ident($($args),*)
+ }
+ }
+ }
+ } else if variant_string.starts_with("DefaultCall") {
+ if arity == 0 {
+ quote! {
+ (#name, default) => {
+ Instruction::#variant_ident
+ }
+ }
+ } else {
+ 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, arena: &mut Arena) -> 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_inbuilt(name: Atom, arity: usize) -> bool {
+ match (name, arity) {
+ #(
+ #is_inbuilt_arms,
+ )*
+ _ => false,
+ }
+ }
+
+ pub fn name(&self) -> Atom {
+ match self {
+ #(
+ #clause_type_name_arms,
+ )*
+ }
+ }
+
+ pub fn is_inlined(name: Atom, arity: usize) -> bool {
+ match (name, arity) {
+ #(
+ #is_inlined_arms,
+ )*
+ _ => false,
+ }
+ }
+ }
+
+ #[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 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
+ );*
+ }
+
+ pub use _instr as instr; // https://github.com/rust-lang/rust/pull/52234#issuecomment-976702997
+ }
+}
+
+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 {
+ variant.ident = id;
+ variant.attrs.clear();
+
+ variant
+}
+
+fn prop_from_ident<DiscriminantT>(id: &Ident, key: &'static str) -> &'static str
+ where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug
+{
+ let disc = match DiscriminantT::from_str(id.to_string().as_str()) {
+ Ok(disc) => disc,
+ Err(_) => {
+ panic!("can't generate discriminant {}", id);
+ }
+ };
+
+ match disc.get_str(key) {
+ Some(prop) => prop,
+ None => {
+ panic!("can't find property {} of discriminant {:?}", key, disc);
+ }
+ }
+}
+
+#[derive(Clone, Copy)]
+enum Arity {
+ Static(usize),
+ Ident(&'static str)
+}
+
+impl From<&'static str> for Arity {
+ fn from(arity: &'static str) -> Self {
+ usize::from_str_radix(&arity, 10)
+ .map(Arity::Static)
+ .unwrap_or_else(|_| Arity::Ident(arity))
+ }
+}
+
+#[derive(Clone, Copy)]
+enum CountableInference {
+ HasDefault,
+ NotCounted,
+}
+
+struct InstructionData {
+ instr_variants: Vec<(&'static str, Arity, CountableInference, Variant)>,
+ clause_type_variants: Vec<(&'static str, Arity, Variant)>,
+ builtin_type_variants: Vec<(&'static str, Arity, Variant)>,
+ inlined_type_variants: Vec<(&'static str, Arity, Variant)>,
+ system_clause_type_variants: Vec<(&'static str, Arity, Variant)>,
+ compare_number_variants: Vec<(&'static str, Arity, Variant)>,
+ compare_term_variants: Vec<(&'static str, Arity, Variant)>,
+ repl_code_ptr_variants: Vec<(&'static str, Arity, Variant)>,
+}
+
+impl InstructionData {
+ fn new() -> Self {
+ Self {
+ instr_variants: vec![],
+ clause_type_variants: vec![],
+ builtin_type_variants: vec![],
+ inlined_type_variants: vec![],
+ system_clause_type_variants: vec![],
+ compare_number_variants: vec![],
+ compare_term_variants: vec![],
+ repl_code_ptr_variants: vec![],
+ }
+ }
+
+ fn label_variant(&mut self, id: &Ident, prefix: &'static str, variant: Variant) {
+ let (name, arity, countable_inference) = if id == "CompareNumber" {
+ let (name, arity) = add_discriminant_data::<CompareNumberDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.compare_number_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else if id == "CompareTerm" {
+ let (name, arity) = add_discriminant_data::<CompareTermDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.compare_term_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else if id == "BuiltInClauseType" {
+ let (name, arity) = add_discriminant_data::<BuiltInClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.builtin_type_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else if id == "InlinedClauseType" {
+ let (name, arity) = add_discriminant_data::<InlinedClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.inlined_type_variants,
+ );
+
+ (name, arity, CountableInference::NotCounted)
+ } else if id == "REPLCodePtr" {
+ let (name, arity) = add_discriminant_data::<REPLCodePtrDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.repl_code_ptr_variants,
+ );
+
+ (name, arity, CountableInference::NotCounted)
+ } else if id == "SystemClauseType" {
+ let (name, arity) = add_discriminant_data::<SystemClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.system_clause_type_variants,
+ );
+
+ (name, arity, CountableInference::NotCounted)
+ } else if id == "InstructionTemplate" {
+ ( prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Name"),
+ Arity::from(prop_from_ident::<InstructionTemplateDiscriminants>(&variant.ident, "Arity")),
+ CountableInference::NotCounted
+ )
+ } else if id == "ClauseType" {
+ let (name, arity) = add_discriminant_data::<ClauseTypeDiscriminants>(
+ &variant,
+ prefix,
+ &mut self.clause_type_variants,
+ );
+
+ (name, arity, CountableInference::HasDefault)
+ } else {
+ panic!("type ID is: {}", id);
+ };
+
+ let v_string = variant.ident.to_string();
+
+ let v_ident = if v_string.starts_with("Call") {
+ format_ident!("{}", v_string["Call".len() ..])
+ } else {
+ variant.ident.clone()
+ };
+
+ let generated_variant = create_instr_variant(
+ format_ident!("{}{}", prefix, v_ident),
+ variant.clone(),
+ );
+
+ self.instr_variants.push(
+ (name, arity, countable_inference, generated_variant)
+ );
+ }
+
+ fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) {
+ if let Data::Enum(DataEnum { variants, .. }) = input.data {
+ for mut variant in variants {
+ if let Some(field) = variant.fields.iter().next() {
+ if let Some(input) = derive_input(&field.ty) {
+ self.generate_instruction_enum_loop(input);
+ continue;
+ }
+ }
+
+ if input.ident == "InstructionTemplate" {
+ variant.attrs.clear();
+ self.label_variant(&input.ident, "", variant);
+ continue;
+ }
+
+ self.label_variant(&input.ident, "Call", variant.clone());
+ self.label_variant(&input.ident, "Execute", variant.clone());
+
+ if input.ident == "BuiltInClauseType" ||
+ input.ident == "CompareNumber" ||
+ input.ident == "CompareTerm" ||
+ input.ident == "ClauseType"
+ {
+ self.label_variant(&input.ident, "DefaultCall", variant.clone());
+ self.label_variant(&input.ident, "DefaultExecute", variant);
+ }
+ }
+ } else {
+ panic!("{} must be an enum!", input.ident);
+ }
+ }
+}
}
fn get_unary_instr(
- name: ClauseName,
+ &self,
+ name: Atom,
a1: ArithmeticTerm,
t: usize,
- ) -> Result<ArithmeticInstruction, ArithmeticError> {
- match name.as_str() {
- "abs" => Ok(ArithmeticInstruction::Abs(a1, t)),
- "-" => Ok(ArithmeticInstruction::Neg(a1, t)),
- "+" => Ok(ArithmeticInstruction::Plus(a1, t)),
- "cos" => Ok(ArithmeticInstruction::Cos(a1, t)),
- "sin" => Ok(ArithmeticInstruction::Sin(a1, t)),
- "tan" => Ok(ArithmeticInstruction::Tan(a1, t)),
- "log" => Ok(ArithmeticInstruction::Log(a1, t)),
- "exp" => Ok(ArithmeticInstruction::Exp(a1, t)),
- "sqrt" => Ok(ArithmeticInstruction::Sqrt(a1, t)),
- "acos" => Ok(ArithmeticInstruction::ACos(a1, t)),
- "asin" => Ok(ArithmeticInstruction::ASin(a1, t)),
- "atan" => Ok(ArithmeticInstruction::ATan(a1, t)),
- "float" => Ok(ArithmeticInstruction::Float(a1, t)),
- "truncate" => Ok(ArithmeticInstruction::Truncate(a1, t)),
- "round" => Ok(ArithmeticInstruction::Round(a1, t)),
- "ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
- "floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
- "float_integer_part" => Ok(ArithmeticInstruction::FloatIntegerPart(a1, t)),
- "float_fractional_part" => Ok(ArithmeticInstruction::FloatFractionalPart(a1, t)),
- "sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
- "\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
- _ => Err(ArithmeticError::NonEvaluableFunctor(
- Constant::Atom(name, None),
- 1,
- )),
+ ) -> Result<Instruction, ArithmeticError> {
+ match name {
+ atom!("abs") => Ok(Instruction::Abs(a1, t)),
+ atom!("-") => Ok(Instruction::Neg(a1, t)),
+ atom!("+") => Ok(Instruction::Plus(a1, t)),
+ atom!("cos") => Ok(Instruction::Cos(a1, t)),
+ atom!("sin") => Ok(Instruction::Sin(a1, t)),
+ atom!("tan") => Ok(Instruction::Tan(a1, t)),
+ atom!("log") => Ok(Instruction::Log(a1, t)),
+ atom!("asinh") => Ok(Instruction::ASinh(a1, t)),
+ atom!("acosh") => Ok(Instruction::ACosh(a1, t)),
+ atom!("atanh") => Ok(Instruction::ATanh(a1, t)),
+ atom!("sinh") => Ok(Instruction::Sinh(a1, t)),
+ atom!("cosh") => Ok(Instruction::Cosh(a1, t)),
+ atom!("tanh") => Ok(Instruction::Tanh(a1, t)),
+ atom!("log10") => Ok(Instruction::Log10(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!("float_integer_part") => Ok(Instruction::FloatIntegerPart(a1, t)),
++ atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)),
+ atom!("sign") => Ok(Instruction::Sign(a1, t)),
+ atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
+ _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
}
}
))
}
}
+ (Number::Fixnum(_), n2) | (Number::Integer(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- pub(crate) fn float_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let f1 = result_f(&n1, rnd_f);
- let f2 = result_f(&n2, rnd_f);
+pub(crate) fn int_floor_div(
+ n1: Number,
+ n2: Number,
+ arena: &mut Arena,
+) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let div_atom = atom!("div");
+ functor_stub(div_atom, 2)
+ };
- let stub = MachineError::functor_stub(clause_name!("(**)"), 2);
+ let modulus = modulus(n1, n2, arena)?;
+ let n1 = try_numeric_result!(sub(n1, modulus, arena), stub_gen)?;
- let f1 = try_numeric_result!(self, f1, stub)?;
- let f2 = try_numeric_result!(self, f2, stub)?;
+ idiv(n1, n2, arena)
+}
- let result = result_f(&Number::Float(OrderedFloat(f1.powf(f2))), rnd_f);
+pub(crate) fn shr(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let shr_atom = atom!(">>");
+ functor_stub(shr_atom, 2)
+ };
- Ok(Number::Float(OrderedFloat(try_numeric_result!(
- self, result, stub
- )?)))
+ if n2.is_integer() && n2.is_negative() {
+ return shl(n1, neg(n2, arena), arena);
}
- pub(crate) fn pow(
- &self,
- n1: Number,
- n2: Number,
- culprit: &'static str,
- ) -> Result<Number, MachineStub> {
- if n2.is_negative() && n1.is_zero() {
- let stub = MachineError::functor_stub(clause_name!(culprit), 2);
- return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num();
+ let n2_i = n2.get_num();
+
+ let n1 = Integer::from(n1_i);
+
+ if let Ok(n2) = usize::try_from(n2_i) {
+ return Ok(Number::arena_from(n1 >> n2, arena));
+ } else {
+ return Ok(Number::arena_from(n1 >> usize::max_value(), arena));
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+
+ match n2.to_usize() {
+ Some(n2) => Ok(Number::arena_from(n1 >> n2, arena)),
+ _ => {
+ Ok(Number::arena_from(n1 >> usize::max_value(), arena))
+ },
+ }
}
+ (Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
+ Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
+ _ => {
+ Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()),arena))
+ },
+ },
+ (Number::Integer(n1), Number::Integer(n2)) => match n2.to_usize() {
+ Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 >> n2), arena)),
+ _ => {
+ Ok(Number::arena_from(Integer::from(&*n1 >> usize::max_value()), arena))
+ },
+ },
+ (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
+ }
+}
- self.float_pow(n1, n2)
+pub(crate) fn shl(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let shl_atom = atom!("<<");
+ functor_stub(shl_atom, 2)
+ };
+
+ if n2.is_integer() && n2.is_negative() {
+ return shr(n1, neg(n2, arena), arena);
}
- #[inline]
- pub(crate) fn unary_float_fn_template<FloatFn>(
- &self,
- n1: Number,
- f: FloatFn,
- ) -> Result<f64, MachineStub>
- where
- FloatFn: Fn(f64) -> f64,
- {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num();
+ let n2_i = n2.get_num();
- let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
- let f1 = result_f(&Number::Float(OrderedFloat(f(f1))), rnd_f);
+ let n1 = Integer::from(n1_i);
- try_numeric_result!(self, f1, stub)
+ if let Ok(n2) = usize::try_from(n2_i) {
+ return Ok(Number::arena_from(n1 << n2, arena));
+ } else {
+ return Ok(Number::arena_from(n1 << usize::max_value(), arena));
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+
+ match n2.to_u32() {
+ Some(n2) => Ok(Number::arena_from(n1 << n2, arena)),
+ _ => {
+ Ok(Number::arena_from(n1 << usize::max_value(), arena))
+ }
+ }
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => match usize::try_from(n2.get_num()) {
+ Ok(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
+ _ => {
+ Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena))
+ }
+ },
+ (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
+ Some(n2) => Ok(Number::arena_from(Integer::from(&*n1 << n2), arena)),
+ _ => {
+ Ok(Number::arena_from(Integer::from(&*n1 << usize::max_value()),arena))
+ }
+ },
+ (Number::Integer(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (Number::Fixnum(_), n2) => Err(numerical_type_error(ValidType::Integer, n2, stub_gen)),
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn sin(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.sin())
- }
+pub(crate) fn and(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let and_atom = atom!("/\\");
+ functor_stub(and_atom, 2)
+ };
- #[inline]
- pub(crate) fn cos(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.cos())
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ Ok(Number::arena_from(n1.get_num() & n2.get_num(), arena))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 & &*n2, arena))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from(
+ &*n1 & Integer::from(n2.get_num()),
+ arena,
+ )),
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1 & &*n2), arena))
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn tan(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.tan())
- }
+pub(crate) fn or(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let or_atom = atom!("\\/");
+ functor_stub(or_atom, 2)
+ };
- #[inline]
- pub(crate) fn log(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.log(f64::consts::E))
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ Ok(Number::arena_from(n1.get_num() | n2.get_num(), arena))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 | &*n2, arena))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from(
+ &*n1 | Integer::from(n2.get_num()),
+ arena,
+ )),
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1 | &*n2), arena))
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn exp(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.exp())
- }
+pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let xor_atom = atom!("xor");
+ functor_stub(xor_atom, 2)
+ };
- #[inline]
- pub(crate) fn asin(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.asin())
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ Ok(Number::arena_from(n1.get_num() ^ n2.get_num(), arena))
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 ^ &*n2, arena))
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::arena_from(
+ &*n1 ^ Integer::from(n2.get_num()),
+ arena,
+ )),
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(&*n1 ^ &*n2), arena))
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, Number::Integer(_)) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
+ _ => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn acos(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.acos())
- }
+pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let mod_atom = atom!("mod");
+ functor_stub(mod_atom, 2)
+ };
- #[inline]
- pub(crate) fn atan(&self, n1: Number) -> Result<f64, MachineStub> {
- self.unary_float_fn_template(n1, |f| f.atan())
- }
+ match (x, y) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
- #[inline]
- pub(crate) fn sqrt(&self, n1: Number) -> Result<f64, MachineStub> {
- if n1.is_negative() {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
- return Err(self.error_form(MachineError::evaluation_error(EvalError::Undefined), stub));
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1_i = n1.get_num();
+ Ok(Number::arena_from(n1_i.rem_floor(n2_i), arena))
+ }
}
-
- self.unary_float_fn_template(n1, |f| f.sqrt())
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1,
+ arena,
+ ))
+ }
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
+
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n2 = Integer::from(n2_i);
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1,
+ arena,
+ ))
+ }
+ }
+ (Number::Integer(x), Number::Integer(y)) => {
+ if &*y == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(
+ <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1,
+ arena,
+ ))
+ }
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn float(&self, n: Number) -> Result<f64, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
- try_numeric_result!(self, result_f(&n, rnd_f), stub)
+pub(crate) fn remainder(x: Number, y: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let rem_atom = atom!("rem");
+ functor_stub(rem_atom, 2)
+ };
+
+ match (x, y) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
+
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1_i = n1.get_num();
+ Ok(Number::arena_from(n1_i % n2_i, arena))
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(n1 % &*n2, arena))
+ }
+ }
+ (Number::Integer(n1), Number::Fixnum(n2)) => {
+ let n2_i = n2.get_num();
+
+ if n2_i == 0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ let n2 = Integer::from(n2_i);
+ Ok(Number::arena_from(&*n1 % n2, arena))
+ }
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ if &*n2 == &0 {
+ Err(zero_divisor_eval_error(stub_gen))
+ } else {
+ Ok(Number::arena_from(Integer::from(&*n1 % &*n2), arena))
+ }
+ }
+ (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => {
+ Err(numerical_type_error(ValidType::Integer, n2, stub_gen))
+ }
+ (n1, _) => Err(numerical_type_error(ValidType::Integer, n1, stub_gen)),
}
+}
- #[inline]
- pub(crate) fn floor(&self, n1: Number) -> Number {
- rnd_i(&n1).to_owned()
+pub(crate) fn gcd(n1: Number, n2: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let gcd_atom = atom!("gcd");
+ functor_stub(gcd_atom, 2)
+ };
+
+ match (n1, n2) {
+ (Number::Fixnum(n1), Number::Fixnum(n2)) => {
+ let n1_i = n1.get_num() as isize;
+ let n2_i = n2.get_num() as isize;
+
+ if let Some(result) = isize_gcd(n1_i, n2_i) {
+ Ok(Number::arena_from(result, arena))
+ } else {
+ Ok(Number::arena_from(
+ Integer::from(n1_i).gcd(&Integer::from(n2_i)),
+ arena,
+ ))
+ }
+ }
+ (Number::Fixnum(n1), Number::Integer(n2)) | (Number::Integer(n2), Number::Fixnum(n1)) => {
+ let n1 = Integer::from(n1.get_num());
+ Ok(Number::arena_from(Integer::from(n2.gcd_ref(&n1)), arena))
+ }
+ (Number::Integer(n1), Number::Integer(n2)) => {
+ Ok(Number::arena_from(Integer::from(n1.gcd_ref(&n2)), arena))
+ }
+ (Number::Float(f), _) | (_, Number::Float(f)) => {
+ let n = Number::Float(f);
+ Err(numerical_type_error(ValidType::Integer, n, stub_gen))
+ }
+ (Number::Rational(r), _) | (_, Number::Rational(r)) => {
+ let n = Number::Rational(r);
+ Err(numerical_type_error(ValidType::Integer, n, stub_gen))
+ }
}
+}
- #[inline]
- pub(crate) fn ceiling(&self, n1: Number) -> Number {
- -self.floor(-n1)
+pub(crate) fn atan2(n1: Number, n2: Number) -> Result<f64, MachineStubGen> {
+ if n1.is_zero() && n2.is_zero() {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
+
+ Err(undefined_eval_error(stub_gen))
+ } else {
+ let f1 = float(n1)?;
+ let f2 = float(n2)?;
+
+ unary_float_fn_template(Number::Float(OrderedFloat(f1)), |f| f.atan2(f2))
}
+}
- #[inline]
- pub(crate) fn truncate(&self, n: Number) -> Number {
- if n.is_negative() {
- -self.floor(n.abs())
- } else {
- self.floor(n)
- }
+#[inline]
+pub(crate) fn sin(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.sin())
+}
+
+#[inline]
+pub(crate) fn cos(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.cos())
+}
+
+#[inline]
+pub(crate) fn tan(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.tan())
+}
+
+#[inline]
+pub(crate) fn log(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.log(f64::consts::E))
+}
+
+#[inline]
+pub(crate) fn exp(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.exp())
+}
+
+#[inline]
+pub(crate) fn asin(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.asin())
+}
+
+#[inline]
+pub(crate) fn acos(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.acos())
+}
+
+#[inline]
+pub(crate) fn atan(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.atan())
+}
+
+#[inline]
+pub(crate) fn asinh(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.asinh())
+}
+
+#[inline]
+pub(crate) fn acosh(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.acosh())
+}
+
+#[inline]
+pub(crate) fn atanh(n1: Number) -> Result<f64, MachineStubGen> {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
+
+ let f1 = try_numeric_result!(result_f(&n1), stub_gen)?;
+
+ try_numeric_result!(if f1 == 1.0 || f1 == -1.0 {
+ Err(EvalError::Undefined)
+ } else {
+ result_f(&Number::Float(OrderedFloat(f1.atanh())))
+ },
+ stub_gen)
+}
+
+#[inline]
+pub(crate) fn sinh(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.sinh())
+}
+
+#[inline]
+pub(crate) fn cosh(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.cosh())
+}
+
+#[inline]
+pub(crate) fn tanh(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.tanh())
+}
+
+#[inline]
+pub(crate) fn log10(n1: Number) -> Result<f64, MachineStubGen> {
+ unary_float_fn_template(n1, |f| f.log(10f64))
+}
+
++#[inline]
++pub(crate) fn float_fractional_part(n1: Number) -> Result<f64, MachineStubGen> {
++ unary_float_fn_template(n1, |f| f.fract())
++}
++
++#[inline]
++pub(crate) fn float_integer_part(n1: Number) -> Result<f64, MachineStubGen> {
++ unary_float_fn_template(n1, |f| f.trunc())
++}
++
+#[inline]
+pub(crate) fn sqrt(n1: Number) -> Result<f64, MachineStubGen> {
+ if n1.is_negative() {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
+
+ return Err(undefined_eval_error(stub_gen));
}
- pub(crate) fn round(&self, n: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("is"), 2);
+ unary_float_fn_template(n1, |f| f.sqrt())
+}
+
+#[inline]
+pub(crate) fn floor(n1: Number, arena: &mut Arena) -> Number {
+ rnd_i(&n1, arena)
+}
+
+
- let result = n + Number::Float(OrderedFloat(0.5f64));
- let result = try_numeric_result!(self, result, stub)?;
+#[inline]
+pub(crate) fn ceiling(n1: Number, arena: &mut Arena) -> Number {
+ let n1 = neg(n1, arena);
+ let n1 = floor(n1, arena);
+
+ neg(n1, arena)
+}
- Ok(self.floor(result))
+#[inline]
+pub(crate) fn truncate(n: Number, arena: &mut Arena) -> Number {
+ if n.is_negative() {
+ let n = abs(n, arena);
+ let n = floor(n, arena);
+
+ neg(n, arena)
+ } else {
+ floor(n, arena)
}
+}
- pub(crate) fn shr(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(>>)"), 2);
+pub(crate) fn round(n: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ let stub_gen = || {
+ let is_atom = atom!("is");
+ functor_stub(is_atom, 2)
+ };
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- let n1 = Integer::from(n1);
+ let result = add(n, Number::Float(OrderedFloat(0.5f64)), arena);
+ let result = try_numeric_result!(result, stub_gen)?;
- if let Ok(n2) = u32::try_from(n2) {
- return Ok(Number::from(n1 >> n2));
- } else {
- return Ok(Number::from(n1 >> u32::max_value()));
- }
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
+ Ok(floor(result, arena))
+}
- match n2.to_u32() {
- Some(n2) => Ok(Number::from(n1 >> n2)),
- _ => Ok(Number::from(n1 >> u32::max_value())),
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) {
- Ok(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))),
- _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))),
- },
- (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
- Some(n2) => Ok(Number::from(Integer::from(&*n1 >> n2))),
- _ => Ok(Number::from(Integer::from(&*n1 >> u32::max_value()))),
- },
- (Number::Integer(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
- }
-
- pub(crate) fn shl(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(<<)"), 2);
-
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- let n1 = Integer::from(n1);
-
- if let Ok(n2) = u32::try_from(n2) {
- return Ok(Number::from(n1 << n2));
- } else {
- return Ok(Number::from(n1 << u32::max_value()));
- }
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
+pub(crate) fn bitwise_complement(n1: Number, arena: &mut Arena) -> Result<Number, MachineStubGen> {
+ match n1 {
+ Number::Fixnum(n) => Ok(Number::Fixnum(Fixnum::build_with(!n.get_num()))),
+ Number::Integer(n1) => Ok(Number::arena_from(Integer::from(!&*n1), arena)),
+ _ => {
+ let stub_gen = || {
+ let bitwise_atom = atom!("\\");
+ functor_stub(bitwise_atom, 2)
+ };
+
+ Err(numerical_type_error(ValidType::Integer, n1, stub_gen))
+ }
+ }
+}
- match n2.to_u32() {
- Some(n2) => Ok(Number::from(n1 << n2)),
- _ => Ok(Number::from(n1 << u32::max_value())),
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => match u32::try_from(n2) {
- Ok(n2) => Ok(Number::from(Integer::from(&*n1 << n2))),
- _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))),
- },
- (Number::Integer(n1), Number::Integer(n2)) => match n2.to_u32() {
- Some(n2) => Ok(Number::from(Integer::from(&*n1 << n2))),
- _ => Ok(Number::from(Integer::from(&*n1 << u32::max_value()))),
- },
- (Number::Integer(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
- }
-
- pub(crate) fn bitwise_complement(&self, n1: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(\\)"), 2);
-
- match n1 {
- Number::Fixnum(n) => Ok(Number::Fixnum(!n)),
- Number::Integer(n1) => Ok(Number::from(Integer::from(!&*n1))),
- _ => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
- }
-
- pub(crate) fn xor(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(xor)"), 2);
-
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 ^ n2)),
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 ^ &*n2))
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 ^ Integer::from(n2))),
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(&*n1 ^ &*n2)))
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
- }
-
- pub(crate) fn and(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(/\\)"), 2);
-
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 & n2)),
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 & &*n2))
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 & Integer::from(n2))),
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(&*n1 & &*n2)))
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
- }
-
- pub(crate) fn or(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(\\/)"), 2);
-
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => Ok(Number::from(n1 | n2)),
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- let n1 = Integer::from(n1);
- Ok(Number::from(n1 | &*n2))
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => Ok(Number::from(&*n1 | Integer::from(n2))),
- (Number::Integer(n1), Number::Integer(n2)) => {
- Ok(Number::from(Integer::from(&*n1 | &*n2)))
- }
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
- }
- }
-
- pub(crate) fn modulus(&self, x: Number, y: Number) -> Result<Number, MachineStub> {
- let stub = MachineError::functor_stub(clause_name!("(mod)"), 2);
+impl MachineState {
+ #[inline]
+ pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result<Number, MachineStub> {
+ match at {
+ &ArithmeticTerm::Reg(r) => {
+ let value = self.store(self.deref(self[r]));
- match (x, y) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(n1.rem_floor(n2)))
- }
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 == &0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- let n1 = Integer::from(n1);
- Ok(Number::from(
- <(Integer, Integer)>::from(n1.div_rem_floor_ref(&*n2)).1,
- ))
+ match Number::try_from(value) {
+ Ok(n) => Ok(n),
+ Err(_) => self.arith_eval_by_metacall(value),
}
}
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if n2 == 0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- let n2 = Integer::from(n2);
- Ok(Number::from(
- <(Integer, Integer)>::from(n1.div_rem_floor_ref(&n2)).1,
- ))
- }
- }
- (Number::Integer(x), Number::Integer(y)) => {
- if &*y == &0 {
- Err(self
- .error_form(MachineError::evaluation_error(EvalError::ZeroDivisor), stub))
- } else {
- Ok(Number::from(
- <(Integer, Integer)>::from(x.div_rem_floor_ref(&*y)).1,
- ))
- }
+ &ArithmeticTerm::Interm(i) => {
+ Ok(mem::replace(&mut self.interms[i - 1], Number::Fixnum(Fixnum::build_with(0))))
}
- (Number::Integer(_), n2) | (Number::Fixnum(_), n2) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n2),
- stub,
- )),
- (n1, _) => Err(self.error_form(
- MachineError::type_error(self.heap.h(), ValidType::Integer, n1),
- stub,
- )),
+ &ArithmeticTerm::Number(n) => Ok(n),
}
}
}
}
- pub(crate) fn max(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n1 > n2 {
- Ok(Number::Fixnum(n1))
- } else {
- Ok(Number::Fixnum(n2))
- }
+ pub(crate) fn arith_eval_by_metacall(&mut self, value: HeapCellValue) -> Result<Number, MachineStub> {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+ let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, value);
+
+ while let Some(value) = iter.next() {
+ if value.get_forwarding_bit() {
+ std::mem::drop(iter);
+
+ let (name, arity) = read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ (name, arity)
+ }
+ (HeapCellValueTag::Str, s) => {
+ cell_as_atom_cell!(self.heap[s]).get_name_and_arity()
+ }
+ (HeapCellValueTag::Lis | HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset |
+ HeapCellValueTag::PStrLoc) => {
+ (atom!("."), 2)
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ let err = self.instantiation_error();
+ return Err(self.error_form(err, stub_gen()));
+ }
+ _ => {
+ unreachable!()
+ }
+ );
+
+ let evaluable_error = self.evaluable_error(name, arity);
+ return Err(self.error_form(evaluable_error, stub_gen()));
}
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 > &n1 {
- Ok(Number::Integer(n2))
- } else {
- Ok(Number::Fixnum(n1))
- }
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if &*n1 > &n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Fixnum(n2))
- }
- }
- (Number::Integer(n1), Number::Integer(n2)) => {
- if n1 > n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Integer(n2))
- }
- }
- (n1, n2) => {
- let stub = MachineError::functor_stub(clause_name!("max"), 2);
- let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
- let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?;
+ let value = unmark_cell_bits!(value);
+
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 2 {
+ let a2 = self.interms.pop().unwrap();
+ let a1 = self.interms.pop().unwrap();
+
+ match name {
+ atom!("+") => self.interms.push(drop_iter_on_err!(
+ self,
+ iter,
+ try_numeric_result!(add(a1, a2, &mut self.arena), stub_gen)
+ )),
+ atom!("-") => self.interms.push(drop_iter_on_err!(
+ self,
+ iter,
+ try_numeric_result!(sub(a1, a2, &mut self.arena), stub_gen)
+ )),
+ atom!("*") => self.interms.push(drop_iter_on_err!(
+ self,
+ iter,
+ try_numeric_result!(mul(a1, a2, &mut self.arena), stub_gen)
+ )),
+ atom!("/") => self.interms.push(
+ drop_iter_on_err!(self, iter, div(a1, a2))
+ ),
+ atom!("**") => self.interms.push(
+ drop_iter_on_err!(self, iter, pow(a1, a2, atom!("is")))
+ ),
+ atom!("^") => self.interms.push(
+ drop_iter_on_err!(self, iter, int_pow(a1, a2, &mut self.arena))
+ ),
+ atom!("max") => self.interms.push(
+ drop_iter_on_err!(self, iter, max(a1, a2))
+ ),
+ atom!("min") => self.interms.push(
+ drop_iter_on_err!(self, iter, min(a1, a2))
+ ),
+ atom!("rdiv") => {
+ let r1 = drop_iter_on_err!(
+ self,
+ iter,
+ rational_from_number(a1, stub_gen, &mut self.arena)
+ );
+
+ let r2 = drop_iter_on_err!(
+ self,
+ iter,
+ rational_from_number(a2, stub_gen, &mut self.arena)
+ );
+
+ let result = arena_alloc!(
+ drop_iter_on_err!(self, iter, rdiv(r1, r2)),
+ &mut self.arena
+ );
+
+ self.interms.push(Number::Rational(result));
+ }
+ atom!("//") => self.interms.push(
+ drop_iter_on_err!(self, iter, idiv(a1, a2, &mut self.arena))
+ ),
+ atom!("div") => self.interms.push(
+ drop_iter_on_err!(self, iter, int_floor_div(a1, a2, &mut self.arena))
+ ),
+ atom!(">>") => self.interms.push(
+ drop_iter_on_err!(self, iter, shr(a1, a2, &mut self.arena))
+ ),
+ atom!("<<") => self.interms.push(
+ drop_iter_on_err!(self, iter, shl(a1, a2, &mut self.arena))
+ ),
+ atom!("/\\") => self.interms.push(
+ drop_iter_on_err!(self, iter, and(a1, a2, &mut self.arena))
+ ),
+ atom!("\\/") => self.interms.push(
+ drop_iter_on_err!(self, iter, or(a1, a2, &mut self.arena))
+ ),
+ atom!("xor") => self.interms.push(
+ drop_iter_on_err!(self, iter, xor(a1, a2, &mut self.arena))
+ ),
+ atom!("mod") => self.interms.push(
+ drop_iter_on_err!(self, iter, modulus(a1, a2, &mut self.arena))
+ ),
+ atom!("rem") => self.interms.push(
+ drop_iter_on_err!(self, iter, remainder(a1, a2, &mut self.arena))
+ ),
+ atom!("atan2") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, atan2(a1, a2))
+ ))),
+ atom!("gcd") => self.interms.push(
+ drop_iter_on_err!(self, iter, gcd(a1, a2, &mut self.arena))
+ ),
+ _ => {
+ let evaluable_stub = functor_stub(name, 2);
+ let stub = stub_gen();
+
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(ValidType::Evaluable, evaluable_stub);
+ return Err(self.error_form(type_error, stub));
+ }
+ }
- Ok(Number::Float(cmp::max(OrderedFloat(f1), OrderedFloat(f2))))
- }
- }
- }
+ continue;
+ } else if arity == 1 {
+ let a1 = self.interms.pop().unwrap();
+
+ match name {
+ atom!("-") => self.interms.push(neg(a1, &mut self.arena)),
+ atom!("+") => self.interms.push(a1),
+ atom!("cos") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, cos(a1))
+ ))),
+ atom!("sin") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, sin(a1))
+ ))),
+ atom!("tan") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, tan(a1))
+ ))),
+ atom!("cosh") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, cosh(a1))
+ ))),
+ atom!("sinh") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, sinh(a1))
+ ))),
+ atom!("tanh") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, tanh(a1))
+ ))),
+ atom!("acosh") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, acosh(a1))
+ ))),
+ atom!("asinh") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, asinh(a1))
+ ))),
+ atom!("atanh") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, atanh(a1))
+ ))),
+ atom!("log10") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, log10(a1))
+ ))),
++ atom!("float_fractional_part") => self.interms.push(Number::Float(OrderedFloat(
++ drop_iter_on_err!(self, iter, float_fractional_part(a1))
++ ))),
++ atom!("float_integer_part") => self.interms.push(Number::Float(OrderedFloat(
++ drop_iter_on_err!(self, iter, float_integer_part(a1))
++ ))),
+ atom!("sqrt") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, sqrt(a1))
+ ))),
+ atom!("log") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, log(a1))
+ ))),
+ atom!("exp") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, exp(a1))
+ ))),
+ atom!("acos") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, acos(a1))
+ ))),
+ atom!("asin") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, asin(a1))
+ ))),
+ atom!("atan") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, atan(a1))
+ ))),
+ atom!("abs") => self.interms.push(abs(a1, &mut self.arena)),
+ atom!("float") => self.interms.push(Number::Float(OrderedFloat(
+ drop_iter_on_err!(self, iter, float(a1))
+ ))),
+ atom!("truncate") => self.interms.push(truncate(a1, &mut self.arena)),
+ atom!("round") => self.interms.push(drop_iter_on_err!(self, iter, round(a1, &mut self.arena))),
+ atom!("ceiling") => self.interms.push(ceiling(a1, &mut self.arena)),
+ atom!("floor") => self.interms.push(floor(a1, &mut self.arena)),
+ atom!("\\") => self.interms.push(
+ drop_iter_on_err!(self, iter, bitwise_complement(a1, &mut self.arena))
+ ),
+ atom!("sign") => self.interms.push(a1.sign()),
+ _ => {
+ let evaluable_stub = functor_stub(name, 1);
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(
+ ValidType::Evaluable,
+ evaluable_stub,
+ );
- pub(crate) fn min(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
- match (n1, n2) {
- (Number::Fixnum(n1), Number::Fixnum(n2)) => {
- if n1 < n2 {
- Ok(Number::Fixnum(n1))
- } else {
- Ok(Number::Fixnum(n2))
+ let stub = stub_gen();
+ return Err(self.error_form(type_error, stub));
+ }
+ }
+
+ continue;
+ } else if arity == 0 {
+ match name {
+ atom!("pi") => {
+ self.interms.push(Number::Float(OrderedFloat(f64::consts::PI)));
+ continue;
+ }
+ atom!("e") => {
+ self.interms.push(Number::Float(OrderedFloat(f64::consts::E)));
+ continue;
+ }
+ atom!("epsilon") => {
+ self.interms.push(Number::Float(OrderedFloat(f64::EPSILON)));
+ continue;
+ }
+ _ => {
+ }
+ }
+ }
+
+ std::mem::drop(iter);
+
+ let evaluable_error = self.evaluable_error(name, arity);
+ let stub = stub_gen();
+
+ return Err(self.error_form(evaluable_error, stub));
}
- }
- (Number::Fixnum(n1), Number::Integer(n2)) => {
- if &*n2 < &n1 {
- Ok(Number::Integer(n2))
- } else {
- Ok(Number::Fixnum(n1))
+ (HeapCellValueTag::Fixnum, n) => {
+ self.interms.push(Number::Fixnum(n));
}
- }
- (Number::Integer(n1), Number::Fixnum(n2)) => {
- if &*n1 < &n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Fixnum(n2))
+ (HeapCellValueTag::F64, fl) => {
+ self.interms.push(Number::Float(*fl));
}
- }
- (Number::Integer(n1), Number::Integer(n2)) => {
- if n1 < n2 {
- Ok(Number::Integer(n1))
- } else {
- Ok(Number::Integer(n2))
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ self.interms.push(Number::Integer(n));
+ }
+ (ArenaHeaderTag::Rational, r) => {
+ self.interms.push(Number::Rational(r));
+ }
+ _ => {
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(ValidType::Evaluable, value);
+ let stub = stub_gen();
+
+ return Err(self.error_form(type_error, stub));
+ }
+ )
}
- }
- (n1, n2) => {
- let stub = MachineError::functor_stub(clause_name!("max"), 2);
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar) => {
+ std::mem::drop(iter);
- let f1 = try_numeric_result!(self, result_f(&n1, rnd_f), stub)?;
- let f2 = try_numeric_result!(self, result_f(&n2, rnd_f), stub)?;
+ let instantiation_error = self.instantiation_error();
+ let stub = stub_gen();
- Ok(Number::Float(cmp::min(OrderedFloat(f1), OrderedFloat(f2))))
- }
+ return Err(self.error_form(instantiation_error, stub));
+ }
+ _ => {
+ std::mem::drop(iter);
+
+ let type_error = self.type_error(ValidType::Evaluable, value);
+ let stub = stub_gen();
+
+ return Err(self.error_form(type_error, stub));
+ }
+ )
}
+
+ Ok(self.interms.pop().unwrap())
}
+}
- pub(crate) fn sign(&self, n: Number) -> Number {
- if n.is_positive() {
- Number::from(1)
- } else if n.is_negative() {
- Number::from(-1)
- } else {
- Number::from(0)
- }
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::machine::mock_wam::*;
+
+ #[test]
+ fn arith_eval_by_metacall_tests() {
+ let mut wam = MachineState::new();
+ let mut op_dir = default_op_dir();
+
+ op_dir.insert(
+ (atom!("+"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::In),
+ OpDesc::build_with(500, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("-"), Fixity::Pre),
+ OpDesc::build_with(200, FY as u8),
+ );
+ op_dir.insert(
+ (atom!("*"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+ op_dir.insert(
+ (atom!("/"), Fixity::In),
+ OpDesc::build_with(400, YFX as u8),
+ );
+
+ let term_write_result =
+ parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
+
+ assert_eq!(
+ wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+ Ok(Number::Fixnum(Fixnum::build_with(8))),
+ );
+
+ wam.heap.clear();
+
+ let term_write_result =
+ parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
+
+ assert_eq!(
+ wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+ Ok(Number::Fixnum(Fixnum::build_with(19))),
+ );
+
+ wam.heap.clear();
+
+ let term_write_result =
+ parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
+
+ assert_eq!(
+ wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.heap_loc)),
+ Ok(Number::Fixnum(Fixnum::build_with(-1)))
+ );
}
}
--- /dev/null
+use crate::arena::*;
+use crate::atom_table::*;
+use crate::instructions::*;
+use crate::machine::*;
+use crate::machine::arithmetic_ops::*;
+use crate::machine::machine_errors::*;
+use crate::machine::machine_state::*;
+use crate::types::*;
+
+use crate::try_numeric_result;
+
+use fxhash::FxBuildHasher;
+
+macro_rules! step_or_fail {
+ ($self:expr, $step_e:expr) => {
+ if $self.machine_st.fail {
+ $self.machine_st.backtrack();
+ } else {
+ $step_e;
+ }
+ };
+}
+
+macro_rules! try_or_throw {
+ ($s:expr, $e:expr) => {{
+ match $e {
+ Ok(val) => val,
+ Err(msg) => {
+ $s.throw_exception(msg);
+ $s.backtrack();
+ continue;
+ }
+ }
+ }};
+}
+
+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;
+ }
+ }
+ }};
+}
+
+static INSTRUCTIONS_PER_INTERRUPT_POLL: usize = 256;
+
+impl MachineState {
+ #[inline(always)]
+ fn compare(&mut self) -> CallResult {
+ let stub_gen = || functor_stub(atom!("compare"), 3);
+
+ let a1 = self.store(self.deref(self.registers[1]));
+ let a2 = self.registers[2];
+ let a3 = self.registers[3];
+
+ let check_atom = |machine_st: &mut MachineState, name: Atom, arity: usize| -> Result<(), MachineStub> {
+ match name {
+ atom!(">") | atom!("<") | atom!("=") if arity == 0 => {
+ Ok(())
+ }
+ _ => {
+ let err = machine_st.domain_error(DomainErrorType::Order, a1);
+ Err(machine_st.error_form(err, stub_gen()))
+ }
+ }
+ };
+
+ read_heap_cell!(a1,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
+ check_atom(self, name, arity)?;
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s])
+ .get_name_and_arity();
+
+ check_atom(self, name, arity)?;
+ }
+ (HeapCellValueTag::AttrVar | HeapCellValueTag::Var | HeapCellValueTag::StackVar) => {
+ }
+ _ => {
+ let err = self.type_error(ValidType::Atom, a1);
+ return Err(self.error_form(err, stub_gen()));
+ }
+ );
+
+ let atom = match compare_term_test!(self, a2, a3) {
+ Some(Ordering::Greater) => {
+ atom!(">")
+ }
+ Some(Ordering::Equal) => {
+ atom!("=")
+ }
+ None | Some(Ordering::Less) => {
+ atom!("<")
+ }
+ };
+
+ self.unify_atom(atom, a1);
+ Ok(())
+ }
+
+ 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);
+ }
+
+ fn sort(&mut self) -> CallResult {
+ self.check_sort_errors()?;
+
+ let stub_gen = || functor_stub(atom!("sort"), 2);
+ let mut list = self.try_from_list(self.registers[1], stub_gen)?;
+
+ list.sort_unstable_by(|v1, v2| {
+ compare_term_test!(self, *v1, *v2).unwrap_or(Ordering::Less)
+ });
+
+ list.dedup_by(|v1, v2| {
+ compare_term_test!(self, *v1, *v2) == Some(Ordering::Equal)
+ });
+
+ let heap_addr = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, list.into_iter())
+ );
+
+ let target_addr = self.registers[2];
+
+ unify_fn!(*self, target_addr, heap_addr);
+ Ok(())
+ }
+
+ fn keysort(&mut self, var_comparison: VarComparison) -> CallResult {
+ self.check_keysort_errors()?;
+
+ let stub_gen = || functor_stub(atom!("keysort"), 2);
+ let list = self.try_from_list(self.registers[1], stub_gen)?;
+
+ let mut key_pairs = Vec::with_capacity(list.len());
+
+ for val in list {
+ let key = self.project_onto_key(val)?;
+ key_pairs.push((key, val));
+ }
+
+ key_pairs.sort_by(|a1, a2| {
+ compare_term_test!(self, a1.0, a2.0, var_comparison).unwrap_or(Ordering::Less)
+ });
+
+ let key_pairs = key_pairs.into_iter().map(|kp| kp.1);
+ let heap_addr = heap_loc_as_cell!(
+ iter_to_heap_list(&mut self.heap, key_pairs)
+ );
+
+ let target_addr = self.registers[2];
+
+ unify_fn!(*self, target_addr, heap_addr);
+ Ok(())
+ }
+
+ fn is(&mut self, r: RegType, at: ArithmeticTerm) -> CallResult {
+ let n1 = self.store(self.deref(self[r]));
+
+ match self.get_number(&at)? {
+ Number::Fixnum(n) => self.unify_fixnum(n, n1),
+ Number::Float(n) => {
+ let n = float_alloc!(n.into_inner(), self.arena);
+ self.unify_f64(n, n1)
+ }
+ Number::Integer(n) => self.unify_big_int(n, n1),
+ Number::Rational(n) => self.unify_rational(n, n1),
+ }
+
+ Ok(())
+ }
+
+ #[inline(always)]
+ pub(crate) fn select_switch_on_term_index(
+ &self,
+ addr: HeapCellValue,
+ v: IndexingCodePtr,
+ c: IndexingCodePtr,
+ l: IndexingCodePtr,
+ s: IndexingCodePtr,
+ ) -> IndexingCodePtr {
+ 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, st) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[st])
+ .get_name_and_arity();
+
+ match (name, arity) {
+ (atom!("."), 2) => l,
+ (_, 0) => c,
+ _ => s,
+ }
+ }
+ (HeapCellValueTag::Cons, ptr) => {
+ match ptr.get_tag() {
+ ArenaHeaderTag::Rational | ArenaHeaderTag::Integer => {
+ c
+ }
+ _ => {
+ IndexingCodePtr::Fail
+ }
+ }
+ }
+ _ => {
+ unreachable!();
+ }
+ )
+ }
+
+ #[inline(always)]
+ pub(crate) fn constant_to_literal(&self, addr: HeapCellValue) -> Literal {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Char, c) => {
+ Literal::Char(c)
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ Literal::Fixnum(n)
+ }
+ (HeapCellValueTag::F64, f) => {
+ Literal::Float(f.as_offset())
+ }
+ (HeapCellValueTag::Atom, (atom, arity)) => {
+ debug_assert_eq!(arity, 0);
+ Literal::Atom(atom)
+ }
+ (HeapCellValueTag::Str, s) => {
+ Literal::Atom(cell_as_atom_cell!(self.heap[s]).get_name())
+ }
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Rational, r) => {
+ Literal::Rational(r)
+ }
+ (ArenaHeaderTag::Integer, n) => {
+ Literal::Integer(n)
+ }
+ _ => {
+ unreachable!()
+ }
+ )
+ }
+ _ => {
+ unreachable!()
+ }
+ )
+ }
+
+ #[inline(always)]
+ pub(crate) fn select_switch_on_structure_index(
+ &self,
+ addr: HeapCellValue,
+ hm: &IndexMap<(Atom, usize), IndexingCodePtr, FxBuildHasher>,
+ ) -> IndexingCodePtr {
+ 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.heap[s])
+ .get_name_and_arity();
+
+ match hm.get(&(name, arity)) {
+ Some(offset) => *offset,
+ None => IndexingCodePtr::Fail,
+ }
+ }
+ _ => {
+ IndexingCodePtr::Fail
+ }
+ )
+ }
+}
+
+impl Machine {
+ 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;
+ }
+ }
+ &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;
+ }
+ }
+ &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!();
+ }
+ }
+ }
+ }
+
+ pub(super) fn find_living_dynamic(&self, oi: u32, mut ii: u32) -> Option<(usize, u32, u32, bool)> {
+ let p = self.machine_st.p;
+
+ 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,
+ }
+ }
+ }
+
+ #[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;
+ }
+ _ => {}
+ }
+
+ 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;
+ }
+ }
+ _ => {}
+ }
+
+ true
+ }
+
+ let indexing_lines = self.code[self.machine_st.p].to_indexing_line_mut().unwrap();
+
+ 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 = self.machine_st.select_switch_on_term_index(addr, v, c, l, s);
+
+ 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;
+
+ if !dynamic_external_of_clause_is_valid(self, p + o) {
+ self.machine_st.fail = true;
+ } else {
+ self.machine_st.p += o;
+ }
+
+ break;
+ }
+ IndexingCodePtr::External(o) => {
+ self.machine_st.p += o;
+ break;
+ }
+ IndexingCodePtr::Internal(o) => {
+ index += o;
+ }
+ }
+ }
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(hm)) => {
+ let lit = self.machine_st.constant_to_literal(addr);
+
+ let offset = match hm.get(&lit) {
+ Some(offset) => *offset,
+ _ => IndexingCodePtr::Fail,
+ };
+
+ 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;
+
+ if !dynamic_external_of_clause_is_valid(self, p + o) {
+ self.machine_st.fail = true;
+ } else {
+ self.machine_st.p += o;
+ }
+
+ break;
+ }
+ IndexingCodePtr::External(o) => {
+ self.machine_st.p += o;
+ break;
+ }
+ IndexingCodePtr::Internal(o) => {
+ index += o;
+ }
+ }
+ }
+ IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(hm)) => {
+ let offset = self.machine_st.select_switch_on_structure_index(addr, hm);
+
+ match offset {
+ IndexingCodePtr::Fail => {
+ self.machine_st.fail = true;
+ break;
+ }
+ IndexingCodePtr::DynamicExternal(o) => {
+ let p = self.machine_st.p;
+
+ if !dynamic_external_of_clause_is_valid(self, p + o) {
+ self.machine_st.fail = true;
+ } else {
+ self.machine_st.p += o;
+ }
+
+ 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;
+ }
+ }
+ }
+ }
+
+ #[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;
+
+ 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;
+ }
+
+ let mut p = self.machine_st.p;
+
+ while self.code[p].is_head_instr() {
+ p += 1;
+ }
+
+ let instr = std::mem::replace(
+ &mut self.code[p],
+ Instruction::VerifyAttrInterrupt,
+ );
+
+ self.code[VERIFY_ATTR_INTERRUPT_LOC] = instr;
+ self.machine_st.attr_var_init.cp = p;
+ }
+ &Instruction::VerifyAttrInterrupt => {
+ let (_, arity) = self.code[VERIFY_ATTR_INTERRUPT_LOC].to_name_and_arity();
+ let arity = std::cmp::max(arity, self.machine_st.num_of_args);
+ self.run_verify_attr_interrupt(arity);
+ }
+ &Instruction::Add(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+
+ 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!(add(n1, n2, &mut self.machine_st.arena), stub_gen)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Sub(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+
+ 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;
+ }
+ &Instruction::Mul(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("is"), 2);
+
+ 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!(mul(n1, n2, &mut self.machine_st.arena), stub_gen)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ max(n1, n2)
+ );
+
+ 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.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ min(n1, n2)
+ );
+
+ 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));
+
+ 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.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.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ gcd(n1, n2, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ pow(n1, n2, atom!("**"))
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::RDiv(ref a1, ref a2, t) => {
+ let stub_gen = || functor_stub(atom!("(rdiv)"), 2);
+
+ 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));
+
+ self.machine_st.interms[t - 1] = Number::Rational(arena_alloc!(
+ try_or_throw_gen!(&mut self.machine_st, rdiv(r1, r2)),
+ &mut self.machine_st.arena
+ ));
+
+ 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));
+
+ 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));
+
+ self.machine_st.interms[t - 1] = n.sign();
+ self.machine_st.p += 1;
+ }
+ &Instruction::Neg(ref a1, t) => {
+ let n1 = try_or_throw!(self.machine_st, self.machine_st.get_number(a1));
+
+ self.machine_st.interms[t - 1] = neg(n1, &mut self.machine_st.arena);
+ self.machine_st.p += 1;
+ }
+ &Instruction::BitwiseComplement(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,
+ bitwise_complement(n1, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ div(n1, n2)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ shr(n1, n2, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ shl(n1, n2, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ xor(n1, n2, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ and(n1, n2, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ or(n1, n2, &mut self.machine_st.arena)
+ );
+
+ 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));
+
+ 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;
+ }
+ &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));
+
+ self.machine_st.interms[t - 1] = try_or_throw_gen!(
+ &mut self.machine_st,
+ remainder(n1, n2, &mut self.machine_st.arena)
+ );
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Cos(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, cos(n1))
+ ));
+
+ 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.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, sin(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Tan(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, tan(n1))
+ ));
+
+ 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.interms[t - 1] = Number::Float(OrderedFloat(
+ try_or_throw_gen!(&mut self.machine_st, sqrt(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Log(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, log(n1))
+ ));
+
+ 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.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::ACosh(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, acosh(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::ASinh(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, asinh(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::ATanh(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, atanh(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Cosh(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, cosh(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Sinh(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, sinh(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Tanh(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, tanh(n1))
+ ));
+
+ self.machine_st.p += 1;
+ }
+ &Instruction::Log10(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, log10(n1))
+ ));
+
+ 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::FloatFractionalPart(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_fractional_part(n1))
++ ));
++
++ self.machine_st.p += 1;
++ }
++ &Instruction::FloatIntegerPart(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_integer_part(n1))
++ ));
++
++ 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;
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+
+ 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.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
+ .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);
+ }
+ None => {
+ self.trust_me();
+ }
+ }
+ } 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;
+ }
+ }
+
+ self.machine_st.dynamic_mode = FirstOrNext::Next;
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::DynamicInternalElse(..) => {
+ let p = self.machine_st.p;
+
+ match self.find_living_dynamic_else(p) {
+ Some((p, next_i)) => {
+ self.machine_st.p = p;
+ self.machine_st.oip = 0;
+ self.machine_st.iip = 0;
+
+ 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.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
+ .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);
+ }
+ None => {
+ self.trust_me();
+ }
+ }
+ } 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;
+ }
+ }
+
+ self.machine_st.dynamic_mode = FirstOrNext::Next;
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ &Instruction::TryMeElse(offset) => {
+ self.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 => {
+ self.machine_st.neck_cut();
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetLevel(r) => {
+ let b0 = self.machine_st.b0;
+
+ self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(b0 as i64));
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetPrevLevel(r) => {
+ let prev_b = self.machine_st.stack.index_or_frame(self.machine_st.b).prelude.b;
+
+ self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(prev_b as i64));
+ self.machine_st.p += 1;
+ }
+ &Instruction::GetCutPoint(r) => {
+ self.machine_st[r] = fixnum_as_cell!(Fixnum::as_cutpoint(self.machine_st.b as i64));
+ 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::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(VarComparison::Distinct));
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::DefaultExecuteKeySort => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Distinct));
+
+ 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::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(VarComparison::Distinct));
+
+ 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(VarComparison::Distinct));
+
+ 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::CallKeySortWithConstantVarOrdering => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Indistinct));
+
+ 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::ExecuteKeySortWithConstantVarOrdering => {
+ try_or_throw!(self.machine_st, self.machine_st.keysort(VarComparison::Indistinct));
+
+ 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::Str, s) => {
+ let arity = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_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::Str, s) => {
+ let arity = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_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();
+ }
+ }
+ (HeapCellValueTag::Str, s) => {
+ let arity = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_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();
+ }
+ }
+ (HeapCellValueTag::Str, s) => {
+ let arity = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_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::Lis |
+ HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::CStr) => {
+ self.machine_st.p += 1;
+ }
+ (HeapCellValueTag::Str, s) => {
+ let arity = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_arity();
+
+ if arity > 0 {
+ self.machine_st.p += 1;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ (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::Lis |
+ HeapCellValueTag::PStrLoc |
+ HeapCellValueTag::CStr) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ (HeapCellValueTag::Str, s) => {
+ let arity = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_arity();
+
+ if arity > 0 {
+ self.machine_st.p = self.machine_st.cp;
+ } else {
+ self.machine_st.backtrack();
+ }
+ }
+ (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(_) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ 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(_) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ 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 | ArenaHeaderTag::Integer, _r) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ (HeapCellValueTag::Fixnum) => {
+ self.machine_st.p += 1;
+ }
+ _ => {
+ 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 | ArenaHeaderTag::Integer, _r) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ self.machine_st.backtrack();
+ }
+ );
+ }
+ (HeapCellValueTag::Fixnum) => {
+ self.machine_st.p = self.machine_st.cp;
+ }
+ _ => {
+ 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(offset) => {
+ 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.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ }
+ (HeapCellValueTag::CStr) => {
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.push(store_v);
+
+ self.machine_st.s = HeapPtr::PStrChar(h, 0);
+ self.machine_st.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.machine_st.heap[s])
+ .get_name_and_arity();
+
+ if name == atom!(".") && arity == 2 {
+ self.machine_st.s = HeapPtr::HeapCell(s+1);
+ self.machine_st.s_offset = 0;
+ self.machine_st.mode = MachineMode::Read;
+ } else {
+ self.machine_st.backtrack();
+ continue;
+ }
+ }
+ (HeapCellValueTag::Lis, l) => {
+ self.machine_st.s = HeapPtr::HeapCell(l);
+ self.machine_st.s_offset = 0;
+ 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::CStr) => {
+ self.machine_st.match_partial_string(store_v, string, has_tail);
+ }
+ (HeapCellValueTag::AttrVar |
+ HeapCellValueTag::StackVar |
+ HeapCellValueTag::Var) => {
+ let target_cell = self.machine_st.push_str_to_heap(
+ string.as_str(),
+ has_tail,
+ );
+
+ self.machine_st.bind(
+ store_v.as_var().unwrap(),
+ target_cell,
+ );
+ }
+ _ => {
+ self.machine_st.backtrack();
+ continue;
+ }
+ );
+
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::GetStructure(_lvl, 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.s_offset = 0;
+ 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.s_offset += 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.s_offset += 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.s_offset += 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.s_offset += 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.s_offset += 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.s_offset += 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.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 += 1;
+ self.indexed_try(offset);
+ self.machine_st.num_of_args -= 1;
+ }
+ 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
+ .num_cells;
+
+ self.machine_st.cc = cell_as_fixnum!(
+ self.machine_st.stack[stack_loc!(OrFrame, b, n-1)]
+ ).get_num() as usize;
+
+ if is_next_clause {
+ match self.find_living_dynamic(self.machine_st.oip, self.machine_st.iip + 1) {
+ // if we're executing the last instruction
+ // of the internal block pointed to by
+ // self.machine_st.iip, we want trust, not retry.
+ // this is true iff ii + 1 < len.
+ Some(_) => {
+ self.retry(offset);
+
+ try_or_throw!(
+ self.machine_st,
+ (self.machine_st.increment_call_count_fn)(&mut self.machine_st)
+ );
+ }
+ _ => {
+ 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;
+ }
+ }
+
+ self.machine_st.dynamic_mode = FirstOrNext::Next;
+
+ if self.machine_st.fail {
+ self.machine_st.backtrack();
+ }
+ }
+ }
+ }
+ &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(perm_slot, arg) => {
+ let s = stack_loc!(AndFrame, self.machine_st.e, perm_slot);
+ 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::CallFileCopy => {
+ self.file_copy();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteFileCopy => {
+ self.file_copy();
+ 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::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::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::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::CallLookupDBRef => {
+ self.lookup_db_ref();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLookupDBRef => {
+ self.lookup_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::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::CallGetCurrentSCCBlock => {
+ self.get_current_scc_block();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetCurrentSCCBlock => {
+ self.get_current_scc_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::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::CallGetUnknown => {
+ self.get_unknown();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetUnknown => {
+ self.get_unknown();
+ 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::CallDeterministicLengthRundown => {
+ try_or_throw!(self.machine_st, self.det_length_rundown());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDeterministicLengthRundown => {
+ try_or_throw!(self.machine_st, self.det_length_rundown());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallHttpOpen => {
+ try_or_throw!(self.machine_st, self.http_open());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteHttpOpen => {
+ try_or_throw!(self.machine_st, self.http_open());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallHttpListen => {
+ try_or_throw!(self.machine_st, self.http_listen());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteHttpListen => {
+ try_or_throw!(self.machine_st, self.http_listen());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallHttpAccept => {
+ try_or_throw!(self.machine_st, self.http_accept());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteHttpAccept => {
+ try_or_throw!(self.machine_st, self.http_accept());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallHttpAnswer => {
+ try_or_throw!(self.machine_st, self.http_answer());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteHttpAnswer => {
+ try_or_throw!(self.machine_st, self.http_answer());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallLoadForeignLib => {
+ try_or_throw!(self.machine_st, self.load_foreign_lib());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadForeignLib => {
+ try_or_throw!(self.machine_st, self.load_foreign_lib());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallForeignCall => {
+ try_or_throw!(self.machine_st, self.foreign_call());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteForeignCall => {
+ try_or_throw!(self.machine_st, self.foreign_call());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDefineForeignStruct => {
+ try_or_throw!(self.machine_st, self.define_foreign_struct());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDefineForeignStruct => {
+ try_or_throw!(self.machine_st, self.define_foreign_struct());
+ 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::CallReadFromChars => {
+ try_or_throw!(self.machine_st, self.read_from_chars());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteReadFromChars => {
+ try_or_throw!(self.machine_st, self.read_from_chars());
+ 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::CallResetSCCBlock => {
+ self.reset_scc_block();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteResetSCCBlock => {
+ self.reset_scc_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::CallPushBallStack => {
+ self.push_ball_stack();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePushBallStack => {
+ self.push_ball_stack();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPopBallStack => {
+ self.pop_ball_stack();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePopBallStack => {
+ self.pop_ball_stack();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallPopFromBallStack => {
+ self.pop_from_ball_stack();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecutePopFromBallStack => {
+ self.pop_from_ball_stack();
+ 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::CallSetUnknown => {
+ self.set_unknown();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteSetUnknown => {
+ self.set_unknown();
+ 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::CallInlinedInstructions => {
+ self.inlined_instructions();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteInlinedInstructions => {
+ self.inlined_instructions();
+ 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(self.machine_st.registers[1]);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteLoadContextModule => {
+ self.load_context_module(self.machine_st.registers[1]);
+ 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 => {
+ let key = self
+ .machine_st
+ .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
+
+ self.machine_st.fail = !self.indices.builtin_property(key);
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteBuiltInProperty => {
+ let key = self
+ .machine_st
+ .read_predicate_key(self.machine_st.registers[1], self.machine_st.registers[2]);
+
+ self.machine_st.fail = !self.indices.builtin_property(key);
+ 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;
+ }
+ &Instruction::CallPredicateDefined => {
+ self.machine_st.fail = !self.predicate_defined();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePredicateDefined => {
+ self.machine_st.fail = !self.predicate_defined();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallStripModule => {
+ self.strip_module();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteStripModule => {
+ self.strip_module();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPrepareCallClause(arity) => {
+ try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePrepareCallClause(arity) => {
+ try_or_throw!(self.machine_st, self.prepare_call_clause(arity));
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallCompileInlineOrExpandedGoal => {
+ try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteCompileInlineOrExpandedGoal => {
+ try_or_throw!(self.machine_st, self.compile_inline_or_expanded_goal());
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallIsExpandedOrInlined => {
+ self.machine_st.fail = !self.is_expanded_or_inlined();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteIsExpandedOrInlined => {
+ self.machine_st.fail = !self.is_expanded_or_inlined();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallFastCallN(arity) => {
+ let call_at_index = |wam: &mut Machine, name, arity, ptr| {
+ wam.try_call(name, arity, ptr)
+ };
+
+ try_or_throw!(self.machine_st, self.fast_call(arity, call_at_index));
+
+ 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::ExecuteFastCallN(arity) => {
+ let call_at_index = |wam: &mut Machine, name, arity, ptr| {
+ wam.try_execute(name, arity, ptr)
+ };
+
+ try_or_throw!(self.machine_st, self.fast_call(arity, call_at_index));
+
+ 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::CallGetClauseP => {
+ let module_name = cell_as_atom!(self.deref_register(3));
+
+ let (n, p) = self.get_clause_p(module_name);
+
+ let r = self.machine_st.registers[2];
+ let r = self.machine_st.store(self.machine_st.deref(r));
+
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.extend(functor!(atom!("-"), [fixnum(n), fixnum(p)]));
+
+ let r = r.as_var().unwrap();
+ self.machine_st.bind(r, str_loc_as_cell!(h));
+
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetClauseP => {
+ let module_name = cell_as_atom!(self.deref_register(3));
+
+ let (n, p) = self.get_clause_p(module_name);
+
+ let r = self.machine_st.registers[2];
+ let r = self.machine_st.store(self.machine_st.deref(r));
+
+ let h = self.machine_st.heap.len();
+ self.machine_st.heap.extend(functor!(atom!("-"), [fixnum(n), fixnum(p)]));
+
+ let r = r.as_var().unwrap();
+ self.machine_st.bind(r, str_loc_as_cell!(h));
+
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallInvokeClauseAtP => {
+ let key_cell = self.machine_st.registers[1];
+ let key = self.machine_st.name_and_arity_from_heap(key_cell).unwrap();
+
+ let l = self.machine_st.registers[3];
+ let l = self.machine_st.store(self.machine_st.deref(l));
+
+ let l = match Number::try_from(l) {
+ Ok(Number::Fixnum(l)) => l.get_num() as usize,
+ _ => unreachable!(),
+ };
+
+ let p = self.machine_st.registers[4];
+ let p = self.machine_st.store(self.machine_st.deref(p));
+
+ let p = match Number::try_from(p) {
+ Ok(Number::Fixnum(p)) => p.get_num() as usize,
+ _ => unreachable!(),
+ };
+
+ let module_name = cell_as_atom!(self.deref_register(6));
+
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
+ _ => CompilationTarget::Module(module_name),
+ };
+
+ let skeleton = self.indices.get_predicate_skeleton_mut(
+ &compilation_target,
+ &key,
+ ).unwrap();
+
+ match skeleton.target_pos_of_clause_clause_loc(l) {
+ Some(n) => {
+ let r = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[5],
+ ));
+
+ self.machine_st.unify_fixnum(Fixnum::build_with(n as i64), r);
+ }
+ None => {}
+ }
+
+ self.machine_st.call_at_index(2, p);
+ }
+ &Instruction::ExecuteInvokeClauseAtP => {
+ let key_cell = self.machine_st.registers[1];
+ let key = self.machine_st.name_and_arity_from_heap(key_cell).unwrap();
+
+ let l = self.machine_st.registers[3];
+ let l = self.machine_st.store(self.machine_st.deref(l));
+
+ let l = match Number::try_from(l) {
+ Ok(Number::Fixnum(l)) => l.get_num() as usize,
+ _ => unreachable!(),
+ };
+
+ let p = self.machine_st.registers[4];
+ let p = self.machine_st.store(self.machine_st.deref(p));
+
+ let p = match Number::try_from(p) {
+ Ok(Number::Fixnum(p)) => p.get_num() as usize,
+ _ => unreachable!(),
+ };
+
+ let module_name = cell_as_atom!(self.deref_register(6));
+
+ let compilation_target = match module_name {
+ atom!("user") => CompilationTarget::User,
+ _ => CompilationTarget::Module(module_name),
+ };
+
+ let skeleton = self.indices.get_predicate_skeleton_mut(
+ &compilation_target,
+ &key,
+ ).unwrap();
+
+ match skeleton.target_pos_of_clause_clause_loc(l) {
+ Some(n) => {
+ let r = self.machine_st.store(self.machine_st.deref(
+ self.machine_st.registers[5],
+ ));
+
+ self.machine_st.unify_fixnum(Fixnum::build_with(n as i64), r);
+ }
+ None => {}
+ }
+
+ self.machine_st.execute_at_index(2, p);
+ }
+ &Instruction::CallGetFromAttributedVarList => {
+ self.get_from_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetFromAttributedVarList => {
+ self.get_from_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallPutToAttributedVarList => {
+ self.put_to_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecutePutToAttributedVarList => {
+ self.put_to_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDeleteFromAttributedVarList => {
+ self.delete_from_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteDeleteFromAttributedVarList => {
+ self.delete_from_attributed_variable_list();
+ step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
+ }
+ &Instruction::CallDeleteAllAttributesFromVar => {
+ self.delete_all_attributes_from_var();
+ self.machine_st.p += 1;
+ }
+ &Instruction::ExecuteDeleteAllAttributesFromVar => {
+ self.delete_all_attributes_from_var();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallUnattributedVar => {
+ self.machine_st.unattributed_var();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteUnattributedVar => {
+ self.machine_st.unattributed_var();
+ self.machine_st.p = self.machine_st.cp;
+ }
+ &Instruction::CallGetDBRefs => {
+ self.get_db_refs();
+ step_or_fail!(self, self.machine_st.p += 1);
+ }
+ &Instruction::ExecuteGetDBRefs => {
+ self.get_db_refs();
+ step_or_fail!(self, 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!(),
+ }
+ }
+ }
+}