mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 23:05:21 +00:00
Estimated hours taken: Branches: main, release Reorganize the code in the compiler to centralize the code which handles output of floating point literals. compiler/c_util.m: Add new routines make_float_literal and output_float_literal. These output to 17 digits precision. Also add some comments. compiler/mlds_to_c.m: compiler/llds_out.m: compiler/mlds_to_java.m: compiler/ilasm.m: Use the new routines. Also add some comments. tests/hard_coded/Mmakefile: tests/hard_coded/float_consistency.m: tests/hard_coded/float_consistency.exp: A regression test.
1816 lines
54 KiB
Mathematica
1816 lines
54 KiB
Mathematica
%-----------------------------------------------------------------------------%
|
|
% Copyright (C) 1999-2002 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.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% ilasm - Generate IL for the ilasm assembler
|
|
% Main author: trd.
|
|
%
|
|
%
|
|
% 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 io, list, term, std_util, bool, integer.
|
|
:- import_module ml_backend__ilds.
|
|
|
|
:- pred ilasm__output(
|
|
list(decl)::in, io__state::di, io__state::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 char, string, pprint, getopt.
|
|
:- import_module require, int, term_io, varset, bool.
|
|
:- import_module libs__globals, libs__options, hlds__error_util.
|
|
:- import_module backend_libs__c_util. % for output_float_literal
|
|
|
|
|
|
% 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), string,
|
|
pred(T, ilasm_info, ilasm_info, io__state, io__state),
|
|
ilasm_info, ilasm_info, io__state, io__state).
|
|
:- mode ilasm__write_list(in, in, pred(in, in, out, di, uo) is det,
|
|
in, out, di, uo) is det.
|
|
|
|
ilasm__write_list([], _Separator, _OutputPred, Info, Info) --> [].
|
|
ilasm__write_list([E | Es], Separator, OutputPred, Info0, Info) -->
|
|
call(OutputPred, E, Info0, Info1),
|
|
(
|
|
{ Es = [] }
|
|
;
|
|
{ Es = [_|_] },
|
|
io__write_string(Separator)
|
|
),
|
|
ilasm__write_list(Es, Separator, OutputPred, Info1, Info).
|
|
|
|
|
|
ilasm__output(Blocks) -->
|
|
{ Info0 = ilasm_info("") },
|
|
ilasm__output(Blocks, Info0, _Info).
|
|
|
|
:- pred ilasm__output(list(decl)::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
ilasm__output(Blocks, Info0, Info) -->
|
|
ilasm__write_list(Blocks, "\n\n", output_decl, Info0, Info),
|
|
io__write_string("\n\n").
|
|
|
|
|
|
:- pred ilasm__output_decl(decl::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
ilasm__output_decl(custom(CustomDecl), Info0, Info) -->
|
|
output_custom_decl(CustomDecl, Info0, Info).
|
|
ilasm__output_decl(class(Attrs, Id, Extends, Implements, Contents),
|
|
Info0, Info) -->
|
|
io__write_string(".class "),
|
|
io__write_list(Attrs, " ", output_classattr),
|
|
( { Attrs \= [] } ->
|
|
io__write_string(" ")
|
|
;
|
|
[]
|
|
),
|
|
output_id(Id),
|
|
(
|
|
{ Extends = extends(ExtendsModule) },
|
|
io__write_string(" extends "),
|
|
output_class_name(ExtendsModule, Info0, Info1)
|
|
;
|
|
{ Info1 = Info0 },
|
|
{ Extends = extends_nothing }
|
|
),
|
|
{ Implements = implements(ImplementsList) },
|
|
(
|
|
{ ImplementsList = [_|_] }
|
|
->
|
|
io__write_string(" implements "),
|
|
ilasm__write_list(ImplementsList, ", ", output_class_name,
|
|
Info1, Info2)
|
|
;
|
|
{ Info2 = Info1 }
|
|
),
|
|
io__write_string(" {\n"),
|
|
ilasm__write_list(Contents, "\n", output_class_member, Info2, Info),
|
|
io__write_string("\n}").
|
|
ilasm__output_decl(namespace(DottedName, Contents), Info0, Info) -->
|
|
( { DottedName \= [] } ->
|
|
io__write_string(".namespace "),
|
|
output_dotted_name(DottedName),
|
|
io__write_string(" {\n"),
|
|
output(Contents, Info0, Info),
|
|
io__write_string("}\n")
|
|
;
|
|
output(Contents, Info0, Info)
|
|
).
|
|
ilasm__output_decl(method(MethodHead, MethodDecls), Info0, Info) -->
|
|
io__write_string(".method "),
|
|
output_methodhead(MethodHead, Info0, Info1),
|
|
io__write_string("\n{\n"),
|
|
ilasm__write_list(MethodDecls, "\n", output_method_body_decl,
|
|
Info1, Info),
|
|
io__write_string("}\n").
|
|
ilasm__output_decl(data(TLS, MaybeId, Body), Info, Info) -->
|
|
io__write_string(".data "),
|
|
( { TLS = yes } ->
|
|
io__write_string("tls ")
|
|
;
|
|
[]
|
|
),
|
|
( { MaybeId = yes(Id) } ->
|
|
output_id(Id),
|
|
io__write_string(" = ")
|
|
;
|
|
[]
|
|
),
|
|
output_data_body(Body).
|
|
|
|
ilasm__output_decl(comment_term(CommentTerm), Info, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
( { PrintComments = yes } ->
|
|
io__write_string("// "),
|
|
{ varset__init(VarSet) },
|
|
term_io__write_term(VarSet, CommentTerm),
|
|
io__write_string("\n")
|
|
;
|
|
[]
|
|
).
|
|
|
|
ilasm__output_decl(comment_thing(Thing), Info, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
( { PrintComments = yes } ->
|
|
{ Doc = label("// ", to_doc(Thing)) },
|
|
write(70, Doc),
|
|
io__nl
|
|
;
|
|
[]
|
|
).
|
|
|
|
ilasm__output_decl(comment(CommentStr), Info, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
( { PrintComments = yes } ->
|
|
output_comment_string(CommentStr)
|
|
;
|
|
[]
|
|
).
|
|
|
|
ilasm__output_decl(extern_assembly(AsmName, AssemblyDecls), Info0, Info) -->
|
|
io__write_string(".assembly extern "),
|
|
output_id(AsmName),
|
|
io__write_string("{\n"),
|
|
list__foldl2((pred(A::in, I0::in, I::out, di, uo) is det -->
|
|
output_assembly_decl(A, I0, I),
|
|
io__write_string("\n\t")
|
|
), AssemblyDecls, Info0, Info),
|
|
io__write_string("\n}\n").
|
|
|
|
|
|
ilasm__output_decl(assembly(AsmName), Info0, Info) -->
|
|
io__write_string(".assembly "),
|
|
output_id(AsmName),
|
|
{ Info = Info0 ^ current_assembly := AsmName },
|
|
io__write_string(" { }").
|
|
|
|
ilasm__output_decl(file(FileName), Info, Info) -->
|
|
io__write_string(".file "),
|
|
output_id(FileName).
|
|
|
|
ilasm__output_decl(extern_module(ModName), Info, Info) -->
|
|
io__write_string(".module extern "),
|
|
output_id(ModName).
|
|
|
|
|
|
:- pred ilasm__output_class_member(class_member::in, ilasm_info::in,
|
|
ilasm_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
ilasm__output_class_member(method(MethodHead, MethodDecls), Info0, Info) -->
|
|
% 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),
|
|
( { MethodHead = methodhead(_, cctor, _, _) } ->
|
|
globals__io_set_option(debug_il_asm, bool(no)),
|
|
ilasm__output_decl(method(MethodHead, MethodDecls),
|
|
Info0, Info),
|
|
globals__io_set_option(debug_il_asm, DebugIlAsm)
|
|
;
|
|
ilasm__output_decl(method(MethodHead, MethodDecls),
|
|
Info0, Info)
|
|
).
|
|
|
|
ilasm__output_class_member(custom(CustomDecl), Info0, Info) -->
|
|
output_custom_decl(CustomDecl, Info0, Info).
|
|
|
|
ilasm__output_class_member(
|
|
field(FieldAttrs, Type, IlId, MaybeOffset, Initializer),
|
|
Info0, Info) -->
|
|
io__write_string(".field "),
|
|
( { MaybeOffset = yes(Offset) } ->
|
|
output_int32(Offset),
|
|
io__write_string(" ")
|
|
;
|
|
[]
|
|
),
|
|
io__write_list(FieldAttrs, " ", io__write),
|
|
io__write_string("\n\t"),
|
|
output_type(Type, Info0, Info),
|
|
io__write_string("\n\t"),
|
|
output_id(IlId),
|
|
output_field_initializer(Initializer).
|
|
|
|
ilasm__output_class_member(
|
|
property(Type, Name, MaybeGet, MaybeSet), Info0, Info) -->
|
|
io__write_string(".property instance "),
|
|
output_type(Type, Info0, Info1),
|
|
io__write_string(" "),
|
|
output_id(Name),
|
|
io__write_string("() {"),
|
|
( { MaybeGet = yes(methodhead(_, GetMethodName, GetSignature, _)) },
|
|
io__nl,
|
|
io__write_string("\t.get instance "),
|
|
output_name_signature_and_call_conv(GetSignature,
|
|
yes(GetMethodName), "\t\t", Info1, Info2)
|
|
; { MaybeGet = no },
|
|
{ Info2 = Info1 }
|
|
),
|
|
( { MaybeSet = yes(methodhead(_, SetMethodName, SetSignature, _)) },
|
|
io__nl,
|
|
io__write_string("\t.set instance "),
|
|
output_name_signature_and_call_conv(SetSignature,
|
|
yes(SetMethodName), "\t\t", Info2, Info)
|
|
; { MaybeSet = no },
|
|
{ Info = Info2 }
|
|
),
|
|
io__write_string("\n}\n").
|
|
|
|
ilasm__output_class_member(nested_class(Attrs, Id, Extends, Implements,
|
|
Contents), Info0, Info) -->
|
|
ilasm__output_decl(class(Attrs, Id, Extends, Implements, Contents),
|
|
Info0, Info).
|
|
|
|
ilasm__output_class_member(comment(CommentStr), Info, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
( { PrintComments = yes } ->
|
|
output_comment_string(CommentStr)
|
|
;
|
|
[]
|
|
).
|
|
|
|
ilasm__output_class_member(comment_term(CommentTerm), Info, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
( { PrintComments = yes } ->
|
|
io__write_string("// "),
|
|
{ varset__init(VarSet) },
|
|
term_io__write_term(VarSet, CommentTerm),
|
|
io__nl
|
|
;
|
|
[]
|
|
).
|
|
|
|
ilasm__output_class_member(comment_thing(Thing), Info, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
( { PrintComments = yes } ->
|
|
{ Doc = label("// ", to_doc(Thing)) },
|
|
write(70, Doc),
|
|
io__nl
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred ilasm__output_methodhead(methodhead::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
ilasm__output_methodhead(methodhead(Attrs, MethodName, Signature,
|
|
ImplAttrs), Info0, Info) -->
|
|
io__write_list(Attrs, " ", io__write),
|
|
( { Attrs \= [] } ->
|
|
io__write_string(" ")
|
|
;
|
|
[]
|
|
),
|
|
output_name_signature_and_call_conv(Signature, yes(MethodName), "\t",
|
|
Info0, Info),
|
|
io__write_list(ImplAttrs, " ", io__write).
|
|
|
|
:- pred ilasm__output_method_body_decl(method_body_decl::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
ilasm__output_method_body_decl(emitbyte(Int32), I, I) -->
|
|
io__write_string(".emitbyte "),
|
|
output_int32(Int32).
|
|
|
|
ilasm__output_method_body_decl(custom(CustomDecl), Info0, Info) -->
|
|
output_custom_decl(CustomDecl, Info0, Info).
|
|
|
|
ilasm__output_method_body_decl(maxstack(Int32), I, I) -->
|
|
io__write_string(".maxstack "),
|
|
output_int32(Int32).
|
|
|
|
ilasm__output_method_body_decl(entrypoint, I, I) -->
|
|
io__write_string(".entrypoint ").
|
|
|
|
ilasm__output_method_body_decl(zeroinit, I, I) -->
|
|
io__write_string(".zeroinit ").
|
|
|
|
ilasm__output_method_body_decl(instrs(Instrs), Info0, Info) -->
|
|
output_instructions(Instrs, Info0, Info).
|
|
|
|
ilasm__output_method_body_decl(label(Label), I, I) -->
|
|
output_label(Label),
|
|
io__write_string(":").
|
|
|
|
:- pred output_label(label::in, io__state::di, io__state::uo) is det.
|
|
output_label(Label) -->
|
|
io__write_string(Label).
|
|
|
|
:- pred output_class_name(ilds__class_name::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_class_name(ClassName, Info0, Info) -->
|
|
output_structured_name(ClassName, Info0, Info).
|
|
|
|
:- pred output_call_conv(call_conv::in, io__state::di, io__state::uo) is det.
|
|
output_call_conv(call_conv(IsInstance, IlCallConv)) -->
|
|
(
|
|
{ IsInstance = yes }
|
|
->
|
|
io__write_string("instance ")
|
|
;
|
|
io__write(IlCallConv),
|
|
io__write_string(" ")
|
|
).
|
|
|
|
:- pred output_name_signature_and_call_conv(signature::in,
|
|
maybe(member_name)::in, string::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_name_signature_and_call_conv(signature(CallConv, ReturnType,
|
|
ArgTypes), MaybeMethodName, Indent, Info0, Info) -->
|
|
output_call_conv(CallConv),
|
|
io__write_string("\n"),
|
|
io__write_string(Indent),
|
|
output_ret_type(ReturnType, Info0, Info1),
|
|
( { MaybeMethodName = yes(MethodName) } ->
|
|
io__write_string("\n"),
|
|
io__write_string(Indent),
|
|
output_member_name(MethodName)
|
|
;
|
|
io__write_string(" ")
|
|
),
|
|
( { ArgTypes = [] } ->
|
|
io__write_string("()"),
|
|
{ Info = Info0 }
|
|
;
|
|
io__write_string("(\n\t\t"),
|
|
ilasm__write_list(ArgTypes, ",\n\t\t", output_param,
|
|
Info1, Info),
|
|
io__write_string("\n\t)")
|
|
).
|
|
|
|
:- pred output_member_name(member_name::in, io__state::di,
|
|
io__state::uo) is det.
|
|
output_member_name(MethodName) -->
|
|
( { MethodName = ctor },
|
|
io__write_string(".ctor")
|
|
; { MethodName = cctor },
|
|
io__write_string(".cctor")
|
|
; { MethodName = id(IlId) },
|
|
output_id(IlId)
|
|
).
|
|
|
|
:- pred output_ret_type(ret_type::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_ret_type(void, I, I) --> io__write_string("void").
|
|
output_ret_type(simple_type(Type), Info0, Info) -->
|
|
output_simple_type(Type, Info0, Info).
|
|
|
|
:- pred output_local(pair(ilds__id, ilds__type)::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_local(Id - Type, Info0, Info) -->
|
|
output_type(Type, Info0, Info),
|
|
io__write_string(" "),
|
|
output_id(Id).
|
|
|
|
:- pred output_param(pair(ilds__type, maybe(ilds__id))::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_param(Type - no, Info0, Info) -->
|
|
output_type(Type, Info0, Info).
|
|
output_param(Type - yes(Id), Info0, Info) -->
|
|
output_type(Type, Info0, Info),
|
|
io__write_string(" "),
|
|
output_id(Id).
|
|
|
|
:- pred output_type(ilds__type::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
output_type(ilds__type(Modifiers, SimpleType), Info0, Info) -->
|
|
io__write_list(Modifiers, " ", output_modifier),
|
|
output_simple_type(SimpleType, Info0, Info).
|
|
|
|
:- pred output_simple_type(simple_type::in,
|
|
ilasm_info::in, ilasm_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
output_simple_type(int8, I, I) --> io__write_string("int8").
|
|
output_simple_type(int16, I, I) --> io__write_string("int16").
|
|
output_simple_type(int32, I, I) --> io__write_string("int32").
|
|
output_simple_type(int64, I, I) --> io__write_string("int64").
|
|
output_simple_type(uint8, I, I) --> io__write_string("unsigned int8").
|
|
output_simple_type(uint16, I, I) --> io__write_string("unsigned int16").
|
|
output_simple_type(uint32, I, I) --> io__write_string("unsigned int32").
|
|
output_simple_type(uint64, I, I) --> io__write_string("unsigned int64").
|
|
output_simple_type(native_int, I, I) --> io__write_string("native int").
|
|
output_simple_type(native_uint, I, I) --> io__write_string("native unsigned int").
|
|
output_simple_type(float32, I, I) --> io__write_string("float32").
|
|
output_simple_type(float64, I, I) --> io__write_string("float64").
|
|
output_simple_type(native_float, I, I) --> io__write_string("native float").
|
|
output_simple_type(bool, I, I) --> io__write_string("bool").
|
|
output_simple_type(char, I, I) --> io__write_string("char").
|
|
output_simple_type(object, I, I) --> io__write_string("object").
|
|
output_simple_type(string, I, I) --> io__write_string("string").
|
|
output_simple_type(refany, I, I) --> io__write_string("refany").
|
|
output_simple_type(class(Name), Info0, Info) -->
|
|
( { name_to_simple_type(Name, Type) } ->
|
|
( { Type = reference(SimpleType) } ->
|
|
output_simple_type(SimpleType, Info0, Info)
|
|
;
|
|
% If it is a value type then we are
|
|
% refering to the boxed version of the
|
|
% value type.
|
|
io__write_string("class "),
|
|
output_structured_name(Name, Info0, Info)
|
|
)
|
|
;
|
|
io__write_string("class "),
|
|
output_structured_name(Name, Info0, Info)
|
|
).
|
|
output_simple_type(valuetype(Name), Info0, Info) -->
|
|
( { name_to_simple_type(Name, Type) } ->
|
|
( { Type = value(SimpleType) } ->
|
|
output_simple_type(SimpleType, Info0, Info)
|
|
;
|
|
{ unexpected(this_file, "builtin reference type") }
|
|
)
|
|
;
|
|
io__write_string("valuetype "),
|
|
output_structured_name(Name, Info0, Info)
|
|
).
|
|
output_simple_type(interface(Name), Info0, Info) -->
|
|
io__write_string("interface "),
|
|
output_structured_name(Name, Info0, Info).
|
|
output_simple_type('[]'(Type, Bounds), Info0, Info) -->
|
|
output_type(Type, Info0, Info),
|
|
output_bounds(Bounds).
|
|
output_simple_type('*'(Type), Info0, Info) -->
|
|
output_type(Type, Info0, Info),
|
|
io__write_string("*").
|
|
output_simple_type('&'(Type), Info0, Info) -->
|
|
output_type(Type, Info0, Info),
|
|
io__write_string("&").
|
|
|
|
:- 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__state::di,
|
|
io__state::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) -->
|
|
{ error("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__state::di, io__state::uo) is det.
|
|
output_bounds(Bounds) -->
|
|
io__write_string("["),
|
|
io__write_list(Bounds, ", ", output_bound),
|
|
io__write_string("]").
|
|
|
|
:- pred output_bound(bound::in, io__state::di, io__state::uo) is det.
|
|
output_bound(upper(X)) -->
|
|
io__write_int(X).
|
|
output_bound(lower(X)) -->
|
|
io__write_int(X),
|
|
io__write_string("...").
|
|
output_bound(between(X, Y)) -->
|
|
io__write_int(X),
|
|
io__write_string("..."),
|
|
io__write_int(Y).
|
|
|
|
|
|
|
|
:- pred output_modifier(ilds__type_modifier::in, io__state::di,
|
|
io__state::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__state::di, io__state::uo) is det.
|
|
|
|
output_instructions(Instructions, Info0, Info) -->
|
|
globals__io_lookup_bool_option(auto_comments, PrintComments),
|
|
globals__io_lookup_bool_option(debug_il_asm, DebugIlAsm),
|
|
(
|
|
{ DebugIlAsm = yes },
|
|
list__foldl2(output_debug_instruction, Instructions, Info0,
|
|
Info)
|
|
;
|
|
{ DebugIlAsm = no },
|
|
list__foldl2(output_instruction(PrintComments), Instructions,
|
|
Info0, Info)
|
|
).
|
|
|
|
|
|
% 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__state::di, io__state::uo) is det.
|
|
|
|
output_debug_instruction(Instr, Info0, Info) -->
|
|
|
|
% 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 } ->
|
|
{ Info = Info0 }
|
|
|
|
% Contexts are messy, let's ignore them for now.
|
|
; { Instr = context(_, _) } ->
|
|
{ Info = Info0 }
|
|
|
|
; { Instr = start_block(catch(ClassName), Id) } ->
|
|
output_instr(start_block(catch(ClassName), Id), Info0, Info1),
|
|
io__write_string("\n"),
|
|
io__write_string("\t"),
|
|
output_trace_instr(Instr, Info1, Info),
|
|
io__write_string("\n")
|
|
|
|
; { Instr = start_block(scope(Locals), Id) } ->
|
|
{ string__format("{\t// #%d", [i(Id)], S) },
|
|
io__write_string(S),
|
|
io__nl,
|
|
output_trace(S),
|
|
|
|
( { Locals = [] } ->
|
|
{ Info = Info0 }
|
|
;
|
|
% output the .locals decl
|
|
io__write_string("\t.locals (\n\t\t"),
|
|
ilasm__write_list(Locals, ",\n\t\t", output_local,
|
|
Info0, Info1),
|
|
io__write_string("\n\t)"),
|
|
io__write_string("\n"),
|
|
|
|
% trace the .locals decl
|
|
io__write_string("\t\tldstr """),
|
|
io__write_string(".locals (\\n\\t\\t"),
|
|
ilasm__write_list(Locals, ",\\n\\t\\t", output_local,
|
|
Info1, Info),
|
|
io__write_string(")"),
|
|
io__write_string("\\n"""),
|
|
io__write_string("\n"),
|
|
io__write_string("\t\tcall void ['mscorlib']System.Console::Write(class ['mscorlib']System.String)\n")
|
|
)
|
|
|
|
;
|
|
output_trace_instr(Instr, Info0, Info1),
|
|
|
|
io__write_string("\t"),
|
|
output_instr(Instr, Info1, Info),
|
|
io__write_string("\n")
|
|
).
|
|
|
|
:- pred output_trace_instr(instr::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_trace_instr(Instr, Info0, Info) -->
|
|
io__write_string("\t\tldstr """),
|
|
% We have to quote loadstrings.
|
|
( { Instr = ldstr(LoadString) } ->
|
|
{ Info = Info0 },
|
|
io__write_string("ldstr \\"""),
|
|
output_escaped_string(LoadString, '\"'),
|
|
io__write_string("\\""")
|
|
% XXX there could be issues with
|
|
% comments containing embedded newlines
|
|
; { Instr = comment(Comment) } ->
|
|
{ Info = Info0 },
|
|
io__write_string("comment: "),
|
|
io__write_string(Comment)
|
|
;
|
|
output_instr(Instr, Info0, Info)
|
|
),
|
|
io__write_string("\\n"),
|
|
io__write_string("""\n"),
|
|
io__write_string("\t\tcall void ['mscorlib']System.Console::Write(class ['mscorlib']System.String)\n").
|
|
|
|
|
|
:- pred output_trace(string, io__state, io__state).
|
|
:- mode output_trace(in, di, uo) is det.
|
|
output_trace(S) -->
|
|
io__write_string("\t\tldstr """),
|
|
io__write_string(S),
|
|
io__write_string("\\n""\n"),
|
|
io__write_string("\t\tcall void ['mscorlib']System.Console::Write(class System.String)\n").
|
|
|
|
:- pred output_instruction(bool::in, instr::in,
|
|
ilasm_info::in, ilasm_info::out, io__state::di, io__state::uo) is det.
|
|
|
|
output_instruction(PrintComments, Instr, Info0, Info) -->
|
|
( { Instr = comment(_), PrintComments = no } ->
|
|
{ Info = Info0 }
|
|
;
|
|
io__write_string("\t"),
|
|
output_instr(Instr, Info0, Info),
|
|
io__write_string("\n")
|
|
).
|
|
|
|
:- pred output_instr(instr::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
output_instr(il_asm_code(Code, _MaxStack), I, I) -->
|
|
io__write_string(Code).
|
|
|
|
output_instr(comment(Comment), I, I) -->
|
|
output_comment_string(Comment).
|
|
|
|
output_instr(label(Label), I, I) -->
|
|
output_label(Label),
|
|
io__write_string(":").
|
|
|
|
output_instr(start_block(scope(Locals), Id), Info0, Info) -->
|
|
io__write_string("{"),
|
|
io__write_string("\t// #"),
|
|
io__write_int(Id),
|
|
( { Locals = [] } ->
|
|
{ Info = Info0 }
|
|
;
|
|
io__write_string("\n\t.locals (\n\t\t"),
|
|
ilasm__write_list(Locals, ",\n\t\t", output_local, Info0, Info),
|
|
io__write_string("\n\t)\n")
|
|
).
|
|
|
|
output_instr(start_block(try, Id), I, I) -->
|
|
io__write_string(".try {"),
|
|
io__write_string("\t// #"),
|
|
io__write_int(Id).
|
|
|
|
output_instr(start_block(catch(ClassName), Id), Info0, Info) -->
|
|
io__write_string("catch "),
|
|
output_class_name(ClassName, Info0, Info),
|
|
io__write_string(" {"),
|
|
io__write_string("\t// #"),
|
|
io__write_int(Id).
|
|
|
|
output_instr(end_block(scope(_), Id), I, I) -->
|
|
io__write_string("}"),
|
|
io__write_string("\t// #"),
|
|
io__write_int(Id).
|
|
|
|
output_instr(end_block(catch(_), Id), I, I) -->
|
|
io__write_string("}"),
|
|
io__write_string("\t// #"),
|
|
io__write_int(Id),
|
|
io__write_string(" (catch block)").
|
|
|
|
output_instr(end_block(try, Id), I, I) -->
|
|
io__write_string("}"),
|
|
io__write_string("\t// #"),
|
|
io__write_int(Id),
|
|
io__write_string(" (try block)").
|
|
|
|
output_instr(context(File, Line), I, I) -->
|
|
io_lookup_bool_option(line_numbers, LineNumbers),
|
|
( { LineNumbers = yes } ->
|
|
io__write_string("\n\t.line "),
|
|
io__write_int(Line),
|
|
io__write_string(" '"),
|
|
io__write_string(File),
|
|
io__write_string("'")
|
|
;
|
|
[]
|
|
).
|
|
|
|
output_instr(call(MethodRef), Info0, Info) -->
|
|
io__write_string("call\t"),
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
output_instr(callvirt(MethodRef), Info0, Info) -->
|
|
io__write_string("callvirt\t"),
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
output_instr(calli(Signature), Info0, Info) -->
|
|
io__write_string("calli\t"),
|
|
output_name_signature_and_call_conv(Signature, no, "\t\t", Info0, Info).
|
|
|
|
output_instr(ret, I, I) -->
|
|
io__write_string("ret").
|
|
output_instr((and), I, I) -->
|
|
io__write_string("and").
|
|
output_instr(arglist, I, I) -->
|
|
io__write_string("arglist").
|
|
output_instr(break, I, I) -->
|
|
io__write_string("break").
|
|
output_instr(ceq, I, I) -->
|
|
io__write_string("ceq").
|
|
output_instr(ckfinite, I, I) -->
|
|
io__write_string("ckfinite").
|
|
output_instr(cpblk, I, I) -->
|
|
io__write_string("cpblk").
|
|
output_instr(dup, I, I) -->
|
|
io__write_string("dup").
|
|
output_instr(endfilter, I, I) -->
|
|
io__write_string("endfilter").
|
|
output_instr(endfinally, I, I) -->
|
|
io__write_string("endfinally").
|
|
output_instr(initblk, I, I) -->
|
|
io__write_string("initblk").
|
|
output_instr(ldnull, I, I) -->
|
|
io__write_string("ldnull").
|
|
output_instr(localloc, I, I) -->
|
|
io__write_string("localloc").
|
|
output_instr(neg, I, I) -->
|
|
io__write_string("neg").
|
|
output_instr(nop, I, I) -->
|
|
io__write_string("nop").
|
|
output_instr((not), I, I) -->
|
|
io__write_string("not").
|
|
output_instr((or), I, I) -->
|
|
io__write_string("or").
|
|
output_instr(pop, I, I) -->
|
|
io__write_string("pop").
|
|
output_instr(shl, I, I) -->
|
|
io__write_string("shl").
|
|
output_instr(tailcall, I, I) -->
|
|
io__write_string("tail.").
|
|
output_instr(volatile, I, I) -->
|
|
io__write_string("volatile").
|
|
output_instr(xor, I, I) -->
|
|
io__write_string("xor").
|
|
output_instr(ldlen, I, I) -->
|
|
io__write_string("ldlen").
|
|
output_instr(throw, I, I) -->
|
|
io__write_string("throw").
|
|
|
|
% There are short forms of various instructions.
|
|
% The assembler can't generate them for you.
|
|
output_instr(ldarg(index(Index)), I, I) -->
|
|
( { Index < 4 } ->
|
|
io__write_string("ldarg."),
|
|
io__write_int(Index)
|
|
; { Index < 256 } ->
|
|
io__write_string("ldarg.s\t"),
|
|
output_index(Index)
|
|
;
|
|
io__write_string("ldarg\t"),
|
|
output_index(Index)
|
|
).
|
|
output_instr(ldarg(name(Id)), I, I) -->
|
|
io__write_string("ldarg\t"),
|
|
output_id(Id).
|
|
|
|
% Lots of short forms for loading integer.
|
|
% XXX Should probably put the magic numbers in functions.
|
|
output_instr(ldc(Type, Const), I, I) -->
|
|
( { ( Type = int32 ; Type = bool ), Const = i(IntConst) } ->
|
|
( { IntConst < 8, IntConst >= 0 } ->
|
|
io__write_string("ldc.i4."),
|
|
io__write_int(IntConst)
|
|
; { IntConst = -1 } ->
|
|
io__write_string("ldc.i4.m1")
|
|
; { IntConst < 128, IntConst > -128 } ->
|
|
io__write_string("ldc.i4.s\t"),
|
|
io__write_int(IntConst)
|
|
;
|
|
io__write_string("ldc.i4\t"),
|
|
io__write_int(IntConst)
|
|
)
|
|
; { Type = int64, Const = i(IntConst) } ->
|
|
io__write_string("ldc.i8\t"),
|
|
io__write_int(IntConst)
|
|
; { Type = float32, Const = f(FloatConst) } ->
|
|
io__write_string("ldc.r4\t"),
|
|
c_util__output_float_literal(FloatConst)
|
|
; { Type = float64, Const = f(FloatConst) } ->
|
|
io__write_string("ldc.r8\t"),
|
|
c_util__output_float_literal(FloatConst)
|
|
;
|
|
{ error("Inconsistent arguments in ldc instruction") }
|
|
).
|
|
|
|
output_instr(ldstr(String), I, I) -->
|
|
io__write_string("ldstr\t"),
|
|
output_string_constant(String).
|
|
|
|
|
|
% XXX might use this later.
|
|
:- func max_efficient_encoding_short = int.
|
|
max_efficient_encoding_short = 256.
|
|
|
|
output_instr(add(Overflow, Signed), I, I) -->
|
|
io__write_string("add"),
|
|
output_overflow(Overflow),
|
|
output_signed(Signed).
|
|
|
|
output_instr(beq(Target), I, I) -->
|
|
io__write_string("beq "),
|
|
output_target(Target).
|
|
|
|
output_instr(bge(Signed, Target), I, I) -->
|
|
io__write_string("bge"),
|
|
output_signed(Signed),
|
|
io__write_string("\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(bgt(Signed, Target), I, I) -->
|
|
io__write_string("bgt"),
|
|
output_signed(Signed),
|
|
io__write_string("\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(ble(Signed, Target), I, I) -->
|
|
io__write_string("ble"),
|
|
output_signed(Signed),
|
|
io__write_string("\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(blt(Signed, Target), I, I) -->
|
|
io__write_string("blt"),
|
|
output_signed(Signed),
|
|
io__write_string("\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(bne(Signed, Target), I, I) -->
|
|
io__write_string("bne"),
|
|
output_signed(Signed),
|
|
io__write_string("\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(br(Target), I, I) -->
|
|
io__write_string("br\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(brfalse(Target), I, I) -->
|
|
io__write_string("brfalse\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(brtrue(Target), I, I) -->
|
|
io__write_string("brtrue\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(cgt(Signed), I, I) -->
|
|
io__write_string("cgt"),
|
|
output_signed(Signed).
|
|
|
|
output_instr(clt(Signed), I, I) -->
|
|
io__write_string("clt"),
|
|
output_signed(Signed).
|
|
|
|
output_instr(conv(SimpleType), I, I) -->
|
|
io__write_string("conv."),
|
|
output_simple_type_opcode(SimpleType).
|
|
|
|
output_instr(div(Signed), I, I) -->
|
|
io__write_string("div"),
|
|
output_signed(Signed).
|
|
|
|
output_instr(jmp(MethodRef), Info0, Info) -->
|
|
io__write_string("jmp\t"),
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(ldarga(Variable), I, I) -->
|
|
io__write_string("ldarga\t"),
|
|
( { Variable = index(Index) }, output_index(Index)
|
|
; { Variable = name(Name) }, output_id(Name)
|
|
).
|
|
|
|
output_instr(ldftn(MethodRef), Info0, Info) -->
|
|
io__write_string("ldftn\t"),
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
output_instr(ldind(SimpleType), I, I) -->
|
|
io__write_string("ldind."),
|
|
output_simple_type_opcode(SimpleType).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(ldloc(Variable), I, I) -->
|
|
io__write_string("ldloc\t"),
|
|
( { Variable = index(Index) }, output_index(Index)
|
|
; { Variable = name(Name) }, output_id(Name)
|
|
).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(ldloca(Variable), I, I) -->
|
|
io__write_string("ldloca\t"),
|
|
( { Variable = index(Index) }, output_index(Index)
|
|
; { Variable = name(Name) }, output_id(Name)
|
|
).
|
|
|
|
output_instr(leave(Target), I, I) -->
|
|
io__write_string("leave\t"),
|
|
output_target(Target).
|
|
|
|
output_instr(mul(Overflow, Signed), I, I) -->
|
|
io__write_string("mul"),
|
|
output_overflow(Overflow),
|
|
output_signed(Signed).
|
|
|
|
output_instr(rem(Signed), I, I) -->
|
|
io__write_string("rem"),
|
|
output_signed(Signed).
|
|
|
|
output_instr(shr(Signed), I, I) -->
|
|
io__write_string("shr"),
|
|
output_signed(Signed).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(starg(Variable), I, I) -->
|
|
io__write_string("starg\t"),
|
|
( { Variable = index(Index) }, output_index(Index)
|
|
; { Variable = name(Name) }, output_id(Name)
|
|
).
|
|
|
|
% XXX can use short encoding for indexes
|
|
output_instr(stind(SimpleType), I, I) -->
|
|
io__write_string("stind."),
|
|
output_simple_type_opcode(SimpleType).
|
|
|
|
output_instr(stloc(Variable), I, I) -->
|
|
io__write_string("stloc\t"),
|
|
( { Variable = index(Index) }, output_index(Index)
|
|
; { Variable = name(Name) }, output_id(Name)
|
|
).
|
|
|
|
output_instr(sub(OverFlow, Signed), I, I) -->
|
|
io__write_string("sub"),
|
|
output_overflow(OverFlow),
|
|
output_signed(Signed).
|
|
|
|
output_instr(switch(Targets), I, I) -->
|
|
io__write_string("switch ("),
|
|
io__write_list(Targets, ", ", output_target),
|
|
io__write_string(")").
|
|
|
|
output_instr(unaligned(_), I, I) -->
|
|
io__write_string("unaligned.").
|
|
|
|
output_instr(box(Type), Info0, Info) -->
|
|
io__write_string("box\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(castclass(Type), Info0, Info) -->
|
|
(
|
|
{ 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__write_string("castclass\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(cpobj(Type), Info0, Info) -->
|
|
io__write_string("cpobj\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(initobj(Type), Info0, Info) -->
|
|
io__write_string("initobj\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(isinst(Type), Info0, Info) -->
|
|
io__write_string("isinst\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(ldelem(SimpleType), I, I) -->
|
|
io__write_string("ldelem."),
|
|
output_simple_type_opcode(SimpleType).
|
|
|
|
output_instr(ldelema(Type), Info0, Info) -->
|
|
io__write_string("ldelema\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(ldfld(FieldRef), Info0, Info) -->
|
|
io__write_string("ldfld\t"),
|
|
output_fieldref(FieldRef, Info0, Info).
|
|
|
|
output_instr(ldflda(FieldRef), Info0, Info) -->
|
|
io__write_string("ldflda\t"),
|
|
output_fieldref(FieldRef, Info0, Info).
|
|
|
|
output_instr(ldobj(Type), Info0, Info) -->
|
|
io__write_string("ldobj\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(ldsfld(FieldRef), Info0, Info) -->
|
|
io__write_string("ldsfld\t"),
|
|
output_fieldref(FieldRef, Info0, Info).
|
|
|
|
output_instr(ldsflda(FieldRef), Info0, Info) -->
|
|
io__write_string("ldsflda\t"),
|
|
output_fieldref(FieldRef, Info0, Info).
|
|
|
|
% XXX should be implemented
|
|
output_instr(ldtoken(_), I, I) --> { error("output not implemented") }.
|
|
|
|
output_instr(ldvirtftn(MethodRef), Info0, Info) -->
|
|
io__write_string("ldvirtftn\t"),
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
output_instr(mkrefany(Type), Info0, Info) -->
|
|
io__write_string("mkrefany\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(newarr(Type), Info0, Info) -->
|
|
io__write_string("newarr\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(newobj(MethodRef), Info0, Info) -->
|
|
io__write_string("newobj\t"),
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
output_instr(refanytype, I, I) -->
|
|
io__write_string("refanytype").
|
|
|
|
output_instr(refanyval(Type), Info0, Info) -->
|
|
io__write_string("refanyval\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(rethrow, I, I) -->
|
|
io__write_string("rethrow").
|
|
|
|
output_instr(stelem(SimpleType), I, I) -->
|
|
io__write_string("stelem."),
|
|
output_simple_type_opcode(SimpleType).
|
|
|
|
output_instr(stfld(FieldRef), Info0, Info) -->
|
|
io__write_string("stfld\t"),
|
|
output_fieldref(FieldRef, Info0, Info).
|
|
|
|
output_instr(stobj(Type), Info0, Info) -->
|
|
io__write_string("stobj\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(sizeof(Type), Info0, Info) -->
|
|
io__write_string("sizeof\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
output_instr(stsfld(FieldRef), Info0, Info) -->
|
|
io__write_string("stsfld\t"),
|
|
output_fieldref(FieldRef, Info0, Info).
|
|
|
|
output_instr(unbox(Type), Info0, Info) -->
|
|
io__write_string("unbox\t"),
|
|
output_type(Type, Info0, Info).
|
|
|
|
:- pred output_overflow(overflow::in, io__state::di,
|
|
io__state::uo) is det.
|
|
output_overflow(OverFlow) -->
|
|
(
|
|
{ OverFlow = checkoverflow },
|
|
io__write_string(".ovf")
|
|
;
|
|
{ OverFlow = nocheckoverflow }
|
|
).
|
|
|
|
:- pred output_signed(signed::in, io__state::di, io__state::uo) is det.
|
|
output_signed(Signed) -->
|
|
(
|
|
{ Signed = signed }
|
|
;
|
|
{ Signed = unsigned },
|
|
io__write_string(".un")
|
|
).
|
|
|
|
:- pred output_target(target::in, io__state::di, io__state::uo) is det.
|
|
output_target(offset_target(Target)) -->
|
|
io__write_int(Target).
|
|
output_target(label_target(Label)) -->
|
|
output_label(Label).
|
|
|
|
|
|
:- pred output_fieldref(fieldref::in,
|
|
ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_fieldref(fieldref(Type, ClassMemberName), Info0, Info) -->
|
|
output_type(Type, Info0, Info1),
|
|
io__write_string("\n\t\t"),
|
|
output_class_member_name(ClassMemberName, Info1, Info).
|
|
|
|
:- pred output_methodref(methodref::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_methodref(methoddef(call_conv(IsInstance, _), ReturnType,
|
|
ClassMemberName, ArgTypes), Info0, Info) -->
|
|
( { IsInstance = yes } ->
|
|
io__write_string("instance ")
|
|
;
|
|
[]
|
|
),
|
|
output_ret_type(ReturnType, Info0, Info1),
|
|
io__write_string("\n\t\t"),
|
|
output_class_member_name(ClassMemberName, Info1, Info2),
|
|
( { ArgTypes = [] } ->
|
|
io__write_string("()\n"),
|
|
{ Info = Info0 }
|
|
;
|
|
io__write_string("(\n\t\t\t"),
|
|
ilasm__write_list(ArgTypes, ",\n\t\t\t", output_type,
|
|
Info2, Info),
|
|
io__write_string("\n\t\t)")
|
|
).
|
|
output_methodref(local_method(call_conv(IsInstance, _), ReturnType,
|
|
MethodName, ArgTypes), Info0, Info) -->
|
|
( { IsInstance = yes } ->
|
|
io__write_string("instance ")
|
|
;
|
|
[]
|
|
),
|
|
output_ret_type(ReturnType, Info0, Info1),
|
|
io__write_string("\n\t\t"),
|
|
output_member_name(MethodName),
|
|
( { ArgTypes = [] } ->
|
|
io__write_string("()\n"),
|
|
{ Info = Info0 }
|
|
;
|
|
io__write_string("(\n\t\t\t"),
|
|
ilasm__write_list(ArgTypes, ",\n\t\t\t", output_type,
|
|
Info1, Info),
|
|
io__write_string("\n\t\t)")
|
|
).
|
|
|
|
:- pred output_classattr(classattr::in, io__state::di, io__state::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__state::di, io__state::uo) is det.
|
|
|
|
ilasm__output_assembly_decl(version(A, B, C, D), I, I) -->
|
|
io__format(".ver %d:%d:%d:%d", [i(A), i(B), i(C), i(D)]).
|
|
ilasm__output_assembly_decl(public_key_token(Token), I, I) -->
|
|
io__write_string(".publickeytoken = ( "),
|
|
io__write_list(Token, " ", output_hexbyte),
|
|
io__write_string(" ) ").
|
|
ilasm__output_assembly_decl(hash(Hash), I, I) -->
|
|
io__write_string(".hash = ( "),
|
|
io__write_list(Hash, " ", output_hexbyte),
|
|
io__write_string(" ) ").
|
|
ilasm__output_assembly_decl(custom(CustomDecl), Info0, Info) -->
|
|
output_custom_decl(CustomDecl, Info0, Info).
|
|
|
|
:- pred output_custom_decl(custom_decl::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_custom_decl(custom_decl(Type, MaybeOwner, StringOrBytes),
|
|
Info0, Info) -->
|
|
io__write_string(".custom "),
|
|
|
|
( { MaybeOwner = yes(Owner) } ->
|
|
io__write_string(" ("),
|
|
output_custom_type(Owner, Info0, Info1),
|
|
io__write_string(") ")
|
|
;
|
|
{ Info1 = Info0 }
|
|
),
|
|
output_custom_type(Type, Info1, Info),
|
|
( { StringOrBytes = bytes(Bytes) } ->
|
|
io__write_string(" = ("),
|
|
io__write_list(Bytes, " ", output_hexbyte),
|
|
io__write_string(")")
|
|
;
|
|
{ sorry(this_file, "custom_decl of this sort") }
|
|
),
|
|
io__write_string("\n").
|
|
|
|
:- pred output_custom_type(custom_type::in, ilasm_info::in, ilasm_info::out,
|
|
io__state::di, io__state::uo) is det.
|
|
output_custom_type(type(Type), Info0, Info) -->
|
|
output_type(Type, Info0, Info).
|
|
output_custom_type(methodref(MethodRef), Info0, Info) -->
|
|
output_methodref(MethodRef, Info0, Info).
|
|
|
|
:- pred output_index(index::in, io__state::di, io__state::uo) is det.
|
|
output_index(Index) -->
|
|
io__write_int(Index).
|
|
|
|
:- pred output_string_constant(string::in, io__state::di, io__state::uo)
|
|
is det.
|
|
output_string_constant(String) -->
|
|
io__write_string(""""),
|
|
output_escaped_string(String, '\"'),
|
|
io__write_string("""").
|
|
|
|
:- pred output_class_member_name(class_member_name::in,
|
|
ilasm_info::in, ilasm_info::out, io__state::di, io__state::uo) is det.
|
|
output_class_member_name(class_member_name(StructuredName, MemberName),
|
|
Info0, Info) -->
|
|
output_structured_name(StructuredName, Info0, Info),
|
|
io__write_string("::"),
|
|
output_member_name(MemberName).
|
|
|
|
:- pred output_structured_name(structured_name::in, ilasm_info::in,
|
|
ilasm_info::out, io__state::di, io__state::uo) is det.
|
|
output_structured_name(structured_name(Asm, DottedName, NestedClasses),
|
|
Info, Info) -->
|
|
globals__io_lookup_bool_option(separate_assemblies, SeparateAssemblies),
|
|
( { Asm = assembly(Assembly) },
|
|
maybe_output_quoted_assembly_name(Assembly, Info)
|
|
; { Asm = module(Module, Assembly) },
|
|
( { SeparateAssemblies = yes },
|
|
maybe_output_quoted_assembly_name(Module, Info)
|
|
; { SeparateAssemblies = no },
|
|
(
|
|
{ Info ^ current_assembly \= "" },
|
|
{ string__prefix(Module,
|
|
Info ^ current_assembly) }
|
|
->
|
|
{ quote_id(Module ++ ".dll",
|
|
QuotedModuleName) },
|
|
io__format("[.module %s]",
|
|
[s(QuotedModuleName)])
|
|
;
|
|
maybe_output_quoted_assembly_name(Assembly,
|
|
Info)
|
|
)
|
|
)
|
|
),
|
|
output_dotted_name(DottedName),
|
|
output_nested_class_quals(NestedClasses).
|
|
|
|
|
|
:- pred maybe_output_quoted_assembly_name(ilds__id::in, ilasm_info::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
maybe_output_quoted_assembly_name(Assembly, Info) -->
|
|
( { Assembly \= "", Assembly \= Info ^ current_assembly } ->
|
|
{ quote_id(Assembly, QuotedAssemblyName) },
|
|
io__format("[%s]", [s(QuotedAssemblyName)])
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred output_dotted_name(namespace_qual_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
output_dotted_name(Name) -->
|
|
io__write_list(Name, ".", output_id).
|
|
|
|
:- pred output_nested_class_quals(nested_class_name::in,
|
|
io__state::di, io__state::uo) is det.
|
|
output_nested_class_quals(Name) -->
|
|
list__foldl(
|
|
(pred(Id::in, di, uo) is det -->
|
|
io__write_char('/'), output_id(Id)),
|
|
Name).
|
|
|
|
:- pred output_id(ilds__id::in, io__state::di, io__state::uo) is det.
|
|
output_id(Id) -->
|
|
{ quote_id(Id, QuotedId) },
|
|
io__write_string(QuotedId).
|
|
|
|
:- pred output_field_initializer(field_initializer::in, io__state::di,
|
|
io__state::uo) is det.
|
|
output_field_initializer(none) --> [].
|
|
output_field_initializer(at(Id)) -->
|
|
io__write_string(" at "),
|
|
output_id(Id).
|
|
output_field_initializer(equals(FieldInit)) -->
|
|
io__write_string(" = "),
|
|
output_field_init(FieldInit).
|
|
|
|
:- pred output_field_init(field_init::in, io__state::di, io__state::uo) is det.
|
|
output_field_init(binary_float64(Int64)) -->
|
|
io__write_string("float64("),
|
|
output_int64(Int64),
|
|
io__write_string(")").
|
|
output_field_init(binary_float32(Int32)) -->
|
|
io__write_string("float32("),
|
|
output_int32(Int32),
|
|
io__write_string(")").
|
|
output_field_init(wchar_ptr(String)) -->
|
|
io__write_string("wchar *("),
|
|
io__write(String),
|
|
io__write_string(")").
|
|
% XXX should check for invalid data_items
|
|
output_field_init(data_item(DataItem)) -->
|
|
( { DataItem = char_ptr(String) } ->
|
|
io__write(String)
|
|
;
|
|
output_data_item(DataItem)
|
|
).
|
|
|
|
|
|
:- pred output_data_body(data_body::in, io__state::di, io__state::uo) is det.
|
|
output_data_body(itemlist(DataItemList)) -->
|
|
io__write_string("{"),
|
|
io__write_list(DataItemList, ", ", output_data_item),
|
|
io__write_string("}").
|
|
output_data_body(item(DataItem)) -->
|
|
output_data_item(DataItem).
|
|
|
|
:- pred output_data_item(data_item::in, io__state::di, io__state::uo) is det.
|
|
output_data_item(float64(Float)) -->
|
|
io__write_string("float64("),
|
|
output_float64(Float),
|
|
io__write_string(")").
|
|
output_data_item(float32(Float32)) -->
|
|
io__write_string("float32("),
|
|
output_float32(Float32),
|
|
io__write_string(")").
|
|
output_data_item(int64(Int64)) -->
|
|
io__write_string("int64("),
|
|
output_int64(Int64),
|
|
io__write_string(")").
|
|
output_data_item(int32(Int32)) -->
|
|
io__write_string("int32("),
|
|
output_int32(Int32),
|
|
io__write_string(")").
|
|
output_data_item(int16(Int16)) -->
|
|
io__write_string("int16("),
|
|
output_int16(Int16),
|
|
io__write_string(")").
|
|
output_data_item(int8(Int8)) -->
|
|
io__write_string("int8("),
|
|
output_int8(Int8),
|
|
io__write_string(")").
|
|
output_data_item(char_ptr(String)) -->
|
|
io__write_string("char *("),
|
|
io__write(String),
|
|
io__write_string(")").
|
|
output_data_item('&'(Id)) -->
|
|
io__write_string("&("),
|
|
output_id(Id),
|
|
io__write_string(")").
|
|
output_data_item(bytearray(Bytes)) -->
|
|
io__write_string("bytearray("),
|
|
io__write_list(Bytes, " ", output_hexbyte),
|
|
io__write_string(")").
|
|
|
|
:- pred output_float64(float64::in, io__state::di, io__state::uo) is det.
|
|
output_float64(float64(Float)) -->
|
|
io__write_float(Float).
|
|
|
|
:- pred output_float32(float32::in, io__state::di, io__state::uo) is det.
|
|
output_float32(float32(Float)) -->
|
|
io__write_float(Float).
|
|
|
|
:- pred output_int64(int64::in, io__state::di, io__state::uo) is det.
|
|
output_int64(int64(Integer)) -->
|
|
io__write_string(integer__to_string(Integer)).
|
|
|
|
:- pred output_int32(int32::in, io__state::di, io__state::uo) is det.
|
|
output_int32(int32(Int)) -->
|
|
io__write_int(Int).
|
|
|
|
:- pred output_int16(int16::in, io__state::di, io__state::uo) is det.
|
|
output_int16(int16(Int)) -->
|
|
io__write_int(Int).
|
|
|
|
:- pred output_int8(int8::in, io__state::di, io__state::uo) is det.
|
|
output_int8(int8(Int)) -->
|
|
io__write_int(Int).
|
|
|
|
:- pred output_byte(byte::in, io__state::di, io__state::uo) is det.
|
|
output_byte(Byte) --> output_int8(Byte).
|
|
|
|
:- pred output_hexbyte(byte::in, io__state::di, io__state::uo) is det.
|
|
output_hexbyte(int8(Int)) -->
|
|
{ string__int_to_base_string(Int, 16, Tmp) },
|
|
io__write_string(Tmp).
|
|
|
|
:- pred output_comment_string(string::in, io__state::di, io__state::uo) is det.
|
|
output_comment_string(Comment) -->
|
|
io__write_string("// "),
|
|
{ CommentDoc = separated(text, line,
|
|
string__words((pred('\n'::in) is semidet :- true), Comment)) },
|
|
{ Doc = label("\t// ", CommentDoc) },
|
|
write(70, Doc).
|
|
|
|
% 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__state::di, io__state::uo) is det.
|
|
output_escaped_string(String, EscapeChar) -->
|
|
{ escape_string(String, EscapeChar, EscapedString) },
|
|
io__write_string(EscapedString).
|
|
|
|
% 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.
|