Files
mercury/compiler/prog_util.m
Julien Fischer f519e26173 Add builtin 64-bit integer types -- Part 1.
Add the new builtin types: int64 and uint64.

Support for these new types will need to be bootstrapped over several changes.
This is the first such change and does the following:

- Extends the compiler to recognise 'int64' and 'uint64' as builtin types.
- Extends the set of builtin arithmetic, bitwise and relational operators
  to cover the new types.
- Adds the new internal option '--unboxed-int64s' to the compiler; this will be
  used to control whether 64-bit integer types are boxed or not.
- Extends all of the code generators to handle the new types.
- Extends the runtimes to support the new types.
- Adds new modules to the standard library intend to contain basic operations
  on the new types.  (These are currently empty and not documented.)

There are bunch of limitations marks with "XXX INT64"; these will be lifted in
part 2 of this change.  Also, 64-bit integer types are currently always boxed,
again this limitation will be lifted in later changes.

compiler/options.m:
    Add the new option --unboxed-int64s.

compiler/prog_type.m:
compiler/prog_data.m:
compiler/builtin_lib_types.m:
     Recognise int64 and uint64 as builtin types.

compiler/builtin_ops.m:
     Add builtin operations for the new types.

compiler/hlds_data.m:
     Add new tag types for the new types.

compiler/ctgc.selector.m:
compiler/dead_proc_elim.m:
compiler/export.m:
compiler/foreign.m:
compiler/goal_util.m:
compiler/higher_order.m:
compiler/hlds_code_util.m:
compiler/hlds_dependency_graph.m:
compiler/hlds_out_pred.m:
compiler/hlds_out_util.m:
compiler/implementation_defined_literals.m:
compiler/inst_check.m:
compiler/mercury_to_mercury.m:
compiler/mode_util.m:
compiler/module_qual.qualify_items.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/parse_tree_to_term.m:
compiler/parse_type_name.m:
compiler/polymorphism.m:
compiler/prog_out.m:
compiler/prog_util.m:
compiler/rbmm.execution_path.m:
compiler/rtti.m:
compiler/table_gen.m:
compiler/type_util.m:
compiler/typecheck.m:
compiler/unify_gen.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
    Conform to the above changes to the parse tree and HLDS.

compiler/c_util.m:
    Support writing out constants of the new types.

compiler/llds.m:
    Add a representation for constants of the new types to the LLDS.

compiler/stack_layout.m:
    Add a new field to the stack layout params that records whether
    64-bit integers are boxed or not.

compiler/call_gen.:m
compiler/code_info.m:
compiler/disj_gen.m:
compiler/dupproc.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/llds_out_data.m:
compiler/llds_out_instr.m:
compiler/lookup_switch.m:
compiler/mercury_compile_llds_back_end.m:
compiler/prog_rep.m:
compiler/prog_rep_tables.m:
compiler/var_locn.m b/compiler/var_locn.m:
    Support the new types in the LLDS code generator.

compiler/mlds.m:
    Support constants of the new types in the MLDS.

compiler/ml_call_gen.m:
compiler/ml_code_util.m:
compiler/ml_global_data.m:
compiler/ml_rename_classes.m:
compiler/ml_top_gen.m:
compiler/ml_type_gen.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/mlds_to_target_util.m:
compiler/rtti_to_mlds.m:
     Conform to the above changes to the MLDS.

compiler/mlds_to_c.m:
compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
    Generate the appropriate target code for constants of the new types
    and operations involving them.

compiler/bytecode.m:
compiler/bytecode_gen.m:
    Handle the new types in the bytecode generator; we just abort if we
    encounter them for now.

compiler/elds.m:
compiler/elds_to_erlang.m:
compiler/erl_call_gen.m:
compiler/erl_code_util.m:
compiler/erl_unify_gen.m:
    Handle the new types in the Erlang code generator.

library/private_builtin.m:
    Add placeholders for the builtin unify and compare operations for
    the new types.  Since the bootstrapping compiler will not recognise
    the new types we give them polymorphic arguments.  These can be
    replaced after this change has bootstrapped.

    Update the Java list of TypeCtorRep constants here.

library/int64.m:
library/uint64.m:
    New modules that will eventually contain builtin operations on the new
    types.

library/library.m:
library/MODULES_UNDOC:
    Do not include the above modules in the library documentation for now.

library/construct.m:
library/erlang_rtti_implementation.m:
library/rtti_implementation.m:
library/table_statistics.m:
deep_profiler/program_representation_utils.m:
mdbcomp/program_representation.m:
    Handle the new types.

configure.ac:
runtime/mercury_conf.h.in:
    Define the macro MR_BOXED_INT64S.  For now it is always defined, support for
    unboxed 64-bit integers will be enabled in a later change.

runtime/mercury_dotnet.cs.in:
java/runtime/TypeCtorRep.java:
runtime/mercury_type_info.h:
    Update the list of type_ctor reps.

runtime/mercury.h:
runtime/mercury_int.[ch]:
    Add macros for int64 / uint64 -> MR_Word conversion, boxing and
    unboxing.

    Add functions for hashing 64-bit integer types suitable for use
    with the tabling mechanism.

runtime/mercury_tabling.[ch]:
    Add additional HashTableSlot structs for 64-bit integer types.

    Omit the '%' character from the conversion specifiers we pass via
    the 'key_format' argument to the macros that generate the table lookup
    function.  This is so we can use the C99 exact size integer conversion
    specifiers (e.g. PRIu64 etc.) directly here.

