[m-rev.] diff: C# interface for .NET backend.

Fergus Henderson fjh at cs.mu.OZ.AU
Thu May 3 02:12:05 AEST 2001


On 01-May-2001, Tyson Dowd <trd at cs.mu.OZ.AU> wrote:
mlds.m:
> +	;	outline_target_code(
> +				foreign_language,
> +					% the foreign language of this code
> +				list(mlds__lval),
> +					% where to store return value(s)
> +				string
> +					% the user's foreign language code
> +		)
> +			% Do whatever is specified by the string, which
> +			% can be any piece of code in the specified
> +			% foreign language (C#, managed C++, or
> +			% whatever).
> +			% This is implemented by calling an externally
> +			% defined function, which the backend must
> +			% generate the definition for (in some other
> +			% file perhaps) and calling it.

Why does this have a list of where to store the return values?
And why doesn't it have a list of the input argument rvals (or their names)?

> Index: compiler/mlds_to_csharp.m
...
> +	%
> +	% Generate the `__csharp_code.cs' file which contains the c sharp
> +	% code.
> +	%
> +output_csharp_code(MLDS) -->
> +	{ MLDS = mlds(ModuleName, _ForeignCode, _Imports, _Defns) },
> +	output_src_start(ModuleName), 
> +	io__nl,
> +
> +	generate_c_code(MLDS),
...
> +:- pred generate_c_code(mlds, io__state, io__state).
> +:- mode generate_c_code(in, di, uo) is det.
> +generate_c_code(MLDS) -->

s/generate_c_code/generate_csharp_code/g ?

> +	generate_foreign_header_code(mercury_module_name_to_mlds(ModuleName),
> +		ForeignCode),
> +
> +	{ Namespace0 = get_class_namespace(ClassName) },
> +	{ list__reverse(Namespace0) = [Head | Tail] ->
> +		Namespace = list__reverse([Head ++ "__csharp_code" | Tail])
> +	;
> +		Namespace = Namespace0
> +	},
> +
> +	io__write_list(Namespace, "\n", 
> +		(pred(N::in, di, uo) is det -->
> +			io__format("namespace %s {", [s(N)])
> +	)),

The namespace name here should be (1) escaped (by prefixing it with "@") and/or
(2) mangled, in case it (1) is a C# keyword or (2) contains special characters
((2) is not very important, but (1) is not unlikely and should be handled
correctly).

> +:- pred generate_method_c_code(mlds_module_name, mlds__defn,
> +		io__state, io__state).
> +:- mode generate_method_c_code(in, in, di, uo) is det.
> +
> +	% XXX we don't handle export
> +generate_method_c_code(_, defn(export(_), _, _, _)) --> [].
> +generate_method_c_code(_, defn(data(_), _, _, _)) --> [].
> +generate_method_c_code(_, defn(type(_, _), _, _, _)) --> [].
> +generate_method_c_code(_ModuleName, 

s/c_code/csharp_code/g ?

...
> +		;
> +			% IL doesn't support multiple return values
> +			sorry(this_file, "multiple return values")

s/IL/C#/ ?

> +:- pred write_csharp_statement(mlds__statement, io__state, io__state).
> +:- mode write_csharp_statement(in, di, uo) is det.
> +write_csharp_statement(statement(Statement, _Context)) -->
> +	( 
> +		{ Statement = atomic(outline_target_code(csharp,
> +			_Lvals, Code)) } 
> +	->
> +		io__write_string(Code),
> +		io__nl
> +	;
> +		{ Statement = block(Defns, Statements) }
> +	->
> +		io__write_list(Defns, "", write_csharp_defn_decl),
> +		io__write_string("{\n"),
> +		io__write_list(Statements, "", write_csharp_statement),
> +		io__write_string("\n}\n")
> +	;
> +		{ Statement = return(Rvals) }
> +	->
> +		( { Rvals = [Rval] } ->
> +			io__write_string("return "),
> +			write_csharp_rval(Rval),
> +			io__write_string(";\n")
> +		;
> +			{ sorry(this_file, "multiple return values") }
> +		)
> +	;
> +		{ functor(Statement, SFunctor, Arity) },
> +		io__write_string("// unimplemented: "), 
> +		io__write_string(SFunctor), 
> +		io__write_string("/"), 
> +		io__write(Arity),
> +		io__nl
> +	).

You should at least output something which will cause the C Sharp compiler to
report an error, rather than silently ignoring it.  Or just call error/1.

> +%-------------------------------------------------------------------
> +% code below here is not used.
> +%-------------------------------------------------------------------

That comment is not true.
For example, there's a call to write_csharp_rval immediately above,
and write_csharp_rval is defined below that comment:

> +:- pred write_csharp_rval(mlds__rval, io__state, io__state).
> +:- mode write_csharp_rval(in, di, uo) is det.
> +write_csharp_rval(lval(Lval)) -->
> +	write_csharp_lval(Lval).
> +write_csharp_rval(mkword(_Tag, _Rval)) -->
> +	io__write_string(" /* mkword rval -- unimplemented */ ").
> +write_csharp_rval(const(RvalConst)) -->
> +	write_csharp_rval_const(RvalConst).
> +write_csharp_rval(unop(Unop, Rval)) -->
> +	( 
> +		{ Unop = std_unop(StdUnop) },
> +		{ c_util__unary_prefix_op(StdUnop, UnopStr) }
> +	->
> +		io__write_string(UnopStr),
> +		io__write_string("("),
> +		write_csharp_rval(Rval),
> +		io__write_string(")")
> +	;
> +		{ Unop = cast(Type) }
> +	->
> +		io__write_string("("),
> +		write_csharp_parameter_type(Type),
> +		io__write_string(") "),
> +		write_csharp_rval(Rval)
> +	;
> +		io__write_string(" /* XXX box or unbox unop -- unimplemented */ "),
> +		write_csharp_rval(Rval)
> +	).

That XXX is another place where something which is unimplemented
will get silently ignored and may result in wrong code being generated.
Better to call error/1.

> +write_csharp_rval(binop(Binop, Rval1, Rval2)) -->
> +	( 
> +		{ c_util__binary_infix_op(Binop, BinopStr) }
> +	->
> +		io__write_string("("),
> +		write_csharp_rval(Rval1),
> +		io__write_string(") "),
> +		io__write_string(BinopStr),
> +		io__write_string(" ("),
> +		write_csharp_rval(Rval2),
> +		io__write_string(")")
> +	;
> +		io__write_string(" /* binop rval -- unimplemented */ ")
> +	).

Likewise here.

> +write_csharp_rval(mem_addr(_)) -->
> +	io__write_string(" /* mem_addr rval -- unimplemented */ ").

And here.

> +:- pred write_csharp_rval_const(mlds__rval_const, io__state, io__state).
> +:- mode write_csharp_rval_const(in, di, uo) is det.
> +write_csharp_rval_const(true) --> io__write_string("1").
> +write_csharp_rval_const(false) --> io__write_string("0").
> +write_csharp_rval_const(int_const(I)) --> io__write_int(I).
> +write_csharp_rval_const(float_const(F)) --> io__write_float(F).
> +	% XXX We don't quote this correctly.
> +write_csharp_rval_const(string_const(S)) --> 
> +	io__write_string(""""),
> +	io__write_string(S),
> +	io__write_string("""").

That XXX should be fixed.
You can use c_util__output_quoted_string.

> +write_csharp_rval_const(multi_string_const(_L, _S)) --> 
> +	io__write_string(" /* multi_string_const rval -- unimplemented */ ").

Likewise here, you can use c_util__output_multi_quoted_string.

> +write_csharp_rval_const(data_addr_const(_)) --> 
> +	io__write_string(" /* data_addr_const rval -- unimplemented */ ").

That XXX is another place where something which is unimplemented
will get silently ignored and may result in wrong code being generated.
Better to call error/1.

> +write_csharp_rval_const(null(_)) --> 
> +	io__write_string("0").

C# has a "null" keyword; you should use it.

> +:- pred write_csharp_defn_decl(mlds__defn, io__state, io__state).
> +:- mode write_csharp_defn_decl(in, di, uo) is det.
> +write_csharp_defn_decl(Defn) -->
> +	{ Defn = mlds__defn(Name, _Context, _Flags, DefnBody) },
> +	( { DefnBody = data(Type, _Initializer) },
> +  	  { Name = data(var(VarName)) }
> +	->

Fix the non-standard indentation.

> +		write_csharp_parameter_type(Type),
> +		io__write_string(" "),
> +		write_mlds_var_name_for_parameter(VarName),
> +		io__write_string(";\n")
> +	;
> +		io__write_string("// unimplemented defn decl\n")
> +	).

That is another place where something which is unimplemented
will get silently ignored and may result in wrong code being generated.
Better to call error/1.  Also it should have an XXX.

> +	% XXX need to revisit this and choose types appropriately
> +:- pred write_il_simple_type_as_csharp_type(simple_type::in,
> +	io__state::di, io__state::uo) is det.
> +write_il_simple_type_as_csharp_type(int8) --> 
> +	io__write_string("int").
> +write_il_simple_type_as_csharp_type(int16) --> 
> +	io__write_string("int").
> +write_il_simple_type_as_csharp_type(int32) --> 
> +	io__write_string("int").
> +write_il_simple_type_as_csharp_type(int64) --> 
> +	io__write_string("int").

That code looks pretty wrong to me; wouldn't it be better to just call error/1
here?

The types you want here are sbyte, short, int, and long repectively.

> +write_il_simple_type_as_csharp_type(uint8) --> 
> +	io__write_string("unsigned int").
> +write_il_simple_type_as_csharp_type(uint16) --> 
> +	io__write_string("unsigned int").
> +write_il_simple_type_as_csharp_type(uint32) --> 
> +	io__write_string("unsigned int").
> +write_il_simple_type_as_csharp_type(uint64) --> 
> +	io__write_string("unsigned int").

Here it should be byte, ushort, uint, ulong.

> +write_il_simple_type_as_csharp_type(native_int) --> 
> +	io__write_string("int").
> +write_il_simple_type_as_csharp_type(native_uint) --> 
> +	io__write_string("unsigned int").

That's a bug: s/unsigned int/uint/

> +write_il_simple_type_as_csharp_type(float32) --> 
> +	io__write_string("float").
> +write_il_simple_type_as_csharp_type(float64) --> 
> +	io__write_string("float").

float64 is "double", not "float".

> +write_il_simple_type_as_csharp_type(bool) --> 
> +	io__write_string("int").

s/int/bool/

> +		% XXX this is not the right syntax
> +write_il_simple_type_as_csharp_type(value_class(ClassName)) --> 
> +	write_csharp_class_name(ClassName).

Better to call error/1, I think.

> +		% XXX this is not the right syntax
> +write_il_simple_type_as_csharp_type(interface(ClassName)) --> 
> +	write_csharp_class_name(ClassName).

Better to call error/1, I think.

> +		% XXX this needs more work
> +write_il_simple_type_as_csharp_type('[]'(_Type, _Bounds)) --> 
> +	io__write_string("object[]").

Better to call error/1, I think.

(Or at very very least s/object/System.Object/,
but I think it's really quite wrong to ignore the _Type,
so error/1 is probably better.)

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list