mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 23:05:21 +00:00
Estimated hours taken: 4 Branches: main compiler/*.m: Use expect/3 in place of require/2 throughout most of the compiler. Use unexpected/2 (or sorry/2) in place of error/1 in more places. Fix more dodgy assertion error messages. s/map(prog_var, mer_type)/vartypes/ where the latter is meant.
1910 lines
57 KiB
Mathematica
1910 lines
57 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2005 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% File: ilasm.m.
|
|
% Main author: trd.
|
|
|
|
% Generate IL for the ilasm assembler.
|
|
%
|
|
% IL assembler syntax is documented in the Microsoft .NET Framework SDK.
|
|
% See ilds.m for links to the documentation.
|
|
%
|
|
% This code is a little messy. Some of the code here is a hangover from
|
|
% earlier versions of the assembler grammar.
|
|
%
|
|
% To do:
|
|
% [ ] Implement missing instructions.
|
|
% [ ] Add any missing functionality from the assembler grammar
|
|
% (events, properties, etc).
|
|
% [ ] Fix up all the XXXs.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module ml_backend__ilasm.
|
|
|
|
:- interface.
|
|
|
|
:- import_module ml_backend.ilds.
|
|
|
|
:- import_module bool.
|
|
:- import_module integer.
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module std_util.
|
|
:- import_module term.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred ilasm__output(list(decl)::in, io::di, io::uo) is det.
|
|
|
|
:- type int64 ---> int64(integer).
|
|
:- type int32 ---> int32(int).
|
|
:- type int16 ---> int16(int).
|
|
:- type int8 ---> int8(int).
|
|
:- type byte == int8.
|
|
:- type float64 ---> float64(float).
|
|
:- type float32 ---> float32(float).
|
|
|
|
% A top level declaration in IL assembler.
|
|
:- type decl
|
|
% .class declaration
|
|
---> class(
|
|
list(classattr), % attributes for the class
|
|
ilds__id, % name of the class
|
|
extends, % what is the parent class
|
|
implements, % what interfaces are
|
|
% implemented
|
|
list(class_member) % methods and fields
|
|
)
|
|
% .namespace declaration
|
|
; namespace(
|
|
namespace_qual_name, % namespace name
|
|
list(decl) % contents
|
|
)
|
|
% .method (a global function)
|
|
% there are lots of restriction on global functions so
|
|
% don't get too excited about using them for anything.
|
|
% In particular, you can't reference a namespace
|
|
% qualified global function from outside the module.
|
|
; method(
|
|
methodhead,
|
|
method_defn
|
|
)
|
|
% .data (module local data)
|
|
; data(
|
|
bool, % is data in thread local storage?
|
|
maybe(ilds__id), % id to name this data
|
|
data_body % body of data
|
|
)
|
|
|
|
% .file
|
|
% Declares a file associated with the current assembly
|
|
; file(ilds__id)
|
|
|
|
% .module extern
|
|
% declares a module name.
|
|
; extern_module(ilds__id)
|
|
|
|
% .assembly extern
|
|
% declares an assembly name, and possibly its strong
|
|
% name/version number.
|
|
; extern_assembly(ilds__id, list(assembly_decl))
|
|
|
|
% .assembly
|
|
% defines an assembly
|
|
; assembly(ilds__id)
|
|
|
|
% .custom
|
|
% a custom attribute
|
|
; custom(custom_decl)
|
|
|
|
% comments
|
|
; comment_term(term)
|
|
% print almost anything using pprint__to_doc
|
|
% (see library/pprint.m for limitations).
|
|
; some [T] comment_thing(T)
|
|
; comment(string).
|
|
|
|
:- type assembly_decl
|
|
---> version(int, int, int, int) % version number
|
|
; hash(list(int8)) % hash
|
|
; public_key_token(list(int8)) % public key token
|
|
; custom(custom_decl). % a custom attribute
|
|
|
|
% a method definition is just a list of body decls.
|
|
:- type method_defn == list(method_body_decl).
|
|
|
|
:- type methodhead
|
|
---> methodhead(
|
|
list(methattr), % method attributes
|
|
member_name, % method name
|
|
signature, % method signature
|
|
list(implattr) % implementation attributes
|
|
).
|
|
|
|
:- type class_member
|
|
% .method (a class method)
|
|
---> method(
|
|
methodhead, % name, signature, attributes
|
|
method_defn % definition of method
|
|
)
|
|
% .field (a class field)
|
|
; field(
|
|
list(fieldattr), % attributes
|
|
ilds__type, % field type
|
|
ilds__id, % field name
|
|
maybe(int32), % offset for explicit layout
|
|
field_initializer % initializer
|
|
)
|
|
% .property (a class property)
|
|
; property(
|
|
ilds__type, % property type
|
|
ilds__id, % property name
|
|
maybe(methodhead), % get property
|
|
maybe(methodhead) % set property
|
|
)
|
|
% .class (a nested class)
|
|
; nested_class(
|
|
list(classattr), % attributes for the class
|
|
ilds__id, % name of the class
|
|
extends, % what is the parent class
|
|
implements, % what interfaces are
|
|
% implemented
|
|
list(class_member) % methods and fields
|
|
)
|
|
; custom(custom_decl) % custom attribute
|
|
% comments
|
|
; comment_term(term)
|
|
; comment(string)
|
|
% print almost anything using pprint__to_doc
|
|
% (see library/pprint.m for limitations).
|
|
; some [T] comment_thing(T).
|
|
|
|
:- type field_initializer
|
|
---> none % no initializer
|
|
; at(ilds__id) % initialize with .data at given location
|
|
; equals(field_init). % initialize with constant
|
|
|
|
% note that for some reason the syntax for field_init is almost,
|
|
% but not quite the same as data items.
|
|
:- type field_init
|
|
---> data_item(data_item) % most data_items are valid
|
|
% XXX unicode is not yet implemented, don't use
|
|
% wchar_ptr unless you intend to implement it
|
|
; wchar_ptr(string) % a string to convert to unicode
|
|
; binary_float32(int32) % binary rep. of float
|
|
; binary_float64(int64). % binary rep. of double
|
|
|
|
% a parent class to extend
|
|
:- type extends
|
|
---> extends(ilds__class_name)
|
|
; extends_nothing.
|
|
|
|
% a list of interfaces that we implement
|
|
:- type implements
|
|
---> implements(list(ilds__class_name)).
|
|
|
|
% declarations that can form the body of a method.
|
|
:- type method_body_decl
|
|
---> emitbyte(int32) % raw byte output (danger! danger!)
|
|
% "emits an int32 to the code section of the method"
|
|
% according to the IL Assembly Language
|
|
% Programmers' Reference.
|
|
% This probably means it can output IL
|
|
% bytecodes.
|
|
; maxstack(int32) % maximum stack size
|
|
% "Defines the maximum size of the stack,
|
|
% specified by the int32"
|
|
% But does it measure in bits, nibbles, bytes,
|
|
% words or something else?
|
|
; entrypoint % is this "main"?
|
|
; zeroinit % initialize locals to zero.
|
|
; custom(custom_decl) % custom attribute
|
|
; instrs(list(instr)) % instructions
|
|
; label(string). % a label
|
|
|
|
% attributes that a class can have.
|
|
% see SDK documentation for what they all mean.
|
|
:- type classattr
|
|
---> abstract ; ansi
|
|
; auto ; autochar
|
|
; beforefieldinit ; explicit
|
|
; interface ; nestedassembly
|
|
; nestedfamandassem ; nestedfamily
|
|
; nestedfamorassem ; nestedprivate
|
|
; nestedpublic ; private
|
|
; public ; rtspecialname
|
|
; sealed ; sequential
|
|
; serializable ; specialname
|
|
; unicode.
|
|
|
|
% attributes that a method can have.
|
|
% see SDK documentation for what they all mean.
|
|
:- type methattr
|
|
---> abstract ; assembly ; famandassem ; family
|
|
; famorassem ; final ; hidebysig ; newslot
|
|
; private ; privatescope ; public
|
|
; rtspecialname ; specialname ; static
|
|
; synchronized ; virtual ; pinvokeimpl.
|
|
|
|
% attributes that a field can have.
|
|
% see SDK documentation for what they all mean.
|
|
:- type fieldattr
|
|
---> assembly ; famandassem ; family ; famorassem
|
|
; initonly ; literal ; notserialized ; pinvokeimpl
|
|
; private ; privatescope ; public ; static
|
|
; volatile.
|
|
|
|
% attributes that a method implementation can have.
|
|
% see SDK documentation for what they all mean.
|
|
:- type implattr
|
|
---> il ; implemented ; internalcall ; managed
|
|
; native ; ole ; optil ; runtime
|
|
; unmanaged.
|
|
|
|
% the body of a .data declaration
|
|
:- type data_body
|
|
---> itemlist(list(data_item))
|
|
; item(data_item).
|
|
|
|
% various constants that can be used in .data declarations
|
|
:- type data_item
|
|
---> float32(float32)
|
|
; float64(float64)
|
|
; int64(int64)
|
|
; int32(int32)
|
|
; int16(int16)
|
|
; int8(int8)
|
|
; char_ptr(string)
|
|
; '&'(ilds__id)
|
|
; bytearray(list(byte)). % output as two digit hex, e.g.
|
|
% 01 F7 0A
|
|
|
|
:- type custom_decl --->
|
|
custom_decl(
|
|
custom_type,
|
|
maybe(custom_type),
|
|
qstring_or_bytes
|
|
).
|
|
|
|
:- type qstring_or_bytes
|
|
---> qstring(string)
|
|
; bytes(list(int8))
|
|
; no_initalizer.
|
|
|
|
:- type custom_type
|
|
---> type(ilds__type)
|
|
; methodref(ilds__methodref).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module backend_libs.c_util. % for output_float_literal
|
|
:- import_module libs.compiler_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.options.
|
|
|
|
:- import_module bool.
|
|
:- import_module char.
|
|
:- import_module getopt_io.
|
|
:- import_module int.
|
|
:- import_module pprint.
|
|
:- import_module string.
|
|
:- import_module term_io.
|
|
:- import_module varset.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Some versions of the IL assembler enforce a rule that if you output
|
|
% .assembly foo { }
|
|
% you are not allowed to use the assembly reference in the rest of
|
|
% the file, e.g.
|
|
% [foo]blah.bletch
|
|
% Instead you have to output just
|
|
% blah.bletch
|
|
%
|
|
% So we need to duplicate this checking in the output phase and
|
|
% make sure we don't output [foo].
|
|
%
|
|
% It's a good idea to do this anyway, as there is apparently a
|
|
% performance hit if you use assembly references to a symbol that is
|
|
% in the local assembly.
|
|
|
|
:- type ilasm_info --->
|
|
ilasm_info(
|
|
current_assembly :: ilds__id
|
|
).
|
|
|
|
:- pred ilasm__write_list(list(T)::in, string::in,
|
|
pred(T, ilasm_info, ilasm_info, io, io)
|
|
::in(pred(in, in, out, di, uo) is det),
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
ilasm__write_list([], _Separator, _OutputPred, !Info, !IO).
|
|
ilasm__write_list([E | Es], Separator, OutputPred, !Info, !IO) :-
|
|
call(OutputPred, E, !Info, !IO),
|
|
(
|
|
Es = []
|
|
;
|
|
Es = [_ | _],
|
|
io__write_string(Separator, !IO)
|
|
),
|
|
ilasm__write_list(Es, Separator, OutputPred, !Info, !IO).
|
|
|
|
ilasm__output(Blocks, !IO) :-
|
|
Info0 = ilasm_info(""),
|
|
ilasm__output(Blocks, Info0, _Info, !IO).
|
|
|
|
:- pred ilasm__output(list(decl)::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
ilasm__output(Blocks, !Info, !IO) :-
|
|
ilasm__write_list(Blocks, "\n\n", output_decl, !Info, !IO),
|
|
io__write_string("\n\n", !IO).
|
|
|
|
:- pred ilasm__output_decl(decl::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
ilasm__output_decl(custom(CustomDecl), !Info, !IO) :-
|
|
output_custom_decl(CustomDecl, !Info, !IO).
|
|
ilasm__output_decl(class(Attrs, Id, Extends, Implements, Contents), !Info,
|
|
!IO) :-
|
|
io__write_string(".class ", !IO),
|
|
io__write_list(Attrs, " ", output_classattr, !IO),
|
|
(
|
|
Attrs = [_ | _],
|
|
io__write_string(" ", !IO)
|
|
;
|
|
Attrs = []
|
|
),
|
|
output_id(Id, !IO),
|
|
(
|
|
Extends = extends(ExtendsModule),
|
|
io__write_string(" extends ", !IO),
|
|
output_class_name(ExtendsModule, !Info, !IO)
|
|
;
|
|
Extends = extends_nothing
|
|
),
|
|
Implements = implements(ImplementsList),
|
|
(
|
|
ImplementsList = [_ | _],
|
|
io__write_string(" implements ", !IO),
|
|
ilasm__write_list(ImplementsList, ", ", output_class_name,
|
|
!Info, !IO)
|
|
;
|
|
ImplementsList = []
|
|
),
|
|
io__write_string(" {\n", !IO),
|
|
ilasm__write_list(Contents, "\n", output_class_member, !Info, !IO),
|
|
io__write_string("\n}", !IO).
|
|
ilasm__output_decl(namespace(DottedName, Contents), !Info, !IO) :-
|
|
(
|
|
DottedName = [_ | _],
|
|
io__write_string(".namespace ", !IO),
|
|
output_dotted_name(DottedName, !IO),
|
|
io__write_string(" {\n", !IO),
|
|
output(Contents, !Info, !IO),
|
|
io__write_string("}\n", !IO)
|
|
;
|
|
DottedName = [],
|
|
output(Contents, !Info, !IO)
|
|
).
|
|
ilasm__output_decl(method(MethodHead, MethodDecls), !Info, !IO) :-
|
|
io__write_string(".method ", !IO),
|
|
output_methodhead(MethodHead, !Info, !IO),
|
|
io__write_string("\n{\n", !IO),
|
|
ilasm__write_list(MethodDecls, "\n", output_method_body_decl, !Info,
|
|
!IO),
|
|
io__write_string("}\n", !IO).
|
|
ilasm__output_decl(data(TLS, MaybeId, Body), !Info, !IO) :-
|
|
io__write_string(".data ", !IO),
|
|
( TLS = yes ->
|
|
io__write_string("tls ", !IO)
|
|
;
|
|
true
|
|
),
|
|
( MaybeId = yes(Id) ->
|
|
output_id(Id, !IO),
|
|
io__write_string(" = ", !IO)
|
|
;
|
|
true
|
|
),
|
|
output_data_body(Body, !IO).
|
|
ilasm__output_decl(comment_term(CommentTerm), !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
( PrintComments = yes ->
|
|
io__write_string("// ", !IO),
|
|
varset__init(VarSet),
|
|
term_io__write_term(VarSet, CommentTerm, !IO),
|
|
io__write_string("\n", !IO)
|
|
;
|
|
true
|
|
).
|
|
ilasm__output_decl(comment_thing(Thing), !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
( PrintComments = yes ->
|
|
Doc = label("// ", to_doc(Thing)),
|
|
write(70, Doc, !IO),
|
|
io__nl(!IO)
|
|
;
|
|
true
|
|
).
|
|
ilasm__output_decl(comment(CommentStr), !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
(
|
|
PrintComments = yes,
|
|
output_comment_string(CommentStr, !IO)
|
|
;
|
|
PrintComments = no
|
|
).
|
|
ilasm__output_decl(extern_assembly(AsmName, AssemblyDecls), !Info, !IO) :-
|
|
io__write_string(".assembly extern ", !IO),
|
|
output_id(AsmName, !IO),
|
|
io__write_string("{\n", !IO),
|
|
list__foldl2((pred(A::in, I0::in, I::out, IO0::di, IO::uo) is det :-
|
|
output_assembly_decl(A, I0, I, IO0, IO1),
|
|
io__write_string("\n\t", IO1, IO)
|
|
), AssemblyDecls, !Info, !IO),
|
|
io__write_string("\n}\n", !IO).
|
|
ilasm__output_decl(assembly(AsmName), !Info, !IO) :-
|
|
io__write_string(".assembly ", !IO),
|
|
output_id(AsmName, !IO),
|
|
!:Info = !.Info ^ current_assembly := AsmName,
|
|
io__write_string(" { }", !IO).
|
|
ilasm__output_decl(file(FileName), !Info, !IO) :-
|
|
io__write_string(".file ", !IO),
|
|
output_id(FileName, !IO).
|
|
ilasm__output_decl(extern_module(ModName), !Info, !IO) :-
|
|
io__write_string(".module extern ", !IO),
|
|
output_id(ModName, !IO).
|
|
|
|
:- pred ilasm__output_class_member(class_member::in, ilasm_info::in,
|
|
ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
ilasm__output_class_member(method(MethodHead, MethodDecls), !Info, !IO) :-
|
|
% Don't do debug output on class constructors, since
|
|
% they are automatically generated and take forever to
|
|
% run.
|
|
globals__io_lookup_option(debug_il_asm, DebugIlAsm, !IO),
|
|
( MethodHead = methodhead(_, cctor, _, _) ->
|
|
globals__io_set_option(debug_il_asm, bool(no), !IO),
|
|
ilasm__output_decl(method(MethodHead, MethodDecls), !Info, !IO),
|
|
globals__io_set_option(debug_il_asm, DebugIlAsm, !IO)
|
|
;
|
|
ilasm__output_decl(method(MethodHead, MethodDecls), !Info, !IO)
|
|
).
|
|
|
|
ilasm__output_class_member(custom(CustomDecl), !Info, !IO) :-
|
|
output_custom_decl(CustomDecl, !Info, !IO).
|
|
|
|
ilasm__output_class_member(
|
|
field(FieldAttrs, Type, IlId, MaybeOffset, Initializer),
|
|
!Info, !IO) :-
|
|
io__write_string(".field ", !IO),
|
|
(
|
|
MaybeOffset = yes(Offset),
|
|
output_int32(Offset, !IO),
|
|
io__write_string(" ", !IO)
|
|
;
|
|
MaybeOffset = no
|
|
),
|
|
io__write_list(FieldAttrs, " ", io__write, !IO),
|
|
io__write_string("\n\t", !IO),
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string("\n\t", !IO),
|
|
output_id(IlId, !IO),
|
|
output_field_initializer(Initializer, !IO).
|
|
ilasm__output_class_member(
|
|
property(Type, Name, MaybeGet, MaybeSet), !Info, !IO) :-
|
|
io__write_string(".property instance ", !IO),
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string(" ", !IO),
|
|
output_id(Name, !IO),
|
|
io__write_string("() {", !IO),
|
|
(
|
|
MaybeGet = yes(methodhead(_, GetMethodName, GetSignature, _)),
|
|
io__nl(!IO),
|
|
io__write_string("\t.get instance ", !IO),
|
|
output_name_signature_and_call_conv(GetSignature,
|
|
yes(GetMethodName), "\t\t", !Info, !IO)
|
|
;
|
|
MaybeGet = no
|
|
),
|
|
(
|
|
MaybeSet = yes(methodhead(_, SetMethodName, SetSignature, _)),
|
|
io__nl(!IO),
|
|
io__write_string("\t.set instance ", !IO),
|
|
output_name_signature_and_call_conv(SetSignature,
|
|
yes(SetMethodName), "\t\t", !Info, !IO)
|
|
;
|
|
MaybeSet = no
|
|
),
|
|
io__write_string("\n}\n", !IO).
|
|
ilasm__output_class_member(nested_class(Attrs, Id, Extends, Implements,
|
|
Contents), !Info, !IO) :-
|
|
ilasm__output_decl(class(Attrs, Id, Extends, Implements, Contents),
|
|
!Info, !IO).
|
|
ilasm__output_class_member(comment(CommentStr), !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
(
|
|
PrintComments = yes,
|
|
output_comment_string(CommentStr, !IO)
|
|
;
|
|
PrintComments = no
|
|
).
|
|
ilasm__output_class_member(comment_term(CommentTerm), !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
(
|
|
PrintComments = yes,
|
|
io__write_string("// ", !IO),
|
|
varset__init(VarSet),
|
|
term_io__write_term(VarSet, CommentTerm, !IO),
|
|
io__nl(!IO)
|
|
;
|
|
PrintComments = no
|
|
).
|
|
ilasm__output_class_member(comment_thing(Thing), !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
(
|
|
PrintComments = yes,
|
|
Doc = label("// ", to_doc(Thing)),
|
|
write(70, Doc, !IO),
|
|
io__nl(!IO)
|
|
;
|
|
PrintComments = no
|
|
).
|
|
|
|
:- pred ilasm__output_methodhead(methodhead::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
ilasm__output_methodhead(methodhead(Attrs, MethodName, Signature, ImplAttrs),
|
|
!Info, !IO) :-
|
|
io__write_list(Attrs, " ", io__write, !IO),
|
|
(
|
|
Attrs = [_ | _],
|
|
io__write_string(" ", !IO)
|
|
;
|
|
Attrs = []
|
|
),
|
|
output_name_signature_and_call_conv(Signature, yes(MethodName), "\t",
|
|
!Info, !IO),
|
|
io__write_list(ImplAttrs, " ", io__write, !IO).
|
|
|
|
:- pred ilasm__output_method_body_decl(method_body_decl::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
ilasm__output_method_body_decl(emitbyte(Int32), !Info, !IO) :-
|
|
io__write_string(".emitbyte ", !IO),
|
|
output_int32(Int32, !IO).
|
|
ilasm__output_method_body_decl(custom(CustomDecl), !Info, !IO) :-
|
|
output_custom_decl(CustomDecl, !Info, !IO).
|
|
ilasm__output_method_body_decl(maxstack(Int32), !Info, !IO) :-
|
|
io__write_string(".maxstack ", !IO),
|
|
output_int32(Int32, !IO).
|
|
ilasm__output_method_body_decl(entrypoint, !Info, !IO) :-
|
|
io__write_string(".entrypoint ", !IO).
|
|
ilasm__output_method_body_decl(zeroinit, !Info, !IO) :-
|
|
io__write_string(".zeroinit ", !IO).
|
|
ilasm__output_method_body_decl(instrs(Instrs), !Info, !IO) :-
|
|
output_instructions(Instrs, !Info, !IO).
|
|
ilasm__output_method_body_decl(label(Label), !Info, !IO) :-
|
|
output_label(Label, !IO),
|
|
io__write_string(":", !IO).
|
|
|
|
:- pred output_label(label::in, io::di, io::uo) is det.
|
|
|
|
output_label(Label, !IO) :-
|
|
io__write_string(Label, !IO).
|
|
|
|
:- pred output_class_name(ilds__class_name::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_class_name(ClassName, !Info, !IO) :-
|
|
output_structured_name(ClassName, !.Info, !IO).
|
|
|
|
:- pred output_call_conv(call_conv::in, io::di, io::uo) is det.
|
|
|
|
output_call_conv(call_conv(IsInstance, IlCallConv), !IO) :-
|
|
(
|
|
IsInstance = yes,
|
|
io__write_string("instance ", !IO)
|
|
;
|
|
IsInstance = no,
|
|
io__write(IlCallConv, !IO),
|
|
io__write_string(" ", !IO)
|
|
).
|
|
|
|
:- pred output_name_signature_and_call_conv(signature::in,
|
|
maybe(member_name)::in, string::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_name_signature_and_call_conv(signature(CallConv, ReturnType, ArgTypes),
|
|
MaybeMethodName, Indent, !Info, !IO) :-
|
|
output_call_conv(CallConv, !IO),
|
|
io__write_string("\n", !IO),
|
|
io__write_string(Indent, !IO),
|
|
output_ret_type(ReturnType, !Info, !IO),
|
|
(
|
|
MaybeMethodName = yes(MethodName),
|
|
io__write_string("\n", !IO),
|
|
io__write_string(Indent, !IO),
|
|
output_member_name(MethodName, !IO)
|
|
;
|
|
MaybeMethodName = no,
|
|
io__write_string(" ", !IO)
|
|
),
|
|
(
|
|
ArgTypes = [],
|
|
io__write_string("()", !IO)
|
|
;
|
|
ArgTypes = [_ | _],
|
|
io__write_string("(\n\t\t", !IO),
|
|
ilasm__write_list(ArgTypes, ",\n\t\t", output_param,
|
|
!Info, !IO),
|
|
io__write_string("\n\t)", !IO)
|
|
).
|
|
|
|
:- pred output_member_name(member_name::in, io::di, io::uo) is det.
|
|
|
|
output_member_name(MethodName, !IO) :-
|
|
(
|
|
MethodName = ctor,
|
|
io__write_string(".ctor", !IO)
|
|
;
|
|
MethodName = cctor,
|
|
io__write_string(".cctor", !IO)
|
|
;
|
|
MethodName = id(IlId),
|
|
output_id(IlId, !IO)
|
|
).
|
|
|
|
:- pred output_ret_type(ret_type::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_ret_type(void, !Info, !IO) :-
|
|
io__write_string("void", !IO).
|
|
output_ret_type(simple_type(Type), !Info, !IO) :-
|
|
output_simple_type(Type, !Info, !IO).
|
|
|
|
:- pred output_local(pair(ilds__id, ilds__type)::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_local(Id - Type, !Info, !IO) :-
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string(" ", !IO),
|
|
output_id(Id, !IO).
|
|
|
|
:- pred output_param(pair(ilds__type, maybe(ilds__id))::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_param(Type - no, !Info, !IO) :-
|
|
output_type(Type, !Info, !IO).
|
|
output_param(Type - yes(Id), !Info, !IO) :-
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string(" ", !IO),
|
|
output_id(Id, !IO).
|
|
|
|
:- pred output_type(ilds__type::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_type(ilds__type(Modifiers, SimpleType), !Info, !IO) :-
|
|
io__write_list(Modifiers, " ", output_modifier, !IO),
|
|
output_simple_type(SimpleType, !Info, !IO).
|
|
|
|
:- pred output_simple_type(simple_type::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_simple_type(int8, !Info, !IO) :-
|
|
io__write_string("int8", !IO).
|
|
output_simple_type(int16, !Info, !IO) :-
|
|
io__write_string("int16", !IO).
|
|
output_simple_type(int32, !Info, !IO) :-
|
|
io__write_string("int32", !IO).
|
|
output_simple_type(int64, !Info, !IO) :-
|
|
io__write_string("int64", !IO).
|
|
output_simple_type(uint8, !Info, !IO) :-
|
|
io__write_string("unsigned int8", !IO).
|
|
output_simple_type(uint16, !Info, !IO) :-
|
|
io__write_string("unsigned int16", !IO).
|
|
output_simple_type(uint32, !Info, !IO) :-
|
|
io__write_string("unsigned int32", !IO).
|
|
output_simple_type(uint64, !Info, !IO) :-
|
|
io__write_string("unsigned int64", !IO).
|
|
output_simple_type(native_int, !Info, !IO) :-
|
|
io__write_string("native int", !IO).
|
|
output_simple_type(native_uint, !Info, !IO) :-
|
|
io__write_string("native unsigned int", !IO).
|
|
output_simple_type(float32, !Info, !IO) :-
|
|
io__write_string("float32", !IO).
|
|
output_simple_type(float64, !Info, !IO) :-
|
|
io__write_string("float64", !IO).
|
|
output_simple_type(native_float, !Info, !IO) :-
|
|
io__write_string("native float", !IO).
|
|
output_simple_type(bool, !Info, !IO) :-
|
|
io__write_string("bool", !IO).
|
|
output_simple_type(char, !Info, !IO) :-
|
|
io__write_string("char", !IO).
|
|
output_simple_type(object, !Info, !IO) :-
|
|
io__write_string("object", !IO).
|
|
output_simple_type(string, !Info, !IO) :-
|
|
io__write_string("string", !IO).
|
|
output_simple_type(refany, !Info, !IO) :-
|
|
io__write_string("refany", !IO).
|
|
output_simple_type(class(Name), !Info, !IO) :-
|
|
( name_to_simple_type(Name, Type) ->
|
|
( Type = reference(SimpleType) ->
|
|
output_simple_type(SimpleType, !Info, !IO)
|
|
;
|
|
% If it is a value type then we are
|
|
% refering to the boxed version of the
|
|
% value type.
|
|
io__write_string("class ", !IO),
|
|
output_structured_name(Name, !.Info, !IO)
|
|
)
|
|
;
|
|
io__write_string("class ", !IO),
|
|
output_structured_name(Name, !.Info, !IO)
|
|
).
|
|
output_simple_type(valuetype(Name), !Info, !IO) :-
|
|
( name_to_simple_type(Name, Type) ->
|
|
( Type = value(SimpleType) ->
|
|
output_simple_type(SimpleType, !Info, !IO)
|
|
;
|
|
unexpected(this_file, "builtin reference type")
|
|
)
|
|
;
|
|
io__write_string("valuetype ", !IO),
|
|
output_structured_name(Name, !.Info, !IO)
|
|
).
|
|
output_simple_type(interface(Name), !Info, !IO) :-
|
|
io__write_string("interface ", !IO),
|
|
output_structured_name(Name, !.Info, !IO).
|
|
output_simple_type('[]'(Type, Bounds), !Info, !IO) :-
|
|
output_type(Type, !Info, !IO),
|
|
output_bounds(Bounds, !IO).
|
|
output_simple_type('*'(Type), !Info, !IO) :-
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string("*", !IO).
|
|
output_simple_type('&'(Type), !Info, !IO) :-
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string("&", !IO).
|
|
|
|
:- type ref_or_value
|
|
---> reference(simple_type)
|
|
; value(simple_type).
|
|
|
|
% If possible converts a class name to a simple type and an
|
|
% indicator of whether or not that simple type is a reference or
|
|
% value class.
|
|
:- pred name_to_simple_type(class_name::in, ref_or_value::out) is semidet.
|
|
|
|
name_to_simple_type(Name, Type) :-
|
|
% Parition II section 'Built-in Types' (Section 7.2) states
|
|
% that all builtin types *must* be referenced by their
|
|
% special encoding in signatures.
|
|
% See Parition I 'Built-In Types' % (Section 8.2.2) for the
|
|
% list of all builtin types.
|
|
Name = structured_name(AssemblyName, QualifiedName, _),
|
|
AssemblyName = assembly("mscorlib"),
|
|
QualifiedName = ["System", TypeName],
|
|
(
|
|
TypeName = "Boolean",
|
|
Type = value(bool)
|
|
;
|
|
TypeName = "Char",
|
|
Type = value(char)
|
|
;
|
|
TypeName = "Object",
|
|
Type = reference(object)
|
|
;
|
|
TypeName = "String",
|
|
Type = reference(string)
|
|
;
|
|
TypeName = "Single",
|
|
Type = value(float32)
|
|
;
|
|
TypeName = "Double",
|
|
Type = value(float64)
|
|
;
|
|
TypeName = "SByte",
|
|
Type = value(int8)
|
|
;
|
|
TypeName = "Int16",
|
|
Type = value(int16)
|
|
;
|
|
TypeName = "Int32",
|
|
Type = value(int32)
|
|
;
|
|
TypeName = "Int64",
|
|
Type = value(int64)
|
|
;
|
|
TypeName = "IntPtr",
|
|
Type = value(native_int)
|
|
;
|
|
TypeName = "UIntPtr",
|
|
Type = value(native_uint)
|
|
;
|
|
TypeName = "TypedReference",
|
|
Type = value(refany)
|
|
;
|
|
TypeName = "Byte",
|
|
Type = value(uint8)
|
|
;
|
|
TypeName = "UInt16",
|
|
Type = value(uint16)
|
|
;
|
|
TypeName = "UInt32",
|
|
Type = value(uint32)
|
|
;
|
|
TypeName = "UInt64",
|
|
Type = value(uint64)
|
|
).
|
|
|
|
% The names are all different if it is an opcode.
|
|
% There's probably a very implementation dependent reason for
|
|
% this.
|
|
:- pred output_simple_type_opcode(simple_type::in, io::di, io::uo) is det.
|
|
|
|
output_simple_type_opcode(int8) --> io__write_string("i1").
|
|
output_simple_type_opcode(int16) --> io__write_string("i2").
|
|
output_simple_type_opcode(int32) --> io__write_string("i4").
|
|
output_simple_type_opcode(int64) --> io__write_string("i8").
|
|
output_simple_type_opcode(uint8) --> io__write_string("u1").
|
|
output_simple_type_opcode(uint16) --> io__write_string("u2").
|
|
output_simple_type_opcode(uint32) --> io__write_string("u4").
|
|
output_simple_type_opcode(uint64) --> io__write_string("u8").
|
|
output_simple_type_opcode(native_int) --> io__write_string("i").
|
|
output_simple_type_opcode(native_uint) --> io__write_string("u").
|
|
output_simple_type_opcode(float32) --> io__write_string("r4").
|
|
output_simple_type_opcode(float64) --> io__write_string("r8").
|
|
output_simple_type_opcode(native_float) -->
|
|
{ unexpected(this_file, "unable to create opcode for native_float") }.
|
|
% XXX should i4 be used for bool?
|
|
output_simple_type_opcode(bool) --> io__write_string("i4").
|
|
output_simple_type_opcode(char) --> io__write_string("i2").
|
|
|
|
% all reference types use "ref" as their opcode.
|
|
% XXX is "ref" here correct for value classes?
|
|
output_simple_type_opcode(object) --> io__write_string("ref").
|
|
output_simple_type_opcode(string) --> io__write_string("ref").
|
|
output_simple_type_opcode(refany) --> io__write_string("ref").
|
|
output_simple_type_opcode(class(_Name)) --> io__write_string("ref").
|
|
output_simple_type_opcode(valuetype(_Name)) --> io__write_string("ref").
|
|
output_simple_type_opcode(interface(_Name)) --> io__write_string("ref").
|
|
output_simple_type_opcode('[]'(_Type, _Bounds)) --> io__write_string("ref").
|
|
output_simple_type_opcode('*'(_Type)) --> io__write_string("ref").
|
|
output_simple_type_opcode('&'(_Type)) --> io__write_string("ref").
|
|
|
|
:- pred output_bounds(bounds::in, io::di, io::uo) is det.
|
|
|
|
output_bounds(Bounds, !IO) :-
|
|
io__write_string("[", !IO),
|
|
io__write_list(Bounds, ", ", output_bound, !IO),
|
|
io__write_string("]", !IO).
|
|
|
|
:- pred output_bound(bound::in, io::di, io::uo) is det.
|
|
|
|
output_bound(upper(X), !IO) :-
|
|
io__write_int(X, !IO).
|
|
output_bound(lower(X), !IO) :-
|
|
io__write_int(X, !IO),
|
|
io__write_string("...", !IO).
|
|
output_bound(between(X, Y), !IO) :-
|
|
io__write_int(X, !IO),
|
|
io__write_string("...", !IO),
|
|
io__write_int(Y, !IO).
|
|
|
|
:- pred output_modifier(ilds__type_modifier::in, io::di, io::uo) is det.
|
|
|
|
output_modifier(const) --> io__write_string("const").
|
|
output_modifier(volatile) --> io__write_string("volatile").
|
|
output_modifier(readonly) --> io__write_string("readonly").
|
|
|
|
:- pred output_instructions(list(instr)::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_instructions(Instructions, !Info, !IO) :-
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments, !IO),
|
|
globals__io_lookup_bool_option(debug_il_asm, DebugIlAsm, !IO),
|
|
(
|
|
DebugIlAsm = yes,
|
|
list__foldl2(output_debug_instruction, Instructions,
|
|
!Info, !IO)
|
|
;
|
|
DebugIlAsm = no,
|
|
list__foldl2(output_instruction(PrintComments), Instructions,
|
|
!Info, !IO)
|
|
).
|
|
|
|
% We write each instruction before we execute it.
|
|
% This is a nice way of debugging IL as it executes, although as
|
|
% the IL debugger improves we might not need this any more.
|
|
:- pred output_debug_instruction(instr::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_debug_instruction(Instr, !Info, !IO) :-
|
|
|
|
% We can't handle tailcalls easily -- you need to put
|
|
% it out as
|
|
% trace the tail instruction
|
|
% trace the call instruction
|
|
% output the tail instruction
|
|
% output the call instruction
|
|
% For the moment we'll just ignore tailcalls.
|
|
( Instr = tailcall ->
|
|
true
|
|
; Instr = context(_, _) ->
|
|
% Contexts are messy, let's ignore them for now.
|
|
true
|
|
; Instr = start_block(catch(ClassName), Id) ->
|
|
output_instr(start_block(catch(ClassName), Id), !Info, !IO),
|
|
io__write_string("\n", !IO),
|
|
io__write_string("\t", !IO),
|
|
output_trace_instr(Instr, !Info, !IO),
|
|
io__write_string("\n", !IO)
|
|
; Instr = start_block(scope(Locals), Id) ->
|
|
string__format("{\t// #%d", [i(Id)], S),
|
|
io__write_string(S, !IO),
|
|
io__nl(!IO),
|
|
output_trace(S, !IO),
|
|
(
|
|
Locals = []
|
|
;
|
|
Locals = [_ | _],
|
|
% output the .locals decl
|
|
io__write_string("\t.locals (\n\t\t", !IO),
|
|
ilasm__write_list(Locals, ",\n\t\t", output_local,
|
|
!Info, !IO),
|
|
io__write_string("\n\t)", !IO),
|
|
io__write_string("\n", !IO),
|
|
|
|
% trace the .locals decl
|
|
io__write_string("\t\tldstr """, !IO),
|
|
io__write_string(".locals (\\n\\t\\t", !IO),
|
|
ilasm__write_list(Locals, ",\\n\\t\\t", output_local,
|
|
!Info, !IO),
|
|
io__write_string(")", !IO),
|
|
io__write_string("\\n""", !IO),
|
|
io__write_string("\n", !IO),
|
|
io__write_string("\t\tcall void " ++
|
|
"['mscorlib']System.Console::" ++
|
|
"Write(class ['mscorlib']System.String)\n",
|
|
!IO)
|
|
)
|
|
;
|
|
output_trace_instr(Instr, !Info, !IO),
|
|
io__write_string("\t", !IO),
|
|
output_instr(Instr, !Info, !IO),
|
|
io__write_string("\n", !IO)
|
|
).
|
|
|
|
:- pred output_trace_instr(instr::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_trace_instr(Instr, !Info, !IO) :-
|
|
io__write_string("\t\tldstr """, !IO),
|
|
% We have to quote loadstrings.
|
|
( Instr = ldstr(LoadString) ->
|
|
io__write_string("ldstr \\""", !IO),
|
|
output_escaped_string(LoadString, '\"', !IO),
|
|
io__write_string("\\""", !IO)
|
|
% XXX there could be issues with
|
|
% comments containing embedded newlines
|
|
; Instr = comment(Comment) ->
|
|
io__write_string("comment: ", !IO),
|
|
io__write_string(Comment, !IO)
|
|
;
|
|
output_instr(Instr, !Info, !IO)
|
|
),
|
|
io__write_string("\\n", !IO),
|
|
io__write_string("""\n", !IO),
|
|
io__write_string("\t\tcall void ['mscorlib']System.Console::" ++
|
|
"Write(class ['mscorlib']System.String)\n", !IO).
|
|
|
|
:- pred output_trace(string::in, io::di, io::uo) is det.
|
|
|
|
output_trace(S, !IO) :-
|
|
io__write_string("\t\tldstr """, !IO),
|
|
io__write_string(S, !IO),
|
|
io__write_string("\\n""\n", !IO),
|
|
io__write_string("\t\tcall void " ++
|
|
"['mscorlib']System.Console::Write(class System.String)\n",
|
|
!IO).
|
|
|
|
:- pred output_instruction(bool::in, instr::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_instruction(PrintComments, Instr, !Info, !IO) :-
|
|
(
|
|
Instr = comment(_),
|
|
PrintComments = no
|
|
->
|
|
true
|
|
;
|
|
io__write_string("\t", !IO),
|
|
output_instr(Instr, !Info, !IO),
|
|
io__write_string("\n", !IO)
|
|
).
|
|
|
|
:- pred output_instr(instr::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_instr(il_asm_code(Code, _MaxStack), !Info, !IO) :-
|
|
io__write_string(Code, !IO).
|
|
output_instr(comment(Comment), !Info, !IO) :-
|
|
output_comment_string(Comment, !IO).
|
|
output_instr(label(Label), !Info, !IO) :-
|
|
output_label(Label, !IO),
|
|
io__write_string(":", !IO).
|
|
output_instr(start_block(scope(Locals), Id), !Info, !IO) :-
|
|
io__write_string("{", !IO),
|
|
io__write_string("\t// #", !IO),
|
|
io__write_int(Id, !IO),
|
|
(
|
|
Locals = []
|
|
;
|
|
Locals = [_ | _],
|
|
io__write_string("\n\t.locals (\n\t\t", !IO),
|
|
ilasm__write_list(Locals, ",\n\t\t", output_local, !Info, !IO),
|
|
io__write_string("\n\t)\n", !IO)
|
|
).
|
|
output_instr(start_block(try, Id), !Info, !IO) :-
|
|
io__write_string(".try {", !IO),
|
|
io__write_string("\t// #", !IO),
|
|
io__write_int(Id, !IO).
|
|
output_instr(start_block(catch(ClassName), Id), !Info, !IO) :-
|
|
io__write_string("catch ", !IO),
|
|
output_class_name(ClassName, !Info, !IO),
|
|
io__write_string(" {", !IO),
|
|
io__write_string("\t// #", !IO),
|
|
io__write_int(Id, !IO).
|
|
output_instr(end_block(scope(_), Id), !Info, !IO) :-
|
|
io__write_string("}", !IO),
|
|
io__write_string("\t// #", !IO),
|
|
io__write_int(Id, !IO).
|
|
output_instr(end_block(catch(_), Id), !Info, !IO) :-
|
|
io__write_string("}", !IO),
|
|
io__write_string("\t// #", !IO),
|
|
io__write_int(Id, !IO),
|
|
io__write_string(" (catch block)", !IO).
|
|
output_instr(end_block(try, Id), !Info, !IO) :-
|
|
io__write_string("}", !IO),
|
|
io__write_string("\t// #", !IO),
|
|
io__write_int(Id, !IO),
|
|
io__write_string(" (try block)", !IO).
|
|
output_instr(context(File, Line), !Info, !IO) :-
|
|
io_lookup_bool_option(line_numbers, LineNumbers, !IO),
|
|
(
|
|
LineNumbers = yes,
|
|
io__write_string("\n\t.line ", !IO),
|
|
io__write_int(Line, !IO),
|
|
io__write_string(" '", !IO),
|
|
io__write_string(File, !IO),
|
|
io__write_string("'", !IO)
|
|
;
|
|
LineNumbers = no
|
|
).
|
|
output_instr(call(MethodRef), !Info, !IO) :-
|
|
io__write_string("call\t", !IO),
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
output_instr(callvirt(MethodRef), !Info, !IO) :-
|
|
io__write_string("callvirt\t", !IO),
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
output_instr(calli(Signature), !Info, !IO) :-
|
|
io__write_string("calli\t", !IO),
|
|
output_name_signature_and_call_conv(Signature, no, "\t\t", !Info, !IO).
|
|
output_instr(ret, !Info, !IO) :-
|
|
io__write_string("ret", !IO).
|
|
output_instr(bitwise_and, !Info, !IO) :-
|
|
io__write_string("and", !IO).
|
|
output_instr(arglist, !Info, !IO) :-
|
|
io__write_string("arglist", !IO).
|
|
output_instr(break, !Info, !IO) :-
|
|
io__write_string("break", !IO).
|
|
output_instr(ceq, !Info, !IO) :-
|
|
io__write_string("ceq", !IO).
|
|
output_instr(ckfinite, !Info, !IO) :-
|
|
io__write_string("ckfinite", !IO).
|
|
output_instr(cpblk, !Info, !IO) :-
|
|
io__write_string("cpblk", !IO).
|
|
output_instr(dup, !Info, !IO) :-
|
|
io__write_string("dup", !IO).
|
|
output_instr(endfilter, !Info, !IO) :-
|
|
io__write_string("endfilter", !IO).
|
|
output_instr(endfinally, !Info, !IO) :-
|
|
io__write_string("endfinally", !IO).
|
|
output_instr(initblk, !Info, !IO) :-
|
|
io__write_string("initblk", !IO).
|
|
output_instr(ldnull, !Info, !IO) :-
|
|
io__write_string("ldnull", !IO).
|
|
output_instr(localloc, !Info, !IO) :-
|
|
io__write_string("localloc", !IO).
|
|
output_instr(neg, !Info, !IO) :-
|
|
io__write_string("neg", !IO).
|
|
output_instr(nop, !Info, !IO) :-
|
|
io__write_string("nop", !IO).
|
|
output_instr(bitwise_not, !Info, !IO) :-
|
|
io__write_string("not", !IO).
|
|
output_instr(bitwise_or, !Info, !IO) :-
|
|
io__write_string("or", !IO).
|
|
output_instr(pop, !Info, !IO) :-
|
|
io__write_string("pop", !IO).
|
|
output_instr(shl, !Info, !IO) :-
|
|
io__write_string("shl", !IO).
|
|
output_instr(tailcall, !Info, !IO) :-
|
|
io__write_string("tail.", !IO).
|
|
output_instr(volatile, !Info, !IO) :-
|
|
io__write_string("volatile", !IO).
|
|
output_instr(bitwise_xor, !Info, !IO) :-
|
|
io__write_string("xor", !IO).
|
|
output_instr(ldlen, !Info, !IO) :-
|
|
io__write_string("ldlen", !IO).
|
|
output_instr(throw, !Info, !IO) :-
|
|
io__write_string("throw", !IO).
|
|
% There are short forms of various instructions.
|
|
% The assembler can't generate them for you.
|
|
output_instr(ldarg(index(Index)), !Info, !IO) :-
|
|
( Index < 4 ->
|
|
io__write_string("ldarg.", !IO),
|
|
io__write_int(Index, !IO)
|
|
; Index < 256 ->
|
|
io__write_string("ldarg.s\t", !IO),
|
|
output_index(Index, !IO)
|
|
;
|
|
io__write_string("ldarg\t", !IO),
|
|
output_index(Index, !IO)
|
|
).
|
|
output_instr(ldarg(name(Id)), !Info, !IO) :-
|
|
io__write_string("ldarg\t", !IO),
|
|
output_id(Id, !IO).
|
|
|
|
% Lots of short forms for loading integer.
|
|
% XXX Should probably put the magic numbers in functions.
|
|
output_instr(ldc(Type, Const), !Info, !IO) :-
|
|
( ( Type = int32 ; Type = bool ), Const = i(IntConst) ->
|
|
( IntConst < 8, IntConst >= 0 ->
|
|
io__write_string("ldc.i4.", !IO),
|
|
io__write_int(IntConst, !IO)
|
|
; IntConst = -1 ->
|
|
io__write_string("ldc.i4.m1", !IO)
|
|
; IntConst < 128, IntConst > -128 ->
|
|
io__write_string("ldc.i4.s\t", !IO),
|
|
io__write_int(IntConst, !IO)
|
|
;
|
|
io__write_string("ldc.i4\t", !IO),
|
|
io__write_int(IntConst, !IO)
|
|
)
|
|
; Type = int64, Const = i(IntConst) ->
|
|
io__write_string("ldc.i8\t", !IO),
|
|
io__write_int(IntConst, !IO)
|
|
; Type = float32, Const = f(FloatConst) ->
|
|
io__write_string("ldc.r4\t", !IO),
|
|
c_util__output_float_literal(FloatConst, !IO)
|
|
; Type = float64, Const = f(FloatConst) ->
|
|
io__write_string("ldc.r8\t", !IO),
|
|
c_util__output_float_literal(FloatConst, !IO)
|
|
;
|
|
unexpected(this_file,
|
|
"Inconsistent arguments in ldc instruction")
|
|
).
|
|
|
|
output_instr(ldstr(String), !Info, !IO) :-
|
|
io__write_string("ldstr\t", !IO),
|
|
output_string_constant(String, !IO).
|
|
|
|
output_instr(add(Overflow, Signed), !Info, !IO) :-
|
|
io__write_string("add", !IO),
|
|
output_overflow(Overflow, !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(beq(Target), !Info, !IO) :-
|
|
io__write_string("beq ", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(bge(Signed, Target), !Info, !IO) :-
|
|
io__write_string("bge", !IO),
|
|
output_signed(Signed, !IO),
|
|
io__write_string("\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(bgt(Signed, Target), !Info, !IO) :-
|
|
io__write_string("bgt", !IO),
|
|
output_signed(Signed, !IO),
|
|
io__write_string("\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(ble(Signed, Target), !Info, !IO) :-
|
|
io__write_string("ble", !IO),
|
|
output_signed(Signed, !IO),
|
|
io__write_string("\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(blt(Signed, Target), !Info, !IO) :-
|
|
io__write_string("blt", !IO),
|
|
output_signed(Signed, !IO),
|
|
io__write_string("\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(bne(Signed, Target), !Info, !IO) :-
|
|
io__write_string("bne", !IO),
|
|
output_signed(Signed, !IO),
|
|
io__write_string("\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(br(Target), !Info, !IO) :-
|
|
io__write_string("br\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(brfalse(Target), !Info, !IO) :-
|
|
io__write_string("brfalse\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(brtrue(Target), !Info, !IO) :-
|
|
io__write_string("brtrue\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(cgt(Signed), !Info, !IO) :-
|
|
io__write_string("cgt", !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(clt(Signed), !Info, !IO) :-
|
|
io__write_string("clt", !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(conv(SimpleType), !Info, !IO) :-
|
|
io__write_string("conv.", !IO),
|
|
output_simple_type_opcode(SimpleType, !IO).
|
|
|
|
output_instr(div(Signed), !Info, !IO) :-
|
|
io__write_string("div", !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(jmp(MethodRef), !Info, !IO) :-
|
|
io__write_string("jmp\t", !IO),
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(ldarga(Variable), !Info, !IO) :-
|
|
io__write_string("ldarga\t", !IO),
|
|
(
|
|
Variable = index(Index),
|
|
output_index(Index, !IO)
|
|
;
|
|
Variable = name(Name),
|
|
output_id(Name, !IO)
|
|
).
|
|
|
|
output_instr(ldftn(MethodRef), !Info, !IO) :-
|
|
io__write_string("ldftn\t", !IO),
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
|
|
output_instr(ldind(SimpleType), !Info, !IO) :-
|
|
io__write_string("ldind.", !IO),
|
|
output_simple_type_opcode(SimpleType, !IO).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(ldloc(Variable), !Info, !IO) :-
|
|
io__write_string("ldloc\t", !IO),
|
|
(
|
|
Variable = index(Index),
|
|
output_index(Index, !IO)
|
|
;
|
|
Variable = name(Name),
|
|
output_id(Name, !IO)
|
|
).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(ldloca(Variable), !Info, !IO) :-
|
|
io__write_string("ldloca\t", !IO),
|
|
(
|
|
Variable = index(Index),
|
|
output_index(Index, !IO)
|
|
;
|
|
Variable = name(Name),
|
|
output_id(Name, !IO)
|
|
).
|
|
|
|
output_instr(leave(Target), !Info, !IO) :-
|
|
io__write_string("leave\t", !IO),
|
|
output_target(Target, !IO).
|
|
|
|
output_instr(mul(Overflow, Signed), !Info, !IO) :-
|
|
io__write_string("mul", !IO),
|
|
output_overflow(Overflow, !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(rem(Signed), !Info, !IO) :-
|
|
io__write_string("rem", !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(shr(Signed), !Info, !IO) :-
|
|
io__write_string("shr", !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(starg(Variable), !Info, !IO) :-
|
|
io__write_string("starg\t", !IO),
|
|
(
|
|
Variable = index(Index),
|
|
output_index(Index, !IO)
|
|
;
|
|
Variable = name(Name),
|
|
output_id(Name, !IO)
|
|
).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(stind(SimpleType), !Info, !IO) :-
|
|
io__write_string("stind.", !IO),
|
|
output_simple_type_opcode(SimpleType, !IO).
|
|
|
|
output_instr(stloc(Variable), !Info, !IO) :-
|
|
io__write_string("stloc\t", !IO),
|
|
(
|
|
Variable = index(Index),
|
|
output_index(Index, !IO)
|
|
;
|
|
Variable = name(Name),
|
|
output_id(Name, !IO)
|
|
).
|
|
|
|
output_instr(sub(OverFlow, Signed), !Info, !IO) :-
|
|
io__write_string("sub", !IO),
|
|
output_overflow(OverFlow, !IO),
|
|
output_signed(Signed, !IO).
|
|
|
|
output_instr(switch(Targets), !Info, !IO) :-
|
|
io__write_string("switch (", !IO),
|
|
io__write_list(Targets, ", ", output_target, !IO),
|
|
io__write_string(")", !IO).
|
|
|
|
output_instr(unaligned(_), !Info, !IO) :-
|
|
io__write_string("unaligned.", !IO).
|
|
|
|
output_instr(box(Type), !Info, !IO) :-
|
|
io__write_string("box\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(castclass(Type), !Info, !IO) :-
|
|
(
|
|
Type = type(_, '[]'(ElementType, _)),
|
|
ElementType = type(_, class(Name)),
|
|
Name = structured_name(assembly("mscorlib"),
|
|
["System", "Type"], _)
|
|
->
|
|
% XXX There is bug where castclass to System.Type[]
|
|
% sometimes erroneously fails, so we comment out these
|
|
% castclass's.
|
|
io__write_string("// ", !IO)
|
|
;
|
|
true
|
|
),
|
|
io__write_string("castclass\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(cpobj(Type), !Info, !IO) :-
|
|
io__write_string("cpobj\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(initobj(Type), !Info, !IO) :-
|
|
io__write_string("initobj\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(isinst(Type), !Info, !IO) :-
|
|
io__write_string("isinst\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(ldelem(SimpleType), !Info, !IO) :-
|
|
io__write_string("ldelem.", !IO),
|
|
output_simple_type_opcode(SimpleType, !IO).
|
|
|
|
output_instr(ldelema(Type), !Info, !IO) :-
|
|
io__write_string("ldelema\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(ldfld(FieldRef), !Info, !IO) :-
|
|
io__write_string("ldfld\t", !IO),
|
|
output_fieldref(FieldRef, !Info, !IO).
|
|
|
|
output_instr(ldflda(FieldRef), !Info, !IO) :-
|
|
io__write_string("ldflda\t", !IO),
|
|
output_fieldref(FieldRef, !Info, !IO).
|
|
|
|
output_instr(ldobj(Type), !Info, !IO) :-
|
|
io__write_string("ldobj\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(ldsfld(FieldRef), !Info, !IO) :-
|
|
io__write_string("ldsfld\t", !IO),
|
|
output_fieldref(FieldRef, !Info, !IO).
|
|
|
|
output_instr(ldsflda(FieldRef), !Info, !IO) :-
|
|
io__write_string("ldsflda\t", !IO),
|
|
output_fieldref(FieldRef, !Info, !IO).
|
|
|
|
% XXX should be implemented
|
|
output_instr(ldtoken(_), !Info, !IO) :-
|
|
sorry(this_file, "output not implemented").
|
|
|
|
output_instr(ldvirtftn(MethodRef), !Info, !IO) :-
|
|
io__write_string("ldvirtftn\t", !IO),
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
|
|
output_instr(mkrefany(Type), !Info, !IO) :-
|
|
io__write_string("mkrefany\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(newarr(Type), !Info, !IO) :-
|
|
io__write_string("newarr\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(newobj(MethodRef), !Info, !IO) :-
|
|
io__write_string("newobj\t", !IO),
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
|
|
output_instr(refanytype, !Info, !IO) :-
|
|
io__write_string("refanytype", !IO).
|
|
|
|
output_instr(refanyval(Type), !Info, !IO) :-
|
|
io__write_string("refanyval\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(rethrow, !Info, !IO) :-
|
|
io__write_string("rethrow", !IO).
|
|
|
|
output_instr(stelem(SimpleType), !Info, !IO) :-
|
|
io__write_string("stelem.", !IO),
|
|
output_simple_type_opcode(SimpleType, !IO).
|
|
|
|
output_instr(stfld(FieldRef), !Info, !IO) :-
|
|
io__write_string("stfld\t", !IO),
|
|
output_fieldref(FieldRef, !Info, !IO).
|
|
|
|
output_instr(stobj(Type), !Info, !IO) :-
|
|
io__write_string("stobj\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(sizeof(Type), !Info, !IO) :-
|
|
io__write_string("sizeof\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
output_instr(stsfld(FieldRef), !Info, !IO) :-
|
|
io__write_string("stsfld\t", !IO),
|
|
output_fieldref(FieldRef, !Info, !IO).
|
|
|
|
output_instr(unbox(Type), !Info, !IO) :-
|
|
io__write_string("unbox\t", !IO),
|
|
output_type(Type, !Info, !IO).
|
|
|
|
% XXX might use this later.
|
|
:- func max_efficient_encoding_short = int.
|
|
|
|
max_efficient_encoding_short = 256.
|
|
|
|
:- pred output_overflow(overflow::in, io::di, io::uo) is det.
|
|
|
|
output_overflow(OverFlow, !IO) :-
|
|
(
|
|
OverFlow = checkoverflow,
|
|
io__write_string(".ovf", !IO)
|
|
;
|
|
OverFlow = nocheckoverflow
|
|
).
|
|
|
|
:- pred output_signed(signed::in, io::di, io::uo) is det.
|
|
|
|
output_signed(Signed, !IO) :-
|
|
(
|
|
Signed = signed
|
|
;
|
|
Signed = unsigned,
|
|
io__write_string(".un", !IO)
|
|
).
|
|
|
|
:- pred output_target(target::in, io::di, io::uo) is det.
|
|
|
|
output_target(offset_target(Target), !IO) :-
|
|
io__write_int(Target, !IO).
|
|
output_target(label_target(Label), !IO) :-
|
|
output_label(Label, !IO).
|
|
|
|
:- pred output_fieldref(fieldref::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
output_fieldref(fieldref(Type, ClassMemberName), !Info, !IO) :-
|
|
output_type(Type, !Info, !IO),
|
|
io__write_string("\n\t\t", !IO),
|
|
output_class_member_name(ClassMemberName, !.Info, !IO).
|
|
|
|
:- pred output_methodref(methodref::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_methodref(methoddef(call_conv(IsInstance, _), ReturnType,
|
|
ClassMemberName, ArgTypes), !Info, !IO) :-
|
|
(
|
|
IsInstance = yes,
|
|
io__write_string("instance ", !IO)
|
|
;
|
|
IsInstance = no
|
|
),
|
|
output_ret_type(ReturnType, !Info, !IO),
|
|
io__write_string("\n\t\t", !IO),
|
|
output_class_member_name(ClassMemberName, !.Info, !IO),
|
|
(
|
|
ArgTypes = [],
|
|
io__write_string("()\n", !IO)
|
|
;
|
|
ArgTypes = [_ | _],
|
|
io__write_string("(\n\t\t\t", !IO),
|
|
ilasm__write_list(ArgTypes, ",\n\t\t\t", output_type,
|
|
!Info, !IO),
|
|
io__write_string("\n\t\t)", !IO)
|
|
).
|
|
output_methodref(local_method(call_conv(IsInstance, _), ReturnType,
|
|
MethodName, ArgTypes), !Info, !IO) :-
|
|
(
|
|
IsInstance = yes,
|
|
io__write_string("instance ", !IO)
|
|
;
|
|
IsInstance = no
|
|
),
|
|
output_ret_type(ReturnType, !Info, !IO),
|
|
io__write_string("\n\t\t", !IO),
|
|
output_member_name(MethodName, !IO),
|
|
(
|
|
ArgTypes = [],
|
|
io__write_string("()\n", !IO)
|
|
;
|
|
ArgTypes = [_ | _],
|
|
io__write_string("(\n\t\t\t", !IO),
|
|
ilasm__write_list(ArgTypes, ",\n\t\t\t", output_type,
|
|
!Info, !IO),
|
|
io__write_string("\n\t\t)", !IO)
|
|
).
|
|
|
|
:- pred output_classattr(classattr::in, io::di, io::uo) is det.
|
|
|
|
output_classattr(abstract) --> io__write_string("abstract").
|
|
output_classattr(ansi) --> io__write_string("ansi").
|
|
output_classattr(auto) --> io__write_string("auto").
|
|
output_classattr(autochar) --> io__write_string("autochar").
|
|
output_classattr(beforefieldinit) --> io__write_string("beforefieldinit").
|
|
output_classattr(explicit) --> io__write_string("explicit").
|
|
output_classattr(interface) --> io__write_string("interface").
|
|
output_classattr(nestedassembly) --> io__write_string("nested assembly").
|
|
output_classattr(nestedfamandassem) --> io__write_string("nested famandassem").
|
|
output_classattr(nestedfamily) --> io__write_string("nested family").
|
|
output_classattr(nestedfamorassem) --> io__write_string("nested famorassem").
|
|
output_classattr(nestedprivate) --> io__write_string("nested private").
|
|
output_classattr(nestedpublic) --> io__write_string("nested public").
|
|
output_classattr(private) --> io__write_string("private").
|
|
output_classattr(public) --> io__write_string("public").
|
|
output_classattr(rtspecialname) --> io__write_string("rtspecialname").
|
|
output_classattr(sealed) --> io__write_string("sealed").
|
|
output_classattr(sequential) --> io__write_string("sequential").
|
|
output_classattr(serializable) --> io__write_string("serializable").
|
|
output_classattr(specialname) --> io__write_string("specialname").
|
|
output_classattr(unicode) --> io__write_string("unicode").
|
|
|
|
:- pred ilasm__output_assembly_decl(assembly_decl::in,
|
|
ilasm_info::in, ilasm_info::out, io::di, io::uo) is det.
|
|
|
|
ilasm__output_assembly_decl(version(A, B, C, D), !Info, !IO) :-
|
|
io__format(".ver %d:%d:%d:%d", [i(A), i(B), i(C), i(D)], !IO).
|
|
ilasm__output_assembly_decl(public_key_token(Token), !Info, !IO) :-
|
|
io__write_string(".publickeytoken = ( ", !IO),
|
|
io__write_list(Token, " ", output_hexbyte, !IO),
|
|
io__write_string(" ) ", !IO).
|
|
ilasm__output_assembly_decl(hash(Hash), !Info, !IO) :-
|
|
io__write_string(".hash = ( ", !IO),
|
|
io__write_list(Hash, " ", output_hexbyte, !IO),
|
|
io__write_string(" ) ", !IO).
|
|
ilasm__output_assembly_decl(custom(CustomDecl), !Info, !IO) :-
|
|
output_custom_decl(CustomDecl, !Info, !IO).
|
|
|
|
:- pred output_custom_decl(custom_decl::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_custom_decl(custom_decl(Type, MaybeOwner, StringOrBytes), !Info, !IO) :-
|
|
io__write_string(".custom ", !IO),
|
|
(
|
|
MaybeOwner = yes(Owner),
|
|
io__write_string(" (", !IO),
|
|
output_custom_type(Owner, !Info, !IO),
|
|
io__write_string(") ", !IO)
|
|
;
|
|
MaybeOwner = no
|
|
),
|
|
output_custom_type(Type, !Info, !IO),
|
|
( StringOrBytes = bytes(Bytes) ->
|
|
io__write_string(" = (", !IO),
|
|
io__write_list(Bytes, " ", output_hexbyte, !IO),
|
|
io__write_string(")", !IO)
|
|
;
|
|
sorry(this_file, "custom_decl of this sort")
|
|
),
|
|
io__write_string("\n", !IO).
|
|
|
|
:- pred output_custom_type(custom_type::in, ilasm_info::in, ilasm_info::out,
|
|
io::di, io::uo) is det.
|
|
|
|
output_custom_type(type(Type), !Info, !IO) :-
|
|
output_type(Type, !Info, !IO).
|
|
output_custom_type(methodref(MethodRef), !Info, !IO) :-
|
|
output_methodref(MethodRef, !Info, !IO).
|
|
|
|
:- pred output_index(index::in, io::di, io::uo) is det.
|
|
|
|
output_index(Index, !IO) :-
|
|
io__write_int(Index, !IO).
|
|
|
|
:- pred output_string_constant(string::in, io::di, io::uo) is det.
|
|
|
|
output_string_constant(String, !IO) :-
|
|
io__write_string("""", !IO),
|
|
output_escaped_string(String, '\"', !IO),
|
|
io__write_string("""", !IO).
|
|
|
|
:- pred output_class_member_name(class_member_name::in, ilasm_info::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_class_member_name(class_member_name(StructuredName, MemberName), Info,
|
|
!IO) :-
|
|
output_structured_name(StructuredName, Info, !IO),
|
|
io__write_string("::", !IO),
|
|
output_member_name(MemberName, !IO).
|
|
|
|
:- pred output_structured_name(structured_name::in, ilasm_info::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_structured_name(structured_name(Asm, DottedName, NestedClasses), Info,
|
|
!IO) :-
|
|
globals__io_lookup_bool_option(separate_assemblies, SeparateAssemblies,
|
|
!IO),
|
|
(
|
|
Asm = assembly(Assembly),
|
|
maybe_output_quoted_assembly_name(Assembly, Info, !IO)
|
|
;
|
|
Asm = module(Module, Assembly),
|
|
(
|
|
SeparateAssemblies = yes,
|
|
maybe_output_quoted_assembly_name(Module, Info, !IO)
|
|
;
|
|
SeparateAssemblies = no,
|
|
(
|
|
Info ^ current_assembly \= "",
|
|
string__prefix(Module, Info ^ current_assembly)
|
|
->
|
|
quote_id(Module ++ ".dll", QuotedModuleName),
|
|
io__format("[.module %s]",
|
|
[s(QuotedModuleName)], !IO)
|
|
;
|
|
maybe_output_quoted_assembly_name(Assembly,
|
|
Info, !IO)
|
|
)
|
|
)
|
|
),
|
|
output_dotted_name(DottedName, !IO),
|
|
output_nested_class_quals(NestedClasses, !IO).
|
|
|
|
:- pred maybe_output_quoted_assembly_name(ilds__id::in, ilasm_info::in,
|
|
io::di, io::uo) is det.
|
|
|
|
maybe_output_quoted_assembly_name(Assembly, Info, !IO) :-
|
|
(
|
|
Assembly \= "",
|
|
Assembly \= Info ^ current_assembly
|
|
->
|
|
quote_id(Assembly, QuotedAssemblyName),
|
|
io__format("[%s]", [s(QuotedAssemblyName)], !IO)
|
|
;
|
|
true
|
|
).
|
|
|
|
:- pred output_dotted_name(namespace_qual_name::in, io::di, io::uo) is det.
|
|
|
|
output_dotted_name(Name, !IO) :-
|
|
io__write_list(Name, ".", output_id, !IO).
|
|
|
|
:- pred output_nested_class_quals(nested_class_name::in,
|
|
io::di, io::uo) is det.
|
|
|
|
output_nested_class_quals(Name, !IO) :-
|
|
list__foldl(
|
|
(pred(Id::in, IO0::di, IO::uo) is det :-
|
|
io__write_char('/', IO0, IO1),
|
|
output_id(Id, IO1, IO)
|
|
),
|
|
Name, !IO).
|
|
|
|
:- pred output_id(ilds__id::in, io::di, io::uo) is det.
|
|
|
|
output_id(Id, !IO) :-
|
|
quote_id(Id, QuotedId),
|
|
io__write_string(QuotedId, !IO).
|
|
|
|
:- pred output_field_initializer(field_initializer::in, io::di, io::uo) is det.
|
|
|
|
output_field_initializer(none, !IO).
|
|
output_field_initializer(at(Id), !IO) :-
|
|
io__write_string(" at ", !IO),
|
|
output_id(Id, !IO).
|
|
output_field_initializer(equals(FieldInit), !IO) :-
|
|
io__write_string(" = ", !IO),
|
|
output_field_init(FieldInit, !IO).
|
|
|
|
:- pred output_field_init(field_init::in, io::di, io::uo) is det.
|
|
|
|
output_field_init(binary_float64(Int64), !IO) :-
|
|
io__write_string("float64(", !IO),
|
|
output_int64(Int64, !IO),
|
|
io__write_string(")", !IO).
|
|
output_field_init(binary_float32(Int32), !IO) :-
|
|
io__write_string("float32(", !IO),
|
|
output_int32(Int32, !IO),
|
|
io__write_string(")", !IO).
|
|
output_field_init(wchar_ptr(String), !IO) :-
|
|
io__write_string("wchar *(", !IO),
|
|
io__write(String, !IO),
|
|
io__write_string(")", !IO).
|
|
% XXX should check for invalid data_items
|
|
output_field_init(data_item(DataItem), !IO) :-
|
|
( DataItem = char_ptr(String) ->
|
|
io__write(String, !IO)
|
|
;
|
|
output_data_item(DataItem, !IO)
|
|
).
|
|
|
|
:- pred output_data_body(data_body::in, io::di, io::uo) is det.
|
|
|
|
output_data_body(itemlist(DataItemList), !IO) :-
|
|
io__write_string("{", !IO),
|
|
io__write_list(DataItemList, ", ", output_data_item, !IO),
|
|
io__write_string("}", !IO).
|
|
output_data_body(item(DataItem), !IO) :-
|
|
output_data_item(DataItem, !IO).
|
|
|
|
:- pred output_data_item(data_item::in, io::di, io::uo) is det.
|
|
|
|
output_data_item(float64(Float), !IO) :-
|
|
io__write_string("float64(", !IO),
|
|
output_float64(Float, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(float32(Float32), !IO) :-
|
|
io__write_string("float32(", !IO),
|
|
output_float32(Float32, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(int64(Int64), !IO) :-
|
|
io__write_string("int64(", !IO),
|
|
output_int64(Int64, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(int32(Int32), !IO) :-
|
|
io__write_string("int32(", !IO),
|
|
output_int32(Int32, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(int16(Int16), !IO) :-
|
|
io__write_string("int16(", !IO),
|
|
output_int16(Int16, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(int8(Int8), !IO) :-
|
|
io__write_string("int8(", !IO),
|
|
output_int8(Int8, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(char_ptr(String), !IO) :-
|
|
io__write_string("char *(", !IO),
|
|
io__write(String, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item('&'(Id), !IO) :-
|
|
io__write_string("&(", !IO),
|
|
output_id(Id, !IO),
|
|
io__write_string(")", !IO).
|
|
output_data_item(bytearray(Bytes), !IO) :-
|
|
io__write_string("bytearray(", !IO),
|
|
io__write_list(Bytes, " ", output_hexbyte, !IO),
|
|
io__write_string(")", !IO).
|
|
|
|
:- pred output_float64(float64::in, io::di, io::uo) is det.
|
|
|
|
output_float64(float64(Float), !IO) :-
|
|
io__write_float(Float, !IO).
|
|
|
|
:- pred output_float32(float32::in, io::di, io::uo) is det.
|
|
|
|
output_float32(float32(Float), !IO) :-
|
|
io__write_float(Float, !IO).
|
|
|
|
:- pred output_int64(int64::in, io::di, io::uo) is det.
|
|
|
|
output_int64(int64(Integer), !IO) :-
|
|
io__write_string(integer__to_string(Integer), !IO).
|
|
|
|
:- pred output_int32(int32::in, io::di, io::uo) is det.
|
|
|
|
output_int32(int32(Int), !IO) :-
|
|
io__write_int(Int, !IO).
|
|
|
|
:- pred output_int16(int16::in, io::di, io::uo) is det.
|
|
|
|
output_int16(int16(Int), !IO) :-
|
|
io__write_int(Int, !IO).
|
|
|
|
:- pred output_int8(int8::in, io::di, io::uo) is det.
|
|
|
|
output_int8(int8(Int), !IO) :-
|
|
io__write_int(Int, !IO).
|
|
|
|
:- pred output_byte(byte::in, io::di, io::uo) is det.
|
|
|
|
output_byte(Byte, !IO) :-
|
|
output_int8(Byte, !IO).
|
|
|
|
:- pred output_hexbyte(byte::in, io::di, io::uo) is det.
|
|
|
|
output_hexbyte(int8(Int), !IO) :-
|
|
string__int_to_base_string(Int, 16, Tmp),
|
|
io__write_string(Tmp, !IO).
|
|
|
|
:- pred output_comment_string(string::in, io::di, io::uo) is det.
|
|
|
|
output_comment_string(Comment, !IO) :-
|
|
io__write_string("// ", !IO),
|
|
CommentDoc = separated(text, line,
|
|
string__words((pred('\n'::in) is semidet :- true), Comment)),
|
|
Doc = label("\t// ", CommentDoc),
|
|
write(70, Doc, !IO).
|
|
|
|
% We need to quote all the IDs we output to avoid bumping into
|
|
% keywords that assembler uses (there are a lot of them, and
|
|
% there is no list available).
|
|
:- pred quote_id(ilds__id::in, string::out) is det.
|
|
|
|
quote_id(Id, QuotedId) :-
|
|
escape_string(Id, '\'', EscapedId),
|
|
string__append_list(["'", EscapedId, "'"], QuotedId).
|
|
|
|
:- pred output_escaped_string(string::in, char::in, io::di, io::uo) is det.
|
|
|
|
output_escaped_string(String, EscapeChar, !IO) :-
|
|
escape_string(String, EscapeChar, EscapedString),
|
|
io__write_string(EscapedString, !IO).
|
|
|
|
% Replace all Rep0 with backslash quoted Rep0 in Str0,
|
|
% giving the escaped string Str.
|
|
% We also escape embedded newlines and other characters.
|
|
% We already do some name mangling during code generation that
|
|
% means we avoid most weird characters here.
|
|
:- pred escape_string(string::in, char::in, string::out) is det.
|
|
|
|
escape_string(Str0, ReplaceChar, Str) :-
|
|
string__to_char_list(Str0, CharList0),
|
|
list__foldl(
|
|
(pred(Char::in, E0::in, E::out) is det :-
|
|
( escape_special_char(Char, QuoteChar) ->
|
|
E = [QuoteChar, '\\' | E0]
|
|
; Char = ReplaceChar ->
|
|
E = [ReplaceChar, '\\' | E0]
|
|
;
|
|
E = [Char | E0]
|
|
)
|
|
), CharList0, [], CharList),
|
|
string__from_rev_char_list(CharList, Str).
|
|
|
|
% Characters that should be escaped in strings, and the
|
|
% character to escape with.
|
|
:- pred escape_special_char(char::in, char::out) is semidet.
|
|
|
|
escape_special_char('\\', '\\').
|
|
escape_special_char('\n', 'n').
|
|
escape_special_char('\t', 't').
|
|
escape_special_char('\b', 'b').
|
|
|
|
:- func this_file = string.
|
|
|
|
this_file = "ilasm.m".
|
|
|
|
:- end_module ilasm.
|