runtime/mercury_hash_lookup_or_add_body.h:
    Add the '%' character that was omitted above to the call to debug_key_msg.

runtime/mercury_memory.h:
     Add new builtin allocation sites for boxed 64-bit integer types.

runtime/mercury_builtin_types.[ch]:
runtime/mercury_builitn_types_proc_layouts.h:
runtime/mercury_construct.c:
runtime/mercury_deconstruct.c:
runtime/mercury_deep_copy_body.h:
runtime/mercury_ml_expand_body.h:
runtime/mercury_table_type_body.h:
runtime/mercury_tabling_macros.h:
runtime/mercury_tabling_preds.h:
runtime/mercury_term_size.c:
runtime/mercury_unify_compare_body.h:
    Add the new builtin types and handle them throughout the runtime.

runtime/Mmakefile:
    Add mercury_int.c to the list of .c files.

doc/reference_manual.texi:
     Add the new types to the list of reserved type names.

     Add the mapping from the new types to their target language types.
     These are commented out for now.
2018-01-12 09:29:24 -05:00

919 lines
35 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 1994-2001, 2003-2012 The University of Melbourne.
% Copyright (C) 2014-2017 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: prog_util.
% Main author: fjh.
%
% Various utility predicates acting on the parse tree data structure.
%
%-----------------------------------------------------------------------------%
:- module parse_tree.prog_util.
:- interface.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_data_pragma.
:- import_module parse_tree.prog_item.
:- import_module integer.
:- import_module list.
:- import_module maybe.
:- import_module term.
:- import_module varset.
%-----------------------------------------------------------------------------%
% Given a possible module qualified sym_name and a list of argument types
% and a context, construct a term. This is used to construct types.
%
:- pred construct_qualified_term(sym_name::in, list(term(T))::in,
term(T)::out) is det.
:- pred construct_qualified_term_with_context(sym_name::in, list(term(T))::in,
prog_context::in, term(T)::out) is det.
%-----------------------------------------------------------------------------%
% adjust_func_arity(PredOrFunc, FuncArity, PredArity).
%
% We internally store the arity as the length of the argument list
% including the return value, which is one more than the arity
% of the function reported in error messages.
%
:- pred adjust_func_arity(pred_or_func, int, int).
:- mode adjust_func_arity(in, in, out) is det.
:- mode adjust_func_arity(in, out, in) is det.
%-----------------------------------------------------------------------------%
% make_pred_name_with_context(ModuleName, Prefix, PredOrFunc,
% PredName, Line, Counter, SymName):
%
% Create a predicate name and return it as SymName. Create the name
% based on the Prefix, the PredOrFunc, the base name PredName,
% and the line number Line.
%
% For use in cases where we create more than one predicate for the
% same line, we also include the per-line distinguishing Counter
% in the name.
%
:- pred make_pred_name_with_context(module_name::in, string::in,
pred_or_func::in, string::in, int::in, int::in, sym_name::out) is det.
% make_pred_name_with_context(ModuleName, Prefix, MaybePredOrFunc,
% PredName, NewPredId, SymName):
%
% Create a predicate name and return it as SymName. Create the name
% based on the Prefix, the (maybe) PredOrFunc, the base name PredName,
% and the pred-name-suffix generating scheme described by NewPredId.
%
:- pred make_pred_name(module_name::in, string::in, maybe(pred_or_func)::in,
string::in, new_pred_id::in, sym_name::out) is det.
:- type new_pred_id
---> newpred_counter(int, int) % Line number, Counter
; newpred_type_subst(tvarset, type_subst)
; newpred_unused_args(list(int))
; newpred_parallel_args(list(int))
; newpred_parallel_loop_control
; newpred_structure_reuse(int, list(int)) % Mode, no-clobber
% arguments.
; newpred_distance_granularity(int). % Distance
%-----------------------------------------------------------------------------%
:- type maybe_modes == maybe(list(mer_mode)).
% A pred declaration may contains just types, as in
% :- pred list.append(list(T), list(T), list(T)).
% or it may contain both types and modes, as in
% :- pred list.append(list(T)::in, list(T)::in, list(T)::output).
%
% This predicate takes the argument list of a pred declaration, splits it
% into two separate lists for the types and (if present) the modes.
%
:- pred split_types_and_modes(list(type_and_mode)::in, list(mer_type)::out,
maybe_modes::out) is det.
:- pred split_type_and_mode(type_and_mode::in, mer_type::out,
maybe(mer_mode)::out) is det.
%-----------------------------------------------------------------------------%
% Perform a substitution on a goal.
%
:- pred rename_in_goal(prog_var::in, prog_var::in, goal::in, goal::out) is det.
%-----------------------------------------------------------------------------%
% Various predicates for accessing the cons_id type.
% Given a cons_id and a list of argument terms, convert it into a term.
% Works only on the cons_ids that can be expressed in source programs,
% so it fails e.g. on pred_consts and type_ctor_info_consts.
%
:- pred cons_id_and_args_to_term(cons_id::in, list(term(T))::in, term(T)::out)
is semidet.
% Get the arity of a cons_id, aborting on pred_const and
% type_ctor_info_const.
%
:- func cons_id_arity(cons_id) = arity.
% Get the arity of a cons_id. Return a `no' on those cons_ids
% where cons_id_arity/2 would normally abort.
%
:- func cons_id_maybe_arity(cons_id) = maybe(arity).
% The reverse conversion - make a cons_id for a functor.
% Given a const and an arity for the functor, create a cons_id.
%
:- pred make_functor_cons_id(const::in, arity::in, cons_id::out) is semidet.
:- pred det_make_functor_cons_id(const::in, arity::in, cons_id::out) is det.
% source_integer_to_int(Base, Integer, Int):
%
% Convert an arbitrary precision integer to a native int. For base 10, this
% predicate succeeds iff the value of Integer does not exceed int.max_int.
% For other bases, this predicate succeeds iff the value of Integer can be
% represented by an unsigned integer of the same width as `int', and `Int'
% is the signed integer with the same bit pattern as that unsigned value.
% The rationale for this behaviour is that non base 10 integers are assumed
% to denote bit patterns and that in Mercury source files it is useful to
% be able to write values with the high bit set (e.g. 0x80000000 on 32-bit
% machines) that would be greater than max_int if interpreted as a positive
% integer.
%
% XXX UINT - we should revisit the the above behaviour once support for
% unsigned integers is stable.
%
:- pred source_integer_to_int(integer_base::in, integer::in, int::out)
is semidet.
%-----------------------------------------------------------------------------%
% Strip the module qualifier from the given cons_id or sym_name.
%
:- pred strip_module_qualifier_from_cons_id(cons_id::in, cons_id::out) is det.
:- pred strip_module_qualifier_from_sym_name(sym_name::in, sym_name::out)
is det.
% Strip the module qualifier from the given cons_id or sym_name, but
% only if the module named by that qualifier is the public builtin module.
%
:- pred strip_builtin_qualifier_from_cons_id(cons_id::in, cons_id::out) is det.
:- pred strip_builtin_qualifier_from_sym_name(sym_name::in, sym_name::out)
is det.
%-----------------------------------------------------------------------------%
% make_n_fresh_vars(Name, N, VarSet0, Vars, VarSet):
% `Vars' is a list of `N' fresh variables allocated from
% `VarSet0'. The variables will be named "<Name>1", "<Name>2",
% "<Name>3", and so on, where <Name> is the value of `Name'.
% `VarSet' is the resulting varset.
%
:- pred make_n_fresh_vars(string::in, int::in, list(var(T))::out,
varset(T)::in, varset(T)::out) is det.
% Given the list of predicate arguments for a predicate that
% is really a function, split that list into the function arguments
% and the function return type.
%
:- pred pred_args_to_func_args(list(T)::in, list(T)::out, T::out) is det.
% Get the last two arguments from the list, failing if there
% aren't at least two arguments.
%
:- pred get_state_args(list(T)::in, list(T)::out, T::out, T::out) is semidet.
% Get the last two arguments from the list, aborting if there
% aren't at least two arguments.
%
:- pred get_state_args_det(list(T)::in, list(T)::out, T::out, T::out) is det.
%-----------------------------------------------------------------------------%
% Add new type variables for those introduced by a type qualification.
%
:- pred get_new_tvars(list(tvar)::in, tvarset::in, tvarset::in, tvarset::out,
tvar_name_map::in, tvar_name_map::out,
tvar_renaming::in, tvar_renaming::out) is det.
%-----------------------------------------------------------------------------%
% Convert a list of goals into a conjunction.
%
:- func goal_list_to_conj(prog_context, list(goal)) = goal.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module mdbcomp.
:- import_module mdbcomp.builtin_modules.
:- import_module parse_tree.mercury_to_mercury.
:- import_module parse_tree.prog_out.
:- import_module bool.
:- import_module int.
:- import_module map.
:- import_module pair.
:- import_module require.
:- import_module string.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
construct_qualified_term(SymName, ArgTerms, Term) :-
term.context_init(Context),
construct_qualified_term_with_context(SymName, ArgTerms, Context, Term).
construct_qualified_term_with_context(SymName, ArgTerms, Context, Term) :-
(
SymName = qualified(ModuleSymName, Name),
construct_qualified_term_with_context(ModuleSymName, [], Context,
ModuleTerm),
UnqualifiedTerm = term.functor(term.atom(Name), ArgTerms, Context),
Term = term.functor(term.atom("."),
[ModuleTerm, UnqualifiedTerm], Context)
;
SymName = unqualified(Name),
Term = term.functor(term.atom(Name), ArgTerms, Context)
).
%-----------------------------------------------------------------------------%
adjust_func_arity(pf_predicate, Arity, Arity).
adjust_func_arity(pf_function, Arity - 1, Arity).
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
split_types_and_modes(TypesAndModes, Types, MaybeModes) :-
split_types_and_modes_2(TypesAndModes, yes, Types, Modes, Result),
(
Result = yes,
MaybeModes = yes(Modes)
;
Result = no,
MaybeModes = no
).
:- pred split_types_and_modes_2(list(type_and_mode)::in, bool::in,
list(mer_type)::out, list(mer_mode)::out, bool::out) is det.
% T = type, M = mode, TM = combined type and mode
split_types_and_modes_2([], Result, [], [], Result).
split_types_and_modes_2([TM | TMs], Result0, [T | Ts], [M | Ms], Result) :-
split_type_and_mode(TM, Result0, T, M, Result1),
split_types_and_modes_2(TMs, Result1, Ts, Ms, Result).
% If a pred declaration specifies modes for some but not all of the
% arguments, then the modes are ignored - should this be an error instead?
% trd: this should never happen because the parser will detect these cases.
%
:- pred split_type_and_mode(type_and_mode::in, bool::in,
mer_type::out, mer_mode::out, bool::out) is det.
split_type_and_mode(type_only(T), _, T, from_to_mode(free, free), no).
split_type_and_mode(type_and_mode(T, M), R, T, M, R).
split_type_and_mode(type_only(T), T, no).
split_type_and_mode(type_and_mode(T, M), T, yes(M)).
%-----------------------------------------------------------------------------%
rename_in_goal(OldVar, NewVar, Goal0, Goal) :-
(
( Goal0 = true_expr(_Context)
; Goal0 = fail_expr(_Context)
),
Goal = Goal0
;
Goal0 = conj_expr(Context, SubGoalA0, SubGoalB0),
rename_in_goal(OldVar, NewVar, SubGoalA0, SubGoalA),
rename_in_goal(OldVar, NewVar, SubGoalB0, SubGoalB),
Goal = conj_expr(Context, SubGoalA, SubGoalB)
;
Goal0 = par_conj_expr(Context, SubGoalA0, SubGoalB0),
rename_in_goal(OldVar, NewVar, SubGoalA0, SubGoalA),
rename_in_goal(OldVar, NewVar, SubGoalB0, SubGoalB),
Goal = par_conj_expr(Context, SubGoalA, SubGoalB)
;
Goal0 = disj_expr(Context, SubGoalA0, SubGoalB0),
rename_in_goal(OldVar, NewVar, SubGoalA0, SubGoalA),
rename_in_goal(OldVar, NewVar, SubGoalB0, SubGoalB),
Goal = disj_expr(Context, SubGoalA, SubGoalB)
;
Goal0 = not_expr(Context, SubGoal0),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = not_expr(Context, SubGoal)
;
Goal0 = quant_expr(QuantType, QuantVarsKind, Context, Vars0, SubGoal0),
rename_in_vars(OldVar, NewVar, Vars0, Vars),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = quant_expr(QuantType, QuantVarsKind, Context, Vars, SubGoal)
;
Goal0 = promise_purity_expr(Context, Purity, SubGoal0),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = promise_purity_expr(Context, Purity, SubGoal)
;
Goal0 = promise_equivalent_solutions_expr(Context,
Vars0, StateVars0, DotSVars0, ColonSVars0, SubGoal0),
rename_in_vars(OldVar, NewVar, Vars0, Vars),
rename_in_vars(OldVar, NewVar, StateVars0, StateVars),
rename_in_vars(OldVar, NewVar, DotSVars0, DotSVars),
rename_in_vars(OldVar, NewVar, ColonSVars0, ColonSVars),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = promise_equivalent_solutions_expr(Context,
Vars, StateVars, DotSVars, ColonSVars, SubGoal)
;
Goal0 = promise_equivalent_solution_sets_expr(Context,
Vars0, StateVars0, DotSVars0, ColonSVars0, SubGoal0),
rename_in_vars(OldVar, NewVar, Vars0, Vars),
rename_in_vars(OldVar, NewVar, StateVars0, StateVars),
rename_in_vars(OldVar, NewVar, DotSVars0, DotSVars),
rename_in_vars(OldVar, NewVar, ColonSVars0, ColonSVars),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = promise_equivalent_solution_sets_expr(Context,
Vars, StateVars, DotSVars, ColonSVars, SubGoal)
;
Goal0 = promise_equivalent_solution_arbitrary_expr(Context,
Vars0, StateVars0, DotSVars0, ColonSVars0, SubGoal0),
rename_in_vars(OldVar, NewVar, Vars0, Vars),
rename_in_vars(OldVar, NewVar, StateVars0, StateVars),
rename_in_vars(OldVar, NewVar, DotSVars0, DotSVars),
rename_in_vars(OldVar, NewVar, ColonSVars0, ColonSVars),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = promise_equivalent_solution_arbitrary_expr(Context,
Vars, StateVars,
DotSVars, ColonSVars, SubGoal)
;
Goal0 = disable_warnings_expr(Context, HeadWarnings, TailWarnings,
SubGoal0),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = disable_warnings_expr(Context, HeadWarnings, TailWarnings,
SubGoal)
;
Goal0 = require_detism_expr(Context, Detism, SubGoal0),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = require_detism_expr(Context, Detism, SubGoal)
;
Goal0 = require_complete_switch_expr(Context, Var0, SubGoal0),
rename_in_plain_or_dot_var(OldVar, NewVar, Var0, Var),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = require_complete_switch_expr(Context, Var, SubGoal)
;
Goal0 = require_switch_arms_detism_expr(Context,
Var0, Detism, SubGoal0),
rename_in_plain_or_dot_var(OldVar, NewVar, Var0, Var),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = require_switch_arms_detism_expr(Context,
Var, Detism, SubGoal)
;
Goal0 = trace_expr(Context, CompileTime, RunTime, MaybeIO0, Mutables0,
SubGoal0),
(
MaybeIO0 = no,
MaybeIO = no
;
MaybeIO0 = yes(IOStateVar0),
rename_in_var(OldVar, NewVar, IOStateVar0, IOStateVar),
MaybeIO = yes(IOStateVar)
),
list.map(rename_in_trace_mutable_var(OldVar, NewVar),
Mutables0, Mutables),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
Goal = trace_expr(Context, CompileTime, RunTime, MaybeIO, Mutables,
SubGoal)
;
Goal0 = atomic_expr(Context, InVars0, OutVars0, MaybeVars0,
MainGoal0, OrElseGoal0),
rename_in_atomic_varlist(OldVar, NewVar, InVars0, InVars),
rename_in_atomic_varlist(OldVar, NewVar, OutVars0, OutVars),
(
MaybeVars0 = no,
MaybeVars = no
;
MaybeVars0 = yes(TransVars0),
list.map(rename_in_var(OldVar, NewVar),
TransVars0, TransVars),
MaybeVars = yes(TransVars)
),
rename_in_goal(OldVar, NewVar, MainGoal0, MainGoal),
list.map(rename_in_goal(OldVar, NewVar), OrElseGoal0, OrElseGoal),
Goal = atomic_expr(Context, InVars, OutVars, MaybeVars,
MainGoal, OrElseGoal)
;
Goal0 = try_expr(Context, MaybeIO0, SubGoal0, Then0, MaybeElse0,
Catches0, MaybeCatchAny0),
rename_in_maybe_var(OldVar, NewVar, MaybeIO0, MaybeIO),
rename_in_goal(OldVar, NewVar, SubGoal0, SubGoal),
rename_in_goal(OldVar, NewVar, Then0, Then),
(
MaybeElse0 = yes(Else0),
rename_in_goal(OldVar, NewVar, Else0, Else),
MaybeElse = yes(Else)
;
MaybeElse0 = no,
MaybeElse = no
),
list.map(rename_in_catch_expr(OldVar, NewVar), Catches0, Catches),
(
MaybeCatchAny0 = yes(catch_any_expr(CatchAnyVar0, CatchAnyGoal0)),
rename_in_var(OldVar, NewVar, CatchAnyVar0, CatchAnyVar),
rename_in_goal(OldVar, NewVar, CatchAnyGoal0, CatchAnyGoal),
MaybeCatchAny = yes(catch_any_expr(CatchAnyVar, CatchAnyGoal))
;
MaybeCatchAny0 = no,
MaybeCatchAny = no
),
Goal = try_expr(Context, MaybeIO, SubGoal, Then, MaybeElse,
Catches, MaybeCatchAny)
;
Goal0 = implies_expr(Context, SubGoalA0, SubGoalB0),
rename_in_goal(OldVar, NewVar, SubGoalA0, SubGoalA),
rename_in_goal(OldVar, NewVar, SubGoalB0, SubGoalB),
Goal = implies_expr(Context, SubGoalA, SubGoalB)
;
Goal0 = equivalent_expr(Context, SubGoalA0, SubGoalB0),
rename_in_goal(OldVar, NewVar, SubGoalA0, SubGoalA),
rename_in_goal(OldVar, NewVar, SubGoalB0, SubGoalB),
Goal = equivalent_expr(Context, SubGoalA, SubGoalB)
;
Goal0 = if_then_else_expr(Context, Vars0, StateVars0,
Cond0, Then0, Else0),
rename_in_vars(OldVar, NewVar, Vars0, Vars),
rename_in_vars(OldVar, NewVar, StateVars0, StateVars),
rename_in_goal(OldVar, NewVar, Cond0, Cond),
rename_in_goal(OldVar, NewVar, Then0, Then),
rename_in_goal(OldVar, NewVar, Else0, Else),
Goal = if_then_else_expr(Context, Vars, StateVars,
Cond, Then, Else)
;
Goal0 = event_expr(Context, Name, Terms0),
term.rename_var_in_terms(OldVar, NewVar, Terms0, Terms),
Goal = event_expr(Context, Name, Terms)
;
Goal0 = call_expr(Context, SymName, Terms0, Purity),
term.rename_var_in_terms(OldVar, NewVar, Terms0, Terms),
Goal = call_expr(Context, SymName, Terms, Purity)
;
Goal0 = unify_expr(Context, TermA0, TermB0, Purity),
term.rename_var_in_term(OldVar, NewVar, TermA0, TermA),
term.rename_var_in_term(OldVar, NewVar, TermB0, TermB),
Goal = unify_expr(Context, TermA, TermB, Purity)
).
:- pred rename_in_atomic_varlist(prog_var::in, prog_var::in,
atomic_component_state::in, atomic_component_state::out) is det.
rename_in_atomic_varlist(OldVar, NewVar, Comp0, Comp) :-
(
Comp0 = atomic_state_var(SVar0),
rename_in_var(OldVar, NewVar, SVar0, SVar),
Comp = atomic_state_var(SVar)
;
Comp0 = atomic_var_pair(IVar0, OVar0),
rename_in_var(OldVar, NewVar, IVar0, IVar),
rename_in_var(OldVar, NewVar, OVar0, OVar),
Comp = atomic_var_pair(IVar, OVar)
).
:- pred rename_in_trace_mutable_var(prog_var::in, prog_var::in,
trace_mutable_var::in, trace_mutable_var::out) is det.
rename_in_trace_mutable_var(OldVar, NewVar, TMV0, TMV) :-
TMV0 = trace_mutable_var(MutableName, StateVar0),
rename_in_var(OldVar, NewVar, StateVar0, StateVar),
TMV = trace_mutable_var(MutableName, StateVar).
:- pred rename_in_plain_or_dot_var(prog_var::in, prog_var::in,
plain_or_dot_var::in, plain_or_dot_var::out) is det.
rename_in_plain_or_dot_var(OldVar, NewVar, PODVar0, PODVar) :-
(
PODVar0 = podv_plain(Var0),
rename_in_var(OldVar, NewVar, Var0, Var),
PODVar = podv_plain(Var)
;
PODVar0 = podv_dot(DotVar0),
rename_in_var(OldVar, NewVar, DotVar0, DotVar),
PODVar = podv_dot(DotVar)
).
:- pred rename_in_vars(prog_var::in, prog_var::in,
list(prog_var)::in, list(prog_var)::out) is det.
rename_in_vars(_, _, [], []).
rename_in_vars(OldVar, NewVar, [Var0 | Vars0], [Var | Vars]) :-
rename_in_var(OldVar, NewVar, Var0, Var),
rename_in_vars(OldVar, NewVar, Vars0, Vars).
:- pred rename_in_var(prog_var::in, prog_var::in,
prog_var::in, prog_var::out) is det.
rename_in_var(OldVar, NewVar, Var0, Var) :-
( if Var0 = OldVar then
Var = NewVar
else
Var = Var0
).
:- pred rename_in_maybe_var(prog_var::in, prog_var::in,
maybe(prog_var)::in, maybe(prog_var)::out) is det.
rename_in_maybe_var(OldVar, NewVar, MaybeVar0, MaybeVar) :-
(
MaybeVar0 = yes(Var0),
rename_in_var(OldVar, NewVar, Var0, Var),
MaybeVar = yes(Var)
;
MaybeVar0 = no,
MaybeVar = no
).
:- pred rename_in_catch_expr(prog_var::in, prog_var::in,
catch_expr::in, catch_expr::out) is det.
rename_in_catch_expr(OldVar, NewVar, Catch0, Catch) :-
Catch0 = catch_expr(Term0, Goal0),
term.rename_var_in_term(OldVar, NewVar, Term0, Term),
rename_in_goal(OldVar, NewVar, Goal0, Goal),
Catch = catch_expr(Term, Goal).
%-----------------------------------------------------------------------------%
make_pred_name_with_context(ModuleName, Prefix, PredOrFunc, PredName,
Line, Counter, SymName) :-
make_pred_name(ModuleName, Prefix, yes(PredOrFunc), PredName,
newpred_counter(Line, Counter), SymName).
make_pred_name(ModuleName, Prefix, MaybePredOrFunc, PredName,
NewPredId, SymName) :-
(
MaybePredOrFunc = yes(PredOrFunc),
PFS = pred_or_func_to_str(PredOrFunc)
;
MaybePredOrFunc = no,
PFS = "pred_or_func"
),
(
NewPredId = newpred_counter(Line, Counter),
string.format("%d__%d", [i(Line), i(Counter)], PredIdStr)
;
NewPredId = newpred_type_subst(VarSet, TypeSubst),
SubstToString = (pred(SubstElem::in, SubstStr::out) is det :-
SubstElem = Var - Type,
varset.lookup_name(VarSet, Var, VarName),
TypeString = mercury_type_to_string(VarSet, print_name_only, Type),
string.append_list([VarName, " = ", TypeString], SubstStr)
),
list_to_string(SubstToString, TypeSubst, PredIdStr)
;
( NewPredId = newpred_unused_args(Args)
; NewPredId = newpred_parallel_args(Args)
),
list_to_string(int_to_string, Args, PredIdStr)
;
NewPredId = newpred_structure_reuse(ModeNum, Args),
int_to_string(ModeNum, ModeStr),
list_to_string(int_to_string, Args, ArgsStr),
PredIdStr = ModeStr ++ "__" ++ ArgsStr
;
NewPredId = newpred_distance_granularity(Distance),
int_to_string(Distance, PredIdStr)
;
NewPredId = newpred_parallel_loop_control,
PredIdStr = ""
),
string.format("%s__%s__%s__%s",
[s(Prefix), s(PFS), s(PredName), s(PredIdStr)], Name),
SymName = qualified(ModuleName, Name).
:- pred list_to_string(pred(T, string)::in(pred(in, out) is det),
list(T)::in, string::out) is det.
list_to_string(Pred, List, String) :-
list_to_string_2(Pred, List, ["]"], Strings),
string.append_list(["[" | Strings], String).
:- pred list_to_string_2(pred(T, string)::in(pred(in, out) is det),
list(T)::in, list(string)::in, list(string)::out) is det.
list_to_string_2(_, [], !Strings).
list_to_string_2(Pred, [T | Ts], !Strings) :-
(
Ts = []
;
Ts = [_ | _],
list_to_string_2(Pred, Ts, !Strings),
!:Strings = [", " | !.Strings]
),
call(Pred, T, String),
!:Strings = [String | !.Strings].
%-----------------------------------------------------------------------------%
cons_id_and_args_to_term(int_const(Int), [], Term) :-
term.context_init(Context),
Term = int_to_decimal_term(Int, Context).
cons_id_and_args_to_term(uint_const(UInt), [], Term) :-
term.context_init(Context),
Term = uint_to_decimal_term(UInt, Context).
cons_id_and_args_to_term(float_const(Float), [], Term) :-
term.context_init(Context),
Term = term.functor(term.float(Float), [], Context).
cons_id_and_args_to_term(char_const(Char), [], Term) :-
SymName = unqualified(string.from_char(Char)),
construct_qualified_term(SymName, [], Term).
cons_id_and_args_to_term(string_const(String), [], Term) :-
term.context_init(Context),
Term = term.functor(term.string(String), [], Context).
cons_id_and_args_to_term(tuple_cons(_Arity), Args, Term) :-
SymName = unqualified("{}"),
construct_qualified_term(SymName, Args, Term).
cons_id_and_args_to_term(cons(SymName, _Arity, _TypeCtor), Args, Term) :-
construct_qualified_term(SymName, Args, Term).
cons_id_arity(ConsId) = Arity :-
(
ConsId = cons(_, Arity, _)
;
ConsId = tuple_cons(Arity)
;
ConsId = ground_term_const(_, SubConsId),
Arity = cons_id_arity(SubConsId)
;
( ConsId = int_const(_)
; ConsId = uint_const(_)
; ConsId = int8_const(_)
; ConsId = uint8_const(_)
; ConsId = int16_const(_)
; ConsId = uint16_const(_)
; ConsId = int32_const(_)
; ConsId = uint32_const(_)
; ConsId = int64_const(_)
; ConsId = uint64_const(_)
; ConsId = float_const(_)
; ConsId = char_const(_)
; ConsId = string_const(_)
; ConsId = impl_defined_const(_)
),
Arity = 0
;
( ConsId = closure_cons(_, _)
; ConsId = type_ctor_info_const(_, _, _)
; ConsId = base_typeclass_info_const(_, _, _, _)
; ConsId = type_info_cell_constructor(_)
; ConsId = typeclass_info_cell_constructor
; ConsId = type_info_const(_)
; ConsId = typeclass_info_const(_)
; ConsId = tabling_info_const(_)
; ConsId = deep_profiling_proc_layout(_)
; ConsId = table_io_entry_desc(_)
),
unexpected($pred, "unexpected cons_id")
).
cons_id_maybe_arity(cons(_, Arity, _)) = yes(Arity).
cons_id_maybe_arity(tuple_cons(Arity)) = yes(Arity).
cons_id_maybe_arity(int_const(_)) = yes(0).
cons_id_maybe_arity(uint_const(_)) = yes(0).
cons_id_maybe_arity(int8_const(_)) = yes(0).
cons_id_maybe_arity(uint8_const(_)) = yes(0).
cons_id_maybe_arity(int16_const(_)) = yes(0).
cons_id_maybe_arity(uint16_const(_)) = yes(0).
cons_id_maybe_arity(int32_const(_)) = yes(0).
cons_id_maybe_arity(uint32_const(_)) = yes(0).
cons_id_maybe_arity(int64_const(_)) = yes(0).
cons_id_maybe_arity(uint64_const(_)) = yes(0).
cons_id_maybe_arity(float_const(_)) = yes(0).
cons_id_maybe_arity(char_const(_)) = yes(0).
cons_id_maybe_arity(string_const(_)) = yes(0).
cons_id_maybe_arity(impl_defined_const(_)) = yes(0).
cons_id_maybe_arity(closure_cons(_, _)) = no.
cons_id_maybe_arity(type_ctor_info_const(_, _, _)) = no.
cons_id_maybe_arity(base_typeclass_info_const(_, _, _, _)) = no.
cons_id_maybe_arity(type_info_cell_constructor(_)) = no.
cons_id_maybe_arity(typeclass_info_cell_constructor) = no.
cons_id_maybe_arity(type_info_const(_)) = no.
cons_id_maybe_arity(typeclass_info_const(_)) = no.
cons_id_maybe_arity(ground_term_const(_, ConsId)) =
cons_id_maybe_arity(ConsId).
cons_id_maybe_arity(tabling_info_const(_)) = no.
cons_id_maybe_arity(deep_profiling_proc_layout(_)) = no.
cons_id_maybe_arity(table_io_entry_desc(_)) = no.
make_functor_cons_id(Functor, Arity, ConsId) :-
% The logic of this predicate is duplicated, with minor differences,
% by parse_ordinary_cons_id in superhomogeneous.m.
% Any change here may need a corresponding change there.
require_complete_switch [Functor]
(
Functor = term.atom(Name),
ConsId = cons(unqualified(Name), Arity, cons_id_dummy_type_ctor)
;
Functor = term.integer(Base, Integer, Signedness, Size),
(
Signedness = signed,
(
Size = size_word,
source_integer_to_int(Base, Integer, Int),
ConsId = int_const(Int)
;
Size = size_8_bit,
integer.to_int8(Integer, Int8),
ConsId = int8_const(Int8)
;
Size = size_16_bit,
integer.to_int16(Integer, Int16),
ConsId = int16_const(Int16)
;
Size = size_32_bit,
integer.to_int32(Integer, Int32),
ConsId = int32_const(Int32)
)
;
Signedness = unsigned,
(
Size = size_word,
integer.to_uint(Integer, UInt),
ConsId = uint_const(UInt)
;
Size = size_8_bit,
integer.to_uint8(Integer, UInt8),
ConsId = uint8_const(UInt8)
;
Size = size_16_bit,
integer.to_uint16(Integer, UInt16),
ConsId = uint16_const(UInt16)
;
Size = size_32_bit,
integer.to_uint32(Integer, UInt32),
ConsId = uint32_const(UInt32)
)
)
;
Functor = term.string(String),
ConsId = string_const(String)
;
Functor = term.float(Float),
ConsId = float_const(Float)
;
Functor = term.implementation_defined(Name),
ConsId = impl_defined_const(Name)
).
det_make_functor_cons_id(Functor, Arity, ConsId) :-
( if make_functor_cons_id(Functor, Arity, ConsIdPrime) then
ConsId = ConsIdPrime
else
unexpected($pred, "make_functor_cons_id failed")
).
source_integer_to_int(Base, Integer, Int) :-
require_complete_switch [Base]
(
Base = base_10,
integer.to_int(Integer, Int)
;
( Base = base_2
; Base = base_8
; Base = base_16
),
( if Integer > integer(max_int) then
NegInteger = Integer + integer(min_int) + integer(min_int),
integer.to_int(NegInteger, Int),
Int < 0
else
integer.to_int(Integer, Int)
)
).
%-----------------------------------------------------------------------------%
strip_module_qualifier_from_cons_id(ConsId0, ConsId) :-
( if ConsId0 = cons(Name0, Arity, TypeCtor) then
strip_module_qualifier_from_sym_name(Name0, Name),
ConsId = cons(Name, Arity, TypeCtor)
else
ConsId = ConsId0
).
strip_module_qualifier_from_sym_name(SymName0, SymName) :-
(
SymName0 = qualified(_Module, Name),
SymName = unqualified(Name)
;
SymName0 = unqualified(_Name),
SymName = SymName0
).
strip_builtin_qualifier_from_cons_id(ConsId0, ConsId) :-
( if ConsId0 = cons(Name0, Arity, TypeCtor) then
strip_builtin_qualifier_from_sym_name(Name0, Name),
ConsId = cons(Name, Arity, TypeCtor)
else
ConsId = ConsId0
).
strip_builtin_qualifier_from_sym_name(SymName0, SymName) :-
( if
SymName0 = qualified(Module, Name),
Module = mercury_public_builtin_module
then
SymName = unqualified(Name)
else
SymName = SymName0
).
%-----------------------------------------------------------------------------%
make_n_fresh_vars(BaseName, N, Vars, VarSet0, VarSet) :-
make_n_fresh_vars_loop(BaseName, 1, N, Vars, VarSet0, VarSet).
:- pred make_n_fresh_vars_loop(string::in, int::in, int::in, list(var(T))::out,
varset(T)::in, varset(T)::out) is det.
make_n_fresh_vars_loop(BaseName, Cur, Max, Vars, !VarSet) :-
( if Cur > Max then
Vars = []
else
VarName = BaseName ++ string.int_to_string(Cur),
varset.new_named_var(VarName, HeadVar, !VarSet),
make_n_fresh_vars_loop(BaseName, Cur + 1, Max, TailVars, !VarSet),
Vars = [HeadVar | TailVars]
).
pred_args_to_func_args(PredArgs, FuncArgs, FuncReturn) :-
( if list.split_last(PredArgs, FuncArgsPrime, FuncReturnPrime) then
FuncArgs = FuncArgsPrime,
FuncReturn = FuncReturnPrime
else
unexpected($pred, "function missing return value?")
).
get_state_args(Args0, Args, State0, State) :-
list.reverse(Args0, RevArgs0),
RevArgs0 = [State, State0 | RevArgs],
list.reverse(RevArgs, Args).
get_state_args_det(Args0, Args, State0, State) :-
( if get_state_args(Args0, ArgsPrime, State0Prime, StatePrime) then
Args = ArgsPrime,
State0 = State0Prime,
State = StatePrime
else
unexpected($pred, "get_state_args failed")
).
%-----------------------------------------------------------------------------%
get_new_tvars([], _, !TVarSet, !TVarNameMap, !TVarRenaming).
get_new_tvars([TVar | TVars], VarSet, !TVarSet, !TVarNameMap, !TVarRenaming) :-
( if map.contains(!.TVarRenaming, TVar) then
true
else
( if varset.search_name(VarSet, TVar, TVarName) then
( if map.search(!.TVarNameMap, TVarName, TVarSetVar) then
map.det_insert(TVar, TVarSetVar, !TVarRenaming)
else
varset.new_var(NewTVar, !TVarSet),
varset.name_var(NewTVar, TVarName, !TVarSet),
map.det_insert(TVarName, NewTVar, !TVarNameMap),
map.det_insert(TVar, NewTVar, !TVarRenaming)
)
else
varset.new_var(NewTVar, !TVarSet),
map.det_insert(TVar, NewTVar, !TVarRenaming)
)
),
get_new_tvars(TVars, VarSet, !TVarSet, !TVarNameMap, !TVarRenaming).
%-----------------------------------------------------------------------------%
goal_list_to_conj(Context, []) = true_expr(Context).
goal_list_to_conj(Context, [Goal | Goals]) =
goal_list_to_conj_2(Context, Goal, Goals).
:- func goal_list_to_conj_2(prog_context, goal, list(goal)) = goal.
goal_list_to_conj_2(_, Goal, []) = Goal.
goal_list_to_conj_2(Context, Goal0, [Goal1 | Goals]) =
conj_expr(Context, Goal0, goal_list_to_conj_2(Context, Goal1, Goals)).
%-----------------------------------------------------------------------------%
:- end_module parse_tree.prog_util.
%-----------------------------------------------------------------------------%