From: Mark Date: Fri, 21 Jul 2023 21:13:29 +0000 (-0600) Subject: Merge branch 'add_float_integer_part_and_float_fractional_part_standard_functions... X-Git-Tag: v0.9.2~29^2 X-Git-Url: https://git.sagredo.dev/?a=commitdiff_plain;h=60d9d01a559dfe6adefd2cfa58dca4aa2c31fef7;p=scryer-prolog.git Merge branch 'add_float_integer_part_and_float_fractional_part_standard_functions' of https://github.com/pmoura/scryer-prolog into pmoura-add_float_integer_part_and_float_fractional_part_standard_functions --- 60d9d01a559dfe6adefd2cfa58dca4aa2c31fef7 diff --cc build/instructions_template.rs index 8ec818e6,00000000..3ac76eff mode 100644,000000..100644 --- a/build/instructions_template.rs +++ b/build/instructions_template.rs @@@ -1,3480 -1,0 +1,3490 @@@ +// 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), + // break from loop instruction. + #[strum_discriminants(strum(props(Arity = "0", Name = "break_from_dispatch")))] + BreakFromDispatchLoop, + // swap the verify attr interrupt instruction with the next control instruction. + #[strum_discriminants(strum(props(Arity = "0", Name = "install_verify_attr")))] + InstallVerifyAttr, + // call verify_attrs. + #[strum_discriminants(strum(props(Arity = "0", Name = "verify_attr_interrupt")))] + VerifyAttrInterrupt, + // procedures + CallClause(ClauseType, usize, usize, bool, bool), // ClauseType, + // arity, + // perm_vars, + // last_call, + // use_default_call_policy. +} + +fn derive_input(ty: &Type) -> Option { + let clause_type: Type = parse_quote!{ ClauseType }; + let built_in_clause_type: Type = parse_quote! { BuiltInClauseType }; + let inlined_clause_type: Type = parse_quote! { InlinedClauseType }; + let system_clause_type: Type = parse_quote! { SystemClauseType }; + let compare_term_type: Type = parse_quote! { CompareTerm }; + let compare_number_type: Type = parse_quote! { CompareNumber }; + let repl_code_ptr_type: Type = parse_quote! { REPLCodePtr }; + + if ty == &clause_type { + Some(ClauseType::to_derive_input()) + } else if ty == &built_in_clause_type { + Some(BuiltInClauseType::to_derive_input()) + } else if ty == &inlined_clause_type { + Some(InlinedClauseType::to_derive_input()) + } else if ty == &system_clause_type { + Some(SystemClauseType::to_derive_input()) + } else if ty == &compare_number_type { + Some(CompareNumber::to_derive_input()) + } else if ty == &compare_term_type { + Some(CompareTerm::to_derive_input()) + } else if ty == &repl_code_ptr_type { + Some(REPLCodePtr::to_derive_input()) + } else { + None + } +} + +impl ToTokens for Arity { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Arity::Static(arity) => { + arity.to_tokens(tokens); + } + Arity::Ident(arity) => { + let ident = format_ident!("{}", arity); + tokens.append(ident); + } + } + } +} + +fn add_discriminant_data( + variant: &Variant, + prefix: &'static str, + variant_data: &mut Vec<(&'static str, Arity, Variant)>, +) -> (&'static str, Arity) + where DiscriminantT: FromStr + strum::EnumProperty + std::fmt::Debug +{ + let name = prop_from_ident::(&variant.ident, "Name"); + let arity = Arity::from(prop_from_ident::(&variant.ident, "Arity")); + + if prefix == "Call" { + let mut variant = variant.clone(); + variant.attrs.clear(); + + variant_data.push((name, arity, variant)); + } + + (name, arity) +} + +fn generate_instruction_preface() -> TokenStream { + quote! { + use crate::arena::*; + use crate::arithmetic::*; + use crate::atom_table::*; + use crate::forms::*; + use crate::machine::heap::*; + use crate::machine::machine_errors::MachineStub; + use crate::machine::machine_indices::CodeIndex; + use crate::parser::ast::*; + use crate::types::*; + + use 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), + 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), + DynamicIndexedChoice(VecDeque), + } + + impl From for IndexingLine { + #[inline] + fn from(instr: IndexingInstruction) -> Self { + IndexingLine::Indexing(instr) + } + } + + impl From> for IndexingLine { + #[inline] + fn from(instrs: VecDeque) -> 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; + pub type CodeDeque = VecDeque; + + impl Instruction { + #[inline] + pub fn to_indexing_line_mut(&mut self) -> Option<&mut Vec> { + match self { + Instruction::IndexingCode(ref mut indexing_code) => Some(indexing_code), + _ => None, + } + } + + #[inline] + pub fn to_indexing_line(&self) -> Option<&Vec> { + match self { + Instruction::IndexingCode(ref indexing_code) => Some(indexing_code), + _ => None, + } + } + + #[inline] + pub fn is_head_instr(&self) -> bool { + match self { + Instruction::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, + ) { + 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() -> Vec { + if let Data::Enum(DataEnum { mut variants, .. }) = T::to_derive_input().data { + for variant in &mut variants { + variant.attrs.clear(); + } + + variants.into_iter().collect() + } else { + unreachable!() + } + } + + let clause_type_variants = attributeless_enum::(); + let builtin_type_variants = attributeless_enum::(); + let inlined_type_variants = attributeless_enum::(); + let system_clause_type_variants = attributeless_enum::(); + let repl_code_ptr_variants = attributeless_enum::(); + let compare_number_variants = attributeless_enum::(); + let compare_term_variants = attributeless_enum::(); + + let mut clause_type_from_name_and_arity_arms = vec![]; + let mut clause_type_to_instr_arms = vec![]; + let mut clause_type_name_arms = vec![]; + 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::() { + 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::() { + 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(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::( + &variant, + prefix, + &mut self.compare_number_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "CompareTerm" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.compare_term_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "BuiltInClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.builtin_type_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else if id == "InlinedClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.inlined_type_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "REPLCodePtr" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.repl_code_ptr_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "SystemClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.system_clause_type_variants, + ); + + (name, arity, CountableInference::NotCounted) + } else if id == "InstructionTemplate" { + ( prop_from_ident::(&variant.ident, "Name"), + Arity::from(prop_from_ident::(&variant.ident, "Arity")), + CountableInference::NotCounted + ) + } else if id == "ClauseType" { + let (name, arity) = add_discriminant_data::( + &variant, + prefix, + &mut self.clause_type_variants, + ); + + (name, arity, CountableInference::HasDefault) + } else { + panic!("type ID is: {}", id); + }; + + let v_string = variant.ident.to_string(); + + let v_ident = if v_string.starts_with("Call") { + format_ident!("{}", v_string["Call".len() ..]) + } else { + variant.ident.clone() + }; + + let generated_variant = create_instr_variant( + format_ident!("{}{}", prefix, v_ident), + variant.clone(), + ); + + self.instr_variants.push( + (name, arity, countable_inference, generated_variant) + ); + } + + fn generate_instruction_enum_loop(&mut self, input: syn::DeriveInput) { + if let Data::Enum(DataEnum { variants, .. }) = input.data { + for mut variant in variants { + if let Some(field) = variant.fields.iter().next() { + if let Some(input) = derive_input(&field.ty) { + self.generate_instruction_enum_loop(input); + continue; + } + } + + if input.ident == "InstructionTemplate" { + variant.attrs.clear(); + self.label_variant(&input.ident, "", variant); + continue; + } + + self.label_variant(&input.ident, "Call", variant.clone()); + self.label_variant(&input.ident, "Execute", variant.clone()); + + if input.ident == "BuiltInClauseType" || + input.ident == "CompareNumber" || + input.ident == "CompareTerm" || + input.ident == "ClauseType" + { + self.label_variant(&input.ident, "DefaultCall", variant.clone()); + self.label_variant(&input.ident, "DefaultExecute", variant); + } + } + } else { + panic!("{} must be an enum!", input.ident); + } + } +} diff --cc src/arithmetic.rs index bc58da50,2edd90fd..a75f2efe --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@@ -182,39 -143,36 +182,41 @@@ impl<'a> ArithmeticEvaluator<'a> } fn get_unary_instr( - name: ClauseName, + &self, + name: Atom, a1: ArithmeticTerm, t: usize, - ) -> Result { - 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 { + 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)), } } diff --cc src/machine/arithmetic_ops.rs index 6af111b2,4e3f832a..6be49e8d --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@@ -595,546 -510,364 +595,557 @@@ pub(crate) fn idiv(n1: Number, n2: Numb )) } } + (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 { - 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 { + 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 { + 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 { - 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 { + 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( - &self, - n1: Number, - f: FloatFn, - ) -> Result - 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 { - self.unary_float_fn_template(n1, |f| f.sin()) - } +pub(crate) fn and(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let and_atom = atom!("/\\"); + functor_stub(and_atom, 2) + }; - #[inline] - pub(crate) fn cos(&self, n1: Number) -> Result { - 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 { - self.unary_float_fn_template(n1, |f| f.tan()) - } +pub(crate) fn or(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let or_atom = atom!("\\/"); + functor_stub(or_atom, 2) + }; - #[inline] - pub(crate) fn log(&self, n1: Number) -> Result { - 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 { - self.unary_float_fn_template(n1, |f| f.exp()) - } +pub(crate) fn xor(n1: Number, n2: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let xor_atom = atom!("xor"); + functor_stub(xor_atom, 2) + }; - #[inline] - pub(crate) fn asin(&self, n1: Number) -> Result { - 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 { - self.unary_float_fn_template(n1, |f| f.acos()) - } +pub(crate) fn modulus(x: Number, y: Number, arena: &mut Arena) -> Result { + let stub_gen = || { + let mod_atom = atom!("mod"); + functor_stub(mod_atom, 2) + }; - #[inline] - pub(crate) fn atan(&self, n1: Number) -> Result { - 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 { - 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 { - 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 { + 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 { + 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 { + 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 { + unary_float_fn_template(n1, |f| f.sin()) +} + +#[inline] +pub(crate) fn cos(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.cos()) +} + +#[inline] +pub(crate) fn tan(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.tan()) +} + +#[inline] +pub(crate) fn log(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.log(f64::consts::E)) +} + +#[inline] +pub(crate) fn exp(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.exp()) +} + +#[inline] +pub(crate) fn asin(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.asin()) +} + +#[inline] +pub(crate) fn acos(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.acos()) +} + +#[inline] +pub(crate) fn atan(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.atan()) +} + +#[inline] +pub(crate) fn asinh(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.asinh()) +} + +#[inline] +pub(crate) fn acosh(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.acosh()) +} + +#[inline] +pub(crate) fn atanh(n1: Number) -> Result { + 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 { + unary_float_fn_template(n1, |f| f.sinh()) +} + +#[inline] +pub(crate) fn cosh(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.cosh()) +} + +#[inline] +pub(crate) fn tanh(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.tanh()) +} + +#[inline] +pub(crate) fn log10(n1: Number) -> Result { + unary_float_fn_template(n1, |f| f.log(10f64)) +} + ++#[inline] ++pub(crate) fn float_fractional_part(n1: Number) -> Result { ++ unary_float_fn_template(n1, |f| f.fract()) ++} ++ ++#[inline] ++pub(crate) fn float_integer_part(n1: Number) -> Result { ++ unary_float_fn_template(n1, |f| f.trunc()) ++} ++ +#[inline] +pub(crate) fn sqrt(n1: Number) -> Result { + 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 { - 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 { - let stub = MachineError::functor_stub(clause_name!("(>>)"), 2); +pub(crate) fn round(n: Number, arena: &mut Arena) -> Result { + 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 { - 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 { + 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 { - 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 { - 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 { - 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 { - 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 { - let stub = MachineError::functor_stub(clause_name!("(mod)"), 2); +impl MachineState { + #[inline] + pub fn get_number(&mut self, at: &ArithmeticTerm) -> Result { + 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), } } @@@ -1151,353 -920,95 +1162,359 @@@ } } - pub(crate) fn max(&self, n1: Number, n2: Number) -> Result { - 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 { + 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 { - 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))) + ); } } diff --cc src/machine/dispatch.rs index 8f7e3e91,00000000..fbfa6580 mode 100644,000000..100644 --- a/src/machine/dispatch.rs +++ b/src/machine/dispatch.rs @@@ -1,5342 -1,0 +1,5360 @@@ +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!(), + } + } + } +}