mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 01:13:30 +00:00
It is almost the same as the unsigned_lt builtin op, but it is
implemented as "0 =< Index, Index < Range" just for Java.
This is the first step of the bootstrapping process; the second step
will add a declaration for private_builtin.in_range.
compiler/builtin_ops.m:
As above.
compiler/llds_out_data.m:
compiler/mlds_to_c_data.m:
compiler/mlds_to_cs_data.m:
compiler/mlds_to_java_data.m:
Implement the new operation.
compiler/code_util.m:
compiler/llds.m:
compiler/ml_global_data.m:
compiler/mlds_dump.m:
compiler/opt_debug.m:
Conform to the change above.
compiler/options.m:
Add a way to test whether the installed compiler supports this new op.
tests/warnings/help_text.err_exp:
Expect the new option name.
1167 lines
45 KiB
Mathematica
1167 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, 2024-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.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% 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 uint.
|
|
:- 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_cmp(CmpOp),
|
|
(
|
|
CmpOp = 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)
|
|
;
|
|
( CmpOp = ne, OpStr = "!="
|
|
; CmpOp = lt, OpStr = "<"
|
|
; CmpOp = gt, OpStr = ">"
|
|
; CmpOp = le, OpStr = "<="
|
|
; CmpOp = 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.format(Stream, ") %s 0)", [s(OpStr)], !IO)
|
|
)
|
|
;
|
|
Op = str_nzp,
|
|
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_arith(IntType, ArithOp),
|
|
output_int_arith_binop_for_csharp(Info, Stream, IntType, ArithOp,
|
|
X, Y, !IO)
|
|
;
|
|
Op = int_cmp(_IntType, CmpOp),
|
|
OpStr = cmp_op_c_operator(CmpOp),
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO)
|
|
;
|
|
( Op = unchecked_left_shift(_, _)
|
|
; Op = unchecked_right_shift(_, _)
|
|
; Op = bitwise_and(_)
|
|
; Op = bitwise_or(_)
|
|
; Op = bitwise_xor(_)
|
|
),
|
|
output_int_misc_binop_for_csharp(Info, Stream, Op, X, Y, !IO)
|
|
;
|
|
(
|
|
Op = int_as_uint_cmp(CmpOp),
|
|
( CmpOp = lt, OpStr = "<"
|
|
; CmpOp = le, OpStr = "<="
|
|
)
|
|
;
|
|
Op = in_range,
|
|
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 = float_arith(ArithOp), OpStr =
|
|
arith_op_c_operator(coerce(ArithOp))
|
|
; Op = float_cmp(CmpOp), OpStr = cmp_op_c_operator(CmpOp)
|
|
),
|
|
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
|
|
),
|
|
unexpected($pred, "invalid binary operator")
|
|
).
|
|
|
|
:- pred output_int_arith_binop_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, int_type::in, arith_op::in,
|
|
mlds_rval::in, mlds_rval::in, io::di, io::uo) is det.
|
|
:- pragma no_inline(pred(output_int_arith_binop_for_csharp/8)).
|
|
|
|
output_int_arith_binop_for_csharp(Info, Stream, Type, Op, X, Y, !IO) :-
|
|
( 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 = ""
|
|
),
|
|
OpStr = arith_op_c_operator(Op),
|
|
io.write_string(Stream, Cast, !IO),
|
|
output_basic_binop_for_csharp(Info, Stream, OpStr, X, Y, !IO).
|
|
|
|
:- pred output_int_misc_binop_for_csharp(csharp_out_info::in,
|
|
io.text_output_stream::in, binary_op::in(int_misc_binary_op),
|
|
mlds_rval::in, mlds_rval::in, io::di, io::uo) is det.
|
|
:- pragma no_inline(pred(output_int_misc_binop_for_csharp/7)).
|
|
|
|
output_int_misc_binop_for_csharp(Info, Stream, Op, X, Y, !IO) :-
|
|
(
|
|
( 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 = 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 + 1u, 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\n",
|
|
[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 + 1u,
|
|
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 + 1u,
|
|
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.
|
|
%---------------------------------------------------------------------------%
|