Files
mercury/compiler/java_names.m
Zoltan Somogyi 8dbea9f096 Use a structured representation for MLDS variables.
compiler/mlds.m:
    Replace the old definition of mlds_var_name, which was a string
    with an optional integer. The integer was intended to be the number
    of a HLDS variable, while auxiliary variables created by the compiler,
    which do not correspond to a HLDS variable, would not have the optional
    integer.

    This design has a couple of minor problems. The first is that there is
    no place in the compiler where all the variable names are visible at once,
    and without such a place, we cannot be sure that two names constructed
    for different purposes don't accidentally end up with the same name.
    The probability of such a clash used to be astronomically small
    (which is why this hasn't been a problem), but it was not zero.

    The second problem is that several kinds of compiler-created MLDS variables
    want to have numerical suffixes too, usually with the suffix being a
    unique sequence number used as a means of disambiguation. Most of the
    places where these were created put the numerical suffix into the name
    string itself, while some put the sequence number as the optional integer.

    As it happens, neither of those actions is good when one wants to take
    the independently generated MLDS code of several procedures in an SCC
    and merge them into a single piece of MLDS code. For this, we want to
    rename apart both the HLDS variable numbers and the sequence numbers.
    Having the sequence number baked into the strings themselves obviously
    makes such renumbering unnecessarily hard, while having sequence numbers
    in the slots intended for HLDS variable numbers makes the job impossible
    to do safely.

    This diff switches to a new representation of mlds_var_names that
    has a separate function symbol for each different "origin story"
    that is possible for MLDS variables. This addresses both problems.

    The single predicate that converts this structured representation
    to a string is the place where we can ensure that two semantically
    different MLDS variables never get translated to the same string.
    The current version of this predicate does *not* offer this guarantee,
    but later versions could.

    And having all the integers used in mlds_var_names for different purposes
    stored as arguments of different function symbols (that clearly indicate
    their meaning) makes it possible to rename apart different sets
    of MLDS variables easily and reliably.

    Move the code for converting mlds_var_names from ml_code_util.m to here,
    to make it easier to maintain it together with the mlds_var_name type.

compiler/ml_code_util.m:
    Conform to the above change by generating structured MLDS var names.

    Delete a predicate that is not needed with structured var names.

    Delete the code moved to mlds.m.

    Delete a predicate that has been unused since we deleted the IL backend.

    Add ml_make_boxed_type as a version of ml_make_boxed_types that returns
    exactly one type. This simplifies some code elsewhere.

    Add "hld" to some predicate names to make clear that they are intended
    for use only with --high-level-data.

compiler/ml_type_gen.m:
    Conform to the above change by generating structured MLDS var names.

    Add "hld" to the names of the (many) predicates here that are used
    only with --high-level-data to make clear that fact.

compiler/mlds_to_cs.m:
compiler/mlds_to_java.m:
    Conform to the above change by generating structured MLDS var names.

    Add a "for_csharp" or "for_java" suffix to some predicate names
    to avoid ambiguities.

compiler/ml_accurate_gc.m:
compiler/ml_call_gen.m:
compiler/ml_closure_gen.m:
compiler/ml_commit_gen.m:
compiler/ml_disj_gen.m:
compiler/ml_elim_nested.m:
compiler/ml_foreign_proc_gen.m:
compiler/ml_gen_info.m:
compiler/ml_global_data.m:
compiler/ml_lookup_switch.m:
compiler/ml_optimize.m:
compiler/ml_string_switch.m:
compiler/ml_unify_gen.m:
compiler/ml_util.m:
compiler/mlds_to_c.m:
    Conform to the above change by generating structured MLDS var names.

compiler/prog_type.m:
    Add var_to_type, as a version of var_list_to_type_list that returns
    exactly one type. This simplifies some code elsewhere.

compiler/java_names.m:
    Give some predicates and functions better names.

compiler/ml_code_gen.m:
    Fix typo.
2017-04-24 15:16:36 +10:00

369 lines
12 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2002-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: java_names.m.
% Main authors: juliensf, mjwybrow, wangp.
%
% This module contains utility routines related to naming things in Java/C#
% which are also required in the frontend.
%
%-----------------------------------------------------------------------------%
:- module parse_tree.java_names.
:- interface.
:- import_module mdbcomp.sym_name.
%-----------------------------------------------------------------------------%
% For the C# and Java back-ends, we need to distinguish between module
% qualifiers and type qualifiers, because type names get the case of their
% initial letter inverted (i.e. lowercase => uppercase).
%
% This duplicates mlds_qual_kind so as not to introduce unwanted
% dependencies in either direction.
%
:- type csj_qual_kind
---> module_qual
; type_qual.
% Mangle a name so that it is suitable for Java.
%
:- pred mangle_sym_name_for_java(sym_name::in, csj_qual_kind::in,
string::in, string::out) is det.
% If the given name conflicts with a reserved Java word,
% add a prefix to it to avoid compilation errors.
%
:- func make_valid_java_symbol_name(string) = string.
% Succeeds iff the given string matches a reserved word in Java.
%
:- pred is_java_keyword(string::in) is semidet.
% The package containing the Mercury Java runtime classes.
%
:- func java_mercury_runtime_package_name = sym_name.
%-----------------------------------------------------------------------------%
% Mangle a name so that it is suitable for C#.
%
:- pred mangle_sym_name_for_csharp(sym_name::in, csj_qual_kind::in,
string::in, string::out) is det.
% If the given name conflicts with a reserved C# word,
% add a prefix to it to avoid compilation errors.
%
:- func make_valid_csharp_symbol_name(string) = string.
% Succeeds iff the given string matches a reserved word in C#.
%
:- pred is_csharp_keyword(string::in) is semidet.
% The package containing the Mercury C# runtime classes.
%
:- func csharp_mercury_runtime_package_name = sym_name.
%-----------------------------------------------------------------------------%
% Invert the case of the first letter of the string.
%
:- func flip_initial_case(string) = string.
% Invert the case of the first letter of the last component of
% a (possibly) qualified name.
%
:- func flip_initial_case_of_final_part(sym_name) = sym_name.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module parse_tree.prog_foreign. % for name_mangle
:- import_module char.
:- import_module string.
%-----------------------------------------------------------------------------%
%
% Java naming.
%
mangle_sym_name_for_java(SymName0, QualKind, QualifierOp, JavaSafeName) :-
% Modules in the Mercury standard library get a `mercury' prefix when
% mapped to MLDS module names. Since we place all Java classes inside a
% `jmercury' package, the extra prefix is just redundant so we remove it.
( if strip_outermost_qualifier(SymName0, "mercury", StrippedSymName) then
SymName = StrippedSymName
else
SymName = SymName0
),
mangle_sym_name_for_java_2(SymName, QualKind, MangledSymName),
JavaSafeName = sym_name_to_string_sep(MangledSymName, QualifierOp).
:- pred mangle_sym_name_for_java_2(sym_name::in, csj_qual_kind::in,
sym_name::out) is det.
mangle_sym_name_for_java_2(SymName, QualKind, MangledSymName) :-
(
SymName = unqualified(Name),
JavaSafeName = java_safe_name_component(QualKind, Name),
MangledSymName = unqualified(JavaSafeName)
;
SymName = qualified(ModuleName0, PlainName),
mangle_sym_name_for_java_2(ModuleName0, module_qual,
MangledModuleName),
JavaSafePlainName = java_safe_name_component(QualKind, PlainName),
MangledSymName = qualified(MangledModuleName, JavaSafePlainName)
).
:- func java_safe_name_component(csj_qual_kind, string) = string.
java_safe_name_component(QualKind, Name) = JavaSafeName :-
MangledName = name_mangle_no_leading_digit(Name),
(
QualKind = module_qual,
FlippedName = MangledName
;
QualKind = type_qual,
FlippedName = flip_initial_case(MangledName)
),
JavaSafeName = make_valid_java_symbol_name(FlippedName).
make_valid_java_symbol_name(SymName) = ValidSymName :-
Prefix = "mr_",
( if is_java_keyword(SymName) then
% This is a reserved Java word, add the above prefix.
ValidSymName = Prefix ++ SymName
else if string.append(Prefix, Suffix, SymName) then
% This name already contains the prefix we are adding to
% variables to avoid conflicts, so add an additional '_'.
ValidSymName = Prefix ++ "_" ++ Suffix
else
% Normal name; do nothing.
ValidSymName = SymName
).
is_java_keyword("abstract").
is_java_keyword("boolean").
is_java_keyword("break").
is_java_keyword("byte").
is_java_keyword("case").
is_java_keyword("catch").
is_java_keyword("char").
is_java_keyword("class").
is_java_keyword("const").
is_java_keyword("continue").
is_java_keyword("default").
is_java_keyword("do").
is_java_keyword("double").
is_java_keyword("else").
is_java_keyword("enum").
is_java_keyword("extends").
is_java_keyword("false").
is_java_keyword("final").
is_java_keyword("finally").
is_java_keyword("float").
is_java_keyword("for").
is_java_keyword("goto").
is_java_keyword("if").
is_java_keyword("implements").
is_java_keyword("import").
is_java_keyword("instanceof").
is_java_keyword("int").
is_java_keyword("interface").
is_java_keyword("long").
is_java_keyword("native").
is_java_keyword("new").
is_java_keyword("null").
is_java_keyword("package").
is_java_keyword("private").
is_java_keyword("protected").
is_java_keyword("public").
is_java_keyword("return").
is_java_keyword("short").
is_java_keyword("static").
is_java_keyword("strictfp").
is_java_keyword("super").
is_java_keyword("switch").
is_java_keyword("synchronized").
is_java_keyword("this").
is_java_keyword("throw").
is_java_keyword("throws").
is_java_keyword("transient").
is_java_keyword("true").
is_java_keyword("try").
is_java_keyword("void").
is_java_keyword("volatile").
is_java_keyword("while").
java_mercury_runtime_package_name =
qualified(unqualified("jmercury"), "runtime").
%-----------------------------------------------------------------------------%
%
% C# naming.
%
% XXX Reduce code duplication between C# and Java routines.
mangle_sym_name_for_csharp(SymName, QualKind, QualifierOp, SafeName) :-
mangle_sym_name_for_csharp_2(SymName, QualKind, MangledSymName),
SafeName = sym_name_to_string_sep(MangledSymName, QualifierOp).
:- pred mangle_sym_name_for_csharp_2(sym_name::in, csj_qual_kind::in,
sym_name::out) is det.
mangle_sym_name_for_csharp_2(SymName, QualKind, MangledSymName) :-
(
SymName = unqualified(Name),
SafeName = csharp_safe_name_component(QualKind, Name),
MangledSymName = unqualified(SafeName)
;
SymName = qualified(ModuleName0, PlainName),
mangle_sym_name_for_csharp_2(ModuleName0, module_qual,
MangledModuleName),
SafePlainName = csharp_safe_name_component(QualKind, PlainName),
MangledSymName = qualified(MangledModuleName, SafePlainName)
).
:- func csharp_safe_name_component(csj_qual_kind, string) = string.
csharp_safe_name_component(QualKind, Name) = SafeName :-
MangledName = name_mangle_no_leading_digit(Name),
(
QualKind = module_qual,
FlippedName = MangledName
;
QualKind = type_qual,
FlippedName = flip_initial_case(MangledName)
),
SafeName = make_valid_csharp_symbol_name(FlippedName).
make_valid_csharp_symbol_name(SymName) = ValidSymName :-
Prefix = "mr_",
( if is_csharp_keyword(SymName) then
% This is a reserved word, add the above prefix.
ValidSymName = Prefix ++ SymName
else if string.append(Prefix, Suffix, SymName) then
% This name already contains the prefix we are adding to
% variables to avoid conflicts, so add an additional '_'.
ValidSymName = Prefix ++ "_" ++ Suffix
else
% Normal name; do nothing.
ValidSymName = SymName
).
is_csharp_keyword("abstract").
is_csharp_keyword("as").
is_csharp_keyword("base").
is_csharp_keyword("bool").
is_csharp_keyword("break").
is_csharp_keyword("byte").
is_csharp_keyword("case").
is_csharp_keyword("catch").
is_csharp_keyword("char").
is_csharp_keyword("checked").
is_csharp_keyword("class").
is_csharp_keyword("const").
is_csharp_keyword("continue").
is_csharp_keyword("decimal").
is_csharp_keyword("default").
is_csharp_keyword("delegate").
is_csharp_keyword("do").
is_csharp_keyword("double").
is_csharp_keyword("else").
is_csharp_keyword("enum").
is_csharp_keyword("event").
is_csharp_keyword("explicit").
is_csharp_keyword("extern").
is_csharp_keyword("false").
is_csharp_keyword("finally").
is_csharp_keyword("fixed").
is_csharp_keyword("float").
is_csharp_keyword("for").
is_csharp_keyword("foreach").
is_csharp_keyword("goto").
is_csharp_keyword("if").
is_csharp_keyword("implicit").
is_csharp_keyword("in").
is_csharp_keyword("int").
is_csharp_keyword("interface").
is_csharp_keyword("internal").
is_csharp_keyword("is").
is_csharp_keyword("lock").
is_csharp_keyword("long").
is_csharp_keyword("namespace").
is_csharp_keyword("new").
is_csharp_keyword("null").
is_csharp_keyword("object").
is_csharp_keyword("operator").
is_csharp_keyword("out").
is_csharp_keyword("override").
is_csharp_keyword("params").
is_csharp_keyword("private").
is_csharp_keyword("protected").
is_csharp_keyword("public").
is_csharp_keyword("readonly").
is_csharp_keyword("ref").
is_csharp_keyword("return").
is_csharp_keyword("sbyte").
is_csharp_keyword("sealed").
is_csharp_keyword("short").
is_csharp_keyword("sizeof").
is_csharp_keyword("stackalloc").
is_csharp_keyword("static").
is_csharp_keyword("string").
is_csharp_keyword("struct").
is_csharp_keyword("switch").
is_csharp_keyword("this").
is_csharp_keyword("throw").
is_csharp_keyword("true").
is_csharp_keyword("try").
is_csharp_keyword("typeof").
is_csharp_keyword("uint").
is_csharp_keyword("ulong").
is_csharp_keyword("unchecked").
is_csharp_keyword("unsafe").
is_csharp_keyword("ushort").
is_csharp_keyword("using").
is_csharp_keyword("virtual").
is_csharp_keyword("volatile").
is_csharp_keyword("void").
is_csharp_keyword("while").
csharp_mercury_runtime_package_name =
qualified(unqualified("mercury"), "runtime").
%-----------------------------------------------------------------------------%
flip_initial_case(S0) = S :-
( if string.first_char(S0, First0, Rest) then
( if char.is_upper(First0) then
First = char.to_lower(First0)
else if char.is_lower(First0) then
First = char.to_upper(First0)
else
First = First0
),
string.first_char(S, First, Rest)
else
S = S0
).
flip_initial_case_of_final_part(unqualified(Name)) =
unqualified(flip_initial_case(Name)).
flip_initial_case_of_final_part(qualified(Qual, Name)) =
qualified(Qual, flip_initial_case(Name)).
%-----------------------------------------------------------------------------%
:- end_module parse_tree.java_names.
%-----------------------------------------------------------------------------%