mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
compiler/file_util.m:
Define standard routines for reporting that we couldn't open a file
for either input or output. Rename the one other predicate in this file
that the compiler used for that purpose, so that its call sites
can be redirected to use one of the routines intended for this purpose.
Give these routines the ability to standardize path names (by removing
"./" prefixes from relative path names, and removing all directory names
from adsolute path names) if a new option is given.
compiler/options.m:
Add that (developer-only) option.
compiler/compile_target_code.m:
compiler/copy_util.m:
compiler/export.m:
compiler/llds_out_file.m:
compiler/mercury_compile_front_end.m:
compiler/mercury_compile_make_hlds.m:
compiler/mercury_compile_middle_passes.m:
compiler/mercury_compile_mlds_back_end.m:
compiler/mlds_to_c_file.m:
compiler/mlds_to_cs_file.m:
compiler/mlds_to_java_file.m:
compiler/module_cmds.m:
compiler/opt_deps_spec.m:
compiler/output_imports_graph.m:
compiler/passes_aux.m:
compiler/system_cmds.m:
compiler/write_deps_file.m:
compiler/xml_documentation.m:
Replace all call sites to the file_util.m predicates modified
by this diff. In many cases, it replaces duplicate copies of the
same code with a call. In some cases, redirect the error message
to the progress stream, where it belongs.
tests/invalid/Mercury.options:
tests/invalid/foreign_include_file_missing.err_exp3:
Compile the foreign_include_file_missing test case with the new option,
and add the expected output in C# grades, which (thanks to the option)
no longer includes the pathname of the test directory.
tests/invalid/foreign_include_file_missing.m:
Record what the new .err_exp3 file is for.
tests/warnings/help_text.err_exp:
Expect the new option.
688 lines
26 KiB
Mathematica
688 lines
26 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2000-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2025 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: mlds_to_java_file.m.
|
|
% Main authors: juliensf, mjwybrow, fjh, wangp.
|
|
%
|
|
% Convert MLDS to Java code.
|
|
%
|
|
% DONE:
|
|
% det and semidet predicates
|
|
% multiple output arguments
|
|
% boxing and unboxing
|
|
% conjunctions
|
|
% disjunctions
|
|
% if-then-else's
|
|
% enumerations
|
|
% discriminated unions
|
|
% higher order functions
|
|
% multidet and nondet predicates
|
|
% test tests/benchmarks/*.m
|
|
% generate optimized tailcalls
|
|
% RTTI generation
|
|
% handle foreign code written in Java
|
|
% Support for Java in mmc --make
|
|
% Support for nested modules
|
|
%
|
|
% TODO:
|
|
% - Support nested modules
|
|
% (The problem with current code generation scheme for nested modules
|
|
% is that Java does not allow the name of a class to be the same
|
|
% as the name of its enclosing package. That should work now, but
|
|
% javac doesn't like the filenames we give for submodules.)
|
|
%
|
|
% - Generate names of classes etc. correctly.
|
|
%
|
|
% - General code cleanup
|
|
%
|
|
% - handle static ground terms(?)
|
|
%
|
|
% - support foreign_import_module for Java
|
|
%
|
|
% - handle foreign code written in C
|
|
%
|
|
% NOTES:
|
|
% To avoid namespace conflicts all Java names must be fully qualified,
|
|
% e.g. The classname `String' must be qualified as `java.lang.String'
|
|
% to avoid conflicting with `mercury.String'.
|
|
%
|
|
% There is currently some code threaded through the output predicates (usually
|
|
% a variable called `ExitMethods') which keeps track of, and removes
|
|
% unreachable code. Ideally this would be done as an MLDS->MLDS transformation,
|
|
% preferably in a separate module. Unfortunately this is not possible
|
|
% due to the fact that the back-end generates `break' statements for cases
|
|
% in switches as they are output, meaning that we can't remove them in
|
|
% a pass over the MLDS.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend.mlds_to_java_file.
|
|
:- interface.
|
|
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module libs.
|
|
:- import_module libs.maybe_util.
|
|
:- import_module ml_backend.mlds.
|
|
|
|
:- import_module io.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred output_java_mlds(io.text_output_stream::in, module_info::in,
|
|
mlds::in, maybe_succeeded::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module libs.compiler_util.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.indent.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module ml_backend.ml_global_data.
|
|
:- import_module ml_backend.ml_rename_classes.
|
|
:- import_module ml_backend.ml_util.
|
|
:- import_module ml_backend.mlds_to_java_class.
|
|
:- import_module ml_backend.mlds_to_java_export.
|
|
:- import_module ml_backend.mlds_to_java_func.
|
|
:- import_module ml_backend.mlds_to_java_global.
|
|
:- import_module ml_backend.mlds_to_java_util.
|
|
:- import_module ml_backend.mlds_to_java_wrap.
|
|
:- import_module ml_backend.mlds_to_target_util.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.file_names.
|
|
:- import_module parse_tree.java_names.
|
|
:- import_module parse_tree.parse_tree_out_sym_name.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_data_foreign.
|
|
:- import_module parse_tree.prog_foreign.
|
|
|
|
:- import_module assoc_list.
|
|
:- import_module bool.
|
|
:- import_module cord.
|
|
:- import_module list.
|
|
:- import_module map.
|
|
:- import_module maybe.
|
|
:- import_module multi_map.
|
|
:- import_module pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term_context.
|
|
:- import_module uint.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_java_mlds(ProgressStream, ModuleInfo, MLDS, Succeeded, !IO) :-
|
|
% Note that the Java file name that we use for modules in the
|
|
% Mercury standard library do not include a "mercury." prefix;
|
|
% that is why we don't call mercury_module_name_to_mlds here.
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
ModuleName = mlds_get_module_name(MLDS),
|
|
% XXX LEGACY
|
|
module_name_to_file_name_create_dirs(Globals, $pred,
|
|
ext_cur_ngs_gs_java(ext_cur_ngs_gs_java_java),
|
|
ModuleName, JavaSourceFileName, _JavaSourceFileNameProposed, !IO),
|
|
output_to_file_stream(ProgressStream, Globals, JavaSourceFileName,
|
|
output_java_src_file(ModuleInfo, MLDS), Succeeded, !IO).
|
|
|
|
:- pred output_java_src_file(module_info::in, mlds::in,
|
|
io.text_output_stream::in, list(string)::out, io::di, io::uo) is det.
|
|
|
|
output_java_src_file(ModuleInfo, MLDS, Stream, Errors, !IO) :-
|
|
% Run further transformations on the MLDS.
|
|
MLDS = mlds(ModuleName, Imports, GlobalData,
|
|
ClassDefns0, EnumDefns, EnvDefns0, TableStructDefns0, ProcDefns0,
|
|
InitPreds, FinalPreds, AllForeignCode, ExportedEnums),
|
|
ml_global_data_get_all_global_defns(GlobalData,
|
|
ScalarCellGroupMap, VectorCellGroupMap, _AllocIdMap,
|
|
RttiDefns0, CellDefns0, ClosureWrapperFuncDefns0),
|
|
|
|
% Do NOT enforce the outermost "mercury" qualifier here. This module name
|
|
% is compared with other module names in the MLDS, to avoid unnecessary
|
|
% module qualification.
|
|
MLDS_ModuleName = mercury_module_name_to_mlds(ModuleName),
|
|
|
|
% Find and build list of all methods which would have their addresses
|
|
% taken to be used as a function pointer.
|
|
some [!CodeAddrsInConsts] (
|
|
!:CodeAddrsInConsts = init_code_addrs_in_consts,
|
|
method_ptrs_in_class_defns(ClassDefns0, !CodeAddrsInConsts),
|
|
% There are no method pointers in EnvDefns0.
|
|
method_ptrs_in_global_var_defns(RttiDefns0, !CodeAddrsInConsts),
|
|
method_ptrs_in_global_var_defns(CellDefns0, !CodeAddrsInConsts),
|
|
method_ptrs_in_global_var_defns(TableStructDefns0, !CodeAddrsInConsts),
|
|
method_ptrs_in_function_defns(ClosureWrapperFuncDefns0,
|
|
!CodeAddrsInConsts),
|
|
method_ptrs_in_function_defns(ProcDefns0, !CodeAddrsInConsts),
|
|
|
|
map.values(ScalarCellGroupMap, ScalarCellGroups),
|
|
ScalarCellRows = list.map(func(G) = G ^ mscg_rows, ScalarCellGroups),
|
|
list.foldl(method_ptrs_in_scalars, ScalarCellRows, !CodeAddrsInConsts),
|
|
!.CodeAddrsInConsts = code_addrs_in_consts(_, _, RevSeqNumsCodeAddrs)
|
|
),
|
|
|
|
assoc_list.values(RevSeqNumsCodeAddrs, RevCodeAddrs),
|
|
|
|
make_code_addr_map_for_java(RevCodeAddrs, multi_map.init, CodeAddrsMap),
|
|
map.to_assoc_list(CodeAddrsMap, CodeAddrsAssocList),
|
|
|
|
% Create wrappers in MLDS for all pointer addressed methods.
|
|
list.map_foldl(generate_addr_wrapper_class(MLDS_ModuleName),
|
|
CodeAddrsAssocList, WrapperClassDefns0, map.init, AddrOfMap),
|
|
|
|
% Rename classes with excessively long names.
|
|
list.map_foldl(maybe_shorten_long_class_name,
|
|
ClassDefns0, ClassDefns1, map.init, RenamingMap1),
|
|
list.map_foldl(maybe_shorten_long_class_name,
|
|
WrapperClassDefns0, WrapperClassDefns1, RenamingMap1, RenamingMap2),
|
|
list.map_foldl(maybe_shorten_long_env_name,
|
|
EnvDefns0, EnvDefns1, RenamingMap2, RenamingMap),
|
|
( if map.is_empty(RenamingMap) then
|
|
ClassDefns = ClassDefns0,
|
|
EnvDefns = EnvDefns0,
|
|
WrapperClassDefns = WrapperClassDefns0,
|
|
RttiDefns = RttiDefns0,
|
|
CellDefns = CellDefns0,
|
|
TableStructDefns = TableStructDefns0,
|
|
ClosureWrapperFuncDefns = ClosureWrapperFuncDefns0,
|
|
ProcDefns = ProcDefns0
|
|
else
|
|
Renaming = class_name_renaming(MLDS_ModuleName, RenamingMap),
|
|
list.map(rename_class_names_in_class_defn(Renaming),
|
|
ClassDefns1, ClassDefns),
|
|
list.map(rename_class_names_in_class_defn(Renaming),
|
|
WrapperClassDefns1, WrapperClassDefns),
|
|
list.map(rename_class_names_in_env_defn(Renaming),
|
|
EnvDefns1, EnvDefns),
|
|
list.map(rename_class_names_in_global_var_defn(Renaming),
|
|
RttiDefns0, RttiDefns),
|
|
list.map(rename_class_names_in_global_var_defn(Renaming),
|
|
CellDefns0, CellDefns),
|
|
list.map(rename_class_names_in_global_var_defn(Renaming),
|
|
TableStructDefns0, TableStructDefns),
|
|
list.map(rename_class_names_in_function_defn(Renaming),
|
|
ClosureWrapperFuncDefns0, ClosureWrapperFuncDefns),
|
|
list.map(rename_class_names_in_function_defn(Renaming),
|
|
ProcDefns0, ProcDefns)
|
|
),
|
|
|
|
% Get the foreign code for Java.
|
|
( if map.search(AllForeignCode, lang_java, ForeignCode) then
|
|
ForeignCode = mlds_foreign_code(ForeignDeclCodes, ForeignBodyCodes,
|
|
_FIMSpecs, ExportDefns)
|
|
else
|
|
ForeignDeclCodes = [],
|
|
ForeignBodyCodes = [],
|
|
ExportDefns = []
|
|
),
|
|
|
|
% Output transformed MLDS as Java source.
|
|
%
|
|
% The order is important here, because Java requires static constants
|
|
% be defined before they can be used in static initializers.
|
|
% We start with the Java foreign code declarations, since for
|
|
% library/private_builtin.m they contain static constants
|
|
% that will get used in the RTTI definitions.
|
|
module_name_to_source_file_name(ModuleName, SourceFileName, !IO),
|
|
Info = init_java_out_info(ModuleInfo, SourceFileName, AddrOfMap),
|
|
output_src_start_for_java(Info, Stream, ModuleName, Imports,
|
|
ForeignDeclCodes, ProcDefns, ForeignDeclErrors, !IO),
|
|
list.map_foldl(output_java_body_code(Info, Stream),
|
|
ForeignBodyCodes, ForeignCodeResults, !IO),
|
|
list.filter_map(maybe_is_error, ForeignCodeResults, ForeignCodeErrors),
|
|
|
|
(
|
|
RttiDefns = []
|
|
;
|
|
RttiDefns = [_ | _],
|
|
io.write_string(Stream, "\n// RttiDefns\n", !IO),
|
|
list.foldl(
|
|
output_global_var_defn_for_java(Info, Stream, 1u, oa_alloc_only),
|
|
RttiDefns, !IO),
|
|
output_rtti_assignments_for_java(Info, Stream, 1u, RttiDefns, !IO)
|
|
),
|
|
|
|
( if
|
|
CellDefns = [],
|
|
TableStructDefns = []
|
|
then
|
|
true
|
|
else
|
|
io.write_string(Stream, "\n// Cell and tabling definitions\n", !IO),
|
|
output_global_var_decls_for_java(Info, Stream, 1u, CellDefns, !IO),
|
|
output_global_var_decls_for_java(Info, Stream, 1u,
|
|
TableStructDefns, !IO),
|
|
output_global_var_assignments_for_java(Info, Stream, 1u,
|
|
CellDefns ++ TableStructDefns, !IO)
|
|
),
|
|
|
|
% Scalar common data must appear after the previous data definitions, and
|
|
% the vector common data after that.
|
|
( if map.is_empty(ScalarCellGroupMap) then
|
|
true
|
|
else
|
|
io.write_string(Stream, "\n// Scalar common data\n", !IO),
|
|
output_scalar_common_data_for_java(Info, Stream, 1u,
|
|
ScalarCellGroupMap, !IO)
|
|
),
|
|
|
|
( if map.is_empty(VectorCellGroupMap) then
|
|
true
|
|
else
|
|
io.write_string(Stream, "\n// Vector common data\n", !IO),
|
|
output_vector_common_data_for_java(Info, Stream, 1u,
|
|
VectorCellGroupMap, !IO)
|
|
),
|
|
|
|
list.sort(ClosureWrapperFuncDefns ++ ProcDefns, SortedFuncDefns),
|
|
(
|
|
SortedFuncDefns = []
|
|
;
|
|
SortedFuncDefns = [_ | _],
|
|
io.write_string(Stream, "\n// Function definitions\n", !IO),
|
|
list.foldl(
|
|
output_function_defn_for_java(Info, Stream, 1u, oa_none),
|
|
SortedFuncDefns, !IO)
|
|
),
|
|
|
|
list.sort(WrapperClassDefns ++ ClassDefns, SortedClassDefns),
|
|
(
|
|
SortedClassDefns = []
|
|
;
|
|
SortedClassDefns = [_ | _],
|
|
io.write_string(Stream, "\n// Class definitions\n", !IO),
|
|
list.foldl(output_class_defn_for_java(Info, Stream, 1u),
|
|
SortedClassDefns, !IO)
|
|
),
|
|
|
|
list.sort(EnumDefns, SortedEnumDefns),
|
|
(
|
|
SortedEnumDefns = []
|
|
;
|
|
SortedEnumDefns = [_ | _],
|
|
io.write_string(Stream, "\n// Enum class definitions\n", !IO),
|
|
list.foldl(output_enum_class_defn_for_java(Info, Stream, 1u),
|
|
SortedEnumDefns, !IO)
|
|
),
|
|
|
|
list.sort(EnvDefns, SortedEnvDefns),
|
|
(
|
|
SortedEnvDefns = []
|
|
;
|
|
SortedEnvDefns = [_ | _],
|
|
io.write_string(Stream, "\n// Env definitions\n", !IO),
|
|
list.foldl(output_env_defn_for_java(Info, Stream, 1u),
|
|
SortedEnvDefns, !IO)
|
|
),
|
|
|
|
(
|
|
ExportDefns = []
|
|
;
|
|
ExportDefns = [_ | _],
|
|
io.write_string(Stream, "\n// ExportDefns\n", !IO),
|
|
output_exports_for_java(Info, Stream, 1u, ExportDefns, !IO)
|
|
),
|
|
|
|
(
|
|
ExportedEnums = []
|
|
;
|
|
ExportedEnums = [_ | _],
|
|
io.write_string(Stream, "\n// ExportedEnums\n", !IO),
|
|
output_exported_enums_for_java(Info, Stream, 1u, ExportedEnums, !IO)
|
|
),
|
|
|
|
(
|
|
InitPreds = []
|
|
;
|
|
InitPreds = [_ | _],
|
|
io.write_string(Stream, "\n// InitPreds\n", !IO),
|
|
output_inits_for_java(Stream, 1u, InitPreds, !IO)
|
|
),
|
|
|
|
(
|
|
FinalPreds = []
|
|
;
|
|
FinalPreds = [_ | _],
|
|
io.write_string(Stream, "\n// FinalPreds\n", !IO),
|
|
output_finals_for_java(Stream, 1u, FinalPreds, !IO)
|
|
),
|
|
|
|
set.init(EnvVarNamesSet0),
|
|
list.foldl(accumulate_env_var_names, ProcDefns,
|
|
EnvVarNamesSet0, EnvVarNamesSet1),
|
|
list.foldl(accumulate_env_var_names, ClosureWrapperFuncDefns,
|
|
EnvVarNamesSet1, EnvVarNamesSet),
|
|
( if set.is_empty(EnvVarNamesSet) then
|
|
true
|
|
else
|
|
io.write_string(Stream, "\n// EnvVarNames\n", !IO),
|
|
set.foldl(output_env_var_definition_for_java(Stream, 1u),
|
|
EnvVarNamesSet, !IO)
|
|
),
|
|
|
|
output_src_end_for_java(Info, Stream, ModuleName, !IO),
|
|
% XXX Need to handle non-Java foreign code at this point.
|
|
|
|
Errors = ForeignDeclErrors ++ ForeignCodeErrors.
|
|
|
|
:- pred make_code_addr_map_for_java(list(mlds_code_addr)::in,
|
|
multi_map(arity, mlds_code_addr)::in,
|
|
multi_map(arity, mlds_code_addr)::out) is det.
|
|
|
|
make_code_addr_map_for_java([], !Map).
|
|
make_code_addr_map_for_java([CodeAddr | CodeAddrs], !Map) :-
|
|
CodeAddr = mlds_code_addr(_QualFuncLabel, OrigFuncSignature),
|
|
OrigFuncSignature = mlds_func_signature(OrigArgTypes, _OrigRetTypes),
|
|
list.length(OrigArgTypes, Arity),
|
|
multi_map.set(Arity, CodeAddr, !Map),
|
|
make_code_addr_map_for_java(CodeAddrs, !Map).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output the start and end of a source file.
|
|
%
|
|
|
|
:- pred output_src_start_for_java(java_out_info::in, io.text_output_stream::in,
|
|
mercury_module_name::in, list(mlds_import)::in,
|
|
list(foreign_decl_code)::in, list(mlds_function_defn)::in,
|
|
list(string)::out, io::di, io::uo) is det.
|
|
|
|
output_src_start_for_java(Info, Stream, MercuryModuleName, Imports,
|
|
ForeignDecls, FuncDefns, Errors, !IO) :-
|
|
output_auto_gen_comment(Stream, Info ^ joi_source_filename, !IO),
|
|
io.format(Stream, "// :- module %s.\n\n",
|
|
[s(escaped_sym_name_to_string(MercuryModuleName))], !IO),
|
|
io.write_string(Stream, "package jmercury;\n", !IO),
|
|
|
|
maybe_output_import_comments_for_java(Info, Stream, Imports, !IO),
|
|
list.map_foldl(output_java_decl_code(Info, Stream),
|
|
ForeignDecls, ForeignDeclResults, !IO),
|
|
list.filter_map(maybe_is_error, ForeignDeclResults, Errors),
|
|
|
|
io.write_string(Stream, "public class ", !IO),
|
|
mangle_sym_name_for_java(MercuryModuleName, module_qual, "__", ClassName),
|
|
io.write_string(Stream, ClassName, !IO),
|
|
% The close parenthesis for this open parenthesis is written out
|
|
% by output_src_end_for_java.
|
|
io.write_string(Stream, " {\n", !IO),
|
|
|
|
output_debug_class_init(Info, Stream, MercuryModuleName, "start", !IO),
|
|
|
|
% Check whether this module contains a `main' predicate, and if it does,
|
|
% insert a `main' method in the resulting Java class that
|
|
% calls the `main' predicate.
|
|
( if func_defns_contain_main(FuncDefns) then
|
|
write_main_driver_for_java(Stream, 1u, ClassName, !IO)
|
|
else
|
|
true
|
|
).
|
|
|
|
:- pred write_main_driver_for_java(io.text_output_stream::in, indent::in,
|
|
string::in, io::di, io::uo) is det.
|
|
|
|
write_main_driver_for_java(Stream, Indent, ClassName, !IO) :-
|
|
IndentStr = indent2_string(Indent),
|
|
io.format(Stream, "%spublic static void main(java.lang.String[] args)\n",
|
|
[s(IndentStr)], !IO),
|
|
io.format(Stream, "%s{\n", [s(IndentStr)], !IO),
|
|
% Save the progname and command line arguments in the class variables
|
|
% of `jmercury.runtime.JavaInternal', as well as setting the default
|
|
% exit status.
|
|
Body = [
|
|
"jmercury.runtime.JavaInternal.progname = """ ++ ClassName ++ """;",
|
|
"jmercury.runtime.JavaInternal.args = args;",
|
|
"jmercury.runtime.JavaInternal.exit_status = 0;",
|
|
"library.ML_std_library_init();",
|
|
"benchmarking.ML_initialise();",
|
|
"Runnable run_main = new Runnable() {",
|
|
" public void run() {",
|
|
" " ++ ClassName ++ ".main_2_p_0();",
|
|
" }",
|
|
"};",
|
|
"jmercury.runtime.JavaInternal.runMain(run_main);",
|
|
"io.flush_output_3_p_0(io.stdout_stream_0_f_0());",
|
|
"io.flush_output_3_p_0(io.stderr_stream_0_f_0());",
|
|
"java.lang.System.exit(jmercury.runtime.JavaInternal.exit_status);"
|
|
],
|
|
Indent1Str = indent2_string(Indent + 1u),
|
|
list.foldl(write_indentstr_line(Stream, Indent1Str), Body, !IO),
|
|
io.format(Stream, "%s}\n", [s(IndentStr)], !IO).
|
|
|
|
:- pred output_src_end_for_java(java_out_info::in, io.text_output_stream::in,
|
|
mercury_module_name::in, io::di, io::uo) is det.
|
|
|
|
output_src_end_for_java(Info, Stream, ModuleName, !IO) :-
|
|
output_debug_class_init(Info, Stream, ModuleName, "end", !IO),
|
|
% The open parenthesis for this close parenthesis was written out
|
|
% by output_src_start_for_java.
|
|
io.write_string(Stream, "}\n", !IO),
|
|
AutoComments = Info ^ joi_auto_comments,
|
|
(
|
|
AutoComments = yes,
|
|
io.format(Stream, "// :- end_module %s.\n",
|
|
[s(escaped_sym_name_to_string(ModuleName))], !IO)
|
|
;
|
|
AutoComments = no
|
|
).
|
|
|
|
:- pred output_debug_class_init(java_out_info::in, io.text_output_stream::in,
|
|
mercury_module_name::in, string::in, io::di, io::uo) is det.
|
|
|
|
output_debug_class_init(Info, Stream, ModuleName, State, !IO) :-
|
|
DebugClassInit = get_debug_class_init(Info),
|
|
(
|
|
DebugClassInit = yes,
|
|
list.foldl(io.write_string(Stream), [
|
|
" static {\n",
|
|
" if (System.getenv(""MERCURY_DEBUG_CLASS_INIT"") != null) {\n",
|
|
" System.out.println(""[", sym_name_mangle(ModuleName),
|
|
" ", State, " init]"");\n",
|
|
" }\n",
|
|
" }\n"
|
|
], !IO)
|
|
;
|
|
DebugClassInit = no
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output imports.
|
|
%
|
|
|
|
:- pred maybe_output_import_comments_for_java(java_out_info::in,
|
|
io.text_output_stream::in, list(mlds_import)::in, io::di, io::uo) is det.
|
|
|
|
maybe_output_import_comments_for_java(Info, Stream, Imports, !IO) :-
|
|
AutoComments = Info ^ joi_auto_comments,
|
|
(
|
|
AutoComments = yes,
|
|
list.foldl(output_import_comment_for_java(Stream), Imports, !IO),
|
|
(
|
|
Imports = []
|
|
;
|
|
Imports = [_ | _],
|
|
io.nl(Stream, !IO)
|
|
)
|
|
;
|
|
AutoComments = no
|
|
).
|
|
|
|
:- pred output_import_comment_for_java(io.text_output_stream::in,
|
|
mlds_import::in, io::di, io::uo) is det.
|
|
|
|
output_import_comment_for_java(Stream, Import, !IO) :-
|
|
Import = mlds_import(ImportType, ModuleName),
|
|
(
|
|
ImportType = user_visible_interface,
|
|
unexpected($pred,
|
|
"import_type `user_visible_interface' in Java backend")
|
|
;
|
|
ImportType = compiler_visible_interface
|
|
),
|
|
mangle_sym_name_for_java(ModuleName, module_qual, "__", ClassFile),
|
|
% There are issues related to using import statements and Java's naming
|
|
% conventions. To avoid these problems, we output dependencies as comments
|
|
% only. This is ok, since we always use fully qualified names anyway.
|
|
io.format(Stream, "// import %s;\n", [s(ClassFile)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for working with Java `foreign_code'.
|
|
%
|
|
|
|
:- pred output_java_decl_code(java_out_info::in, io.text_output_stream::in,
|
|
foreign_decl_code::in, maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_java_decl_code(Info, Stream, DeclCode, Res, !IO) :-
|
|
DeclCode = foreign_decl_code(Lang, _IsLocal, LiteralOrInclude, Context),
|
|
(
|
|
Lang = lang_java,
|
|
output_java_foreign_literal_or_include(Info, Stream,
|
|
LiteralOrInclude, Context, Res, !IO)
|
|
;
|
|
( Lang = lang_c
|
|
; Lang = lang_csharp
|
|
),
|
|
sorry($pred, "foreign decl other than Java")
|
|
).
|
|
|
|
:- pred output_java_body_code(java_out_info::in, io.text_output_stream::in,
|
|
foreign_body_code::in, maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_java_body_code(Info, Stream, ForeignBodyCode, Res, !IO) :-
|
|
ForeignBodyCode = foreign_body_code(Lang, LiteralOrInclude, Context),
|
|
% Only output Java code.
|
|
(
|
|
Lang = lang_java,
|
|
output_java_foreign_literal_or_include(Info, Stream,
|
|
LiteralOrInclude, Context, Res, !IO)
|
|
;
|
|
( Lang = lang_c
|
|
; Lang = lang_csharp
|
|
),
|
|
sorry($pred, "foreign code other than Java")
|
|
).
|
|
|
|
:- pred output_java_foreign_literal_or_include(java_out_info::in,
|
|
io.text_output_stream::in, foreign_literal_or_include::in,
|
|
prog_context::in, maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_java_foreign_literal_or_include(Info, Stream, LiteralOrInclude,
|
|
Context, Res, !IO) :-
|
|
(
|
|
LiteralOrInclude = floi_literal(Code),
|
|
write_string_with_context_block(Info, Stream, 0u, Code, Context, !IO),
|
|
Res = ok
|
|
;
|
|
LiteralOrInclude = floi_include_file(IncludeFile),
|
|
SourceFileName = Info ^ joi_source_filename,
|
|
make_include_file_path(SourceFileName, IncludeFile, IncludePath),
|
|
output_context_for_java(Stream, Info ^ joi_foreign_line_numbers,
|
|
marker_begin_block, context(IncludePath, 1), !IO),
|
|
ModuleInfo = Info ^ joi_module_info,
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
write_include_file_contents(Stream, Globals, IncludePath, Res, !IO),
|
|
io.nl(Stream, !IO),
|
|
% We don't have the true end context readily available.
|
|
output_context_for_java(Stream, Info ^ joi_foreign_line_numbers,
|
|
marker_end_block, Context, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output calls to module initialisers.
|
|
%
|
|
|
|
:- pred output_inits_for_java(io.text_output_stream::in, indent::in,
|
|
list(string)::in, io::di, io::uo) is det.
|
|
|
|
output_inits_for_java(Stream, Indent, InitPreds, !IO) :-
|
|
(
|
|
InitPreds = []
|
|
;
|
|
InitPreds = [_ | _],
|
|
IndentStr = indent2_string(Indent),
|
|
Indent1Str = indent2_string(Indent + 1u),
|
|
% We call the initialisation predicates from a static initialisation
|
|
% block.
|
|
io.format(Stream, "%sstatic {\n", [s(IndentStr)], !IO),
|
|
list.foldl(output_init_for_java(Stream, Indent1Str), InitPreds, !IO),
|
|
io.format(Stream, "%s}\n", [s(IndentStr)], !IO)
|
|
).
|
|
|
|
:- pred output_init_for_java(io.text_output_stream::in, string::in,
|
|
string::in, io::di, io::uo) is det.
|
|
|
|
output_init_for_java(Stream, IndentStr, InitPred, !IO) :-
|
|
io.format(Stream, "%s%s();\n", [s(IndentStr), s(InitPred)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output module finalisers.
|
|
%
|
|
|
|
:- pred output_finals_for_java(io.text_output_stream::in, indent::in,
|
|
list(string)::in, io::di, io::uo) is det.
|
|
|
|
output_finals_for_java(Stream, Indent, FinalPreds, !IO) :-
|
|
(
|
|
FinalPreds = []
|
|
;
|
|
FinalPreds = [_ | _],
|
|
BeforeBlock = [
|
|
"static {",
|
|
" jmercury.runtime.JavaInternal.register_finaliser(",
|
|
" new java.lang.Runnable() {",
|
|
" public void run() {"
|
|
],
|
|
AfterBlock = [
|
|
" }",
|
|
" }",
|
|
" );",
|
|
"}"
|
|
],
|
|
IndentStr = indent2_string(Indent),
|
|
Indent4Str = indent2_string(Indent + 4u),
|
|
list.foldl(write_indentstr_line(Stream, IndentStr), BeforeBlock, !IO),
|
|
list.foldl(output_final_for_java(Stream, Indent4Str), FinalPreds, !IO),
|
|
list.foldl(write_indentstr_line(Stream, IndentStr), AfterBlock, !IO)
|
|
).
|
|
|
|
:- pred output_final_for_java(io.text_output_stream::in, string::in,
|
|
string::in, io::di, io::uo) is det.
|
|
|
|
output_final_for_java(Stream, IndentStr, FinalPred, !IO) :-
|
|
io.format(Stream, "%s%s();\n", [s(IndentStr), s(FinalPred)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output globals for environment variables.
|
|
%
|
|
|
|
:- pred output_env_var_definition_for_java(io.text_output_stream::in,
|
|
indent::in, string::in, io::di, io::uo) is det.
|
|
|
|
output_env_var_definition_for_java(Stream, Indent, EnvVarName, !IO) :-
|
|
% We use int because the generated code compares against zero, and changing
|
|
% that is more trouble than it's worth as it affects the C backends.
|
|
IndentStr = indent2_string(Indent),
|
|
io.format(Stream, "%sprivate static int mercury_envvar_%s =\n",
|
|
[s(IndentStr), s(EnvVarName)], !IO),
|
|
io.format(Stream, "%sjava.lang.System.getenv(\"%s\") == null ? 0 : 1;\n",
|
|
[s(IndentStr), s(EnvVarName)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ml_backend.mlds_to_java_file.
|
|
%---------------------------------------------------------------------------%
|