1016 lines
45 KiB
C#
1016 lines
45 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Specialized;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using ElementTypes = Bartok.MSIL.ElementTypes;
|
|
using Bartok.MSIL;
|
|
|
|
public class ilgen: ITrackable {
|
|
public static compilation visit(compilation ast, TextWriter w, string[] args, MessageWriter msg) {
|
|
if (msg.Count == 0)
|
|
new ilgen(w, msg).compilation(ast);
|
|
return ast;
|
|
}
|
|
|
|
public Stack asts = new Stack(); // top element is current ast node
|
|
public string mainTypeName = null;
|
|
public StringDictionary moduleMap = new StringDictionary();
|
|
public MessageWriter msg;
|
|
public TextWriter wr;
|
|
public BuiltinTypes T;
|
|
public ilgen(TextWriter wr, compilation_unit ast) : this(wr, new MessageWriter()) {
|
|
T = ((compilation)ast.parent).global.Types;
|
|
}
|
|
public ilgen(TextWriter wr, MessageWriter msg) {
|
|
this.wr = wr;
|
|
this.msg = msg;
|
|
}
|
|
|
|
// ITrackable
|
|
public object subject {
|
|
get { return asts.Count > 0 ? asts.Peek() : null; }
|
|
}
|
|
|
|
public virtual ILState NewILState(ilgen parent) {
|
|
return new ILState(parent);
|
|
}
|
|
public class ILState: gen {
|
|
protected ilgen parent;
|
|
protected int depth = 0;
|
|
public int maxstack = 0;
|
|
protected int offset = 0;
|
|
protected TextWriter w;
|
|
|
|
public ILState(ilgen parent) : base(parent.T, parent.msg, parent.asts) {
|
|
this.parent = parent;
|
|
this.w = parent.wr;
|
|
}
|
|
override public object BeginTry() {
|
|
Emit(".try {{");
|
|
return base.BeginTry();
|
|
}
|
|
override public object BeginFinally(object handle) {
|
|
base.BeginFinally(handle);
|
|
Emit("}}");
|
|
Emit("finally {{");
|
|
return -(int)handle;
|
|
}
|
|
override public void boolean_value(binary_expression ast) {
|
|
base.boolean_value(ast);
|
|
if (!(ast.method != null && ast.method.Type == parent.T.Bool && ast.method.declSpace != null))
|
|
Depth -= 1; // account for two loads in boolean_value
|
|
}
|
|
override public void catch_clause(Type ty, Local sym, statement block, object handle) {
|
|
gotoLabel(OpCodes.Leave, (int)handle);
|
|
Emit("}}");
|
|
Emit("catch {0} {{", ClassRef(ty));
|
|
Depth += 1;
|
|
base.catch_clause(ty, sym, block, handle);
|
|
}
|
|
string ClassRef(Type t) { return parent.ClassRef(t); }
|
|
override public void defLabel(int lab) {
|
|
Emit("{0}:", getLabel(lab));
|
|
}
|
|
public int Depth {
|
|
get { return depth; }
|
|
set {
|
|
//w.WriteLine("//depth={0}", value);
|
|
depth = value;
|
|
if (depth < 0) {
|
|
Debug.Assert(depth >= 0);
|
|
depth = 0;
|
|
}
|
|
maxstack = Math.Max(depth, maxstack);
|
|
}
|
|
}
|
|
public void Emit(string fmt, params object[] operands) {
|
|
w.WriteLine(fmt, operands);
|
|
}
|
|
public void Emit(OpCode op, params string[] operands) {
|
|
w.Write(op);
|
|
foreach (string s in operands)
|
|
w.Write(" {0}", s);
|
|
w.WriteLine();
|
|
switch (op.StackBehaviourPop) {
|
|
case StackBehaviour.Pop0: break;
|
|
case StackBehaviour.Varpop: break;
|
|
case StackBehaviour.Popref:
|
|
case StackBehaviour.Popi:
|
|
case StackBehaviour.Pop1: Depth -= 1; break;
|
|
case StackBehaviour.Pop1_pop1:
|
|
case StackBehaviour.Popi_pop1:
|
|
case StackBehaviour.Popi_popi:
|
|
case StackBehaviour.Popi_popi8:
|
|
case StackBehaviour.Popi_popr4:
|
|
case StackBehaviour.Popi_popr8:
|
|
case StackBehaviour.Popref_pop1:
|
|
case StackBehaviour.Popref_popi: Depth -= 2; break;
|
|
case StackBehaviour.Popi_popi_popi:
|
|
case StackBehaviour.Popref_popi_popi:
|
|
case StackBehaviour.Popref_popi_popi8:
|
|
case StackBehaviour.Popref_popi_popr4:
|
|
case StackBehaviour.Popref_popi_popr8:
|
|
case StackBehaviour.Popref_popi_popref: Depth -= 3; break;
|
|
default: throw new ArgumentException("unknown opcode " + op.ToString());
|
|
}
|
|
switch (op.StackBehaviourPush) {
|
|
case StackBehaviour.Varpush: break;
|
|
case StackBehaviour.Push0: break;
|
|
case StackBehaviour.Pushi:
|
|
case StackBehaviour.Pushi8:
|
|
case StackBehaviour.Pushr4:
|
|
case StackBehaviour.Pushr8:
|
|
case StackBehaviour.Pushref:
|
|
case StackBehaviour.Push1: Depth += 1; break;
|
|
case StackBehaviour.Push1_push1: Depth += 2; break;
|
|
default: throw new ArgumentException("unknown opcode " + op.ToString());
|
|
}
|
|
}
|
|
override public void Emit(OpCode op) { Emit(op, new string[0]); }
|
|
override public void Emit(OpCode op, Constructor x) { Emit(op, (Method)x); }
|
|
override public void Emit(OpCode op, float x) { Emit(op, x.ToString()); }
|
|
override public void Emit(OpCode op, double x) { Emit(op, x.ToString()); }
|
|
override public void Emit(OpCode op, Field x) {
|
|
Emit(op, Name(x.Type), FieldRef(x));
|
|
}
|
|
override public void Emit(OpCode op, Formal x) { Emit(op, (Local)x); }
|
|
override public void Emit(OpCode op, int x) { Emit(op, x.ToString()); }
|
|
override public void Emit(OpCode op, Local x) {
|
|
Emit(op, String.Format("{0} // {1}", x.ordinal, x.Name));
|
|
}
|
|
override public void Emit(OpCode op, Method x) {
|
|
Emit(op, x.IsInstance ? "instance" : "", Name(x.Type), MethodRef(x));
|
|
if (op.Name == "newobj")
|
|
Depth -= x.ArgCount;
|
|
else if (op.Name.StartsWith("call")) {
|
|
Depth -= x.ArgCount + (x.IsInstance ? 1 : 0);
|
|
if (x.Name == "set_Item")
|
|
Depth -= 1; // value argument
|
|
if (x.Type != parent.T.Void)
|
|
Depth += 1;
|
|
}
|
|
}
|
|
override public void Emit(OpCode op, string x) { Emit(op, quote(x)); }
|
|
override public void Emit(OpCode op, Type x) { Emit(op, Name(x)); }
|
|
override public void EmitCreateArray(ArrayType ty, Type ety, int rank) {
|
|
Emit(OpCodes.Newobj, "instance void",
|
|
String.Format("{0}::.ctor({1})", Name(ty), repl(",int32", rank).Substring(1)));
|
|
Depth -= rank;
|
|
}
|
|
override public void EmitLoad(int index) {
|
|
Emit(OpCodes.Ldloc, String.Format("{0} // t{0}", index));
|
|
}
|
|
override public void EmitLoadAddress(int index) {
|
|
Emit(OpCodes.Ldloca, String.Format("{0} // t{0}", index));
|
|
}
|
|
override public void EmitLoadElement(ArrayType ty, Type ety, int rank) {
|
|
Emit(OpCodes.Call, "instance", Name(ety),
|
|
String.Format("{0}::Get({1})", Name(ty), repl(",int32", rank).Substring(1)));
|
|
Depth -= rank + 1;
|
|
Depth += 1;
|
|
}
|
|
override public void EmitLoadElementAddress(ArrayType ty, Type ety, int rank) {
|
|
Emit(OpCodes.Call, "instance", Name(ety), "&",
|
|
String.Format("{0}::Address({1})", Name(ty), repl(",int32", rank).Substring(1)));
|
|
Depth -= rank + 1;
|
|
Depth += 1;
|
|
}
|
|
override public void EmitStore(int index) {
|
|
Emit(OpCodes.Stloc, String.Format("{0} // t{0}", index));
|
|
}
|
|
override public void EmitStoreElement(ArrayType ty, Type ety, int rank) {
|
|
Emit(OpCodes.Call, "instance void",
|
|
String.Format("{0}::Set({1}{2})", Name(ty), repl("int32,", rank), Name(ety)));
|
|
Depth -= rank + 2;
|
|
}
|
|
override public void EmitSwitch(int[] caselabels) {
|
|
Emit(OpCodes.Switch, "(");
|
|
for (int i = 0; i < caselabels.Length; i++)
|
|
Emit("{0},", getLabel(caselabels[i]));
|
|
Emit(")");
|
|
}
|
|
override public void EndTry(object handle) {
|
|
if ((int)handle < 0) {
|
|
Emit("endfinally");
|
|
handle = -(int)handle;
|
|
} else
|
|
gotoLabel(OpCodes.Leave, (int)handle);
|
|
Emit("}} // end .try");
|
|
base.EndTry(handle);
|
|
}
|
|
string FieldRef(Field f) { return parent.FieldRef(f); }
|
|
public string getLabel(int lab) {
|
|
return String.Format("${0}", lab);
|
|
}
|
|
override public void gotoLabel(OpCode inst, int lab) {
|
|
Emit(inst, getLabel(lab));
|
|
}
|
|
string MethodRef(Method m) { return parent.MethodRef(m); }
|
|
string Name(Type ty) { return parent.Name(ty); }
|
|
override public int newLocal(Type ty) {
|
|
return newLocal(ty, String.Format("t{0}", offset));
|
|
}
|
|
override public int newLocal(Type ty, string name) {
|
|
int var = offset++;
|
|
Emit(".locals init ([{0}]{1} '{2}')", var, Name(ty), name);
|
|
return var;
|
|
}
|
|
public static string quote(string str) {
|
|
return '"' + str.Replace("\"", "\\\"") + '"';
|
|
}
|
|
public static string repl(string str, int n) {
|
|
string s = "";
|
|
while (n-- > 0)
|
|
s += str;
|
|
return s;
|
|
}
|
|
override public void statement(statement ast, Method m) {
|
|
base.statement(ast, m);
|
|
if (m.Type != parent.T.Void)
|
|
Depth -= 1;
|
|
}
|
|
override public void string_literal(string_literal ast) {
|
|
Emit(OpCodes.Ldstr, ast.token.str);
|
|
}
|
|
}
|
|
public virtual void Assemble(stringList argv, string input, string output, bool verbose, bool debug) {
|
|
Process p = new Process();
|
|
p.StartInfo.UseShellExecute = false;
|
|
string ilasm = "ilasm";
|
|
foreach (string arg in argv) {
|
|
if (arg.StartsWith("/ilasm:") || arg.StartsWith("-ilasm:")) {
|
|
ilasm = arg.Substring("/ilasm:".Length);
|
|
}
|
|
}
|
|
|
|
p.StartInfo.FileName = ilasm;
|
|
p.StartInfo.Arguments = String.Format("/nologo /quiet {0} /{1} /noautoinherit /output=\"{2}\" \"{3}\"",
|
|
debug ? "/pdb" : "",
|
|
output.ToLower().EndsWith(".exe") ? "exe" : "dll",
|
|
output,
|
|
input);
|
|
if (verbose)
|
|
Console.Error.WriteLine("{0} {1}", p.StartInfo.FileName, p.StartInfo.Arguments);
|
|
p.Start();
|
|
p.WaitForExit();
|
|
if (p.ExitCode != 0)
|
|
{
|
|
msg.Error("ilasm failed, command line: \"{0}\" {1}", p.StartInfo.FileName, p.StartInfo.Arguments);
|
|
}
|
|
}
|
|
public virtual void class_declaration(class_declaration ast) {
|
|
EmitClassHead(ast.sym);
|
|
WriteLine("{{");
|
|
EmitClassBody(ast.attrs, ast.body);
|
|
WriteLine("}} // end of class {0}", ast.sym.FullName);
|
|
}
|
|
public string ClassRef(Type ty) {
|
|
string module = "";
|
|
if (ty.module != null)
|
|
module = String.Format("[{0}]", ModuleName(ty.module));
|
|
string name = "";
|
|
if (ty.RealName.StartsWith("System.") && ty.enclosingType == null)
|
|
name = ty.RealName;
|
|
else {
|
|
// quoting syntax for nested types has changed
|
|
// correct 2.0 syntax is 'namespace-name'.'outer-class-name'/'inner-class-name'
|
|
// incorrect 1.0 syntax is 'namespace-name.outer-class-name/inner-class-name'
|
|
for ( ; ty.enclosingType != null; ty = ty.enclosingType)
|
|
name = "/'" + ty.Name + "'" + name;
|
|
name = "'" + ty.FullName + "'" + name;
|
|
}
|
|
return module + name;
|
|
}
|
|
public virtual void comment(AST ast) {
|
|
if (ast != null) {
|
|
Write("// {0}: ", ast.begin.ToString());
|
|
source.visit((compilation)ast, wr, null, msg);
|
|
WriteLine();
|
|
}
|
|
}
|
|
public virtual void comment(AST ast, string fmt, params string[] args) {
|
|
if (ast != null) {
|
|
Write("// {0}: ", ast.begin.ToString());
|
|
WriteLine(fmt, args);
|
|
}
|
|
}
|
|
public virtual void compilation(compilation ast) {
|
|
T = ast.global.Types;
|
|
string target = ".exe", outdir = "", oname = null, iname = null;
|
|
foreach (string s in ast.args)
|
|
if (s[0] == '/' || s[0] == '-') {
|
|
string arg = s.Substring(1);
|
|
if (arg.StartsWith("out:")) {
|
|
oname = arg.Substring(4);
|
|
iname = Path.GetFileNameWithoutExtension(oname) + ".il";
|
|
} else if (arg.StartsWith("outdir:"))
|
|
outdir = arg.Substring(7).TrimEnd('/', '\\') + "\\";
|
|
else if (arg.StartsWith("main:") || arg.StartsWith("m:"))
|
|
mainTypeName = arg.Substring(arg.IndexOf(':')+1);
|
|
else if (arg.StartsWith("target:") || arg.StartsWith("t:"))
|
|
switch (arg.Substring(arg.IndexOf(':')+1).ToLower()) {
|
|
case "winexe": case "exe": target = ".exe"; break;
|
|
case "library": target = ".dll"; break;
|
|
}
|
|
else if (arg.StartsWith("r:") || arg.StartsWith("reference:")) {
|
|
foreach (string f in arg.Substring(arg.IndexOf(':')+1).Split(','))
|
|
if (f.IndexOf('=') >= 0) {
|
|
string[] map = f.Split('=');
|
|
map[0] = Path.GetFileNameWithoutExtension(map[0]);
|
|
moduleMap[map[0]] = map[1];
|
|
}
|
|
}
|
|
} else if ((s.EndsWith(".cs") || s.EndsWith(".csi")) && iname == null)
|
|
iname = Path.GetFileNameWithoutExtension(s) + ".il";
|
|
if (oname == null && iname == null)
|
|
oname = "a" + target;
|
|
else {
|
|
if (oname == null)
|
|
oname = Path.GetFileNameWithoutExtension(iname) + target;
|
|
iname = outdir + iname;
|
|
}
|
|
try {
|
|
wr.Close();
|
|
wr = new StreamWriter(iname);
|
|
} catch (Exception e) {
|
|
msg.Error("can't write \"{0}\": {1}", iname, e.Message);
|
|
iname = null;
|
|
}
|
|
try {
|
|
SHA1 sha = new SHA1CryptoServiceProvider();
|
|
foreach (string path in ast.assemblyRefs) {
|
|
PELoader pe = new PELoader(path);
|
|
MetaData md = MetaData.loadMetaData(path, pe, false, false);
|
|
MetaDataAssembly mda = (MetaDataAssembly)md.Assemblies[0];
|
|
|
|
WriteLine(".assembly extern '{0}' {{", ModuleName(path));
|
|
WriteLine(".ver {0}:{1}:{2}:{3}",
|
|
mda.MajorVersion,
|
|
mda.MinorVersion,
|
|
mda.BuildNumber,
|
|
mda.RevisionNumber);
|
|
|
|
byte[] hash = sha.ComputeHash(mda.PublicKey);
|
|
Write(".publickeytoken = (");
|
|
int len = hash.Length - 1;
|
|
for (int i = 0; i < 8; i++)
|
|
Emitint(1, (ulong)hash[len - i]);
|
|
WriteLine(" )");
|
|
|
|
#if VERIFY_HASH_USING_REFLECTION
|
|
try {
|
|
Assembly asm = Assembly.LoadFrom(path);
|
|
AssemblyName name = asm.GetName();
|
|
WriteLine("// .assembly extern '{0}' {{", ModuleName(asm.Location));
|
|
WriteLine("// .ver {0}", name.Version.ToString().Replace('.',':'));
|
|
byte[] bytes = name.GetPublicKeyToken();
|
|
if (bytes != null) {
|
|
Write("// .publickeytoken = (");
|
|
for (int i = 0; i < bytes.Length; i++)
|
|
Emitint(1, (ulong)bytes[i]);
|
|
WriteLine(" )");
|
|
}
|
|
}
|
|
catch {
|
|
}
|
|
#endif
|
|
|
|
#if false
|
|
foreach (MetaData md in resolver.MetaDataList) {
|
|
MetaDataAssembly mda = (MetaDataAssembly)md.Assemblies[0];
|
|
}
|
|
XmlNode asm = manifest.CreateNode(XmlNodeType.Element, "assembly", "");
|
|
AddAttribute(asm, "filename", assemblyname);
|
|
if (mda.MajorVersion != 0 || mda.MinorVersion != 0 ||
|
|
mda.BuildNumber != 0 || mda.RevisionNumber != 0) {
|
|
AddAttribute(asm, "version", String.Format("{0}.{1}.{2}.{3}",
|
|
mda.MajorVersion,
|
|
mda.MinorVersion,
|
|
mda.BuildNumber,
|
|
mda.RevisionNumber));
|
|
}
|
|
if (mda.PublicKey != null & mda.PublicKey.Length > 0) {
|
|
AddAttribute(asm, "publickey", String.Format("{0}",
|
|
KeyToString(mda.PublicKey)));
|
|
}
|
|
if (mda.Locale != null && mda.Locale != "") {
|
|
AddAttribute(asm, "locale", mda.Locale);
|
|
}
|
|
AddAttribute(asm, "cache", StripCacheFromPath(file));
|
|
assembliesNode.AppendChild(asm);
|
|
#endif
|
|
|
|
WriteLine("}}");
|
|
}
|
|
WriteLine(".assembly '{0}' {{", Path.GetFileNameWithoutExtension(oname));
|
|
|
|
object o;
|
|
o = Evalattribute(ast.inputs, "System.Reflection.AssemblyVersionAttribute");
|
|
if (o != null && o is String) {
|
|
WriteLine(".ver {0}", ((string)o).Replace('.',':'));
|
|
}
|
|
else {
|
|
WriteLine(".ver 0:0:0:0");
|
|
}
|
|
|
|
o = Evalattribute(ast.inputs, "System.Reflection.AssemblyKeyFileAttribute");
|
|
if (o != null && o is String) {
|
|
string file = outdir + (string)o;
|
|
WriteLine("//publickey({0})", file);
|
|
try {
|
|
FileStream fs = new FileStream(outdir + (string)o,
|
|
FileMode.Open, FileAccess.Read);
|
|
BinaryReader r = new BinaryReader(fs);
|
|
byte[] values = r.ReadBytes(0x10000);
|
|
if (values != null) {
|
|
Write(".publickey = (", file);
|
|
int len = values.Length;
|
|
for (int i = 0; i < len; i++) {
|
|
Write(" {0:x2}", values[i]);
|
|
if (i % 16 == 15) {
|
|
WriteLine();
|
|
Write(" ");
|
|
}
|
|
}
|
|
WriteLine(" )");
|
|
}
|
|
r.Close();
|
|
if (values.Length >= 8) {
|
|
WriteLine(".hash algorithm 0x{0:x2}{1:x2}{2:x2}{3:x2}",
|
|
values[7],
|
|
values[6],
|
|
values[5],
|
|
values[4]);
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
Console.WriteLine("Couldn't access public key {0}", file);
|
|
Console.WriteLine("Exception: {0}", e);
|
|
}
|
|
}
|
|
|
|
foreach (compilation_unit x in ast.inputs)
|
|
compilation_unit_attr(x);
|
|
WriteLine("}}");
|
|
|
|
foreach (compilation_unit x in ast.inputs)
|
|
compilation_unit(x);
|
|
} finally {
|
|
if (wr != Console.Out)
|
|
wr.Close();
|
|
}
|
|
if (iname != null && msg.Count == 0)
|
|
Assemble(ast.args, iname, oname, false, true);
|
|
}
|
|
|
|
public virtual object Evalattribute(compilation_unitList units, string name) {
|
|
if (units != null) {
|
|
foreach (compilation_unit x in units) {
|
|
if (x.attributes != null) {
|
|
foreach (attribute_section s in x.attributes) {
|
|
foreach (attribute a in s.attributes) {
|
|
if (a.sym.RealName == name) {
|
|
foreach (argument n in a.arguments.args) {
|
|
return n.expr.value;
|
|
}
|
|
return "false";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public virtual void compilation_unit_attr(compilation_unit ast) {
|
|
EmitattributeSectionList(ast.attributes);
|
|
}
|
|
public virtual void compilation_unit(compilation_unit ast) {
|
|
foreach (declaration d in ast.declarations)
|
|
declaration(d);
|
|
}
|
|
public virtual void constant_declaration(constant_declaration ast) {
|
|
foreach (const_declarator x in ast.decls) {
|
|
Constant f = x.sym;
|
|
Write(".field ");
|
|
EmitModifiers(f);
|
|
Write("static literal ");
|
|
Write("{0} '{1}' = ", Name(f.Type), f.Name);
|
|
if (f.value is string)
|
|
WriteLine("{0}", ILState.quote((string)f.value));
|
|
else if (f.Type is EnumType)
|
|
EmitDataItem(((EnumType)f.Type).baseType, f.value);
|
|
else
|
|
EmitDataItem(f.Type, f.value);
|
|
}
|
|
}
|
|
public virtual void constructor_declaration(constructor_declaration ast) {
|
|
Method m = ast.sym;
|
|
Write(".method hidebysig specialname rtspecialname ");
|
|
EmitModifiers(m);
|
|
WriteLine("{0} {1}({2}) {3}{{", Name(m.Type), Name(m), Signature(m),
|
|
ast.block == null && m.declSpace.Owner is DelegateType ? "runtime managed " : "");
|
|
EmitattributeSectionList(ast.attrs);
|
|
declarationList body;
|
|
if (ast.parent is class_declaration)
|
|
body = ((class_declaration)ast.parent).body;
|
|
else
|
|
body = ((struct_declaration)ast.parent).body;
|
|
ILState g = NewILState(this);
|
|
if (ast.decl.init != null)
|
|
constructor_initializer(ast.decl.init, body, g);
|
|
if (m.IsStatic)
|
|
foreach (declaration d in body)
|
|
if (d is field_declaration) {
|
|
foreach (field_declarator f in ((field_declaration)d).decls)
|
|
if (f.sym.IsStatic)
|
|
variable_initializer(f.init, f.sym, g);
|
|
} else if (d is event_declaration1)
|
|
foreach (event_declarator e in ((event_declaration1)d).decls)
|
|
if (e.sym.IsStatic)
|
|
variable_initializer(e.init, e.sym, g);
|
|
int i;
|
|
for (i = 0; i < m.ArgCount; i++)
|
|
m[i].ordinal = m.IsInstance ? i + 1 : i;
|
|
if (ast.block != null)
|
|
EmitMethodBody(m, ast.block, g);
|
|
WriteLine("}} // end of constructor {0}", m.FullName);
|
|
}
|
|
public virtual void constructor_initializer(constructor_initializer ast, declarationList body, ILState g) {
|
|
if (ast is base_initializer) {
|
|
foreach (declaration d in body)
|
|
if (d is field_declaration) {
|
|
foreach (field_declarator f in ((field_declaration)d).decls)
|
|
if (f.sym.IsInstance)
|
|
variable_initializer(f.init, f.sym, g);
|
|
} else if (d is event_declaration1)
|
|
foreach (event_declarator e in ((event_declaration1)d).decls)
|
|
if (e.sym.IsInstance)
|
|
variable_initializer(e.init, e.sym, g);
|
|
g.base_initializer((base_initializer)ast);
|
|
} else
|
|
g.this_initializer((this_initializer)ast);
|
|
}
|
|
public virtual void declaration(declaration ast) {
|
|
asts.Push(ast);
|
|
if (ast is class_declaration) class_declaration((class_declaration)ast);
|
|
else if (ast is constant_declaration) constant_declaration((constant_declaration)ast);
|
|
else if (ast is constructor_declaration) constructor_declaration((constructor_declaration)ast);
|
|
else if (ast is delegate_declaration) delegate_declaration((delegate_declaration)ast);
|
|
else if (ast is destructor_declaration) destructor_declaration((destructor_declaration)ast);
|
|
else if (ast is enum_declaration) enum_declaration((enum_declaration)ast);
|
|
else if (ast is event_declaration1) event_declaration1((event_declaration1)ast);
|
|
else if (ast is event_declaration2) event_declaration2((event_declaration2)ast);
|
|
else if (ast is field_declaration) field_declaration((field_declaration)ast);
|
|
else if (ast is indexer_declaration) indexer_declaration((indexer_declaration)ast);
|
|
else if (ast is interface_declaration) interface_declaration((interface_declaration)ast);
|
|
else if (ast is interface_event_declaration) interface_event_declaration((interface_event_declaration)ast);
|
|
else if (ast is interface_indexer_declaration) interface_indexer_declaration((interface_indexer_declaration)ast);
|
|
else if (ast is interface_method_declaration) interface_method_declaration((interface_method_declaration)ast);
|
|
else if (ast is interface_property_declaration) interface_property_declaration((interface_property_declaration)ast);
|
|
else if (ast is method_declaration) method_declaration((method_declaration)ast);
|
|
else if (ast is namespace_declaration) namespace_declaration((namespace_declaration)ast);
|
|
else if (ast is operator_declaration) operator_declaration((operator_declaration)ast);
|
|
else if (ast is property_declaration) property_declaration((property_declaration)ast);
|
|
else if (ast is struct_declaration) struct_declaration((struct_declaration)ast);
|
|
else throw new ArgumentException();
|
|
asts.Pop();
|
|
}
|
|
public virtual void delegate_declaration(delegate_declaration ast) {
|
|
EmitClassHead(ast.sym);
|
|
WriteLine("{{");
|
|
EmitattributeSectionList(ast.attrs);
|
|
foreach (Symbol s in ast.sym)
|
|
if (s is Method)
|
|
EmitMethod((Method)s, null, null, null);
|
|
WriteLine("}} // end of delegate {0}", ast.sym.FullName);
|
|
}
|
|
public virtual void destructor_declaration(destructor_declaration ast) {
|
|
EmitMethod(ast.sym, ast.attrs, ast.block, "specialname rtspecialname");
|
|
}
|
|
public virtual void Emitattribute(attribute ast) {
|
|
if (ast.arguments != null) {
|
|
Write(".custom instance void {0}::.ctor({1}) = (", ClassRef(ast.sym),
|
|
Signature(ast.method, false));
|
|
Emitint(1, 1UL); Emitint(1, 0UL); // prolog 01 00
|
|
foreach (argument x in ast.arguments.args) {
|
|
WriteLine();
|
|
EmitFixedArg(x.expr.value);
|
|
}
|
|
WriteLine();
|
|
Emitint(2, (ulong)ast.arguments.namedargs.Count);
|
|
foreach (named_argument x in ast.arguments.namedargs) {
|
|
WriteLine();
|
|
EmitNamedArg(x);
|
|
}
|
|
} else {
|
|
Write(".custom instance void {0}::.ctor() = (", ClassRef(ast.sym));
|
|
Emitint(1, 1UL); Emitint(1, 0UL); // prolog 01 00
|
|
Emitint(2, 0UL); // no named arguments
|
|
}
|
|
WriteLine(" )");
|
|
}
|
|
public virtual void EmitattributeSectionList(attribute_sectionList attrs) {
|
|
if (attrs != null)
|
|
foreach (attribute_section s in attrs)
|
|
foreach (attribute a in s.attributes)
|
|
Emitattribute(a);
|
|
}
|
|
public virtual void EmitClassHead(ClassType c) {
|
|
Write(".class ");
|
|
if (c.enclosingType != null)
|
|
Write("nested ");
|
|
EmitModifiers(c);
|
|
if (c is InterfaceType)
|
|
Write("interface abstract ");
|
|
WriteLine("'{0}'", c.Name);
|
|
if (c.baseClass != null)
|
|
WriteLine("\textends {0}", ClassRef(c.baseClass));
|
|
if (c.interfaces.Count > 0) {
|
|
Write("\timplements ");
|
|
for (int i = 0; i < c.interfaces.Count; i++) {
|
|
if (i > 0)
|
|
Write(",");
|
|
Write("{0}", ClassRef(c.interfaces[i]));
|
|
}
|
|
WriteLine();
|
|
}
|
|
}
|
|
public virtual void EmitClassBody(attribute_sectionList attrs, declarationList body) {
|
|
EmitattributeSectionList(attrs);
|
|
foreach (declaration d in body)
|
|
declaration(d);
|
|
}
|
|
public virtual void EmitDataItem(Type ty, object value) {
|
|
string name = Name(ty);
|
|
if (name.StartsWith("unsigned "))
|
|
name = name.Substring(9);
|
|
WriteLine("{0}({1})", name, value.ToString());
|
|
}
|
|
public virtual void EmitDefaultAccessor(Event e, Method m) {
|
|
Write(".method hidebysig specialname ");
|
|
EmitModifiers(m);
|
|
if (m.IsInstance) {
|
|
Write("instance ");
|
|
m[0].ordinal = 1;
|
|
} else
|
|
m[0].ordinal = 0;
|
|
WriteLine("void {0}({1} 'value') cil managed synchronized {{", Name(m), Name(m[0].Type));
|
|
if (!m.Is("abstract")) {
|
|
ILState g = NewILState(this);
|
|
g.EmitDefaultAccessor(e, m);
|
|
EmitMethodBody(m, null, g);
|
|
}
|
|
WriteLine("}} // end of method {0}", m.FullName);
|
|
}
|
|
public virtual void EmitEvent(Event t, event_accessorList accessors) {
|
|
WriteLine(".event '{0}' '{1}' {{", t.Type.FullName, t.Name);
|
|
WriteLine(".addon {0}void {1}", t.IsStatic ? "" : "instance ", MethodRef(t.Add));
|
|
WriteLine(".removeon {0}void {1}", t.IsStatic ? "" : "instance ", MethodRef(t.Remove));
|
|
WriteLine("}} // end of event {0}", t.FullName);
|
|
if (accessors != null)
|
|
foreach (event_accessor a in accessors)
|
|
EmitMethod(a.sym, a.attrs, a.block, "specialname rtspecialname");
|
|
}
|
|
public virtual void EmitFixedArg(object value) {
|
|
if (value == null)
|
|
Emitint(1, 0xFFUL);
|
|
else if (value is string)
|
|
Emitstring((string)value);
|
|
else if (value is char)
|
|
Emitint(2, (ulong)(ushort)(char)value);
|
|
else if (value is bool)
|
|
Emitint(1, (bool)value ? 1UL : 0UL);
|
|
else if (value is sbyte) Emitint(1, (ulong)( sbyte)value);
|
|
else if (value is byte) Emitint(1, (ulong)( byte)value);
|
|
else if (value is short) Emitint(2, (ulong)( short)value);
|
|
else if (value is ushort) Emitint(2, (ulong)(ushort)value);
|
|
else if (value is int) Emitint(4, (ulong)( int)value);
|
|
else if (value is uint) Emitint(4, (ulong)( uint)value);
|
|
else if (value is long) Emitint(8, (ulong)( long)value);
|
|
else if (value is ulong) Emitint(8, (ulong) value);
|
|
else
|
|
msg.Error("attribute type '{0}' not yet supported", value.GetType().FullName);
|
|
}
|
|
public virtual void Emitint(int len, ulong value) {
|
|
for (int i = 0; i < len; i++) {
|
|
Write(" {0:x2}", value&0xff);
|
|
value >>= 8;
|
|
}
|
|
}
|
|
public virtual void EmitMethod(Method m, attribute_sectionList attrs, statement body, string extraattributes) {
|
|
Write(".method hidebysig ");
|
|
if (extraattributes != null)
|
|
Write("{0} ", extraattributes);
|
|
EmitModifiers(m);
|
|
if (m.IsInstance)
|
|
Write("instance ");
|
|
WriteLine("{0} {1}({2}) {3}{{", Name(m.Type), Name(m), Signature(m),
|
|
body == null && m.declSpace.Owner is DelegateType ? "runtime managed " : "");
|
|
EmitattributeSectionList(attrs);
|
|
if ((mainTypeName == null || mainTypeName == m.GetType().Name)
|
|
&& m.Name == "Main" && m.IsStatic)
|
|
WriteLine(".entrypoint");
|
|
if (m.interfaceMethod != null)
|
|
WriteLine(".override {0}::'{1}'", ClassRef(m.interfaceMethod.GetType()),
|
|
m.interfaceMethod.Name);
|
|
int i;
|
|
for (i = 0; i < m.ArgCount; i++)
|
|
m[i].ordinal = m.IsInstance ? i + 1 : i;
|
|
if (m.Name == "set_Item")
|
|
((Formal)m.locals["value"]).ordinal = m.IsInstance ? i + 1 : i;
|
|
if (body != null)
|
|
EmitMethodBody(m, body, NewILState(this));
|
|
WriteLine("}} // end of method {0}", m.FullName);
|
|
}
|
|
public virtual void EmitMethodBody(Method m, statement body, ILState g) {
|
|
if (body != null)
|
|
g.statement(body, m);
|
|
WriteLine(".maxstack {0}", g.maxstack);
|
|
Debug.Assert(g.Depth == 0);
|
|
}
|
|
public virtual void EmitModifiers(Symbol t) {
|
|
string emit = "";
|
|
foreach (string mod in t.Modifiers)
|
|
switch (mod) {
|
|
case "new":
|
|
emit += " newslot"; break;
|
|
case "override":
|
|
emit += " virtual"; break;
|
|
case "protected":
|
|
case "internal": case "readonly": case "unsafe":
|
|
break;
|
|
case "sealed":
|
|
emit += t is Method ? " final" : " sealed"; break;
|
|
default:
|
|
emit += " " + mod;
|
|
break;
|
|
}
|
|
if (emit.Length > 1)
|
|
Write("{0} ", emit.Substring(1));
|
|
}
|
|
public virtual void EmitNamedArg(named_argument ast) {
|
|
if (ast.sym is Field)
|
|
Emitint(1, 0x53UL);
|
|
else if (ast.sym is Property)
|
|
Emitint(1, 0x54UL);
|
|
Type ty = ast.sym.Type;
|
|
if (ty == T.Bool) Emitint(1, (ulong)ElementTypes.BOOLEAN);
|
|
else if (ty == T.Byte) Emitint(1, (ulong)ElementTypes.U1);
|
|
else if (ty == T.Char) Emitint(1, (ulong)ElementTypes.CHAR);
|
|
else if (ty == T.Double) Emitint(1, (ulong)ElementTypes.R8);
|
|
else if (ty == T.Short) Emitint(1, (ulong)ElementTypes.I2);
|
|
else if (ty == T.Int) Emitint(1, (ulong)ElementTypes.I4);
|
|
else if (ty == T.Long) Emitint(1, (ulong)ElementTypes.I8);
|
|
else if (ty == T.SByte) Emitint(1, (ulong)ElementTypes.I1);
|
|
else if (ty == T.Float) Emitint(1, (ulong)ElementTypes.R4);
|
|
else if (ty == T.String) Emitint(1, (ulong)ElementTypes.STRING);
|
|
else if (ty == T.UShort) Emitint(1, (ulong)ElementTypes.U2);
|
|
else if (ty == T.UInt) Emitint(1, (ulong)ElementTypes.U4);
|
|
else if (ty == T.ULong) Emitint(1, (ulong)ElementTypes.U8);
|
|
else Debug.Assert(false);
|
|
Emitstring(ast.id.str);
|
|
EmitFixedArg(ast.expr.value);
|
|
}
|
|
public virtual void EmitProperty(Property p, attribute_sectionList attrs, accessor_declarationList decls) {
|
|
Write(".property ");
|
|
if (p.IsInstance)
|
|
Write("instance ");
|
|
WriteLine("{1} {0}() {{", p.Name, Name(p.Type));
|
|
EmitattributeSectionList(attrs);
|
|
foreach (accessor_declaration d in decls) {
|
|
Write(".{0}", d.id.str);
|
|
if (d.sym.IsInstance)
|
|
Write(" instance");
|
|
WriteLine(" {0} {1}", d.id.str == "get" ? Name(p.Type) : "void", MethodRef(d.sym));
|
|
}
|
|
WriteLine("}} // end of {0} {1}", p.Kind, p.FullName);
|
|
foreach (accessor_declaration d in decls)
|
|
EmitMethod(d.sym, d.attrs, d.body, "specialname");
|
|
}
|
|
public virtual void Emitstring(string value) {
|
|
if (value.Length <= 127)
|
|
Emitint(1, (ulong)value.Length);
|
|
else if (value.Length >= 128 && value.Length <= 16383) {
|
|
uint n = (uint)value.Length;
|
|
Emitint(1, ((n>>8)&0x7fUL)|0x80UL);
|
|
Emitint(1, n&0xffUL);
|
|
} else {
|
|
uint n = (uint)value.Length;
|
|
Emitint(1, ((n>>24)&0x1fUL)|0xc0UL);
|
|
Emitint(1, (n>>16)&0xffUL);
|
|
Emitint(1, (n>> 8)&0xffUL);
|
|
Emitint(1, n&0xffUL);
|
|
}
|
|
foreach (char c in value)
|
|
Emitint(1, (ulong)(byte)c);
|
|
}
|
|
public virtual void enum_declaration(enum_declaration ast) {
|
|
EnumType e = ast.sym;
|
|
Write(".class ");
|
|
if (e.enclosingType != null)
|
|
Write("nested ");
|
|
EmitModifiers(e);
|
|
WriteLine("auto ansi serializable sealed '{0}' extends {1}", e.Name, ClassRef(T.Enum));
|
|
WriteLine("{{");
|
|
EmitattributeSectionList(ast.attrs);
|
|
string name = "";
|
|
Type ty;
|
|
for (ty = e; ty.enclosingType != null; ty = ty.enclosingType)
|
|
name = "/" + ty.Name + name;
|
|
name = ty.FullName + name;
|
|
foreach (enum_member_declaration d in ast.body) {
|
|
Write(".field public static literal valuetype '{0}' {1} = ", name, d.sym.Name);
|
|
EmitDataItem(e.baseType, d.sym.value);
|
|
}
|
|
WriteLine(".field public rtspecialname specialname {0} value__", Name(e.baseType));
|
|
WriteLine("}} // end of enumeration {0}", e.FullName);
|
|
}
|
|
public virtual void event_declaration1(event_declaration1 ast) {
|
|
EmitattributeSectionList(ast.attrs);
|
|
foreach (event_declarator d in ast.decls) {
|
|
WriteLine(".field private {2}{0} {1}", Name(d.sym.Type), d.sym.Name, d.sym.IsStatic ? "static " : "");
|
|
EmitEvent(d.sym, null);
|
|
EmitDefaultAccessor(d.sym, d.sym.Add);
|
|
EmitDefaultAccessor(d.sym, d.sym.Remove);
|
|
}
|
|
}
|
|
public virtual void event_declaration2(event_declaration2 ast) {
|
|
EmitattributeSectionList(ast.attrs);
|
|
EmitEvent(ast.sym, ast.accessors);
|
|
}
|
|
public virtual void field_declaration(field_declaration ast) {
|
|
foreach (field_declarator x in ast.decls) {
|
|
Field f = x.sym;
|
|
Write(".field ");
|
|
EmitModifiers(f);
|
|
WriteLine("{0} {1}", Name(f.Type), Name(f));
|
|
EmitattributeSectionList(ast.attrs);
|
|
}
|
|
}
|
|
public string FieldRef(Symbol f) {
|
|
return String.Format("{0}::'{1}'", ClassRef(f.GetType()), f.Name);
|
|
}
|
|
public virtual void indexer_declaration(indexer_declaration ast) {
|
|
foreach (accessor_declaration d in ast.accessors)
|
|
if (d.id.str == "get") {
|
|
WriteLine(".property instance {0} Item({1}) {{", Name(d.sym.Type),
|
|
Signature(d.sym, false));
|
|
break;
|
|
}
|
|
EmitattributeSectionList(ast.attrs);
|
|
foreach (accessor_declaration d in ast.accessors) {
|
|
Write(".{0} instance", d.id.str);
|
|
WriteLine(" {0} {1}", Name(d.sym.Type), MethodRef(d.sym));
|
|
}
|
|
WriteLine("}} // end of property Item");
|
|
foreach (accessor_declaration d in ast.accessors)
|
|
EmitMethod(d.sym, d.attrs, d.body, "specialname");
|
|
}
|
|
public virtual void interface_declaration(interface_declaration ast) {
|
|
EmitClassHead(ast.sym);
|
|
WriteLine("{{");
|
|
EmitClassBody(ast.attrs, ast.body);
|
|
WriteLine("}} // end of interface {0}", ast.sym.FullName);
|
|
}
|
|
public virtual void interface_event_declaration(interface_event_declaration ast) {
|
|
EmitattributeSectionList(ast.attrs);
|
|
EmitEvent(ast.sym, null);
|
|
EmitDefaultAccessor(ast.sym, ast.sym.Add);
|
|
EmitDefaultAccessor(ast.sym, ast.sym.Remove);
|
|
}
|
|
public virtual void interface_indexer_declaration(interface_indexer_declaration ast) {
|
|
foreach (accessor_declaration d in ast.accessors)
|
|
EmitMethod(d.sym, d.attrs, d.body, "specialname");
|
|
}
|
|
public virtual void interface_method_declaration(interface_method_declaration ast) {
|
|
EmitMethod(ast.sym, ast.attrs, null, null);
|
|
}
|
|
public virtual void interface_property_declaration(interface_property_declaration ast) {
|
|
EmitProperty(ast.sym, ast.attrs, ast.accessors);
|
|
}
|
|
public string ModuleName(string path) {
|
|
string name = Path.GetFileNameWithoutExtension(path).ToLower();
|
|
if (moduleMap.ContainsKey(name))
|
|
name = moduleMap[name];
|
|
return name;
|
|
}
|
|
public virtual void method_declaration(method_declaration ast) {
|
|
EmitMethod(ast.sym, ast.attrs, ast.body, null);
|
|
}
|
|
public string MethodRef(Method m) {
|
|
ClassType ty = m.GetType();
|
|
return String.Format("{0}::{1}({2})", ClassRef(ty), Name(m), Signature(m, false));
|
|
}
|
|
public static string Name(Symbol m) {
|
|
if (m is Method && ((Method)m).GetType().Name == m.Name)
|
|
return m.IsStatic ? ".cctor" : ".ctor";
|
|
return String.Format("'{0}'", m.Name);
|
|
}
|
|
public string Name(Type ty) {
|
|
if (ty == T.Bool) return "bool";
|
|
else if (ty == T.Byte) return "unsigned int8";
|
|
else if (ty == T.Char) return "char";
|
|
else if (ty == T.Double) return "float64";
|
|
//else if (ty == T.Decimal)return "decimal";
|
|
else if (ty == T.Short) return "int16";
|
|
else if (ty == T.Int) return "int32";
|
|
else if (ty == T.Long) return "int64";
|
|
else if (ty == T.Object) return "object";
|
|
else if (ty == T.SByte) return "int8";
|
|
else if (ty == T.Float) return "float32";
|
|
else if (ty == T.String) return "string";
|
|
else if (ty == T.UShort) return "unsigned int16";
|
|
else if (ty == T.UInt) return "unsigned int32";
|
|
else if (ty == T.ULong) return "unsigned int64";
|
|
else if (ty == T.Void) return "void";
|
|
else if (ty == T.IntPtr) return "native int";
|
|
else if (ty == T.UIntPtr)return "native unsigned int";
|
|
else if (ty is ManagedPointerType)
|
|
return String.Format("{0}&", Name(((PointerType)ty).elementType));
|
|
else if (ty is UnmanagedPointerType)
|
|
return String.Format("{0}*", Name(((PointerType)ty).elementType));
|
|
else if (ty is ArrayType && ((ArrayType)ty).rank == 1)
|
|
return String.Format("{0}[]", Name(((ArrayType)ty).elementType));
|
|
else if (ty is ArrayType)
|
|
return String.Format("{0}[{1}]", Name(((ArrayType)ty).elementType),
|
|
ILState.repl(",0...", ((ArrayType)ty).rank).Substring(1));
|
|
else if (ty is EnumType || ty is StructType)
|
|
return String.Format("value class {0}", ClassRef(ty));
|
|
else if (ty is ClassType)
|
|
return String.Format("class {0}", ClassRef(ty));
|
|
else
|
|
throw new ArgumentException(ty.ToString());
|
|
}
|
|
public virtual void namespace_declaration(namespace_declaration ast) {
|
|
WriteLine(".namespace {0} {{", ast.sym.FullName);
|
|
foreach (declaration d in ast.nb.declarations)
|
|
declaration(d);
|
|
WriteLine("}} // end of namespace {0}", ast.sym.FullName);
|
|
}
|
|
public virtual void operator_declaration(operator_declaration ast) {
|
|
EmitMethod(ast.op.method, ast.attrs, ast.block, "specialname");
|
|
}
|
|
public virtual void property_declaration(property_declaration ast) {
|
|
EmitProperty(ast.sym, ast.attrs, ast.decls);
|
|
}
|
|
public string Signature(Method m, bool showNames) {
|
|
Signature sig = m.signature;
|
|
StringBuilder sb = new StringBuilder();
|
|
int i;
|
|
for (i = 0; i < sig.ArgCount; i++) {
|
|
if (i > 0)
|
|
sb.Append(',');
|
|
Formal f = sig[i];
|
|
if (f.modifier != null && f.modifier.str == "out")
|
|
sb.Append("[out] ");
|
|
sb.Append(Name(f.Type));
|
|
if (f.modifier != null)
|
|
sb.Append('&');
|
|
if (showNames)
|
|
sb.AppendFormat(" '{0}'", f.Name);
|
|
}
|
|
if (m.Name == "set_Item") {
|
|
Formal f = (Formal)m.locals["value"];
|
|
if (i > 0)
|
|
sb.Append(',');
|
|
sb.Append(Name(f.Type));
|
|
if (showNames)
|
|
sb.AppendFormat(" '{0}'", f.Name);
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
public string Signature(Method m) {
|
|
return Signature(m, true);
|
|
}
|
|
public virtual void struct_declaration(struct_declaration ast) {
|
|
EmitClassHead(ast.sym);
|
|
WriteLine("{{");
|
|
EmitClassBody(ast.attrs, ast.body);
|
|
WriteLine("}} // end of struct {0}", ast.sym.FullName);
|
|
}
|
|
public virtual void variable_initializer(variable_initializer ast, Symbol sym, ILState g) {
|
|
if (ast != null) {
|
|
if (sym.IsInstance)
|
|
g.this_access();
|
|
g.variable_initializer(ast);
|
|
g.EmitStore(sym);
|
|
}
|
|
}
|
|
public virtual void Write(string fmt, params object[] args) {
|
|
wr.Write(fmt, args);
|
|
}
|
|
public virtual void WriteLine() {
|
|
wr.WriteLine();
|
|
}
|
|
public virtual void WriteLine(string fmt, params object[] args) {
|
|
wr.WriteLine(fmt, args);
|
|
}
|
|
}
|