Files
mercury/compiler/java_names.m
Peter Wang 903a4a1f82 Previously, unqualified Mercury modules would result in Java classes which
Branches: main

Previously, unqualified Mercury modules would result in Java classes which
were placed in the default (unnamed) package.  This is a problem as Java
doesn't allow packaged classes to import types from the unpackaged classes.
This patch gives all Java classes generated from Mercury files the "mercury."
package prefix.

mmake support for Java files is even more broken than before.  It expects
Java files to be placed in the same directory but, due to the "mercury."
prefix, even classes for non-nested modules are placed in a subdirectory
called `mercury'.  (The standard library can still be built with mmake using
custom rules.)

Fix creation of `.jar' files.  It is not enough to package the `.class' files
that we know will be produced for each module.  Nested classes generate
separate `.class' files which also need to be included.

Fix creation of the shell script that launches Java programs.


compiler/java_names.m:
        Add a function to add an outermost "mercury" qualifier on module names.

        Make `java_module_name' add the outermost "mercury" qualifier.

compiler/mlds_to_java.m:
        Add the outermost "mercury" qualifier wherever we are writing out
        a package name.

compiler/compile_target_code.m:
        Fix creation of `.jar' files, as described.

        Use a temporary file and @-syntax to pass the list of class files to
        `jar'.

        Pass `jar -C <dir> <class> -C <dir> <class> ...' as -C only affects
        the argument immediately following it.

        Run `jar i' to add an index to jar files.

compiler/file_names.m:
        Add `get_class_dir_name' to return the directory that contains class
        files.

        Make `choose_file_name' work for Java files again (with package
        directories) when `--use-subdirs' is disabled.

compiler/module_cmds.m:
        Make `create_java_shell_script' work correctly when
        `--use-grade-subdirs' is enabled, and when the main module is
        packaged (as it will be).

        Make Java shell scripts get the path to the class directory from $0,
        and make the path to the Java interpreter overridable by an environment
        variable.

        Make `list_class_files_for_jar' scan the directory containing class
        files, to include nested classes.  Return a list of class files.

        Make `list_class_files_for_jar_mmake' use `get_class_dir_name'.

library/Mmakefile:
        Update hacks to build the standard library in the java grade.

mdbcomp/prim_data.m:
        Delete `insert_module_qualifier' as `add_outermost_qualifier'
        is equivalent.

compiler/module_qual.m:
compiler/prog_type.m:
compiler/write_deps_file.m:
        Conform to changes.
2009-05-22 02:51:21 +00:00

306 lines
10 KiB
Mathematica

