mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +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.
440 lines
18 KiB
Mathematica
440 lines
18 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2010-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2018, 2020-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_cs_file.m.
|
|
% Main authors: wangp.
|
|
%
|
|
% Convert MLDS to C# code.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend.mlds_to_cs_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_csharp_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_util.
|
|
:- import_module ml_backend.mlds_to_cs_class.
|
|
:- import_module ml_backend.mlds_to_cs_data.
|
|
:- import_module ml_backend.mlds_to_cs_export.
|
|
:- import_module ml_backend.mlds_to_cs_func.
|
|
:- import_module ml_backend.mlds_to_cs_global.
|
|
:- import_module ml_backend.mlds_to_cs_type.
|
|
:- import_module ml_backend.mlds_to_cs_util.
|
|
:- 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 pair.
|
|
:- import_module require.
|
|
:- import_module set.
|
|
:- import_module string.
|
|
:- import_module term_context.
|
|
:- import_module uint.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_csharp_mlds(ProgressStream, ModuleInfo, MLDS, Succeeded, !IO) :-
|
|
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(ext_cur_ngs_gs_target_cs),
|
|
ModuleName, SourceFileName, _SourceFileNameProposed, !IO),
|
|
output_to_file_stream(ProgressStream, Globals, SourceFileName,
|
|
output_csharp_src_file(ModuleInfo, MLDS), Succeeded, !IO).
|
|
|
|
:- pred output_csharp_src_file(module_info::in, mlds::in,
|
|
io.text_output_stream::in, list(string)::out, io::di, io::uo) is det.
|
|
|
|
output_csharp_src_file(ModuleInfo, MLDS, Stream, Errors, !IO) :-
|
|
% Run further transformations on the MLDS.
|
|
MLDS = mlds(ModuleName, Imports, GlobalData,
|
|
ClassDefns, EnumDefns, EnvDefns, TableStructDefns, ProcDefns,
|
|
InitPreds, FinalPreds, AllForeignCode, ExportedEnums),
|
|
ml_global_data_get_all_global_defns(GlobalData,
|
|
ScalarCellGroupMap, VectorCellGroupMap, _AllocIdMap,
|
|
RttiDefns, CellDefns, ClosureWrapperFuncDefns),
|
|
|
|
% Find 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_global_var_defns(RttiDefns, !CodeAddrsInConsts),
|
|
method_ptrs_in_global_var_defns(CellDefns, !CodeAddrsInConsts),
|
|
method_ptrs_in_global_var_defns(TableStructDefns, !CodeAddrsInConsts),
|
|
method_ptrs_in_function_defns(ClosureWrapperFuncDefns,
|
|
!CodeAddrsInConsts),
|
|
method_ptrs_in_function_defns(ProcDefns, !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(_, _, RevSeqNumCodeAddrs),
|
|
|
|
make_code_addr_map_for_csharp(RevSeqNumCodeAddrs, map.init, CodeAddrs)
|
|
),
|
|
|
|
% Get the foreign code for C#.
|
|
( if map.search(AllForeignCode, lang_csharp, ForeignCode) then
|
|
ForeignCode = mlds_foreign_code(ForeignDeclCodes, ForeignBodyCodes,
|
|
_FIMSpecs, ExportDefns)
|
|
else
|
|
ForeignDeclCodes = [],
|
|
ForeignBodyCodes = [],
|
|
ExportDefns = []
|
|
),
|
|
|
|
% Output transformed MLDS as C# source.
|
|
module_name_to_source_file_name(ModuleName, SourceFileName, !IO),
|
|
Info = init_csharp_out_info(ModuleInfo, SourceFileName, CodeAddrs),
|
|
output_src_start_for_csharp(Info, Stream, ModuleName, Imports,
|
|
ForeignDeclCodes, ProcDefns, ForeignDeclErrors, !IO),
|
|
list.map_foldl(output_csharp_body_code(Info, Stream),
|
|
ForeignBodyCodes, ForeignCodeResults, !IO),
|
|
list.filter_map(maybe_is_error, ForeignCodeResults, ForeignCodeErrors),
|
|
|
|
output_pragma_warning_disable(Stream, !IO),
|
|
|
|
io.write_string(Stream, "\n// RttiDefns\n", !IO),
|
|
list.foldl(
|
|
output_global_var_defn_for_csharp(Info, Stream, 1u, oa_alloc_only),
|
|
RttiDefns, !IO),
|
|
output_rtti_assignments_for_csharp(Info, Stream, 1u, RttiDefns, !IO),
|
|
|
|
io.write_string(Stream, "\n// Cell and tabling definitions\n", !IO),
|
|
output_global_var_decls_for_csharp(Info, Stream, 1u, CellDefns, !IO),
|
|
output_global_var_decls_for_csharp(Info, Stream, 1u,
|
|
TableStructDefns, !IO),
|
|
output_init_global_var_method_for_csharp(Info, Stream, 1u,
|
|
CellDefns ++ TableStructDefns, !IO),
|
|
|
|
% Scalar common data must appear after the previous data definitions,
|
|
% and the vector common data after that.
|
|
io.write_string(Stream, "\n// Scalar common data\n", !IO),
|
|
output_scalar_common_data_for_csharp(Info, Stream, 1u,
|
|
ScalarCellGroupMap, !IO),
|
|
|
|
io.write_string(Stream, "\n// Vector common data\n", !IO),
|
|
output_vector_common_data_for_csharp(Info, Stream, 1u,
|
|
VectorCellGroupMap, !IO),
|
|
|
|
io.write_string(Stream, "\n// Method pointers\n", !IO),
|
|
output_method_ptr_constants(Info, Stream, 1u, CodeAddrs, !IO),
|
|
|
|
io.write_string(Stream, "\n// Function definitions\n", !IO),
|
|
list.sort(ClosureWrapperFuncDefns ++ ProcDefns, SortedFuncDefns),
|
|
list.foldl(
|
|
output_function_defn_for_csharp(Info, Stream, 1u, oa_none),
|
|
SortedFuncDefns, !IO),
|
|
|
|
io.write_string(Stream, "\n// Class definitions\n", !IO),
|
|
list.sort(ClassDefns, SortedClassDefns),
|
|
list.foldl(output_class_defn_for_csharp(Info, Stream, 1u),
|
|
SortedClassDefns, !IO),
|
|
|
|
io.write_string(Stream, "\n// Enum class definitions\n", !IO),
|
|
list.sort(EnumDefns, SortedEnumDefns),
|
|
list.foldl(output_enum_class_defn_for_csharp(Info, Stream, 1u),
|
|
SortedEnumDefns, !IO),
|
|
|
|
io.write_string(Stream, "\n// Env definitions\n", !IO),
|
|
list.sort(EnvDefns, SortedEnvDefns),
|
|
list.foldl(output_env_defn_for_csharp(Info, Stream, 1u),
|
|
SortedEnvDefns, !IO),
|
|
|
|
io.write_string(Stream, "\n// ExportDefns\n", !IO),
|
|
output_exports_for_csharp(Info, Stream, 1u, ExportDefns, !IO),
|
|
|
|
io.write_string(Stream, "\n// ExportedEnums\n", !IO),
|
|
output_exported_enums_for_csharp(Info, Stream, 1u, ExportedEnums, !IO),
|
|
|
|
io.write_string(Stream, "\n// EnvVarNames\n", !IO),
|
|
set.init(EnvVarNamesSet0),
|
|
list.foldl(accumulate_env_var_names, ProcDefns,
|
|
EnvVarNamesSet0, EnvVarNamesSet1),
|
|
list.foldl(accumulate_env_var_names, ClosureWrapperFuncDefns,
|
|
EnvVarNamesSet1, EnvVarNamesSet),
|
|
set.foldl(output_env_var_definition_for_csharp(Stream, 1u),
|
|
EnvVarNamesSet, !IO),
|
|
|
|
StaticCtorCalls = [
|
|
"MR_init_rtti",
|
|
"MR_init_data",
|
|
"MR_init_scalar_common_data",
|
|
"MR_init_vector_common_data"
|
|
| InitPreds
|
|
],
|
|
output_static_constructor(Stream, ModuleName, 1u, StaticCtorCalls,
|
|
FinalPreds, !IO),
|
|
|
|
output_src_end_for_csharp(Stream, ModuleName, !IO),
|
|
|
|
Errors = ForeignDeclErrors ++ ForeignCodeErrors.
|
|
|
|
:- pred make_code_addr_map_for_csharp(assoc_list(int, mlds_code_addr)::in,
|
|
map(mlds_code_addr, string)::in, map(mlds_code_addr, string)::out) is det.
|
|
|
|
make_code_addr_map_for_csharp([], !CodeAddrMap).
|
|
make_code_addr_map_for_csharp([SeqNum - CodeAddr | SeqNumsCodeAddrs],
|
|
!CodeAddrMap) :-
|
|
Name = "MR_method_ptr_" ++ string.from_int(SeqNum),
|
|
map.det_insert(CodeAddr, Name, !CodeAddrMap),
|
|
make_code_addr_map_for_csharp(SeqNumsCodeAddrs, !CodeAddrMap).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output the start and end of a source file.
|
|
%
|
|
|
|
:- pred output_src_start_for_csharp(csharp_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_csharp(Info, Stream, ModuleName, _Imports,
|
|
ForeignDecls, FuncDefns, Errors, !IO) :-
|
|
output_auto_gen_comment(Stream, Info ^ csoi_source_filename, !IO),
|
|
io.format(Stream, "// :- module %s.\n\n",
|
|
[s(escaped_sym_name_to_string(ModuleName))], !IO),
|
|
% The close parenthesis for this open parenthesis is written out
|
|
% by output_src_end_for_csharp.
|
|
io.write_string(Stream, "namespace mercury {\n\n", !IO),
|
|
|
|
list.map_foldl(output_csharp_decl_code(Info, Stream),
|
|
ForeignDecls, ForeignDeclResults, !IO),
|
|
list.filter_map(maybe_is_error, ForeignDeclResults, Errors),
|
|
|
|
mangle_sym_name_for_csharp(ModuleName, module_qual, "__", ClassName),
|
|
% The close parenthesis for this open parenthesis is written out
|
|
% by output_src_end_for_csharp.
|
|
io.format(Stream, "public static class %s {\n", [s(ClassName)], !IO),
|
|
|
|
% Check whether this module contains a `main' predicate, and if it does,
|
|
% then generate a `main' method that calls the `main' predicate.
|
|
( if func_defns_contain_main(FuncDefns) then
|
|
write_main_driver_for_csharp(Stream, 1u, ClassName, !IO)
|
|
else
|
|
true
|
|
).
|
|
|
|
% C# only allows a single static constructor so we just call the real
|
|
% methods that we generated earlier.
|
|
%
|
|
:- pred output_static_constructor(io.text_output_stream::in,
|
|
mercury_module_name::in, indent::in, list(string)::in, list(string)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_static_constructor(Stream, ModuleName, Indent,
|
|
StaticConstructors, FinalPreds, !IO) :-
|
|
IndentStr = indent2_string(Indent),
|
|
Indent1Str = indent2_string(Indent + 1u),
|
|
mangle_sym_name_for_csharp(ModuleName, module_qual, "__", ClassName),
|
|
io.format(Stream, "%sstatic %s() {\n", [s(IndentStr), s(ClassName)], !IO),
|
|
WriteCall =
|
|
( pred(MethodName::in, !.IO::di, !:IO::uo) is det :-
|
|
io.format(Stream, "%s%s();\n",
|
|
[s(Indent1Str), s(MethodName)], !IO)
|
|
),
|
|
list.foldl(WriteCall, StaticConstructors, !IO),
|
|
WriteFinal =
|
|
( pred(FinalPred::in, !.IO::di, !:IO::uo) is det :-
|
|
io.format(Stream,
|
|
"%sSystem.AppDomain.CurrentDomain.ProcessExit +=\n",
|
|
[s(Indent1Str)], !IO),
|
|
io.format(Stream,
|
|
"%s (sender, ev) => %s();\n",
|
|
[s(Indent1Str), s(FinalPred)], !IO)
|
|
),
|
|
list.foldl(WriteFinal, FinalPreds, !IO),
|
|
io.format(Stream, "%s}\n", [s(IndentStr)], !IO).
|
|
|
|
:- pred write_main_driver_for_csharp(io.text_output_stream::in, indent::in,
|
|
string::in, io::di, io::uo) is det.
|
|
|
|
write_main_driver_for_csharp(Stream, Indent, ClassName, !IO) :-
|
|
IndentStr = indent2_string(Indent),
|
|
Indent1Str = indent2_string(Indent + 1u),
|
|
io.format(Stream, "%spublic static void Main(string[] args)\n",
|
|
[s(IndentStr)], !IO),
|
|
io.format(Stream, "%s{\n", [s(IndentStr)], !IO),
|
|
Body = [
|
|
"try {",
|
|
" library.ML_std_library_init();",
|
|
" " ++ ClassName ++ ".main_2_p_0();",
|
|
"} catch (runtime.Exception e) {",
|
|
" exception.ML_report_uncaught_exception(",
|
|
" (univ.Univ_0) e.exception);",
|
|
" if (System.Environment.GetEnvironmentVariable(",
|
|
" ""MERCURY_SUPPRESS_STACK_TRACE"") == null) {",
|
|
" System.Console.Error.WriteLine(e.StackTrace);",
|
|
" }",
|
|
" if (System.Environment.ExitCode == 0) {",
|
|
" System.Environment.ExitCode = 1;",
|
|
" }",
|
|
"}"
|
|
],
|
|
list.foldl(write_indentstr_line(Stream, Indent1Str), Body, !IO),
|
|
io.format(Stream, "%s}\n", [s(IndentStr)], !IO).
|
|
|
|
:- pred output_src_end_for_csharp(io.text_output_stream::in,
|
|
mercury_module_name::in, io::di, io::uo) is det.
|
|
|
|
output_src_end_for_csharp(Stream, ModuleName, !IO) :-
|
|
% The open parenthesis for both of these close parentheses was written out
|
|
% by output_src_start_for_csharp.
|
|
io.write_string(Stream, "}\n\n", !IO),
|
|
io.write_string(Stream, "}\n", !IO),
|
|
io.format(Stream, "// :- end_module %s.\n",
|
|
[s(escaped_sym_name_to_string(ModuleName))], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code for working with `foreign_code'.
|
|
%
|
|
|
|
:- pred output_csharp_decl_code(csharp_out_info::in, io.text_output_stream::in,
|
|
foreign_decl_code::in, maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_csharp_decl_code(Info, Stream, DeclCode, Res, !IO) :-
|
|
DeclCode = foreign_decl_code(Lang, _IsLocal, LiteralOrInclude, Context),
|
|
(
|
|
Lang = lang_csharp,
|
|
output_csharp_foreign_literal_or_include(Info, Stream,
|
|
LiteralOrInclude, Context, Res, !IO)
|
|
;
|
|
( Lang = lang_c
|
|
; Lang = lang_java
|
|
),
|
|
sorry($pred, "foreign decl other than C#")
|
|
).
|
|
|
|
:- pred output_csharp_body_code(csharp_out_info::in, io.text_output_stream::in,
|
|
foreign_body_code::in, maybe_error::out, io::di, io::uo) is det.
|
|
|
|
output_csharp_body_code(Info, Stream, ForeignBodyCode, Res, !IO) :-
|
|
ForeignBodyCode = foreign_body_code(Lang, LiteralOrInclude, Context),
|
|
% Only output C# code.
|
|
(
|
|
Lang = lang_csharp,
|
|
output_csharp_foreign_literal_or_include(Info, Stream,
|
|
LiteralOrInclude, Context, Res, !IO)
|
|
;
|
|
( Lang = lang_c
|
|
; Lang = lang_java
|
|
),
|
|
sorry($pred, "foreign code other than C#")
|
|
).
|
|
|
|
:- pred output_csharp_foreign_literal_or_include(csharp_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_csharp_foreign_literal_or_include(Info, Stream, LiteralOrInclude,
|
|
Context, Res, !IO) :-
|
|
PrintLineNumbers = Info ^ csoi_foreign_line_numbers,
|
|
(
|
|
LiteralOrInclude = floi_literal(Code),
|
|
cs_output_context(Stream, PrintLineNumbers, Context, !IO),
|
|
io.write_string(Stream, Code, !IO),
|
|
Res = ok
|
|
;
|
|
LiteralOrInclude = floi_include_file(IncludeFileName),
|
|
SourceFileName = Info ^ csoi_source_filename,
|
|
make_include_file_path(SourceFileName, IncludeFileName, IncludePath),
|
|
InitialFileContext = context(IncludePath, 1),
|
|
cs_output_context(Stream, PrintLineNumbers, InitialFileContext, !IO),
|
|
ModuleInfo = Info ^ csoi_module_info,
|
|
module_info_get_globals(ModuleInfo, Globals),
|
|
write_include_file_contents(Stream, Globals, IncludePath, Res, !IO)
|
|
),
|
|
io.nl(Stream, !IO),
|
|
cs_output_default_context(Stream, PrintLineNumbers, !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred output_method_ptr_constants(csharp_out_info::in,
|
|
io.text_output_stream::in, indent::in, map(mlds_code_addr, string)::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_method_ptr_constants(Info, Stream, Indent, CodeAddrs, !IO) :-
|
|
IndentStr = indent2_string(Indent),
|
|
map.foldl(output_method_ptr_constant(Info, Stream, IndentStr),
|
|
CodeAddrs, !IO).
|
|
|
|
:- pred output_method_ptr_constant(csharp_out_info::in,
|
|
io.text_output_stream::in, string::in, mlds_code_addr::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_method_ptr_constant(Info, Stream, IndentStr, CodeAddr, Name, !IO) :-
|
|
CodeAddr = mlds_code_addr(_QualFuncLabel, Signature),
|
|
Signature = mlds_func_signature(ArgTypes, RetTypes),
|
|
TypeNameStr = method_ptr_type_to_string(Info, ArgTypes, RetTypes),
|
|
io.format(Stream, "%sprivate static readonly %s %s = ",
|
|
[s(IndentStr), s(TypeNameStr), s(Name)], !IO),
|
|
output_code_addr_for_csharp(Info, Stream, CodeAddr, is_not_for_call, !IO),
|
|
io.write_string(Stream, ";\n", !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Code to output globals for environment variables.
|
|
%
|
|
|
|
:- pred output_env_var_definition_for_csharp(io.text_output_stream::in,
|
|
indent::in, string::in, io::di, io::uo) is det.
|
|
|
|
output_env_var_definition_for_csharp(Stream, Indent, EnvVarName, !IO) :-
|
|
IndentStr = indent2_string(Indent),
|
|
% We use int because the generated code compares against zero, and changing
|
|
% that is more trouble than it is worth, as it affects the C backends.
|
|
io.format(Stream, "%sprivate static int mercury_envvar_%s =\n",
|
|
[s(IndentStr), s(EnvVarName)], !IO),
|
|
io.format(Stream,
|
|
"%s System.Environment.GetEnvironmentVariable(\"%s\") == null" ++
|
|
" ? 0 : 1;\n",
|
|
[s(IndentStr), s(EnvVarName)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ml_backend.mlds_to_cs_file.
|
|
%---------------------------------------------------------------------------%
|