mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
... and almost all calls to get_error_output_stream. Replace them
with ProgressStreams and ErrorStreams passed down from higher in the
call tree.
Use ProgressStreams, not ErrorStreams, to write out error messages about
any failures of filesystem operations. These are not appropriate to put
into a module's .err file, since they are not about an error in the
Mercury code of the module.
compiler/globals.m:
Delete the predicates that return progress streams, and the mutable
behind them.
compiler/passes_aux.m:
Delete the predicates that return progress streams. Delete the
versions of the progress-message-writing predicates that didn't get
the progress stream from their caller.
compiler/*.m:
Pass around ProgressStreams and/or ErrorStreams explicitly,
as mentioned at the top of log message.
In a few places, don't write out error_specs to ErrorStream,
returning it to be printed by our caller, or its caller etc instead.
In some of those places, this allowed the deletion an existing
ErrorStream argument.
Given that get_{progress,error}_output_stream took a ModuleName input,
deleting some of the calls to those predicates left ModuleName unused.
Delete such unused ModuleNames.
In a few places, change argument orders to conform to our usual
programming style.
Fix too-long lines.
1161 lines
45 KiB
Mathematica
1161 lines
45 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2010-2012 The University of Melbourne.
|
|
% Copyright (C) 2013-2018, 2020-2022 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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% Output MLDS lvals, rvals and initializers in C#.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend.mlds_to_cs_data.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.indent.
|
|
:- import_module ml_backend.mlds.
|
|
:- import_module ml_backend.mlds_to_cs_util.
|
|
:- import_module ml_backend.mlds_to_target_util.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred output_lval_for_csharp(csharp_out_info::in, mlds_lval::in,
|
|
io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred output_call_rval_for_csharp(csharp_out_info::in, mlds_rval::in,
|
|
io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
:- pred output_rval_for_csharp(csharp_out_info::in, mlds_rval::in,
|
|
io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
:- type maybe_for_call
|
|
---> is_not_for_call
|
|
; is_for_call.
|
|
|
|
:- pred output_code_addr_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, mlds_code_addr::in, maybe_for_call::in,
|
|
io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Output " = " followed by the given initializer, if any, followed
|
|
% by the given suffix string and a newline.
|
|
%
|
|
% The initializer is printed using output_initializer_body_for_java with
|
|
% not_at_start_of_line (see below).
|
|
%
|
|
:- pred output_initializer_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, output_aux::in, indent::in, mlds_type::in,
|
|
mlds_initializer::in, string::in, io::di, io::uo) is det.
|
|
|
|
% Output the allocation part of the given initializer on the rest
|
|
% of the current line.
|
|
%
|
|
:- pred output_initializer_alloc_only_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, mlds_initializer::in, maybe(mlds_type)::in,
|
|
string::in, io::di, io::uo) is det.
|
|
|
|
% Output the given initializer. The formatting depends on whether
|
|
% the caller tells us that it has printed something on the current line
|
|
% already (not_at_start_of_line) or not (at_start_of_line).
|
|
%
|
|
% If the initializer is for a struct or an array, we put the initializer
|
|
% on separate lines, each indented by the given indent level, regardless
|
|
% of where we start.
|
|
%
|
|
% If the initializer is for a single object, then we put its initializer
|
|
% immediately after the previous of the current line if there is one
|
|
% (not_at_start_of_line); otherwise (at_start_of_line), we indent it by
|
|
% the specified level.
|
|
%
|
|
% In either case, we end the initializer with the given suffix
|
|
% (which will usually be a semicolon or a comma) and a newline.
|
|
%
|
|
:- pred output_initializer_body_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, initializer_starts::in, indent::in,
|
|
mlds_initializer::in, maybe(mlds_type)::in, string::in,
|
|
io::di, io::uo) is det.
|
|
|
|
% Output the given list of initializers with commas between them,
|
|
% putting each initializer on its own line with the given indent.
|
|
% Put the given suffix after the last initializer.
|
|
%
|
|
:- pred output_nonempty_initializer_body_list_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, indent::in, list(mlds_initializer)::in,
|
|
string::in, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.
|
|
:- import_module backend_libs.builtin_ops.
|
|
:- import_module backend_libs.c_util. % for output_quoted_string*
|
|
:- import_module backend_libs.rtti.
|
|
:- import_module hlds.
|
|
:- import_module hlds.hlds_module.
|
|
:- import_module libs.globals.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module ml_backend.ml_util.
|
|
:- import_module ml_backend.mlds_to_cs_name.
|
|
:- import_module ml_backend.mlds_to_cs_type.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.builtin_lib_types.
|
|
:- import_module parse_tree.prog_data.
|
|
:- import_module parse_tree.prog_type.
|
|
|
|
:- import_module int.
|
|
:- import_module int32.
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module term.
|
|
:- import_module uint32.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_lval_for_csharp(Info, Lval, Stream, !IO) :-
|
|
(
|
|
Lval = ml_field(_MaybeTag, PtrRval, _PtrType, FieldId, FieldType),
|
|
(
|
|
FieldId = ml_field_offset(OffsetRval),
|
|
( if
|
|
( FieldType = mlds_generic_type
|
|
; FieldType = mercury_nb_type(type_variable(_, _), _)
|
|
)
|
|
then
|
|
true
|
|
else
|
|
% The field type for field(_, _, offset(_), _, _) lvals
|
|
% must be something that maps to MR_Box.
|
|
unexpected($pred, "unexpected field type")
|
|
),
|
|
% XXX We shouldn't need this cast here, but there are cases where
|
|
% it is needed and the MLDS doesn't seem to generate it.
|
|
io.write_string(Stream, "((object[]) ", !IO),
|
|
output_rval_for_csharp(Info, PtrRval, Stream, !IO),
|
|
io.write_string(Stream, ")[", !IO),
|
|
output_rval_for_csharp(Info, OffsetRval, Stream, !IO),
|
|
io.write_string(Stream, "]", !IO)
|
|
;
|
|
FieldId = ml_field_named(QualFieldVarName, CtorType),
|
|
QualFieldVarName = qual_field_var_name(_, _, FieldVarName),
|
|
FieldVarNameStr =
|
|
field_var_name_to_ll_string_for_csharp(FieldVarName),
|
|
( if FieldVarName = fvn_data_tag then
|
|
% If the field we are trying to access is just a `data_tag'
|
|
% then it is a member of the base class.
|
|
output_bracketed_rval_for_csharp(Info, PtrRval, Stream, !IO),
|
|
io.format(Stream, ".%s", [s(FieldVarNameStr)], !IO)
|
|
else if PtrRval = ml_self(_) then
|
|
% Suppress type cast on `this' keyword. This makes a difference
|
|
% when assigning to `final' member variables in constructor
|
|
% functions.
|
|
output_rval_for_csharp(Info, PtrRval, Stream, !IO),
|
|
io.format(Stream, ".%s", [s(FieldVarNameStr)], !IO)
|
|
else
|
|
% Otherwise the field we are trying to access may be
|
|
% in a derived class. Objects are manipulated as instances
|
|
% of their base class, so we need to downcast to the derived
|
|
% class to access some fields.
|
|
io.format(Stream, "((%s) ",
|
|
[s(type_to_string_for_csharp(Info, CtorType))], !IO),
|
|
output_bracketed_rval_for_csharp(Info, PtrRval, Stream, !IO),
|
|
io.format(Stream, ").%s", [s(FieldVarNameStr)], !IO)
|
|
)
|
|
)
|
|
;
|
|
Lval = ml_mem_ref(Rval, _Type),
|
|
output_bracketed_rval_for_csharp(Info, Rval, Stream, !IO)
|
|
;
|
|
Lval = ml_target_global_var_ref(GlobalVarRef),
|
|
GlobalVarRef = env_var_ref(EnvVarName),
|
|
io.format(Stream, "mercury_envvar_%s", [s(EnvVarName)], !IO)
|
|
;
|
|
Lval = ml_local_var(LocalVarName, _),
|
|
LocalVarNameStr = local_var_name_to_ll_string_for_csharp(LocalVarName),
|
|
io.write_string(Stream, LocalVarNameStr, !IO)
|
|
;
|
|
Lval = ml_global_var(GlobalVarName, _),
|
|
GlobalVarNameStr =
|
|
maybe_qualified_global_var_name_to_string_for_csharp(Info,
|
|
GlobalVarName),
|
|
io.write_string(Stream, GlobalVarNameStr, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_call_rval_for_csharp(Info, Rval, Stream, !IO) :-
|
|
( if
|
|
Rval = ml_const(Const),
|
|
Const = mlconst_code_addr(CodeAddr)
|
|
then
|
|
output_code_addr_for_csharp(Info, Stream, CodeAddr, is_for_call, !IO)
|
|
else
|
|
output_bracketed_rval_for_csharp(Info, Rval, Stream, !IO)
|
|
).
|
|
|
|
:- pred output_bracketed_rval_for_csharp(csharp_out_info::in, mlds_rval::in,
|
|
io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
output_bracketed_rval_for_csharp(Info, Rval, Stream, !IO) :-
|
|
( if
|
|
% If it is just a variable name, then we don't need parentheses.
|
|
( Rval = ml_lval(ml_local_var(_,_))
|
|
; Rval = ml_lval(ml_global_var(_,_))
|
|
; Rval = ml_const(mlconst_code_addr(_))
|
|
)
|
|
then
|
|
output_rval_for_csharp(Info, Rval, Stream, !IO)
|
|
else
|
|
io.write_char(Stream, '(', !IO),
|
|
output_rval_for_csharp(Info, Rval, Stream, !IO),
|
|
io.write_char(Stream, ')', !IO)
|
|
).
|
|
|
|
output_rval_for_csharp(Info, Rval, Stream, !IO) :-
|
|
(
|
|
Rval = ml_lval(Lval),
|
|
output_lval_for_csharp(Info, Lval, Stream, !IO)
|
|
;
|
|
Rval = ml_mkword(_, _),
|
|
unexpected($pred, "tags not supported in C#")
|
|
;
|
|
Rval = ml_const(Const),
|
|
output_rval_const_for_csharp(Info, Stream, Const, !IO)
|
|
;
|
|
Rval = ml_cast(Type, SubRval),
|
|
output_cast_rval_for_csharp(Info, Type, SubRval, Stream, !IO)
|
|
;
|
|
Rval = ml_box(Type, SubRval),
|
|
( if Type = mercury_nb_type(comparison_result_type, _) then
|
|
io.write_string(Stream,
|
|
"builtin.comparison_result_object[(int) ", !IO),
|
|
output_rval_for_csharp(Info, SubRval, Stream, !IO),
|
|
io.write_string(Stream, "]", !IO)
|
|
else
|
|
output_boxed_rval_for_csharp(Info, Type, SubRval, Stream, !IO)
|
|
)
|
|
;
|
|
Rval = ml_unbox(Type, SubRval),
|
|
output_unboxed_rval_for_csharp(Info, Type, SubRval, Stream, !IO)
|
|
;
|
|
Rval = ml_unop(Unop, SubRval),
|
|
output_unop_for_csharp(Info, Stream, Unop, SubRval, !IO)
|
|
;
|
|
Rval = ml_binop(Op, SubRvalA, SubRvalB),
|
|
output_binop_for_csharp(Info, Stream, Op, SubRvalA, SubRvalB, !IO)
|
|
;
|
|
Rval = ml_mem_addr(Lval),
|
|
io.write_string(Stream, "out ", !IO),
|
|
output_lval_for_csharp(Info, Lval, Stream, !IO)
|
|
;
|
|
Rval = ml_scalar_common(_),
|
|
unexpected($pred, "ml_scalar_common")
|
|
;
|
|
Rval = ml_scalar_common_addr(ScalarCommon),
|
|
ScalarCommon = mlds_scalar_common(ModuleName, _Type,
|
|
ml_scalar_common_type_num(TypeNum), RowNum),
|
|
ModuleSymName = mlds_module_name_to_sym_name(ModuleName),
|
|
MangledModuleName =
|
|
strip_mercury_and_mangle_sym_name_for_csharp(ModuleSymName),
|
|
io.format(Stream, "%s.MR_scalar_common_%d[%d]",
|
|
[s(MangledModuleName), i(TypeNum), i(RowNum)], !IO)
|
|
;
|
|
Rval = ml_vector_common_row_addr(VectorCommon, RowRval),
|
|
VectorCommon = mlds_vector_common(_ModuleName, _Type,
|
|
ml_vector_common_type_num(TypeNum), StartRowNum, _NumRows),
|
|
% XXX Why do we print a "MangledModuleName." prefix for scalar common
|
|
% addresses but not for vector common addresses?
|
|
io.format(Stream, "MR_vector_common_%d[%d + ",
|
|
[i(TypeNum), i(StartRowNum)], !IO),
|
|
output_rval_for_csharp(Info, RowRval, Stream, !IO),
|
|
io.write_string(Stream, "]", !IO)
|
|
;
|
|
Rval = ml_self(_),
|
|
io.write_string(Stream, "this", !IO)
|
|
).
|
|
|
|
:- pred output_cast_rval_for_csharp(csharp_out_info::in, mlds_type::in,
|
|
mlds_rval::in, io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
output_cast_rval_for_csharp(Info, Type, Expr, Stream, !IO) :-
|
|
% rtti_to_mlds.m generates casts from int to runtime.PseudoTypeInfo, but
|
|
% for C# we need to treat these as constructions, not casts.
|
|
% Similarly for conversions from TypeCtorInfo to TypeInfo.
|
|
( if
|
|
Type = mlds_pseudo_type_info_type,
|
|
Expr = ml_const(mlconst_int(N))
|
|
then
|
|
maybe_output_inline_comment_for_csharp(Info, Stream, "cast", !IO),
|
|
( if have_preallocated_pseudo_type_var_for_csharp(N) then
|
|
io.write_string(Stream, "runtime.PseudoTypeInfo.K", !IO),
|
|
io.write_int(Stream, N, !IO)
|
|
else
|
|
io.write_string(Stream, "new runtime.PseudoTypeInfo(", !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
)
|
|
else if
|
|
( Type = mercury_nb_type(_, ctor_cat_system(cat_system_type_info))
|
|
; Type = mlds_type_info_type
|
|
)
|
|
then
|
|
% XXX We really should be able to tell if we are casting a
|
|
% TypeCtorInfo or a TypeInfo. Julien says that is probably going to
|
|
% be rather difficult as the compiler doesn't keep track of where
|
|
% type_ctor_infos are acting as type_infos properly. (zs agrees.)
|
|
maybe_output_inline_comment_for_csharp(Info, Stream, "cast", !IO),
|
|
io.write_string(Stream, "runtime.TypeInfo_Struct.maybe_new(", !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
else
|
|
% While the Java backend represents Mercury enums as Java classes
|
|
% with a value field, the C# backend represents them as C# enums.
|
|
% We therefore have no need to get a value field.
|
|
io.format(Stream, "(%s) ",
|
|
[s(type_to_string_for_csharp(Info, Type))], !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO)
|
|
).
|
|
|
|
:- pred have_preallocated_pseudo_type_var_for_csharp(int::in) is semidet.
|
|
|
|
have_preallocated_pseudo_type_var_for_csharp(N) :-
|
|
% Corresponds to static members in class PseudoTypeInfo.
|
|
N >= 1,
|
|
N =< 5.
|
|
|
|
:- pred output_boxed_rval_for_csharp(csharp_out_info::in, mlds_type::in,
|
|
mlds_rval::in, io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
output_boxed_rval_for_csharp(Info, _Type, Expr, Stream, !IO) :-
|
|
% C# does implicit boxing.
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO).
|
|
% ( if csharp_builtin_type(Type, _JavaName, JavaBoxedName, _) then
|
|
% % valueOf may return cached instances instead of creating new objects.
|
|
% io.write_string(Stream, JavaBoxedName, !IO),
|
|
% io.write_string(Stream, ".valueOf(", !IO),
|
|
% output_rval(Info, Expr, !IO),
|
|
% io.write_string(Stream, ")", !IO)
|
|
% else
|
|
% io.write_string(Stream, "((object) (", !IO),
|
|
% output_rval(Info, Expr, !IO),
|
|
% io.write_string(Stream, "))", !IO)
|
|
% ).
|
|
|
|
:- pred output_unboxed_rval_for_csharp(csharp_out_info::in, mlds_type::in,
|
|
mlds_rval::in, io.text_output_stream::in, io::di, io::uo) is det.
|
|
|
|
output_unboxed_rval_for_csharp(Info, Type, Expr, Stream, !IO) :-
|
|
io.format(Stream, "((%s) ",
|
|
[s(type_to_string_for_csharp(Info, Type))], !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred output_unop_for_csharp(csharp_out_info::in, io.text_output_stream::in,
|
|
unary_op::in, mlds_rval::in, io::di, io::uo) is det.
|
|
|
|
output_unop_for_csharp(Info, Stream, UnaryOp, Expr, !IO) :-
|
|
% For the C# backend, there are no tags, so all the tagging operators
|
|
% are no-ops, except for `tag', which always returns zero (a tag of zero
|
|
% means there is no tag).
|
|
(
|
|
UnaryOp = tag ,
|
|
io.write_string(Stream, "/* tag */ 0", !IO)
|
|
;
|
|
( UnaryOp = strip_tag, UnaryOpStr = "/* strip_tag */ "
|
|
; UnaryOp = mkbody, UnaryOpStr = "/* mkbody */ "
|
|
; UnaryOp = unmkbody, UnaryOpStr = "/* unmkbody */ "
|
|
; UnaryOp = logical_not, UnaryOpStr = "!"
|
|
; UnaryOp = hash_string, UnaryOpStr = "mercury.String.hash_1_f_0"
|
|
; UnaryOp = hash_string2, UnaryOpStr = "mercury.String.hash2_1_f_0"
|
|
; UnaryOp = hash_string3, UnaryOpStr = "mercury.String.hash3_1_f_0"
|
|
; UnaryOp = hash_string4, UnaryOpStr = "mercury.String.hash4_1_f_0"
|
|
; UnaryOp = hash_string5, UnaryOpStr = "mercury.String.hash5_1_f_0"
|
|
; UnaryOp = hash_string6, UnaryOpStr = "mercury.String.hash6_1_f_0"
|
|
),
|
|
io.write_string(Stream, UnaryOpStr, !IO),
|
|
io.write_string(Stream, "(", !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
UnaryOp = bitwise_complement(IntType),
|
|
(
|
|
( IntType = int_type_int
|
|
; IntType = int_type_int32
|
|
; IntType = int_type_int64
|
|
; IntType = int_type_uint
|
|
; IntType = int_type_uint32
|
|
; IntType = int_type_uint64
|
|
),
|
|
io.write_string(Stream, "~(", !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
( IntType = int_type_int8, CastStr = "(sbyte)"
|
|
; IntType = int_type_int16, CastStr = "(short)"
|
|
),
|
|
io.write_string(Stream, CastStr, !IO),
|
|
io.write_string(Stream, " ~(", !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
% The result of the bitwise complement of byte or ushort in C#
|
|
% will be promoted to an int. Casting this back to the original
|
|
% type may result in a CS0221 error from the C# compiler
|
|
% due to the possible information loss involved in such a cast.
|
|
% We need to wrap the whole expression in an unchecked context
|
|
% in order to prevent the C# compiler from treating it as an error.
|
|
( IntType = int_type_uint8, CastStr = "(byte)"
|
|
; IntType = int_type_uint16, CastStr = "(ushort)"
|
|
),
|
|
io.write_string(Stream, "unchecked (", !IO),
|
|
io.write_string(Stream, CastStr, !IO),
|
|
io.write_string(Stream, " ~(", !IO),
|
|
output_rval_for_csharp(Info, Expr, Stream, !IO),
|
|
io.write_string(Stream, "))", !IO)
|
|
)
|
|
;
|
|
( UnaryOp = dword_float_get_word0
|
|
; UnaryOp = dword_float_get_word1
|
|
; UnaryOp = dword_int64_get_word0
|
|
; UnaryOp = dword_int64_get_word1
|
|
; UnaryOp = dword_uint64_get_word0
|
|
; UnaryOp = dword_uint64_get_word1
|
|
),
|
|
unexpected($pred, "invalid unary operator")
|
|
).
|
|
|
|
:- pred output_binop_for_csharp(csharp_out_info::in, io.text_output_stream::in,
|
|
binary_op::in, mlds_rval::in, mlds_rval::in, io::di, io::uo) is det.
|
|
|
|
output_binop_for_csharp(Info, Stream, Op, X, Y, !IO) :-
|
|
(
|
|
Op = array_index(_Type),
|
|
output_bracketed_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, "[", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, "]", !IO)
|
|
;
|
|
Op = str_eq,
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, ".Equals(", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
( Op = str_ne, OpStr = "!="
|
|
; Op = str_lt, OpStr = "<"
|
|
; Op = str_gt, OpStr = ">"
|
|
; Op = str_le, OpStr = "<="
|
|
; Op = str_ge, OpStr = ">="
|
|
),
|
|
io.write_string(Stream, "(", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, ".CompareOrdinal(", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ") ", !IO),
|
|
io.write_string(Stream, OpStr, !IO),
|
|
io.write_string(Stream, " 0)", !IO)
|
|
;
|
|
Op = str_cmp,
|
|
io.write_string(Stream, "(", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, ".CompareOrdinal(", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, "))", !IO)
|
|
;
|
|
Op = pointer_equal_conservative,
|
|
io.write_string(Stream, "System.Object.ReferenceEquals(", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, ", ", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
( Op = int_add(_)
|
|
; Op = int_sub(_)
|
|
; Op = int_mul(_)
|
|
; Op = int_div(_)
|
|
; Op = int_mod(_)
|
|
; Op = unchecked_left_shift(_, _)
|
|
; Op = unchecked_right_shift(_, _)
|
|
; Op = bitwise_and(_)
|
|
; Op = bitwise_or(_)
|
|
; Op = bitwise_xor(_)
|
|
; Op = int_lt(_)
|
|
; Op = int_gt(_)
|
|
; Op = int_le(_)
|
|
; Op = int_ge(_)
|
|
),
|
|
output_int_binop_for_csharp(Info, Stream, Op, X, Y, !IO)
|
|
;
|
|
( Op = unsigned_lt, OpStr = "<"
|
|
; Op = unsigned_le, OpStr = "<="
|
|
),
|
|
io.write_string(Stream, "((uint) ", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.format(Stream, " %s (uint) ", [s(OpStr)], !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
( Op = logical_and, OpStr = "&&"
|
|
; Op = logical_or, OpStr = "||"
|
|
; Op = eq(_), OpStr = "=="
|
|
; Op = ne(_), OpStr = "!="
|
|
; Op = float_add, OpStr = "+"
|
|
; Op = float_sub, OpStr = "-"
|
|
; Op = float_mul, OpStr = "*"
|
|
; Op = float_div, OpStr = "/"
|
|
; Op = float_eq, OpStr = "=="
|
|
; Op = float_ne, OpStr = "!="
|
|
; Op = float_lt, OpStr = "<"
|
|
; Op = float_gt, OpStr = ">"
|
|
; Op = float_le, OpStr = "<="
|
|
; Op = float_ge, OpStr = ">="
|
|
),
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO)
|
|
;
|
|
( Op = body
|
|
; Op = string_unsafe_index_code_unit
|
|
; Op = offset_str_eq(_)
|
|
; Op = float_from_dword
|
|
; Op = int64_from_dword
|
|
; Op = uint64_from_dword
|
|
; Op = compound_eq
|
|
; Op = compound_lt
|
|
),
|
|
unexpected($pred, "invalid binary operator")
|
|
).
|
|
|
|
:- pred output_int_binop_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, binary_op::in(int_binary_op),
|
|
mlds_rval::in, mlds_rval::in, io::di, io::uo) is det.
|
|
:- pragma no_inline(pred(output_int_binop_for_csharp/7)).
|
|
|
|
output_int_binop_for_csharp(Info, Stream, Op, X, Y, !IO) :-
|
|
(
|
|
( Op = int_add(Type), OpStr = "+"
|
|
; Op = int_sub(Type), OpStr = "-"
|
|
; Op = int_mul(Type), OpStr = "*"
|
|
; Op = int_div(Type), OpStr = "/"
|
|
; Op = int_mod(Type), OpStr = "%"
|
|
; Op = bitwise_and(Type), OpStr = "&"
|
|
; Op = bitwise_xor(Type), OpStr = "^"
|
|
),
|
|
( Type = int_type_int, Cast = ""
|
|
; Type = int_type_int8, Cast = "(sbyte) "
|
|
; Type = int_type_int16, Cast = "(short) "
|
|
; Type = int_type_int32, Cast = ""
|
|
; Type = int_type_int64, Cast = ""
|
|
; Type = int_type_uint, Cast = ""
|
|
; Type = int_type_uint8, Cast = "(byte) "
|
|
; Type = int_type_uint16, Cast = "(ushort) "
|
|
; Type = int_type_uint32, Cast = ""
|
|
; Type = int_type_uint64, Cast = ""
|
|
),
|
|
io.write_string(Stream, Cast, !IO),
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO)
|
|
;
|
|
Op = bitwise_or(Type),
|
|
OpStr = "|",
|
|
(
|
|
( Type = int_type_int, Cast = ""
|
|
; Type = int_type_int16, Cast = "(short) "
|
|
; Type = int_type_int32, Cast = ""
|
|
; Type = int_type_int64, Cast = ""
|
|
; Type = int_type_uint, Cast = ""
|
|
; Type = int_type_uint8, Cast = "(byte) "
|
|
; Type = int_type_uint16, Cast = "(ushort) "
|
|
; Type = int_type_uint32, Cast = ""
|
|
; Type = int_type_uint64, Cast = ""
|
|
),
|
|
io.write_string(Stream, Cast, !IO),
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO)
|
|
;
|
|
Type = int_type_int8,
|
|
% The special treatment of bitwise-or for int8 is necessary
|
|
% to avoid warning CS0675 from the C# compiler.
|
|
% XXX The Microsoft C# reference manual' section on compiler
|
|
% messages says that this warning is for a "bitwise OR operator
|
|
% used on a sign extended operand". I (zs) understand why this
|
|
% deserves a warning, but do not understand why the same warning
|
|
% does not apply to bitwise AND and bitwise XOR.
|
|
% Unfortunately, the chance that a maintainer of the C# compiler
|
|
% will read this comment is zero :-(
|
|
io.write_string(Stream, "(sbyte) ((byte) ", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, " ", !IO),
|
|
io.write_string(Stream, OpStr, !IO),
|
|
io.write_string(Stream, " (byte) ", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
)
|
|
;
|
|
( Op = int_lt(_Type), OpStr = "<"
|
|
; Op = int_gt(_Type), OpStr = ">"
|
|
; Op = int_le(_Type), OpStr = "<="
|
|
; Op = int_ge(_Type), OpStr = ">="
|
|
),
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO)
|
|
;
|
|
( Op = unchecked_left_shift(Type, ShiftType), OpStr = "<<"
|
|
; Op = unchecked_right_shift(Type, ShiftType), OpStr = ">>"
|
|
),
|
|
% C# does not automatically promote uints to ints, since
|
|
% half of all uints are too big to be represented as ints.
|
|
% However, the only valid shift amounts are very small,
|
|
% so for valid shift amounts, the cast cannot lose information.
|
|
(
|
|
ShiftType = shift_by_int,
|
|
CastY = ""
|
|
;
|
|
ShiftType = shift_by_uint,
|
|
CastY = "(int) "
|
|
),
|
|
( Type = int_type_int, Cast = ""
|
|
; Type = int_type_int8, Cast = "(sbyte) "
|
|
; Type = int_type_int16, Cast = "(short) "
|
|
; Type = int_type_int32, Cast = ""
|
|
; Type = int_type_int64, Cast = ""
|
|
; Type = int_type_uint, Cast = ""
|
|
; Type = int_type_uint8, Cast = "(byte) "
|
|
; Type = int_type_uint16, Cast = "(ushort) "
|
|
; Type = int_type_uint32, Cast = ""
|
|
; Type = int_type_uint64, Cast = ""
|
|
),
|
|
io.write_string(Stream, Cast, !IO),
|
|
io.write_string(Stream, "(", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, " ", !IO),
|
|
io.write_string(Stream, OpStr, !IO),
|
|
io.write_string(Stream, " ", !IO),
|
|
io.write_string(Stream, CastY, !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
).
|
|
|
|
:- pred output_basic_binop_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, string::in, mlds_rval::in, mlds_rval::in,
|
|
io::di, io::uo) is det.
|
|
:- pragma no_inline(pred(output_basic_binop_for_csharp/7)).
|
|
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO) :-
|
|
io.write_string(Stream, "(", !IO),
|
|
output_rval_for_csharp(Info, X, Stream, !IO),
|
|
io.write_string(Stream, " ", !IO),
|
|
io.write_string(Stream, OpStr, !IO),
|
|
io.write_string(Stream, " ", !IO),
|
|
output_rval_for_csharp(Info, Y, Stream, !IO),
|
|
io.write_string(Stream, ")", !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- pred output_rval_const_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, mlds_rval_const::in, io::di, io::uo) is det.
|
|
|
|
output_rval_const_for_csharp(Info, Stream, Const, !IO) :-
|
|
(
|
|
Const = mlconst_true,
|
|
io.write_string(Stream, "true", !IO)
|
|
;
|
|
Const = mlconst_false,
|
|
io.write_string(Stream, "false", !IO)
|
|
;
|
|
Const = mlconst_int(N),
|
|
output_int_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_uint(N),
|
|
output_uint_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_int8(N),
|
|
output_int8_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_uint8(N),
|
|
output_uint8_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_int16(N),
|
|
output_int16_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_uint16(N),
|
|
output_uint16_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_int32(N),
|
|
output_int32_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_uint32(N),
|
|
output_uint32_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_int64(N),
|
|
output_int64_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_uint64(N),
|
|
output_uint64_const_for_csharp(Stream, N, !IO)
|
|
;
|
|
Const = mlconst_char(C),
|
|
io.write_string(Stream, "( ", !IO),
|
|
output_int_const_for_csharp(Stream, C, !IO),
|
|
io.write_string(Stream, ")", !IO)
|
|
;
|
|
Const = mlconst_enum(N, EnumType),
|
|
% Explicit cast required.
|
|
output_cast_rval_for_csharp(Info, EnumType,
|
|
ml_const(mlconst_int(N)), Stream, !IO)
|
|
;
|
|
Const = mlconst_foreign(Lang, Value, Type),
|
|
expect(unify(Lang, lang_csharp), $pred, "language other than C#."),
|
|
% XXX Should we parenthesize this?
|
|
io.format(Stream, "(%s) ",
|
|
[s(type_to_string_for_csharp(Info, Type))], !IO),
|
|
io.write_string(Stream, Value, !IO)
|
|
;
|
|
Const = mlconst_float(FloatVal),
|
|
c_util.output_float_literal(Stream, FloatVal, !IO)
|
|
;
|
|
Const = mlconst_string(String),
|
|
output_quoted_string_csharp(Stream, String, !IO)
|
|
;
|
|
Const = mlconst_multi_string(String),
|
|
output_quoted_multi_string_csharp(Stream, String, !IO)
|
|
;
|
|
Const = mlconst_named_const(TargetPrefixes, NamedConst),
|
|
io.write_string(Stream, TargetPrefixes ^ csharp_prefix, !IO),
|
|
io.write_string(Stream, NamedConst, !IO)
|
|
;
|
|
Const = mlconst_code_addr(CodeAddr),
|
|
map.lookup(Info ^ csoi_code_addrs, CodeAddr, Name),
|
|
io.write_string(Stream, Name, !IO)
|
|
;
|
|
Const = mlconst_data_addr_local_var(VarName),
|
|
VarNameStr = local_var_name_to_ll_string_for_csharp(VarName),
|
|
io.write_string(Stream, VarNameStr, !IO)
|
|
;
|
|
Const = mlconst_data_addr_global_var(ModuleName, VarName),
|
|
MangledModuleName = strip_mercury_and_mangle_sym_name_for_csharp(
|
|
mlds_module_name_to_sym_name(ModuleName)),
|
|
VarNameStr = global_var_name_to_ll_string_for_csharp(VarName),
|
|
io.format(Stream, "%s.%s", [s(MangledModuleName), s(VarNameStr)], !IO)
|
|
;
|
|
Const = mlconst_data_addr_rtti(ModuleName, RttiId),
|
|
MangledModuleName = strip_mercury_and_mangle_sym_name_for_csharp(
|
|
mlds_module_name_to_sym_name(ModuleName)),
|
|
rtti.id_to_c_identifier(RttiId, RttiAddrName0),
|
|
RttiAddrName = limit_identifier_length(RttiAddrName0),
|
|
io.format(Stream, "%s.%s",
|
|
[s(MangledModuleName), s(RttiAddrName)], !IO)
|
|
;
|
|
Const = mlconst_data_addr_tabling(_QualProcLabel, _TablingId),
|
|
unexpected($pred, "NYI: mlconst_data_addr_tabling")
|
|
;
|
|
Const = mlconst_null(Type),
|
|
Initializer = get_default_initializer_for_csharp(Info, Type),
|
|
io.write_string(Stream, Initializer, !IO)
|
|
).
|
|
|
|
:- pred output_int_const_for_csharp(io.text_output_stream::in, int::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_int_const_for_csharp(Stream, N, !IO) :-
|
|
% You may wish to see the comment on output_int_const_for_java
|
|
% in mlds_to_java_data.m.
|
|
( if
|
|
N > 0,
|
|
not int32.from_int(N, _I32),
|
|
uint32.from_int(N, U32)
|
|
then
|
|
% The bit pattern fits in 32 bits, but is too big for a positive
|
|
% integer. The C# compiler will report an error about this unless we
|
|
% tell it otherwise.
|
|
N32 = uint32.cast_to_int(U32),
|
|
io.format(Stream, "unchecked((int) 0x%x)", [i(N32)], !IO)
|
|
else
|
|
io.write_int(Stream, N, !IO)
|
|
).
|
|
|
|
:- pred output_uint_const_for_csharp(io.text_output_stream::in, uint::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_uint_const_for_csharp(Stream, U, !IO) :-
|
|
io.write_uint(Stream, U, !IO),
|
|
io.write_string(Stream, "U", !IO).
|
|
|
|
:- pred output_int8_const_for_csharp(io.text_output_stream::in, int8::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_int8_const_for_csharp(Stream, I8, !IO) :-
|
|
io.write_string(Stream, "(sbyte) ", !IO),
|
|
io.write_int8(Stream, I8, !IO).
|
|
|
|
:- pred output_uint8_const_for_csharp(io.text_output_stream::in, uint8::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_uint8_const_for_csharp(Stream, U8, !IO) :-
|
|
io.write_string(Stream, "(byte) ", !IO),
|
|
io.write_uint8(Stream, U8, !IO).
|
|
|
|
:- pred output_int16_const_for_csharp(io.text_output_stream::in, int16::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_int16_const_for_csharp(Stream, I16, !IO) :-
|
|
io.write_string(Stream, "(short) ", !IO),
|
|
io.write_int16(Stream, I16, !IO).
|
|
|
|
:- pred output_uint16_const_for_csharp(io.text_output_stream::in, uint16::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_uint16_const_for_csharp(Stream, U16, !IO) :-
|
|
io.write_string(Stream, "(ushort) ", !IO),
|
|
io.write_uint16(Stream, U16, !IO).
|
|
|
|
:- pred output_int32_const_for_csharp(io.text_output_stream::in, int32::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_int32_const_for_csharp(Stream, I32, !IO) :-
|
|
io.write_int32(Stream, I32, !IO).
|
|
|
|
:- pred output_uint32_const_for_csharp(io.text_output_stream::in, uint32::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_uint32_const_for_csharp(Stream, U32, !IO) :-
|
|
io.write_uint32(Stream, U32, !IO),
|
|
io.write_string(Stream, "U", !IO).
|
|
|
|
:- pred output_int64_const_for_csharp(io.text_output_stream::in, int64::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_int64_const_for_csharp(Stream, I64, !IO) :-
|
|
io.write_int64(Stream, I64, !IO),
|
|
io.write_string(Stream, "L", !IO).
|
|
|
|
:- pred output_uint64_const_for_csharp(io.text_output_stream::in, uint64::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_uint64_const_for_csharp(Stream, U64, !IO) :-
|
|
io.write_uint64(Stream, U64, !IO),
|
|
io.write_string(Stream, "UL", !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_code_addr_for_csharp(Info, Stream, CodeAddr, IsCall, !IO) :-
|
|
CodeAddr = mlds_code_addr(QualFuncLabel, Signature),
|
|
Signature = mlds_func_signature(ArgTypes, RetTypes),
|
|
(
|
|
IsCall = is_not_for_call,
|
|
% Not a function call, so we are taking the address of the
|
|
% wrapper for that function (method).
|
|
PtrTypeStr = method_ptr_type_to_string(Info, ArgTypes, RetTypes),
|
|
io.format(Stream, "(%s) ", [s(PtrTypeStr)], !IO)
|
|
;
|
|
IsCall = is_for_call
|
|
),
|
|
QualFuncLabel = qual_func_label(ModuleName, FuncLabel),
|
|
FuncLabel = mlds_func_label(ProcLabel, MaybeAux),
|
|
MaybeAuxSuffix = mlds_maybe_aux_func_id_to_suffix(MaybeAux),
|
|
Qualifier = qualifier_to_nll_string_for_csharp(ModuleName, module_qual),
|
|
ProcLabelStr =
|
|
proc_label_to_ll_string_for_csharp(MaybeAuxSuffix, ProcLabel),
|
|
io.format(Stream, "%s.%s", [s(Qualifier), s(ProcLabelStr)], !IO).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
output_initializer_for_csharp(Info, Stream, OutputAux, Indent, Type,
|
|
Initializer, Suffix, !IO) :-
|
|
(
|
|
( Initializer = init_obj(_)
|
|
; Initializer = init_struct(_, _)
|
|
; Initializer = init_array(_)
|
|
),
|
|
io.write_string(Stream, " = ", !IO),
|
|
% Due to cyclic references, we need to separate the allocation and
|
|
% initialisation steps of RTTI structures. If InitStyle is alloc_only,
|
|
% then we output an initializer to allocate a structure without filling
|
|
% in the fields.
|
|
(
|
|
( OutputAux = oa_none
|
|
; OutputAux = oa_cname(_, _)
|
|
; OutputAux = oa_force_init
|
|
),
|
|
output_initializer_body_for_csharp(Info, Stream,
|
|
not_at_start_of_line, Indent + 1, Initializer, yes(Type),
|
|
Suffix, !IO)
|
|
;
|
|
OutputAux = oa_alloc_only,
|
|
output_initializer_alloc_only_for_csharp(Info, Stream,
|
|
Initializer, yes(Type), Suffix, !IO)
|
|
)
|
|
;
|
|
Initializer = no_initializer,
|
|
(
|
|
OutputAux = oa_force_init,
|
|
% Local variables need to be initialised to avoid warnings.
|
|
io.write_string(Stream, " = ", !IO),
|
|
io.write_string(Stream,
|
|
get_default_initializer_for_csharp(Info, Type), !IO)
|
|
;
|
|
( OutputAux = oa_none
|
|
; OutputAux = oa_cname(_, _)
|
|
; OutputAux = oa_alloc_only
|
|
)
|
|
),
|
|
io.format(Stream, "%s\n", [s(Suffix)], !IO)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
output_initializer_alloc_only_for_csharp(Info, Stream, Initializer,
|
|
MaybeType, Suffix, !IO) :-
|
|
(
|
|
Initializer = no_initializer,
|
|
unexpected($pred, "no_initializer")
|
|
;
|
|
Initializer = init_obj(_),
|
|
unexpected($pred, "init_obj")
|
|
;
|
|
Initializer = init_struct(StructType, FieldInits),
|
|
io.write_string(Stream, "new ", !IO),
|
|
( if
|
|
StructType = mercury_nb_type(_, CtorCat),
|
|
type_category_is_array(coerce(CtorCat)) = is_array
|
|
then
|
|
Size = list.length(FieldInits),
|
|
io.format(Stream, "object[%d]%s\n", [i(Size), s(Suffix)], !IO)
|
|
else
|
|
io.format(Stream, "%s()%s\n",
|
|
[s(type_to_string_for_csharp(Info, StructType)), s(Suffix)],
|
|
!IO)
|
|
)
|
|
;
|
|
Initializer = init_array(ElementInits),
|
|
Size = list.length(ElementInits),
|
|
io.write_string(Stream, "new ", !IO),
|
|
(
|
|
MaybeType = yes(Type),
|
|
type_to_string_and_dims_for_csharp(Info, Type,
|
|
BaseTypeName, ArrayDims0),
|
|
make_last_dimension_known_size(ArrayDims0, Size, ArrayDims),
|
|
DimsStr = array_dimensions_to_string(ArrayDims),
|
|
io.format(Stream, "%s%s%s\n",
|
|
[s(BaseTypeName), s(DimsStr), s(Suffix)], !IO)
|
|
;
|
|
MaybeType = no,
|
|
% XXX we need to know the type here
|
|
io.format(Stream, "/* XXX init_array */ object[%d]%s\n",
|
|
[i(Size), s(Suffix)], !IO)
|
|
)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
output_initializer_body_for_csharp(Info, Stream, InitStart, Indent,
|
|
Initializer, MaybeType, Suffix, !IO) :-
|
|
(
|
|
Initializer = no_initializer,
|
|
unexpected($pred, "no_initializer")
|
|
;
|
|
Initializer = init_obj(Rval),
|
|
(
|
|
InitStart = not_at_start_of_line
|
|
;
|
|
InitStart = at_start_of_line,
|
|
write_indent2(Stream, Indent, !IO)
|
|
),
|
|
output_rval_for_csharp(Info, Rval, Stream, !IO),
|
|
io.format(Stream, "%s\n", [s(Suffix)], !IO)
|
|
;
|
|
Initializer = init_struct(StructType, FieldInits),
|
|
(
|
|
InitStart = not_at_start_of_line,
|
|
io.nl(Stream, !IO)
|
|
;
|
|
InitStart = at_start_of_line
|
|
),
|
|
IndentStr = indent2_string(Indent),
|
|
type_to_string_and_dims_for_csharp(Info, StructType,
|
|
TypeStr0, ArrayDims),
|
|
TypeStr = add_array_dimensions(TypeStr0, ArrayDims),
|
|
init_arg_wrappers_cs_java(ArrayDims, LParen, RParen),
|
|
(
|
|
FieldInits = [],
|
|
io.format(Stream, "%snew %s%s%s%s",
|
|
[s(IndentStr), s(TypeStr), s(LParen), s(RParen), s(Suffix)],
|
|
!IO)
|
|
;
|
|
FieldInits = [HeadFieldInit | TailFieldInits],
|
|
io.format(Stream, "%snew %s%s\n",
|
|
[s(IndentStr), s(TypeStr), s(LParen)], !IO),
|
|
output_initializer_body_list_for_csharp(Info, Stream, Indent + 1,
|
|
HeadFieldInit, TailFieldInits, "", !IO),
|
|
io.format(Stream, "%s%s%s\n",
|
|
[s(IndentStr), s(RParen), s(Suffix)], !IO)
|
|
)
|
|
;
|
|
Initializer = init_array(ElementInits),
|
|
(
|
|
InitStart = not_at_start_of_line,
|
|
io.nl(Stream, !IO)
|
|
;
|
|
InitStart = at_start_of_line
|
|
),
|
|
IndentStr = indent2_string(Indent),
|
|
(
|
|
MaybeType = yes(Type),
|
|
TypeStr = type_to_string_for_csharp(Info, Type)
|
|
;
|
|
MaybeType = no,
|
|
% XXX We need to know the type here.
|
|
TypeStr = "/* XXX init_array */ object[]"
|
|
),
|
|
(
|
|
ElementInits = [],
|
|
io.format(Stream, "%snew %s {}%s\n",
|
|
[s(IndentStr), s(TypeStr), s(Suffix)], !IO)
|
|
;
|
|
ElementInits = [HeadElementInit | TailElementInits],
|
|
io.format(Stream, "%snew %s {\n", [s(IndentStr), s(TypeStr)], !IO),
|
|
output_initializer_body_list_for_csharp(Info, Stream, Indent + 1,
|
|
HeadElementInit, TailElementInits, "", !IO),
|
|
io.format(Stream, "%s}%s\n", [s(IndentStr), s(Suffix)], !IO)
|
|
)
|
|
).
|
|
|
|
%---------------------%
|
|
|
|
output_nonempty_initializer_body_list_for_csharp(Info, Stream, Indent, Inits,
|
|
Suffix, !IO) :-
|
|
list.det_head_tail(Inits, HeadInit, TailInits),
|
|
output_initializer_body_list_for_csharp(Info, Stream, Indent,
|
|
HeadInit, TailInits, Suffix, !IO).
|
|
|
|
:- pred output_initializer_body_list_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, indent::in, mlds_initializer::in,
|
|
list(mlds_initializer)::in, string::in, io::di, io::uo) is det.
|
|
|
|
output_initializer_body_list_for_csharp(Info, Stream, Indent,
|
|
HeadInit, TailInits, Suffix, !IO) :-
|
|
(
|
|
TailInits = [],
|
|
output_initializer_body_for_csharp(Info, Stream, at_start_of_line,
|
|
Indent, HeadInit, no, Suffix, !IO)
|
|
;
|
|
TailInits = [HeadTailInit | TailTailInits],
|
|
output_initializer_body_for_csharp(Info, Stream, at_start_of_line,
|
|
Indent, HeadInit, no, ",", !IO),
|
|
output_initializer_body_list_for_csharp(Info, Stream,
|
|
Indent, HeadTailInit, TailTailInits, Suffix, !IO)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% We need to provide initializers for local variables to avoid problems
|
|
% with undefined variables.
|
|
%
|
|
:- func get_default_initializer_for_csharp(csharp_out_info, mlds_type)
|
|
= string.
|
|
|
|
get_default_initializer_for_csharp(Info, Type) = Initializer :-
|
|
(
|
|
Type = mercury_nb_type(_, CtorCat),
|
|
(
|
|
( CtorCat = ctor_cat_system(_)
|
|
; CtorCat = ctor_cat_higher_order
|
|
; CtorCat = ctor_cat_tuple
|
|
; CtorCat = ctor_cat_variable
|
|
; CtorCat = ctor_cat_void
|
|
),
|
|
Initializer = "null"
|
|
;
|
|
( CtorCat = ctor_cat_enum(_)
|
|
; CtorCat = ctor_cat_user(_)
|
|
; CtorCat = ctor_cat_builtin_dummy
|
|
),
|
|
TypeName = type_to_string_for_csharp(Info, Type),
|
|
Initializer = "default(" ++ TypeName ++ ")"
|
|
)
|
|
;
|
|
Type = mlds_builtin_type_int(IntType),
|
|
(
|
|
( IntType = int_type_int
|
|
; IntType = int_type_int8
|
|
; IntType = int_type_int16
|
|
; IntType = int_type_int32
|
|
% C# byte and ushort literals don't have a suffix.
|
|
; IntType = int_type_uint8
|
|
; IntType = int_type_uint16
|
|
),
|
|
Initializer = "0"
|
|
;
|
|
( IntType = int_type_uint
|
|
; IntType = int_type_uint32
|
|
),
|
|
Initializer = "0U"
|
|
;
|
|
IntType = int_type_int64,
|
|
Initializer = "0L"
|
|
;
|
|
IntType = int_type_uint64,
|
|
Initializer = "0UL"
|
|
)
|
|
;
|
|
Type = mlds_builtin_type_float,
|
|
Initializer = "0"
|
|
;
|
|
Type = mlds_builtin_type_char,
|
|
Initializer = "'\\u0000'"
|
|
;
|
|
Type = mlds_builtin_type_string,
|
|
Initializer = "null"
|
|
;
|
|
Type = mlds_native_bool_type,
|
|
Initializer = "false"
|
|
;
|
|
( Type = mlds_mercury_array_type(_)
|
|
; Type = mlds_cont_type(_)
|
|
; Type = mlds_commit_type
|
|
; Type = mlds_class_type(_)
|
|
; Type = mlds_enum_class_type(_)
|
|
; Type = mlds_env_type(_)
|
|
; Type = mlds_struct_type(_)
|
|
; Type = mlds_array_type(_)
|
|
; Type = mlds_mostly_generic_array_type(_)
|
|
; Type = mlds_ptr_type(_)
|
|
; Type = mlds_func_type(_)
|
|
; Type = mlds_generic_type
|
|
; Type = mlds_generic_env_ptr_type
|
|
; Type = mlds_type_info_type
|
|
; Type = mlds_pseudo_type_info_type
|
|
; Type = mlds_rtti_type(_)
|
|
; Type = mlds_tabling_type(_)
|
|
),
|
|
Initializer = "null"
|
|
;
|
|
Type = mlds_foreign_type(ForeignType),
|
|
(
|
|
ForeignType = csharp(csharp_type(CsharpType)),
|
|
Initializer = "default(" ++ CsharpType ++ ")"
|
|
;
|
|
( ForeignType = c(_)
|
|
; ForeignType = java(_)
|
|
),
|
|
unexpected($pred, "wrong foreign language type")
|
|
)
|
|
;
|
|
Type = mlds_unknown_type,
|
|
unexpected($pred, "variable has unknown_type")
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module ml_backend.mlds_to_cs_data.
|
|
%---------------------------------------------------------------------------%
|