%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2002-2009 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,
% which are also required in the frontend.
%
%-----------------------------------------------------------------------------%
:- module parse_tree.java_names.
:- interface.
:- import_module mdbcomp.prim_data.
:- import_module bool.
%-----------------------------------------------------------------------------%
% For the Java back-end, 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 java_qual_kind
---> module_qual
; type_qual.
% Java doesn't allow a fully-qualified class to have the same name as a
% package. Our workaround is to name package components with trailing
% underscores, e.g. `mammal_.primate_.chimp' where `chimp' is a class.
% This is enabled with `package_name_mangling'.
%
% The packages `mercury' and `mercury.runtime' are named without
% underscores simply because there is existing handwritten code already
% using those names.
%
:- type package_name_mangling
---> package_name_mangling
; no_package_name_mangling.
% Mangle a name so that it is suitable for Java.
%
:- pred mangle_sym_name_for_java(sym_name::in, java_qual_kind::in,
string::in, package_name_mangling::in, string::out) is det.
% Returns yes iff the given package is one provided by the Mercury
% implementation, `mercury' or `mercury.runtime'.
%
:- func is_mercury_provided_java_package(sym_name) = bool.
% Used in module_name_to_file_name to derive file names for Java files.
% Returns a module name which each component mangled.
%
:- func java_module_name(module_name) = module_name.
% Return the given module name with an outermost "mercury" qualifier,
% if it is not already present.
%
:- func enforce_outermost_mercury_qualifier(module_name) = module_name.
% If the given name conficts with a reserved Java word we must add a
% prefix to it to avoid compilation errors.
%
:- func valid_java_symbol_name(string) = string.
% Succeeds iff the given string matches a reserved word in Java.
%
:- pred java_is_keyword(string::in) is semidet.
% 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.
% The package containing the Mercury standard library.
%
:- func mercury_std_library_package_name = sym_name.
% The package containing the Mercury Java runtime classes.
%
:- func mercury_runtime_package_name = sym_name.
%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
:- implementation.
:- import_module parse_tree.file_names.
:- import_module parse_tree.prog_foreign. % for name_mangle
:- import_module char.
:- import_module string.
%-----------------------------------------------------------------------------%
mangle_sym_name_for_java(SymName, QualKind, QualifierOp,
PackageNameMangling, JavaSafeName) :-
mangle_sym_name_for_java_2(SymName, QualKind, PackageNameMangling,
MangledSymName),
JavaSafeName = sym_name_to_string_sep(MangledSymName, QualifierOp).
:- pred mangle_sym_name_for_java_2(sym_name::in, java_qual_kind::in,
package_name_mangling::in, sym_name::out) is det.
mangle_sym_name_for_java_2(SymName, QualKind, PackageNameMangling,
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,
PackageNameMangling, MangledModuleName0),
(
PackageNameMangling = package_name_mangling,
MercuryProvided = is_mercury_provided_java_package(ModuleName0),
(
MercuryProvided = yes,
MangledModuleName = MangledModuleName0
;
MercuryProvided = no,
MangledModuleName = append_underscore_sym_name(
MangledModuleName0)
)
;
PackageNameMangling = no_package_name_mangling,
MangledModuleName = MangledModuleName0
),
JavaSafePlainName = java_safe_name_component(QualKind, PlainName),
MangledSymName = qualified(MangledModuleName, JavaSafePlainName)
).
:- func java_safe_name_component(java_qual_kind, string) = string.
java_safe_name_component(QualKind, Name) = JavaSafeName :-
(
QualKind = module_qual,
FlippedName = Name
;
QualKind = type_qual,
FlippedName = flip_initial_case(Name)
),
MangledName = name_mangle(FlippedName),
JavaSafeName = valid_java_symbol_name(MangledName).
is_mercury_provided_java_package(ModuleName) = MercuryProvided :-
( ModuleName = mercury_std_library_package_name ->
MercuryProvided = yes
; ModuleName = mercury_runtime_package_name ->
MercuryProvided = yes
;
MercuryProvided = no
).
:- func append_underscore_sym_name(sym_name) = sym_name.
append_underscore_sym_name(SymName0) = SymName :-
(
SymName0 = unqualified(Name),
SymName = unqualified(Name ++ "_")
;
SymName0 = qualified(ModuleSymName, Name),
SymName = qualified(ModuleSymName, Name ++ "_")
).
%-----------------------------------------------------------------------------%
java_module_name(ModuleName) = JavaModuleName :-
% Put a "mercury" prefix on the module name if it doesn't already have one,
% so that even unqualified module names to end up in a Java package.
% Java doesn't allow packaged classes to import types from the default
% unnamed package. We don't do this earlier so as not to disturb other
% MLDS backends.
QualModuleName = enforce_outermost_mercury_qualifier(ModuleName),
mangle_sym_name_for_java_2(QualModuleName, module_qual,
package_name_mangling, JavaModuleName).
enforce_outermost_mercury_qualifier(ModuleName) = QualModuleName :-
( outermost_qualifier(ModuleName) = "mercury" ->
QualModuleName = ModuleName
;
QualModuleName = add_outermost_qualifier("mercury", ModuleName)
).
%-----------------------------------------------------------------------------%
valid_java_symbol_name(SymName) = ValidSymName :-
Prefix = "mr_",
( java_is_keyword(SymName) ->
% This is a reserved Java word, add the above prefix.
ValidSymName = Prefix ++ SymName
; string.append(Prefix, Suffix, SymName) ->
% This name already contains the prefix we are adding to
% variables to avoid conficts, so add an additional '_'.
ValidSymName = Prefix ++ "_" ++ Suffix
;
% Normal name; do nothing.
ValidSymName = SymName
).
%-----------------------------------------------------------------------------%
java_is_keyword("abstract").
java_is_keyword("boolean").
java_is_keyword("break").
java_is_keyword("byte").
java_is_keyword("case").
java_is_keyword("catch").
java_is_keyword("char").
java_is_keyword("class").
java_is_keyword("const").
java_is_keyword("continue").
java_is_keyword("default").
java_is_keyword("do").
java_is_keyword("double").
java_is_keyword("else").
java_is_keyword("enum").
java_is_keyword("extends").
java_is_keyword("false").
java_is_keyword("final").
java_is_keyword("finally").
java_is_keyword("float").
java_is_keyword("for").
java_is_keyword("goto").
java_is_keyword("if").
java_is_keyword("implements").
java_is_keyword("import").
java_is_keyword("instanceof").
java_is_keyword("int").
java_is_keyword("interface").
java_is_keyword("long").
java_is_keyword("native").
java_is_keyword("new").
java_is_keyword("null").
java_is_keyword("package").
java_is_keyword("private").
java_is_keyword("protected").
java_is_keyword("public").
java_is_keyword("return").
java_is_keyword("short").
java_is_keyword("static").
java_is_keyword("strictfp").
java_is_keyword("super").
java_is_keyword("switch").
java_is_keyword("synchronized").
java_is_keyword("this").
java_is_keyword("throw").
java_is_keyword("throws").
java_is_keyword("transient").
java_is_keyword("true").
java_is_keyword("try").
java_is_keyword("void").
java_is_keyword("volatile").
java_is_keyword("while").
%-----------------------------------------------------------------------------%
flip_initial_case(S0) = S :-
( string.first_char(S0, First0, Rest) ->
( char.is_upper(First0) ->
First = char.to_lower(First0)
; char.is_lower(First0) ->
First = char.to_upper(First0)
;
First = First0
),
string.first_char(S, First, Rest)
;
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)).
%-----------------------------------------------------------------------------%
mercury_std_library_package_name = unqualified("mercury").
mercury_runtime_package_name = qualified(unqualified("mercury"), "runtime").
%-----------------------------------------------------------------------------%
:- func this_file = string.
this_file = "java_names.m".
%-----------------------------------------------------------------------------%
:- end_module java_names.
%-----------------------------------------------------------------------------%