mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
926 lines
30 KiB
Mathematica
926 lines
30 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1997-2008, 2011 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: demangle.m.
|
|
% Author: fjh.
|
|
%
|
|
% A Mercury symbol demangler. This is used to convert symbol names back
|
|
% into a form that users can understand.
|
|
%
|
|
% BEWARE: the code here is duplicated in util/mdemangle.c,
|
|
% so any changes here will need to be duplicated there.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module demangle.
|
|
:- interface.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred demangle(string::in, string::out) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module bool.
|
|
:- import_module char.
|
|
:- import_module int.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
:- import_module string.
|
|
:- import_module pair.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- type pred_category
|
|
---> index
|
|
; unify
|
|
; compare
|
|
; ordinary
|
|
; introduced(introduced_pred_type, int, int, string)
|
|
% type, line, sequence number, pred name
|
|
.
|
|
|
|
:- type introduced_pred_type
|
|
---> ipt_lambda
|
|
; ipt_deforestation
|
|
; ipt_accumulator
|
|
; ipt_type_spec(string).
|
|
|
|
:- type data_category
|
|
---> common
|
|
; info
|
|
; layout
|
|
; functors.
|
|
|
|
demangle(MangledName, Name) :-
|
|
( if demangle_from_asm(MangledName, DemangledName) then
|
|
Name = DemangledName
|
|
else
|
|
Name = MangledName
|
|
).
|
|
|
|
:- pred demangle_from_asm(string::in, string::out) is semidet.
|
|
|
|
demangle_from_asm(!Name) :-
|
|
% skip any leading underscore inserted by the C compiler,
|
|
% and skip the `_entry_' prefix, if any.
|
|
( if string.remove_prefix("_entry_", !Name) then
|
|
true
|
|
else
|
|
maybe_remove_prefix("_", !Name),
|
|
maybe_remove_prefix("_entry_", !Name)
|
|
),
|
|
demangle_from_c(!Name).
|
|
|
|
:- pred demangle_from_c(string::in, string::out) is semidet.
|
|
|
|
demangle_from_c(!Str) :-
|
|
( if demangle_proc_hl(!Str) then
|
|
true
|
|
else if demangle_proc_ll(!Str) then
|
|
true
|
|
else if demangle_data(!Str) then
|
|
true
|
|
else if demangle_typeclass_info(!Str) then
|
|
true
|
|
else
|
|
fail
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred demangle_proc_ll(string::in, string::out) is semidet.
|
|
|
|
demangle_proc_ll(!Str) :-
|
|
remove_prefix("mercury__", !Str),
|
|
|
|
% Strip off the `fn__' prefix, if any.
|
|
( if remove_prefix("fn__", !Str) then
|
|
PredOrFunc = "function"
|
|
else
|
|
PredOrFunc = "predicate"
|
|
),
|
|
|
|
% Get integer from end of string (it might be the mode number,
|
|
% it might be the internal label number).
|
|
remove_trailing_int(Int, !Str),
|
|
|
|
( if m_remove_suffix("i", !Str) then
|
|
% If we got to an `i', that means it is an internal label
|
|
% of the form `mercury__append_3_0_i1'; in that case,
|
|
% save the internal label number and then get the mode number.
|
|
MaybeInternalLabelNum = yes(Int),
|
|
m_remove_suffix("_", !Str),
|
|
remove_trailing_int(ModeNum0, !Str)
|
|
else
|
|
MaybeInternalLabelNum = no,
|
|
ModeNum0 = Int
|
|
),
|
|
|
|
% Scan back past the arity number and then parse it.
|
|
m_remove_suffix("_", !Str),
|
|
remove_trailing_int(Arity, !Str),
|
|
m_remove_suffix("_", !Str),
|
|
|
|
% Now start processing from the start of the string again.
|
|
% Check whether the start of the string matches the name of
|
|
% one of the special compiler-generated predicates; if so,
|
|
% set the `category' to the appropriate value and then
|
|
% skip past the prefix.
|
|
handle_compiler_generated_pred(ModeNum0, Category0, !Str),
|
|
|
|
% Fix any ascii codes mangled in the predicate name,
|
|
fix_mangled_ascii(!Str),
|
|
|
|
% Process the mangling introduced by unused_args.m and higher_order.m.
|
|
% This involves stripping off the `__ua<m>', `__uab<m>', and/or `__ho<n>'
|
|
% added to the end of the predicate/function name, where m is the mode
|
|
% number.
|
|
demangle_unused_args(UnusedArgs, ModeNum0, ModeNum1, !Str),
|
|
demangle_higher_order(HigherOrder, ModeNum1, ModeNum, !Str),
|
|
|
|
% Make sure special predicates with unused_args are reported correctly.
|
|
( if UnusedArgs = yes(_), Category0 \= ordinary then
|
|
remove_trailing_int(Arity, !Str)
|
|
else
|
|
true
|
|
),
|
|
|
|
% Separate the module name from the type name for the compiler
|
|
% generated predicates.
|
|
( if Category0 = ordinary then
|
|
remove_maybe_module_prefix(MaybeModule,
|
|
["IntroducedFrom__", "DeforestationIn__",
|
|
"AccFrom__", "TypeSpecOf__", "UnusedArgs__"], !Str)
|
|
else
|
|
remove_prefix("_", !Str),
|
|
remove_maybe_module_prefix(MaybeModule,
|
|
["IntroducedFrom__", "DeforestationIn__",
|
|
"AccFrom__", "TypeSpecOf__", "UnusedArgs__"], !Str),
|
|
MaybeModule \= yes("")
|
|
),
|
|
|
|
% Remove any prefixes added for introduced predicates,
|
|
% and get the predicate name.
|
|
% XXX We should NOT ignore _Str.
|
|
handle_category_etc(PredName, Category0, Category, !.Str, _Str),
|
|
|
|
% Now, finally, we can construct the demangled symbol name.
|
|
format_proc(Category, MaybeModule, PredOrFunc, PredName,
|
|
Arity, ModeNum, HigherOrder, UnusedArgs, MaybeInternalLabelNum,
|
|
DemangledName),
|
|
!:Str = DemangledName.
|
|
|
|
:- pred demangle_proc_hl(string::in, string::out) is semidet.
|
|
|
|
demangle_proc_hl(!Str) :-
|
|
% Symbols in the Mercury standard library get an additional
|
|
% "mercury__" prefix in their mangled name.
|
|
maybe_remove_prefix("mercury__", !Str),
|
|
|
|
% Get integer from end of string (it might be the mode number,
|
|
% it might be the internal label number).
|
|
remove_trailing_int(Int, !Str),
|
|
( if
|
|
% If we got to another int, that means it is an internal label
|
|
% of the form `append_3_p_0_1'. In that case, save the internal label
|
|
% number and then get the mode number.
|
|
m_remove_suffix("_", !Str),
|
|
remove_trailing_int(ModeNum0, !Str)
|
|
then
|
|
ModeNum1 = ModeNum0,
|
|
MaybeInternalLabelNum0 = yes(Int)
|
|
else
|
|
ModeNum1 = Int,
|
|
MaybeInternalLabelNum0 = no
|
|
),
|
|
|
|
% Handle the "f_" or "p_" suffix which indicates whether
|
|
% the procedure is a function or a predicate.
|
|
( if m_remove_suffix("f_", !Str) then
|
|
PredOrFunc = "function",
|
|
Normal = yes
|
|
else if m_remove_suffix("p_", !Str) then
|
|
PredOrFunc = "predicate",
|
|
Normal = yes
|
|
else
|
|
% It could be a compiler-generated unify or compare predicate.
|
|
PredOrFunc = "predicate",
|
|
Normal = no
|
|
),
|
|
|
|
( if
|
|
% Scan back past the arity number and then parse it.
|
|
m_remove_suffix("_", !Str),
|
|
remove_trailing_int(Arity0, !Str)
|
|
then
|
|
Arity = Arity0,
|
|
ModeNum2 = ModeNum1,
|
|
MaybeInternalLabelNum = MaybeInternalLabelNum0
|
|
else
|
|
% It must be a compiler-generated unify or compare.
|
|
% What we thought were the mode number and label number
|
|
% were actually the arity and mode number.
|
|
Normal = no,
|
|
Arity = ModeNum1,
|
|
yes(ModeNum2) = MaybeInternalLabelNum0,
|
|
MaybeInternalLabelNum = no
|
|
),
|
|
m_remove_suffix("_", !Str),
|
|
|
|
% Process the mangling introduced by unused_args.m and higher_order.m.
|
|
% This involves stripping off the `__ua<m>', `__uab<m>', and/or `__ho<n>'
|
|
% added to the end of the predicate/function name, where m is the mode
|
|
% number.
|
|
demangle_unused_args(UnusedArgs, ModeNum2, ModeNum3, !Str),
|
|
demangle_higher_order(HigherOrder, ModeNum3, ModeNum, !Str),
|
|
|
|
% Make sure special predicates with unused_args are reported correctly.
|
|
( if UnusedArgs = yes(_), Normal = no then
|
|
remove_trailing_int(Arity, !Str)
|
|
else
|
|
true
|
|
),
|
|
|
|
% Separate the module name from the predicate name.
|
|
remove_maybe_module_prefix(MaybeModule0,
|
|
["IntroducedFrom__", "DeforestationIn__",
|
|
"AccFrom__", "TypeSpecOf__", "UnusedArgs__", "__"], !Str),
|
|
|
|
% Check whether the start of the string matches the name of one of the
|
|
% special compiler-generated predicates; if so, set the `category'
|
|
% to the appropriate value and then skip past the prefix.
|
|
% Also check that the mode number is valid for the specified category.
|
|
handle_compiler_generated_pred(ModeNum, Category0, !Str),
|
|
( if Category0 = ordinary then
|
|
true
|
|
else
|
|
remove_prefix("__", !Str)
|
|
),
|
|
|
|
% Check that the setting of the category matches the setting
|
|
% of `Normal' determined above.
|
|
( Normal = yes, Category0 = ordinary
|
|
; Normal = no, Category0 \= ordinary
|
|
),
|
|
|
|
% Fix any mangled ascii codes in the predicate name.
|
|
%
|
|
% XXX This should be done *before* stripping off the mangling added by
|
|
% HLDS->HLDS passes such as unused_args.m and higher_order.m.
|
|
% (Doing it here means that we won't properly demangle names that
|
|
% involve both special characters and unused_args/higher_order
|
|
% specializations.) But for the MLDS back-end, it needs to be done *after*
|
|
% removing the module prefix, and currently that can't be done until after
|
|
% stripping off the `__ua*' and `__ho*' suffixes.
|
|
fix_mangled_ascii(!Str),
|
|
|
|
% Fix any mangled ascii codes in the module name, if any.
|
|
(
|
|
MaybeModule0 = no,
|
|
MaybeModule = no
|
|
;
|
|
MaybeModule0 = yes(ModuleName0),
|
|
fix_mangled_ascii(ModuleName0, ModuleName),
|
|
MaybeModule = yes(ModuleName)
|
|
),
|
|
|
|
% Remove any prefixes added for introduced predicates,
|
|
% and get the predicate name.
|
|
% XXX We should NOT ignore _Str.
|
|
handle_category_etc(PredName, Category0, Category, !.Str, _Str),
|
|
|
|
% Now, finally, we can construct the demangled symbol name.
|
|
format_proc(Category, MaybeModule, PredOrFunc, PredName,
|
|
Arity, ModeNum, HigherOrder, UnusedArgs, MaybeInternalLabelNum,
|
|
DemangledName),
|
|
!:Str = DemangledName.
|
|
|
|
:- pred demangle_unused_args(maybe(pair(int, bool))::out, int::in, int::out,
|
|
string::in, string::out) is det.
|
|
|
|
demangle_unused_args(UnusedArgs, ModeNum0, ModeNum, !Str) :-
|
|
% Process the mangling introduced by unused_args.m.
|
|
% This involves stripping off the `__ua<m>' or `__uab<m>' added to
|
|
% the end of the predicate/function name, where m is the mode number.
|
|
% XXX This is out-of-date. The compiler now generates names
|
|
% such as UnusedArgs__p__[1].
|
|
( if
|
|
remove_trailing_int(UA_ModeNum, !Str),
|
|
m_remove_suffix("__ua", !Str)
|
|
then
|
|
UnusedArgs = yes(ModeNum0 - no),
|
|
ModeNum = UA_ModeNum mod 10000
|
|
else if
|
|
remove_trailing_int(UA_ModeNum, !Str),
|
|
m_remove_suffix("__uab", !Str)
|
|
then
|
|
UnusedArgs = yes(ModeNum0 - yes),
|
|
ModeNum = UA_ModeNum mod 10000
|
|
else
|
|
UnusedArgs = no,
|
|
ModeNum = ModeNum0
|
|
).
|
|
|
|
:- pred demangle_higher_order(maybe(int)::out, int::in, int::out,
|
|
string::in, string::out) is det.
|
|
|
|
demangle_higher_order(HigherOrder, ModeNum0, ModeNum, !Str) :-
|
|
% Process the mangling introduced by higher_order.m.
|
|
% This involves stripping off the `__ho<n>' where
|
|
% n is a unique identifier for this specialized version.
|
|
( if
|
|
remove_trailing_int(HO_Num, !Str),
|
|
m_remove_suffix("__ho", !Str)
|
|
then
|
|
HigherOrder = yes(HO_Num)
|
|
else
|
|
HigherOrder = no
|
|
),
|
|
ModeNum = ModeNum0.
|
|
|
|
% Check whether the start of the string matches the name of one of the
|
|
% special compiler-generated predicates; if so, set the category
|
|
% to the appropriate value and then skip past the prefix.
|
|
% Fails if the mode number is invalid for the specified category.
|
|
%
|
|
:- pred handle_compiler_generated_pred(int::in, pred_category::out,
|
|
string::in, string::out) is semidet.
|
|
|
|
handle_compiler_generated_pred(ModeNum0, Category0, !Str) :-
|
|
( if remove_prefix("__Unify__", !Str) then
|
|
Category0 = unify
|
|
else if remove_prefix("__Compare__", !Str) then
|
|
Category0 = compare,
|
|
% There should only be one mode for compare/3 preds.
|
|
ModeNum0 = 0
|
|
else if remove_prefix("__Index__", !Str) then
|
|
Category0 = index,
|
|
% There should only be one mode for index/2 preds.
|
|
ModeNum0 = 0
|
|
else
|
|
Category0 = ordinary
|
|
).
|
|
|
|
% Remove any prefixes added for introduced predicates,
|
|
% and get the predicate name.
|
|
%
|
|
:- pred handle_category_etc(string::out, pred_category::in, pred_category::out,
|
|
string::in, string::out) is semidet.
|
|
|
|
handle_category_etc(PredName, Category0, Category, !Str) :-
|
|
% We need to look at the pred name and see if it is an introduced predicate
|
|
% (lambda, deforestation, accumulator, etc.).
|
|
% XXX handle multiple prefixes
|
|
|
|
PredName0 = !.Str,
|
|
( if
|
|
( if
|
|
remove_prefix("IntroducedFrom__", !Str)
|
|
then
|
|
IntroducedPredType0 = ipt_lambda
|
|
else if
|
|
remove_prefix("DeforestationIn__", !Str)
|
|
then
|
|
IntroducedPredType0 = ipt_deforestation
|
|
else if
|
|
remove_prefix("AccFrom__", !Str)
|
|
then
|
|
IntroducedPredType0 = ipt_accumulator
|
|
else
|
|
remove_prefix("TypeSpecOf__", !Str),
|
|
IntroducedPredType0 = ipt_type_spec("")
|
|
)
|
|
then
|
|
( if
|
|
remove_prefix("pred__", !Str)
|
|
then
|
|
LambdaPredOrFunc = "pred"
|
|
else if
|
|
remove_prefix("func__", !Str)
|
|
then
|
|
LambdaPredOrFunc = "func"
|
|
else if
|
|
IntroducedPredType0 = ipt_type_spec(_),
|
|
remove_prefix("pred_or_func__", !Str)
|
|
then
|
|
LambdaPredOrFunc = ""
|
|
else
|
|
fail
|
|
),
|
|
( if
|
|
remove_maybe_pred_name(MPredName, !Str),
|
|
MPredName = yes(PredName1),
|
|
( if IntroducedPredType0 = ipt_type_spec(_) then
|
|
remove_type_spec(TypeSpec, !Str),
|
|
IntroducedPredType = ipt_type_spec(TypeSpec),
|
|
Seq = 0,
|
|
Line = 0
|
|
|
|
% The compiler adds a redundant mode number to the predicate
|
|
% name to avoid creating two predicates with the same name
|
|
% (deep profiling doesn't like that). It isn't used here
|
|
% so we just ignore it. The compiler also adds a version number
|
|
% for the argument order used for specialized versions,
|
|
% which can also be ignored.
|
|
else
|
|
IntroducedPredType = IntroducedPredType0,
|
|
remove_int(Line, !Str),
|
|
remove_prefix("__", !Str),
|
|
remove_int(Seq, !Str)
|
|
)
|
|
then
|
|
PredName = PredName1,
|
|
Category = introduced(IntroducedPredType, Line,
|
|
Seq, LambdaPredOrFunc)
|
|
else
|
|
% If we get here it usually means that there were multiple
|
|
% prefixes, which aren't dealt with properly yet. Just treat it
|
|
% as an ordinary name for now.
|
|
Category = ordinary,
|
|
PredName = PredName0
|
|
)
|
|
else
|
|
Category = Category0,
|
|
PredName = PredName0
|
|
).
|
|
|
|
:- pred format_proc(pred_category::in, maybe(string)::in, string::in,
|
|
string::in, int::in, int::in, maybe(int)::in,
|
|
maybe(pair(int, bool))::in, maybe(int)::in,
|
|
string::out) is det.
|
|
|
|
format_proc(Category, MaybeModule, PredOrFunc, PredName, Arity, ModeNum,
|
|
HigherOrder, UnusedArgs, MaybeInternalLabelNum, DemangledName) :-
|
|
format_maybe_module(MaybeModule, PredName, QualifiedName),
|
|
(
|
|
Category = unify,
|
|
string.format("unification predicate for type `%s/%d' mode %d",
|
|
[s(QualifiedName), i(Arity), i(ModeNum)], MainStr)
|
|
;
|
|
Category = compare,
|
|
string.format("compare/3 predicate for type `%s/%d'",
|
|
[s(QualifiedName), i(Arity)], MainStr)
|
|
;
|
|
Category = index,
|
|
string.format("index/2 predicate for type `%s/%d'",
|
|
[s(QualifiedName), i(Arity)], MainStr)
|
|
;
|
|
Category = ordinary,
|
|
string.format("%s `%s/%d' mode %d",
|
|
[s(PredOrFunc), s(QualifiedName), i(Arity), i(ModeNum)], MainStr)
|
|
;
|
|
Category = introduced(Type, Line, Seq, IntroPredOrFunc),
|
|
(
|
|
Type = ipt_lambda,
|
|
string.format("%s goal (#%d) from `%s' line %d",
|
|
[s(IntroPredOrFunc), i(Seq), s(QualifiedName),
|
|
i(Line)], MainStr)
|
|
;
|
|
Type = ipt_deforestation,
|
|
string.format(
|
|
"deforestation procedure (#%d) from `%s' line %d",
|
|
[i(Seq), s(QualifiedName), i(Line)], MainStr)
|
|
;
|
|
Type = ipt_accumulator,
|
|
string.format(
|
|
"accumulator procedure from `%s' line %d",
|
|
[s(QualifiedName), i(Line)], MainStr)
|
|
;
|
|
Type = ipt_type_spec(TypeSpec),
|
|
string.format(
|
|
"%s `%s/%d' mode %d (type specialized %s)",
|
|
[s(PredOrFunc), s(QualifiedName), i(Arity), i(ModeNum),
|
|
s(TypeSpec)], MainStr)
|
|
)
|
|
),
|
|
(
|
|
HigherOrder = yes(HO_Num),
|
|
string.format(" (specialized [#%d])", [i(HO_Num)], HOStr)
|
|
;
|
|
HigherOrder = no,
|
|
HOStr = ""
|
|
),
|
|
(
|
|
UnusedArgs = yes(UA_Num - Extra),
|
|
(
|
|
Extra = yes,
|
|
string.format(" (minus extra unused args [#%d])", [i(UA_Num)],
|
|
UAStr)
|
|
;
|
|
Extra = no,
|
|
string.format(" (minus unused args [#%d])", [i(UA_Num)],
|
|
UAStr)
|
|
)
|
|
;
|
|
UnusedArgs = no,
|
|
UAStr = ""
|
|
),
|
|
(
|
|
MaybeInternalLabelNum = yes(Internal),
|
|
string.format(" label %d", [i(Internal)], LabelStr)
|
|
;
|
|
MaybeInternalLabelNum = no,
|
|
LabelStr = ""
|
|
),
|
|
DemangledName = "<" ++ MainStr ++ HOStr ++ UAStr ++ LabelStr ++ ">".
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
%
|
|
% Code to deal with mercury_data items.
|
|
%
|
|
|
|
:- pred demangle_data(string::in, string::out) is semidet.
|
|
|
|
demangle_data(!Str) :-
|
|
( if remove_prefix("mercury_data_", !Str) then
|
|
% LLDS mangled data
|
|
HighLevel = no
|
|
else
|
|
% MLDS mangled data
|
|
HighLevel = yes,
|
|
maybe_remove_prefix("mercury__", !Str)
|
|
),
|
|
remove_maybe_module_prefix(MaybeModule0,
|
|
["type_ctor_info_", "type_ctor_layout_",
|
|
"type_ctor_functors_", "common_"], !Str),
|
|
( if
|
|
MaybeModule0 = yes("")
|
|
then
|
|
MaybeModule = no
|
|
else if
|
|
% for the MLDS back-end,
|
|
% the module qualifiers get include twice (XXX why?)
|
|
HighLevel = yes,
|
|
MaybeModule0 = yes(Twice)
|
|
then
|
|
Once = string.left(Twice, string.length(Twice) // 2),
|
|
Once = string.right(Twice, string.length(Twice) // 2),
|
|
MaybeModule = yes(Once)
|
|
else
|
|
MaybeModule = MaybeModule0
|
|
),
|
|
( if remove_prefix("type_ctor_info_", !Str) then
|
|
DataCategory = info,
|
|
remove_trailing_int(Arity, !Str),
|
|
m_remove_suffix("_", !Str)
|
|
else if remove_prefix("type_ctor_layout_", !Str) then
|
|
DataCategory = layout,
|
|
remove_trailing_int(Arity, !Str),
|
|
m_remove_suffix("_", !Str)
|
|
else if remove_prefix("type_ctor_functors_", !Str) then
|
|
DataCategory = functors,
|
|
remove_trailing_int(Arity, !Str),
|
|
m_remove_suffix("_", !Str)
|
|
else if remove_prefix("common_", !Str) then
|
|
DataCategory = common,
|
|
remove_trailing_int(Arity, !Str)
|
|
else
|
|
fail
|
|
),
|
|
|
|
fix_mangled_ascii(!Str),
|
|
format_data(DataCategory, MaybeModule, !.Str, Arity, !:Str).
|
|
|
|
:- pred format_data(data_category::in, maybe(string)::in, string::in, int::in,
|
|
string::out) is semidet.
|
|
|
|
format_data(Category, MaybeModule, Name, Arity, Result) :-
|
|
(
|
|
Category = info,
|
|
(
|
|
MaybeModule = yes(Module),
|
|
string.format("<type_ctor_info for type `%s.%s/%d'>",
|
|
[s(Module), s(Name), i(Arity)], Result)
|
|
;
|
|
MaybeModule = no,
|
|
string.format("<type_ctor_info for type `%s/%d'>",
|
|
[s(Name), i(Arity)], Result)
|
|
)
|
|
;
|
|
Category = layout,
|
|
(
|
|
MaybeModule = yes(Module),
|
|
string.format("<type_ctor_layout for type `%s.%s/%d'>",
|
|
[s(Module), s(Name), i(Arity)], Result)
|
|
;
|
|
MaybeModule = no,
|
|
string.format("<type_ctor_layout for type `%s/%d'>",
|
|
[s(Name), i(Arity)], Result)
|
|
)
|
|
;
|
|
Category = functors,
|
|
(
|
|
MaybeModule = yes(Module),
|
|
string.format("<type_ctor_functors for type `%s.%s/%d'>",
|
|
[s(Module), s(Name), i(Arity)], Result)
|
|
;
|
|
MaybeModule = no,
|
|
string.format("<type_ctor_functors for type `%s/%d'>",
|
|
[s(Name), i(Arity)], Result)
|
|
)
|
|
;
|
|
Category = common,
|
|
(
|
|
MaybeModule = yes(Module),
|
|
string.format("<shared constant number %d for module %s>",
|
|
[i(Arity), s(Module)], Result)
|
|
;
|
|
MaybeModule = no,
|
|
fail
|
|
)
|
|
).
|
|
|
|
:- pred demangle_typeclass_info(string::in, string::out) is semidet.
|
|
|
|
demangle_typeclass_info(!Str) :-
|
|
maybe_remove_prefix("mercury_data___", !Str),
|
|
remove_prefix("base_typeclass_info_", !Str),
|
|
remove_maybe_module_prefix(yes(ClassName), ["arity"], !Str),
|
|
ClassName \= "",
|
|
remove_prefix("arity", !Str),
|
|
remove_int(ClassArity, !Str),
|
|
remove_prefix("__", !Str),
|
|
fix_mangled_ascii(!Str),
|
|
% XXX We should NOT ignore _Str.
|
|
demangle_class_args(ClassArity, Args, !.Str, _Str),
|
|
string.format("<instance declaration for %s(%s)>",
|
|
[s(ClassName), s(Args)], !:Str).
|
|
|
|
:- pred demangle_class_args(int::in, string::out, string::in, string::out)
|
|
is semidet.
|
|
|
|
demangle_class_args(Num, FormattedArgs, !Str) :-
|
|
remove_maybe_module_prefix(yes(TypeName), ["arity"], !Str),
|
|
TypeName \= "",
|
|
remove_prefix("arity", !Str),
|
|
remove_int(TypeArity, !Str),
|
|
remove_prefix("__", !Str),
|
|
( if Num > 1 then
|
|
Sep = ", ",
|
|
Num1 = Num - 1,
|
|
demangle_class_args(Num1, Rest, !Str)
|
|
else
|
|
Sep = "",
|
|
Rest = ""
|
|
),
|
|
string.format("%s/%d%s%s",
|
|
[s(TypeName), i(TypeArity), s(Sep), s(Rest)],
|
|
FormattedArgs).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% The compiler changes all names starting with `f_' so that they start
|
|
% with `f__' instead, and uses names starting with `f_' for mangled names
|
|
% which are either descriptions (such as `f_greater_than' for `>')
|
|
% or sequences of decimal representations of ASCII codes separated
|
|
% by underscores. If the name starts with `f__', we must change it back to
|
|
% start with `f_'. Otherwise, if it starts with `f_' we must convert
|
|
% the mnemonic or list of ASCII codes back into an identifier.
|
|
%
|
|
:- pred fix_mangled_ascii(string::in, string::out) is semidet.
|
|
|
|
fix_mangled_ascii(!Str) :-
|
|
( if remove_prefix("f__", !Str) then
|
|
insert_prefix("f_", !Str)
|
|
else if remove_prefix("f_not_equal", !Str) then
|
|
insert_prefix("\\=", !Str)
|
|
else if remove_prefix("f_greater_or_equal", !Str) then
|
|
insert_prefix(">=", !Str)
|
|
else if remove_prefix("f_less_or_equal", !Str) then
|
|
insert_prefix("=<", !Str)
|
|
else if remove_prefix("f_equal", !Str) then
|
|
insert_prefix("=", !Str)
|
|
else if remove_prefix("f_less_than", !Str) then
|
|
insert_prefix("<", !Str)
|
|
else if remove_prefix("f_greater_than", !Str) then
|
|
insert_prefix(">", !Str)
|
|
else if remove_prefix("f_minus", !Str) then
|
|
insert_prefix("-", !Str)
|
|
else if remove_prefix("f_plus", !Str) then
|
|
insert_prefix("+", !Str)
|
|
else if remove_prefix("f_times", !Str) then
|
|
insert_prefix("*", !Str)
|
|
else if remove_prefix("f_slash", !Str) then
|
|
insert_prefix("/", !Str)
|
|
else if remove_prefix("f_comma", !Str) then
|
|
insert_prefix(",", !Str)
|
|
else if remove_prefix("f_semicolon", !Str) then
|
|
insert_prefix(";", !Str)
|
|
else if remove_prefix("f_cut", !Str) then
|
|
insert_prefix("!", !Str)
|
|
else if remove_prefix("f_tuple", !Str) then
|
|
insert_prefix("{}", !Str)
|
|
else if remove_prefix("f_cons", !Str) then
|
|
insert_prefix("[|]", !Str)
|
|
else if remove_prefix("f_nil", !Str) then
|
|
insert_prefix("[]", !Str)
|
|
else if remove_prefix("f_", !Str) then
|
|
fix_mangled_ascii_chars(!Str)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred fix_mangled_ascii_chars(string::in, string::out) is semidet.
|
|
|
|
fix_mangled_ascii_chars(!Str) :-
|
|
remove_int(I, !Str),
|
|
( if remove_prefix("_", !Str) then
|
|
disable_warning [suspicious_recursion] (
|
|
fix_mangled_ascii_chars(!Str)
|
|
)
|
|
else
|
|
true
|
|
),
|
|
char.to_int(C, I) ,
|
|
insert_prefix_char(C, !Str).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred remove_int(int::out, string::in, string::out) is semidet.
|
|
|
|
remove_int(Int, !Str) :-
|
|
remove_digit(Digit, !Str),
|
|
remove_int_2(Digit, Int, !Str).
|
|
|
|
:- pred remove_int_2(int::in, int::out, string::in, string::out) is semidet.
|
|
|
|
remove_int_2(Int0, Int, !Str) :-
|
|
( if remove_digit(Next, !Str) then
|
|
Int1 = Int0 * 10 + Next,
|
|
remove_int_2(Int1, Int, !Str)
|
|
else
|
|
Int = Int0
|
|
).
|
|
|
|
:- pred remove_digit(int::out, string::in, string::out) is semidet.
|
|
|
|
remove_digit(Digit, String0, String) :-
|
|
string.first_char(String0, Char, String),
|
|
digit(Char, Digit).
|
|
|
|
:- pred digit(character::in, int::out) is semidet.
|
|
|
|
digit('0', 0).
|
|
digit('1', 1).
|
|
digit('2', 2).
|
|
digit('3', 3).
|
|
digit('4', 4).
|
|
digit('5', 5).
|
|
digit('6', 6).
|
|
digit('7', 7).
|
|
digit('8', 8).
|
|
digit('9', 9).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred remove_maybe_module_prefix(maybe(string)::out, list(string)::in,
|
|
string::in, string::out) is det.
|
|
|
|
remove_maybe_module_prefix(MaybeModule, StringsToStopAt, String0, String) :-
|
|
( if
|
|
list.member(StopString, StringsToStopAt),
|
|
string.prefix(String0, StopString)
|
|
then
|
|
MaybeModule = no,
|
|
String = String0
|
|
else if
|
|
string.sub_string_search(String0, "__", Index)
|
|
then
|
|
string.left(String0, Index, Module),
|
|
string.length(String0, Len),
|
|
Index2 = Index + 2,
|
|
string.between(String0, Index2, Len, String1),
|
|
( if
|
|
remove_maybe_module_prefix(yes(SubModule),
|
|
StringsToStopAt, String1, String2)
|
|
then
|
|
string.append_list([Module, ".", SubModule], QualifiedModule),
|
|
MaybeModule = yes(QualifiedModule),
|
|
String = String2
|
|
else
|
|
MaybeModule = yes(Module),
|
|
String = String1
|
|
)
|
|
else
|
|
String = String0,
|
|
MaybeModule = no
|
|
).
|
|
|
|
:- pred remove_maybe_pred_name(maybe(string)::out, string::in, string::out)
|
|
is det.
|
|
|
|
remove_maybe_pred_name(MaybePredName, String0, String) :-
|
|
( if string.sub_string_search(String0, "__", Index) then
|
|
string.left(String0, Index, PredName),
|
|
string.length(String0, Len),
|
|
Index2 = Index + 2,
|
|
string.between(String0, Index2, Len, String),
|
|
MaybePredName = yes(PredName)
|
|
else
|
|
String = String0,
|
|
MaybePredName = no
|
|
).
|
|
|
|
:- pred remove_type_spec(string::out, string::in, string::out) is semidet.
|
|
|
|
remove_type_spec(TypeSpec, String0, String) :-
|
|
string.length(String0, Length),
|
|
Length > 2,
|
|
string.unsafe_index(String0, 0, '['),
|
|
NumBrackets = 0,
|
|
find_matching_close_bracket(NumBrackets, Length,
|
|
String0, 1, Index),
|
|
string.split(String0, Index + 1, TypeSpec, String).
|
|
|
|
:- pred find_matching_close_bracket(int::in, int::in, string::in, int::in,
|
|
int::out) is semidet.
|
|
|
|
find_matching_close_bracket(NumBrackets0, Length, String, Index0, Index) :-
|
|
Index0 < Length,
|
|
string.unsafe_index(String, Index0, Char),
|
|
( if Char = ']', NumBrackets0 = 0 then
|
|
Index = Index0
|
|
else
|
|
% Handle matching brackets in type names.
|
|
( if Char = '[' then
|
|
NumBrackets = NumBrackets0 + 1
|
|
else if Char = ']' then
|
|
NumBrackets = NumBrackets0 - 1
|
|
else
|
|
NumBrackets = NumBrackets0
|
|
),
|
|
find_matching_close_bracket(NumBrackets, Length, String,
|
|
Index0 + 1, Index)
|
|
).
|
|
|
|
:- pred maybe_remove_prefix(string::in, string::in, string::out) is det.
|
|
|
|
maybe_remove_prefix(Prefix, !Str) :-
|
|
( if remove_prefix(Prefix, !Str) then
|
|
true
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred m_remove_suffix(string::in, string::in, string::out) is semidet.
|
|
|
|
m_remove_suffix(Suffix, Name0, Name) :-
|
|
string.remove_suffix(Name0, Suffix, Name).
|
|
|
|
:- pred insert_prefix(string::in, string::in, string::out) is det.
|
|
|
|
insert_prefix(Prefix, Name0, Name) :-
|
|
string.append(Prefix, Name0, Name).
|
|
|
|
:- pred insert_prefix_char(char::in, string::in, string::out) is det.
|
|
|
|
insert_prefix_char(Prefix, Name0, Name) :-
|
|
string.first_char(Name, Prefix, Name0).
|
|
|
|
:- pred format_maybe_module(maybe(string)::in, string::in, string::out) is det.
|
|
|
|
format_maybe_module(no, Name, QualifiedName) :-
|
|
string.format("%s", [s(Name)], QualifiedName).
|
|
format_maybe_module(yes(Module), Name, QualifiedName) :-
|
|
string.format("%s.%s", [s(Module), s(Name)], QualifiedName).
|
|
|
|
:- pred remove_trailing_int(int::out, string::in, string::out) is semidet.
|
|
|
|
remove_trailing_int(Int, String0, String) :-
|
|
remove_trailing_digit(Digit, String0, String1),
|
|
( if remove_trailing_int(Rest, String1, String2) then
|
|
Int = Rest * 10 + Digit,
|
|
String = String2
|
|
else
|
|
Int = Digit,
|
|
String = String1
|
|
).
|
|
|
|
:- pred remove_trailing_digit(int::out, string::in, string::out) is semidet.
|
|
|
|
remove_trailing_digit(Digit, String0, String) :-
|
|
string_last_char(String0, Char, String),
|
|
digit(Char, Digit).
|
|
|
|
:- pred string_last_char(string::in, character::out, string::out) is semidet.
|
|
|
|
string_last_char(String0, Char, String) :-
|
|
string.length(String0, Len),
|
|
Len1 = Len - 1,
|
|
string.index(String0, Len1, Char),
|
|
string.left(String0, Len1, String).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module demangle.
|
|
%---------------------------------------------------------------------------%
|