singrdk/base/Windows/csic/emit/gen.cs

1463 lines
50 KiB
C#

using System;
using System.IO;
using System.Collections;
using System.Reflection.Emit;
public class temporary: expression {
public temporary(Type typ, int var) {
this.typ = typ;
this.var = var;
}
public int var = 0;
}
abstract public class gen {
Stack asts; // top element is current ast node
bool checkoverflow = false;
MessageWriter msg;
int nextlab = 1;
BuiltinTypes T;
int retlab = -1; // return label for current method, if return inside try
int retvar = -1; // return value for current method, if return inside try
public gen(BuiltinTypes T, MessageWriter msg) : this(T, msg, new Stack()) {}
public gen(BuiltinTypes T, MessageWriter msg, Stack asts) {
this.T = T;
this.msg = msg;
this.asts = asts;
}
public virtual bool checking {
get { return checkoverflow; }
set { checkoverflow = value; }
}
abstract public void EmitCreateArray(ArrayType ty, Type ety, int rank);
public virtual void array_create(ArrayType aty, array_initializer ast) {
if (aty.rank > 1)
EmitCreateArray(aty, aty.elementType, aty.rank);
else
Emit(OpCodes.Newarr, aty.elementType);
if (ast != null)
array_init(ast, aty, 0, new int[aty.rank]);
}
public virtual void array_creation_expression1(array_creation_expression1 ast) {
foreach (expression x in ast.exprs)
expression(x);
array_create((ArrayType)ast.typ, ast.init);
}
public virtual void array_creation_expression2(array_creation_expression2 ast) {
array_initializer(ast.init);
}
public virtual void array_initializer(array_initializer ast) {
ArrayType aty = (ArrayType)ast.typ;
for (array_initializer x = ast; x != null; ) {
Emit(OpCodes.Ldc_I4, x.a.Count);
x = x.a[0] as array_initializer;
}
array_create(aty, ast);
}
public virtual void array_init(array_initializer ast, ArrayType aty, int index, int[] indices) {
if (ast.a.Count > 0 && ast.a[0] is array_initializer) {
foreach (array_initializer x in ast.a) {
array_init(x, aty, index + 1, indices);
indices[index]++;
}
} else {
indices[index] = 0;
foreach (expr_initializer x in ast.a) {
Emit(OpCodes.Dup);
foreach (int i in indices)
Emit(OpCodes.Ldc_I4, i);
EmitStoreElement(aty, x.expr);
indices[index]++;
}
}
}
public virtual void as_expression(as_expression ast) {
expression(ast.expr);
Emit(OpCodes.Isinst, ast.sym);
}
public virtual void assignment_expression(assignment_expression ast) {
expression(ast.e1, ast.e2);
if (ast.valueUsed)
expression(ast.e2);
}
public virtual void base_access(base_access ast) {
this_access();
Type ty = currentClass(ast);
if (ty is StructType) {
Emit(OpCodes.Ldobj, ty);
Emit(OpCodes.Box, ty);
}
}
public virtual void base_initializer(base_initializer ast) {
this_access();
EmitArgumentList(ast.method, ast.args);
EmitCall(ast.method);
}
public virtual object BeginTry() { return genLabel(1); }
public virtual object BeginFinally(object handle) {
gotoLabel(OpCodes.Leave, (int)handle);
return handle;
}
public virtual void binary_expression(binary_expression ast, int trueLabel, int falseLabel) {
switch (ast.op.str) {
case "&&":
if (falseLabel != 0) {
expression(ast.e1, 0, falseLabel);
expression(ast.e2, 0, falseLabel);
} else if (trueLabel != 0) {
expression(ast.e1, 0, falseLabel = genLabel(1));
expression(ast.e2, trueLabel, 0);
defLabel(falseLabel);
} else
boolean_value(ast);
return;
case "||":
if (trueLabel != 0) {
expression(ast.e1, trueLabel, 0);
expression(ast.e2, trueLabel, 0);
} else if (falseLabel != 0) {
expression(ast.e1, trueLabel = genLabel(1), 0);
expression(ast.e2, 0, falseLabel);
defLabel(trueLabel);
} else
boolean_value(ast);
return;
case "<": comparison(ast.e1.typ.IsUnsigned ? OpCodes.Blt_Un : OpCodes.Blt, ast.e1.typ.IsUnsigned ? OpCodes.Bge_Un : OpCodes.Bge, ast, trueLabel, falseLabel); return;
case "<=": comparison(ast.e1.typ.IsUnsigned ? OpCodes.Ble_Un : OpCodes.Ble, ast.e1.typ.IsUnsigned ? OpCodes.Bgt_Un : OpCodes.Bgt, ast, trueLabel, falseLabel); return;
case ">": comparison(ast.e1.typ.IsUnsigned ? OpCodes.Bgt_Un : OpCodes.Bgt, ast.e1.typ.IsUnsigned ? OpCodes.Ble_Un : OpCodes.Ble, ast, trueLabel, falseLabel); return;
case ">=": comparison(ast.e1.typ.IsUnsigned ? OpCodes.Bge_Un : OpCodes.Bge, ast.e1.typ.IsUnsigned ? OpCodes.Blt_Un : OpCodes.Blt, ast, trueLabel, falseLabel); return;
case "==": comparison(OpCodes.Beq, OpCodes.Bne_Un, ast, trueLabel, falseLabel); return;
case "!=": comparison(OpCodes.Bne_Un, OpCodes.Beq, ast, trueLabel, falseLabel); return;
case ",":
expression(ast.e1);
if (ast.e1.valueUsed)
Emit(OpCodes.Pop);
expression(ast.e2);
return;
}
expression(ast.e1);
expression(ast.e2);
binary_operator(ast.op.str, ast.typ, ast.method);
}
public virtual void binary_operator(string op, Type ty, Method method) {
if (method != null && method.declSpace != null) {
EmitCall(method);
return;
}
if (checking && (ty.IsSigned || ty.IsUnsigned))
switch (op) {
case "+": Emit(ty.IsUnsigned ? OpCodes.Add_Ovf_Un : OpCodes.Add_Ovf); return;
case "-": Emit(ty.IsUnsigned ? OpCodes.Sub_Ovf_Un : OpCodes.Sub_Ovf); return;
case "*": Emit(ty.IsUnsigned ? OpCodes.Mul_Ovf_Un : OpCodes.Mul_Ovf); return;
}
switch (op) {
case "+":
if (ty is DelegateType) {
EmitCall(T.Delegate.FindMethod("Combine", T.Delegate, T.Delegate));
EmitCast(T.Delegate, ty);
} else
Emit(OpCodes.Add);
break;
case "-":
if (ty is DelegateType) {
EmitCall(T.Delegate.FindMethod("Remove", T.Delegate, T.Delegate));
EmitCast(T.Delegate, ty);
} else
Emit(OpCodes.Sub);
break;
case "*": Emit(OpCodes.Mul); break;
case "/": Emit(ty.IsUnsigned ? OpCodes.Div_Un : OpCodes.Div); break;
case "%": Emit(ty.IsUnsigned ? OpCodes.Rem_Un : OpCodes.Rem); break;
case "<<": Emit(OpCodes.Shl); break;
case ">>": Emit(ty.IsUnsigned ? OpCodes.Shr_Un : OpCodes.Shr); break;
case "&": Emit(OpCodes.And); break;
case "|": Emit(OpCodes.Or); break;
case "^": Emit(OpCodes.Xor); break;
default: Debug.Fail(String.Format("unknown binary operator '{0}'", op)); break;
}
}
public virtual void block_statement(block_statement ast) {
foreach (statement s in ast.stmts)
statement(s);
}
public virtual void boolean_literal(boolean_literal ast) {
Emit(OpCodes.Ldc_I4, ast.token.str == "true" ? 1 : 0);
}
public virtual void boolean_value(binary_expression ast) {
if (ast.method != null && ast.method.Type == T.Bool && ast.method.declSpace != null) {
expression(ast.e1);
expression(ast.e2);
EmitCall(ast.method);
} else {
int lab = genLabel(2);
expression(ast, 0, lab);
Emit(OpCodes.Ldc_I4_1);
gotoLabel(lab + 1);
defLabel(lab);
Emit(OpCodes.Ldc_I4_0);
defLabel(lab + 1);
}
}
public virtual void break_statement(break_statement ast) {
if (ast.stmt != null)
gotoLabel(ast.exitstry ? OpCodes.Leave : OpCodes.Br, ast.stmt.lab + 2);
}
public virtual void cast_expression(cast_expression ast) {
expression(ast.expr);
EmitCast(ast.expr.typ, ast.sym);
}
public virtual void catch_clause(Type ty, Local sym, statement block, object handle) {
if (sym == null)
Emit(OpCodes.Pop);
else {
sym.ordinal = newLocal(sym.Type, sym.Name);
EmitStore(sym);
}
statement(block);
}
public virtual void catch_clause(catch_clause ast, object handle) {
catch_clause(ast.ty.sym, ast.sym, ast.block, handle);
}
public virtual void catch_clauses(catch_clauses ast, object handle) {
foreach (catch_clause x in ast.specifics)
catch_clause(x, handle);
if (ast.general != null)
catch_clause(T.Object, null, ast.general, handle);
}
public virtual void character_literal(character_literal ast) {
Emit(OpCodes.Ldc_I4, (int)(char)ast.value);
}
public virtual void checked_expression(checked_expression ast, bool lvalue) {
bool save = checking;
checking = true;
expression(ast.expr, lvalue);
checking = save;
}
public virtual void checked_expression(checked_expression ast, expression rhs) {
bool save = checking;
checking = true;
expression(ast.expr, rhs);
checking = save;
}
public virtual void checked_statement(checked_statement ast) {
bool save = checking;
checking = true;
statement(ast.stmt);
checking = save;
}
public virtual void comparison(OpCode inst, OpCode flip, binary_expression ast, int trueLabel, int falseLabel) {
if (trueLabel == 0 && falseLabel == 0)
boolean_value(ast);
else {
expression(ast.e1);
expression(ast.e2);
if (ast.method != null && ast.method.declSpace != null) {
EmitCall(ast.method);
if (ast.method.Type == T.Bool) {
inst = OpCodes.Brtrue;
flip = OpCodes.Brfalse;
}
}
if (trueLabel != 0)
gotoLabel(inst, trueLabel);
else
gotoLabel(flip, falseLabel);
}
}
public virtual void compound_assignment_expression(compound_assignment_expression ast) {
if (ast.method != null && is_event_access(ast.e1)) {
if (ast.e1 is simple_name && ((simple_name)ast.e1).sym.IsInstance)
this_access();
else if (ast.e1 is expr_access)
expression(((expr_access)ast.e1).expr);
expression(ast.e2);
EmitCall(ast.method);
} else {
expression(ast.e1);
expression(ast.e2);
binary_operator(ast.op.str.TrimEnd('='), ast.typ, ast.opmethod);
temporary rhs = new temporary(ast.typ, newLocal(ast.typ));
EmitStore(rhs.var);
expression(ast.e1, rhs);
if (ast.valueUsed)
expression(rhs);
}
}
public virtual void cond_expression(cond_expression ast) {
int lab = genLabel(2);
expression(ast.cond, 0, lab);
expression(ast.success);
gotoLabel(lab + 1);
defLabel(lab);
expression(ast.failure);
defLabel(lab + 1);
}
public virtual void const_statement(const_statement ast) {
}
public virtual void continue_statement(continue_statement ast) {
if (ast.stmt != null)
gotoLabel(ast.exitstry ? OpCodes.Leave : OpCodes.Br, ast.stmt.lab + 1);
}
public static ClassType currentClass(AST ast) {
for ( ; ast != null; ast = ast.parent)
if (ast is class_declaration)
return ((class_declaration)ast).sym;
else if (ast is struct_declaration)
return ((struct_declaration)ast).sym;
else if (ast is interface_declaration)
return ((interface_declaration)ast).sym;
return null;
}
abstract public void defLabel(int lab);
public virtual void do_statement(do_statement ast) {
ast.lab = genLabel(3);
defLabel(ast.lab);
statement(ast.body);
defLabel(ast.lab + 1);
expression(ast.expr, ast.lab, 0);
defLabel(ast.lab + 2);
}
public virtual void element_access(element_access ast, bool lvalue) {
expression(ast.expr);
if (ast.get != null) {
EmitArgumentList(ast.get, ast.exprs);
if (ast.expr is base_access)
EmitCall(OpCodes.Call, ast.get);
else
EmitCall(ast.get);
} else if (lvalue && ast.expr.typ is ArrayType) {
EmitArgumentList(ast.exprs);
EmitLoadElementAddress((ArrayType)ast.expr.typ);
} else if (ast.expr.typ is ArrayType) {
EmitArgumentList(ast.exprs);
EmitLoadElement((ArrayType)ast.expr.typ);
}
}
public virtual void element_access(element_access ast, expression rhs) {
expression(ast.expr);
if (ast.set != null) {
EmitArgumentList(ast.set, ast.exprs);
expression(rhs);
if (ast.expr is base_access)
EmitCall(OpCodes.Call, ast.set);
else
EmitCall(ast.set);
} else if (ast.expr.typ is ArrayType) {
EmitArgumentList(ast.exprs);
EmitStoreElement((ArrayType)ast.expr.typ, rhs);
}
}
abstract public void Emit(OpCode op);
abstract public void Emit(OpCode op, Constructor x);
abstract public void Emit(OpCode op, double x);
abstract public void Emit(OpCode op, float x);
abstract public void Emit(OpCode op, Field x);
abstract public void Emit(OpCode op, int x);
abstract public void Emit(OpCode op, Formal x);
abstract public void Emit(OpCode op, Local x);
abstract public void Emit(OpCode op, Method x);
abstract public void Emit(OpCode op, string x);
abstract public void Emit(OpCode op, Type x);
public virtual void EmitArgumentList(argumentList args) {
foreach (argument a in args)
expression(a.expr, a.kind != null);
}
public virtual void EmitArgumentList(Method m, argumentList args) {
if (m.IsParams && (args.Count != m.ArgCount
|| !Type.Equals(m[m.ArgCount-1].Type, args[m.ArgCount-1].expr.typ))) {
int i;
for (i = 0; i < m.ArgCount - 1; i++)
expression(args[i].expr, args[i].kind != null);
ArrayType last = (ArrayType)m[i].Type;
Emit(OpCodes.Ldc_I4, args.Count - m.ArgCount + 1);
Emit(OpCodes.Newarr, last.elementType);
for ( ; i < args.Count; i++) {
Emit(OpCodes.Dup);
Emit(OpCodes.Ldc_I4, i - m.ArgCount + 1);
EmitStoreElement(last, args[i].expr);
}
} else
EmitArgumentList(args);
}
public virtual void EmitCall(Method m) {
if (m.Is("virtual"))
EmitCall(OpCodes.Callvirt, m);
else
EmitCall(OpCodes.Call, m);
}
public virtual void EmitCall(Constructor m) {
Emit(OpCodes.Call, m);
}
public virtual void EmitCall(OpCode inst, Method m) {
Emit(inst, m);
}
public virtual void EmitCast(Type from, Type to) {
if (Type.Equals(from, to))
return;
if (from.IsReferenceType && to.IsValueType) {
Emit(OpCodes.Unbox, to);
EmitLoadIndirect(to);
} else if (from.IsValueType && to.IsReferenceType)
Emit(OpCodes.Box, from);
else if (from.IsReferenceType && to.IsReferenceType
&& from == T.Null || to.InheritsFrom(from) || from.InheritsFrom(to) || from.Implements(to)) {
if (to.InheritsFrom(from))
Emit(OpCodes.Castclass, to);
} else if (from is EnumType && to.IsNumeric)
EmitCast(((EnumType)from).baseType, to);
else if (from.IsNumeric && to.IsNumeric) {
if (to == T.SByte || to == T.Bool)
Emit(checking ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
else if (to == T.Short)
Emit(checking ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
else if (to == T.Int)
Emit(checking ? OpCodes.Conv_Ovf_I4 : OpCodes.Conv_I4);
else if (to == T.Long)
Emit(checking ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8);
else if (to == T.Byte)
Emit(checking ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
else if (to == T.UShort || to == T.Char)
Emit(checking ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
else if (to == T.UInt)
Emit(checking ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4);
else if (to == T.ULong)
Emit(checking ? OpCodes.Conv_Ovf_U8 : OpCodes.Conv_U8);
else if (to == T.Float)
Emit(OpCodes.Conv_R4);
else if (to == T.Double)
Emit(OpCodes.Conv_R8);
else
Debug.Fail(String.Format("unknown cast from '{0}' to '{1}'", from.FullName, to.FullName));
} else
Debug.Fail(String.Format("unknown cast from '{0}' to '{1}'", from.FullName, to.FullName));
}
public virtual void EmitDefaultAccessor(Event e, Method m) {
if (m.IsInstance) {
this_access(); // for store, below
this_access();
}
EmitLoad(e);
Emit(OpCodes.Ldarg, m[0]); // value
binary_operator(m.Name.IndexOf("add") >= 0 ? "+" : "-", e.Type, null);
EmitStore(e);
Emit(OpCodes.Ret);
}
public virtual void EmitLoad(int index) {
Emit(OpCodes.Ldloc, index);
}
public virtual void EmitLoad(Symbol f) {
if (f is EnumMember)
Emit(OpCodes.Ldc_I4, (int)((EnumMember)f).value);
else if (f is Constant) {
object value = ((Constant)f).value;
if (value is double)
Emit(OpCodes.Ldc_R8, (double)value);
else if (value is float)
Emit(OpCodes.Ldc_R4, (float)value);
else if (value is string)
Emit(OpCodes.Ldstr, (string)value);
else if (value == null)
Emit(OpCodes.Ldnull);
else
Emit(OpCodes.Ldc_I4, (int)value);
} else if (f is Formal && ((Formal)f).modifier != null) {
Emit(OpCodes.Ldarg, (Formal)f);
EmitLoadIndirect(f.Type);
} else if (f is Formal)
Emit(OpCodes.Ldarg, (Formal)f);
else if (f is Local)
Emit(OpCodes.Ldloc, (Local)f);
else if (f is Field && f.IsStatic)
Emit(OpCodes.Ldsfld, (Field)f);
else if (f is Field && f.IsInstance)
Emit(OpCodes.Ldfld, (Field)f);
else if (f is Property)
EmitCall(((Property)f).Get);
else if (f is Method)
Emit(OpCodes.Ldftn, (Method)f);
}
public virtual void EmitLoadAddress(Symbol f) {
if (f is Formal && ((Formal)f).modifier != null)
Emit(OpCodes.Ldarg, (Formal)f);
else if (f is Formal)
Emit(OpCodes.Ldarga, (Formal)f);
else if (f is Local)
Emit(OpCodes.Ldloca, (Local)f);
else if (f is Field && f.IsStatic)
Emit(OpCodes.Ldsflda, (Field)f);
else if (f is Field && f.IsInstance)
Emit(OpCodes.Ldflda, (Field)f);
else if (f is Property) {
EmitCall(((Property)f).Get);
int index = newLocal(f.Type);
EmitStore(index);
EmitLoadAddress(index);
}
}
public virtual void EmitLoadAddress(int index) {
Emit(OpCodes.Ldloca, index);
}
public virtual void EmitLoadElement(ArrayType ty) {
Type ety = ty.elementType;
if (ety.IsScalarType && ty.rank > 1)
EmitLoadElement(ty, ety, ty.rank);
else if (ety.IsScalarType) {
if (ety is EnumType)
ety = ((EnumType)ety).baseType;
if (ety == T.Bool) Emit(OpCodes.Ldelem_I1);
else if (ety == T.Byte) Emit(OpCodes.Ldelem_U1);
else if (ety == T.Char) Emit(OpCodes.Ldelem_I2);
else if (ety == T.Double) Emit(OpCodes.Ldelem_R8);
else if (ety == T.Short) Emit(OpCodes.Ldelem_I2);
else if (ety == T.Int) Emit(OpCodes.Ldelem_I4);
else if (ety == T.Long) Emit(OpCodes.Ldelem_I8);
else if (ety == T.SByte) Emit(OpCodes.Ldelem_I1);
else if (ety == T.Float) Emit(OpCodes.Ldelem_R4);
else if (ety == T.String) Emit(OpCodes.Ldelem_Ref);
else if (ety == T.UShort) Emit(OpCodes.Ldelem_U2);
else if (ety == T.UInt) Emit(OpCodes.Ldelem_U4);
else if (ety == T.ULong) Emit(OpCodes.Ldelem_I8);
else if (ety is PointerType) Emit(OpCodes.Ldelem_U4);
else Emit(OpCodes.Ldelem_Ref);
} else { // value types
EmitLoadElementAddress(ty);
EmitLoadIndirect(ety);
}
}
abstract public void EmitLoadElement(ArrayType ty, Type ety, int rank);
public virtual void EmitLoadElementAddress(ArrayType ty) {
Type ety = ty.elementType;
if (ty.rank == 1)
Emit(OpCodes.Ldelema, ety);
else
EmitLoadElementAddress(ty, ety, ty.rank);
}
abstract public void EmitLoadElementAddress(ArrayType ty, Type ety, int rank);
public virtual void EmitLoadIndirect(Type ty) {
if (ty is EnumType)
ty = ((EnumType)ty).baseType;
if (!ty.IsScalarType)
Emit(OpCodes.Ldobj, ty);
else if (ty == T.Bool) Emit(OpCodes.Ldind_I1);
else if (ty == T.Byte) Emit(OpCodes.Ldind_U1);
else if (ty == T.Char) Emit(OpCodes.Ldind_I2);
else if (ty == T.Double) Emit(OpCodes.Ldind_R8);
else if (ty == T.Short) Emit(OpCodes.Ldind_I2);
else if (ty == T.Int) Emit(OpCodes.Ldind_I4);
else if (ty == T.Long) Emit(OpCodes.Ldind_I8);
else if (ty == T.SByte) Emit(OpCodes.Ldind_I1);
else if (ty == T.Float) Emit(OpCodes.Ldind_R4);
else if (ty == T.String) Emit(OpCodes.Ldind_Ref);
else if (ty == T.UShort) Emit(OpCodes.Ldind_U2);
else if (ty == T.UInt) Emit(OpCodes.Ldind_U4);
else if (ty == T.ULong) Emit(OpCodes.Ldind_I8);
else if (ty is PointerType) Emit(OpCodes.Ldind_U4);
else Emit(OpCodes.Ldind_Ref);
}
public virtual void EmitStore(int index) {
Emit(OpCodes.Stloc, index);
}
public virtual void EmitStore(Symbol f) {
if (f is Formal && ((Formal)f).modifier != null)
EmitStoreIndirect(((Formal)f).Type);
else if (f is Formal)
Emit(OpCodes.Starg, (Formal)f);
else if (f is Local)
Emit(OpCodes.Stloc, (Local)f);
else if (f is Field && f.IsStatic)
Emit(OpCodes.Stsfld, (Field)f);
else if (f is Field && f.IsInstance)
Emit(OpCodes.Stfld, (Field)f);
else if (f is Property)
EmitCall(((Property)f).Set);
}
abstract public void EmitStoreElement(ArrayType ty, Type ety, int rank);
public virtual void EmitStoreElement(ArrayType ty, expression rhs) {
Type ety = ty.elementType;
if (ety.IsScalarType && ty.rank > 1) {
expression(rhs);
EmitStoreElement(ty, ety, ty.rank);
} else if (ety.IsScalarType) {
expression(rhs);
if (ety is EnumType)
ety = ((EnumType)ety).baseType;
if (ety == T.Bool) Emit(OpCodes.Stelem_I1);
else if (ety == T.Byte) Emit(OpCodes.Stelem_I1);
else if (ety == T.Char) Emit(OpCodes.Stelem_I2);
else if (ety == T.Double) Emit(OpCodes.Stelem_R8);
else if (ety == T.Short) Emit(OpCodes.Stelem_I2);
else if (ety == T.Int) Emit(OpCodes.Stelem_I4);
else if (ety == T.Long) Emit(OpCodes.Stelem_I8);
else if (ety == T.SByte) Emit(OpCodes.Stelem_I1);
else if (ety == T.Float) Emit(OpCodes.Stelem_R4);
else if (ety == T.String) Emit(OpCodes.Stelem_Ref);
else if (ety == T.UShort) Emit(OpCodes.Stelem_I2);
else if (ety == T.UInt) Emit(OpCodes.Stelem_I4);
else if (ety == T.ULong) Emit(OpCodes.Stelem_I8);
else if (ety is PointerType) Emit(OpCodes.Stelem_I4);
else Emit(OpCodes.Stelem_Ref);
} else { // value types
EmitLoadElementAddress(ty);
expression(rhs);
EmitStoreIndirect(ety);
}
}
public virtual void EmitStoreIndirect(Type ty) {
if (ty is EnumType)
ty = ((EnumType)ty).baseType;
if (!ty.IsScalarType)
Emit(OpCodes.Stobj, ty);
else if (ty == T.Bool) Emit(OpCodes.Stind_I1);
else if (ty == T.Byte) Emit(OpCodes.Stind_I1);
else if (ty == T.Char) Emit(OpCodes.Stind_I2);
else if (ty == T.Double) Emit(OpCodes.Stind_R8);
else if (ty == T.Short) Emit(OpCodes.Stind_I2);
else if (ty == T.Int) Emit(OpCodes.Stind_I4);
else if (ty == T.Long) Emit(OpCodes.Stind_I8);
else if (ty == T.SByte) Emit(OpCodes.Stind_I1);
else if (ty == T.Float) Emit(OpCodes.Stind_R4);
else if (ty == T.String) Emit(OpCodes.Stind_Ref);
else if (ty == T.UShort) Emit(OpCodes.Stind_I2);
else if (ty == T.UInt) Emit(OpCodes.Stind_I4);
else if (ty == T.ULong) Emit(OpCodes.Stind_I8);
else if (ty is PointerType) Emit(OpCodes.Stind_I4);
else Emit(OpCodes.Stind_Ref);
}
abstract public void EmitSwitch(int[] caselabels);
public virtual void empty_statement(empty_statement ast) {}
public virtual void EndTry(object handle) { defLabel((int)handle); }
public virtual void expr_access(expr_access ast, bool lvalue) {
if (ast.sym is Type)
return;
expression(ast.expr, ast.expr.typ.IsValueType);
if (ast.sym is Property && ast.sym.Name == "Length"
&& ast.expr.typ is ArrayType && ((ArrayType)ast.expr.typ).rank == 1) {
Emit(OpCodes.Ldlen);
EmitCast(T.UInt, T.Int);
} else if (lvalue)
EmitLoadAddress(ast.sym);
else if (ast.sym is Property && ast.expr is base_access)
EmitCall(OpCodes.Call, ((Property)ast.sym).Get);
else
EmitLoad(ast.sym);
}
public virtual void expr_access(expr_access ast, expression rhs) {
if (ast.sym is Type)
return;
expression(ast.expr, ast.expr.typ.IsValueType);
expression(rhs);
if (ast.sym is Property && ast.expr is base_access)
EmitCall(OpCodes.Call, ((Property)ast.sym).Set);
else
EmitStore(ast.sym);
}
public virtual void expr_initializer(expr_initializer ast) {
expression(ast.expr);
}
public virtual void expression(expression ast) {
asts.Push(ast);
if (ast is array_creation_expression1) array_creation_expression1((array_creation_expression1)ast);
else if (ast is array_creation_expression2) array_creation_expression2((array_creation_expression2)ast);
else if (ast is as_expression) as_expression((as_expression)ast);
else if (ast is assignment_expression) assignment_expression((assignment_expression)ast);
else if (ast is base_access) base_access((base_access)ast);
else if (ast is binary_expression) binary_expression((binary_expression)ast, 0, 0);
else if (ast is literal) literal((literal)ast);
else if (ast is cast_expression) cast_expression((cast_expression)ast);
else if (ast is checked_expression) checked_expression((checked_expression)ast, false);
else if (ast is compound_assignment_expression) compound_assignment_expression((compound_assignment_expression)ast);
else if (ast is cond_expression) cond_expression((cond_expression)ast);
else if (ast is element_access) element_access((element_access)ast, false);
else if (ast is member_access) member_access((member_access)ast, false);
else if (ast is implicit_cast_expression) implicit_cast_expression((implicit_cast_expression)ast);
else if (ast is invocation_expression) invocation_expression((invocation_expression)ast);
else if (ast is is_expression) is_expression((is_expression)ast);
else if (ast is local_expression) local_expression((local_expression)ast, false);
else if (ast is new_expression) new_expression((new_expression)ast);
else if (ast is post_expression) post_expression((post_expression)ast);
else if (ast is pre_expression) pre_expression((pre_expression)ast);
else if (ast is simple_name) simple_name((simple_name)ast, false);
else if (ast is sizeof_expression) sizeof_expression((sizeof_expression)ast);
else if (ast is temporary) temporary((temporary)ast);
else if (ast is this_access) this_access();
else if (ast is typeof_expression) typeof_expression((typeof_expression)ast);
else if (ast is unary_expression) unary_expression((unary_expression)ast, 0, 0);
else if (ast is unchecked_expression) unchecked_expression((unchecked_expression)ast, false);
else throw new ArgumentException();
asts.Pop();
}
public virtual void expression(expression ast, int trueLabel, int falseLabel) {
if (ast is binary_expression)
binary_expression((binary_expression)ast, trueLabel, falseLabel);
else if (ast is unary_expression)
unary_expression((unary_expression)ast, trueLabel, falseLabel);
else {
expression(ast);
if (trueLabel != 0)
gotoLabel(OpCodes.Brtrue, trueLabel);
if (falseLabel != 0)
gotoLabel(OpCodes.Brfalse, falseLabel);
}
}
public virtual void expression(expression ast, bool lvalue) {
asts.Push(ast);
if (ast is checked_expression) checked_expression((checked_expression)ast, lvalue);
else if (ast is element_access) element_access((element_access)ast, lvalue);
else if (ast is member_access) member_access((member_access)ast, lvalue);
else if (ast is local_expression) local_expression((local_expression)ast, lvalue);
else if (ast is simple_name) simple_name((simple_name)ast, lvalue);
else if (ast is unchecked_expression) unchecked_expression((unchecked_expression)ast, lvalue);
else expression(ast);
asts.Pop();
}
public virtual void expression(expression ast, expression rhs) {
asts.Push(ast);
if (ast is checked_expression) checked_expression((checked_expression)ast, rhs);
else if (ast is element_access) element_access((element_access)ast, rhs);
else if (ast is member_access) member_access((member_access)ast, rhs);
else if (ast is local_expression) local_expression((local_expression)ast, rhs);
else if (ast is simple_name) simple_name((simple_name)ast, rhs);
else if (ast is unchecked_expression) unchecked_expression((unchecked_expression)ast, rhs);
else Debug.Fail(String.Format("unknown assignment '{0}'", ast));
asts.Pop();
}
public virtual void expression_statement(expression_statement ast) {
expression(ast.expr);
}
public virtual int genLabel(int n) {
nextlab += n;
return nextlab - n;
}
public virtual void fixed_statement(fixed_statement ast) {
msg.Error("fixed statement not implemented");
}
public virtual void for_decl(for_decl ast) {
local_statement(ast.decl);
}
public virtual void for_init(for_init ast) {
if (ast is for_decl) for_decl((for_decl)ast);
else if (ast is for_list) for_list((for_list)ast);
else throw new ArgumentException();
}
public virtual void for_list(for_list ast) {
foreach (expression x in ast.exprs)
expression(x);
}
public virtual void for_statement(for_statement ast) {
ast.lab = genLabel(4);
if (ast.init != null)
for_init(ast.init);
gotoLabel(ast.lab + 3);
defLabel(ast.lab);
statement(ast.body);
defLabel(ast.lab + 1);
foreach (expression x in ast.iterators)
expression(x);
defLabel(ast.lab + 3);
if (ast.cond != null)
expression(ast.cond, ast.lab, 0);
else
gotoLabel(ast.lab);
defLabel(ast.lab + 2);
}
public virtual void foreach_array(foreach_statement ast) {
//
//foreach (T x in array) S
//=>
//for (int i = 0; i < array.Length; ++i) {
// x = (T)array[i];
// S
//}
//
int index = newLocal(T.Int), array = newLocal(ast.expr.typ);
expression(ast.expr);
EmitStore(array);
Emit(OpCodes.Ldc_I4_0);
EmitStore(index);
gotoLabel(ast.lab + 3);
defLabel(ast.lab);
EmitLoad(array);
EmitLoad(index);
EmitLoadElement((ArrayType)ast.expr.typ);
EmitCast(((ArrayType)ast.expr.typ).elementType, ast.sym.Type);
EmitStore(ast.sym);
statement(ast.body);
defLabel(ast.lab + 1);
EmitLoad(index);
Emit(OpCodes.Ldc_I4_1);
Emit(OpCodes.Add);
EmitStore(index);
defLabel(ast.lab + 3);
EmitLoad(index);
EmitLoad(array);
Emit(OpCodes.Ldlen);
EmitCast(T.UInt, T.Int);
gotoLabel(OpCodes.Blt, ast.lab);
defLabel(ast.lab + 2);
}
public virtual void foreach_withTry(foreach_statement ast, int enumerator) {
//
//try {
// foreach_body expansion...
//} finally {
// IDisposable disposable = enumerator as System.IDisposable;
// if (disposable != null) disposable.Dispose();
//}
//
object handle = BeginTry();
foreach_body(ast, enumerator);
handle = BeginFinally(handle);
EmitLoad(enumerator);
if (ast.GetEnumerator.Type.Implements(T.IDisposable)) {
EmitCast(ast.GetEnumerator.Type, T.IDisposable);
EmitCall(T.IDisposable.FindMethod("Dispose"));
} else {
int disposable = newLocal(T.IDisposable);
Emit(OpCodes.Isinst, T.IDisposable);
EmitStore(disposable);
EmitLoad(disposable);
int lab = genLabel(1);
gotoLabel(OpCodes.Brfalse, lab);
EmitLoad(disposable);
EmitCall(T.IDisposable.FindMethod("Dispose"));
defLabel(lab);
}
EndTry(handle);
defLabel(ast.lab + 3);
}
public virtual void foreach_body(foreach_statement ast, int enumerator) {
//
//foreach (T x in collection) S
//=>
//while (enumerator.MoveNext()) {
// T element = (T)enumerator.Current;
// S
//}
//
gotoLabel(ast.lab + 1);
defLabel(ast.lab);
EmitLoad(enumerator);
EmitLoad(ast.Current);
EmitCast(ast.Current.Type, ast.sym.Type);
EmitStore(ast.sym);
statement(ast.body);
defLabel(ast.lab + 1);
EmitLoad(enumerator);
EmitCall(ast.MoveNext);
gotoLabel(OpCodes.Brtrue, ast.lab);
defLabel(ast.lab + 2);
}
public virtual void foreach_statement(foreach_statement ast) {
ast.lab = genLabel(4);
ast.sym.ordinal = newLocal(ast.sym.Type);
if (ast.expr.typ is ArrayType && ((ArrayType)ast.expr.typ).rank == 1)
foreach_array(ast);
else {
//
//E enumerator = (collection).GetEnumerator();
//or
//IEnumerator enumerator = ((System.Collections.IEnumerable)(collection)).GetEnumerator();
//
int enumerator = newLocal(ast.GetEnumerator.Type);
expression(ast.expr);
EmitCall(ast.GetEnumerator);
EmitStore(enumerator);
if (ast.GetEnumerator.Type.Implements(T.IDisposable)
|| !ast.GetEnumerator.Type.Is("sealed"))
foreach_withTry(ast, enumerator);
else
foreach_body(ast, enumerator);
}
}
public virtual void goto_case_statement(goto_case_statement ast) {
if (ast.label != null)
gotoLabel(ast.exitstry ? OpCodes.Leave : OpCodes.Br, ((switch_section)ast.label.parent).lab);
}
public virtual void goto_default_statement(goto_default_statement ast) {
if (ast.stmt != null)
gotoLabel(ast.exitstry ? OpCodes.Leave : OpCodes.Br, ast.stmt.lab);
}
public virtual void goto_statement(goto_statement ast) {
if (ast.target.lab == 0)
ast.target.lab = genLabel(1);
ast.lab = ast.target.lab;
gotoLabel(ast.exitstry ? OpCodes.Leave : OpCodes.Br, ast.lab);
}
abstract public void gotoLabel(OpCode inst, int lab);
public void gotoLabel(int lab) {
gotoLabel(OpCodes.Br, lab);
}
public virtual void if_statement(if_statement ast) {
ast.lab = genLabel(2);
expression(ast.expr, 0, ast.lab);
statement(ast.thenpart);
if (ast.elsepart != null) {
gotoLabel(ast.lab + 1);
defLabel(ast.lab);
statement(ast.elsepart);
} else
defLabel(ast.lab);
defLabel(ast.lab + 1);
}
public virtual void implicit_cast_expression(implicit_cast_expression ast) {
expression(ast.expr);
EmitCast(ast.expr.typ, ast.typ);
}
public virtual void integer_literal(integer_literal ast) {
if (ast.typ == T.Long || ast.typ == T.ULong)
Emit(OpCodes.Ldc_I8, (long)ast.value);
else
Emit(OpCodes.Ldc_I4, (int)ast.value);
}
public virtual void invocation_expression(invocation_expression ast) {
if (ast.method.IsInstance) {
expression(ast.expr);
if (ast.expr.typ.IsValueType && ast.method.GetType().IsReferenceType)
Emit(OpCodes.Box, ast.expr.typ);
}
EmitArgumentList(ast.method, ast.args);
if (ast.expr is expr_access && ((expr_access)ast.expr).expr is base_access)
EmitCall(OpCodes.Call, ast.method);
else
EmitCall(ast.method);
if (ast.typ != T.Void && !ast.valueUsed)
Emit(OpCodes.Pop);
}
public static bool is_event_access(expression ast) {
Event e = null;
if (ast is simple_name)
e = ((simple_name)ast).sym as Event;
else if (ast is member_access)
e = ((member_access)ast).sym as Event;
if (e == null)
return false;
if (e.GetType() != currentClass(ast))
return true;
return !e.IsFieldLike;
}
public virtual void is_expression(is_expression ast) {
expression(ast.expr);
Emit(OpCodes.Isinst, ast.sym);
}
public virtual void labeled_statement(labeled_statement ast) {
if (ast.lab == 0)
ast.lab = genLabel(1);
defLabel(ast.lab);
statement(ast.stmt);
}
public virtual void literal(literal ast) {
if (ast is boolean_literal) boolean_literal((boolean_literal)ast);
else if (ast is character_literal) character_literal((character_literal)ast);
else if (ast is integer_literal) integer_literal((integer_literal)ast);
else if (ast is null_literal) null_literal((null_literal)ast);
else if (ast is real_literal) real_literal((real_literal)ast);
else if (ast is string_literal) string_literal((string_literal)ast);
else throw new ArgumentException();
}
public virtual void local_expression(local_expression ast, bool lvalue) {
if (ast.value != null) {
expression(ast.value, lvalue);
return;
}
expression(ast.expr, lvalue);
if (ast.expr is assignment_expression)
ast.value = ((assignment_expression)ast.expr).e2;
else if (ast.expr is local_expression)
ast.value = ((local_expression)ast.expr).value;
else {
int temp = newLocal(ast.expr.typ);
Emit(OpCodes.Dup);
EmitStore(temp);
ast.value = new temporary(ast.expr.typ, temp);
}
}
public virtual void local_expression(local_expression ast, expression rhs) {
expression(ast.expr, rhs);
}
public virtual void local_statement(local_statement ast) {
foreach (var_declarator x in ast.vars)
x.sym.ordinal = newLocal(x.sym);
foreach (var_declarator x in ast.vars)
if (x.init != null) {
variable_initializer(x.init);
EmitStore(x.sym);
}
}
public virtual void lock_statement(lock_statement ast) {
int var = newLocal(ast.expr.typ);
expression(ast.expr);
Emit(OpCodes.Dup);
EmitStore(var);
System.Type monitor = System.Type.GetType("System.Threading.Monitor");
// try {
object handle = BeginTry();
EmitCall(T.Monitor.FindMethod("Enter", T.Object));
statement(ast.body);
// } finally {
handle = BeginFinally(handle);
EmitLoad(var);
EmitCall(T.Monitor.FindMethod("Exit", T.Object));
// }
EndTry(handle);
}
public virtual void member_access(member_access ast, bool lvalue) {
if (ast is expr_access) expr_access((expr_access)ast, lvalue);
else if (ast is pointer_access) pointer_access((pointer_access)ast, lvalue);
else if (ast is predefined_access) predefined_access((predefined_access)ast, lvalue);
else throw new ArgumentException();
}
public virtual void member_access(member_access ast, expression rhs) {
if (ast is expr_access) expr_access((expr_access)ast, rhs);
else if (ast is pointer_access) pointer_access((pointer_access)ast, rhs);
else if (ast is predefined_access) predefined_access((predefined_access)ast, rhs);
else throw new ArgumentException();
}
public virtual void new_expression(new_expression ast) {
if (ast.typ == T.Long || ast.typ == T.ULong)
Emit(OpCodes.Ldc_I8, 0L);
else if (ast.typ.IsSigned || ast.typ.IsUnsigned || ast.typ == T.Char
|| ast.typ == T.Bool || ast.typ is EnumType)
Emit(OpCodes.Ldc_I4_0);
else if (ast.typ == T.Double)
Emit(OpCodes.Ldc_R8, 0.0d);
else if (ast.typ == T.Float)
Emit(OpCodes.Ldc_R4, 0.0f);
else if (ast.typ.IsValueType) {
int var = newLocal(ast.typ);
EmitLoadAddress(var);
if (ast.args.Count == 0)
Emit(OpCodes.Initobj, ast.typ);
else {
EmitArgumentList(ast.method, ast.args);
EmitCall(ast.method);
}
EmitLoad(var);
} else if (ast.typ is DelegateType) {
expression e = ast.args[0].expr;
if (e.typ is DelegateType) {
expression(e);
EmitLoad(((DelegateType)ast.typ).invoke);
} else {
Method m;
if (e is simple_name)
m = (Method)((simple_name)e).sym;
else
m = (Method)((member_access)e).sym;
if (m.IsInstance)
expression(e);
else {
Emit(OpCodes.Ldnull);
EmitLoad(m);
}
}
Emit(OpCodes.Newobj, ast.method);
} else {
EmitArgumentList(ast.args);
Emit(OpCodes.Newobj, ast.method);
}
}
abstract public int newLocal(Type ty);
public virtual int newLocal(Local v) {
v.ordinal = newLocal(v.Type);
return v.ordinal;
}
public virtual int newLocal(Type ty, string name) {
return newLocal(ty);
}
public virtual void null_literal(null_literal ast) {
Emit(OpCodes.Ldnull);
}
public virtual void pointer_access(pointer_access ast, bool lvalue) {
msg.Error("pointer access not implemented");
}
public virtual void pointer_access(pointer_access ast, expression rhs) {
msg.Error("pointer access not implemented");
}
public virtual void post_expression(post_expression ast) {
if (ast.method != null && ast.method.declSpace != null) {
expression(ast.expr);
if (ast.valueUsed)
Emit(OpCodes.Dup);
EmitCall(ast.method);
Emit(OpCodes.Pop);
} else {
expression(ast.expr);
if (ast.valueUsed)
Emit(OpCodes.Dup);
Emit(OpCodes.Ldc_I4_1);
binary_operator(ast.op.str.Substring(0, 1), ast.typ, ast.method);
temporary rhs = new temporary(ast.typ, newLocal(ast.typ));
EmitStore(rhs.var);
expression(ast.expr, rhs);
}
}
public virtual void pre_expression(pre_expression ast) {
if (ast.method != null && ast.method.declSpace != null) {
expression(ast.expr);
EmitCall(ast.method);
if (!ast.valueUsed)
Emit(OpCodes.Pop);
} else {
expression(ast.expr);
Emit(OpCodes.Ldc_I4_1);
binary_operator(ast.op.str.Substring(0, 1), ast.typ, ast.method);
temporary rhs = new temporary(ast.typ, newLocal(ast.typ));
EmitStore(rhs.var);
expression(ast.expr, rhs);
if (ast.valueUsed)
expression(rhs);
}
}
public virtual void predefined_access(predefined_access ast, bool lvalue) {
if (ast.sym != null)
EmitLoad(ast.sym);
}
public virtual void predefined_access(predefined_access ast, expression rhs) {
if (ast.sym != null) {
expression(rhs);
EmitStore(ast.sym);
}
}
public virtual void real_literal(real_literal ast) {
if (ast.typ == T.Double)
Emit(OpCodes.Ldc_R8, (double)ast.value);
else
Emit(OpCodes.Ldc_R4, (float)ast.value);
}
public virtual void resource_decl(resource_decl ast, using_statement stmt) {
foreach (var_declarator v in ast.local.vars) {
v.sym.ordinal = newLocal(v.sym.Type, v.sym.Name);
if (v.init != null) {
expression(((expr_initializer)v.init).expr);
EmitStore(v.sym);
}
}
object handle = BeginTry();
// try {
statement(stmt.body);
// } finally {
handle = BeginFinally(handle);
for (int i = ast.local.vars.Count - 1; i >= 0; i--) {
var_declarator v = (var_declarator)ast.local.vars[i];
int lab = 0;
if (ast.local.ty.sym.IsReferenceType) {
lab = genLabel(1);
EmitLoad(v.sym);
gotoLabel(OpCodes.Brfalse /* brnull */, lab);
EmitLoad(v.sym);
} else
EmitLoadAddress(v.sym);
if (ast.method != null)
EmitCall(ast.method);
EmitCall(ast.dispose);
if (lab != 0)
defLabel(lab);
}
// }
EndTry(handle);
}
public virtual void resource_expr(resource_expr ast, using_statement stmt) {
int var = newLocal(ast.expr.typ);
expression(ast.expr);
EmitStore(var);
object handle = BeginTry();
// try {
statement(stmt.body);
// } finally {
handle = BeginFinally(handle);
int lab = 0;
if (ast.expr.typ.IsReferenceType) {
lab = genLabel(1);
EmitLoad(var);
gotoLabel(OpCodes.Brfalse /* brnull */, lab);
EmitLoad(var);
} else
EmitLoadAddress(var);
EmitCall(ast.dispose);
if (lab != 0)
defLabel(lab);
// }
EndTry(handle);
}
public virtual void return_statement(return_statement ast) {
if (ast.expr != null) {
expression(ast.expr);
EmitStore(retvar);
gotoLabel(ast.exitstry ? OpCodes.Leave : OpCodes.Br, retlab);
} else
Emit(OpCodes.Ret);
}
public virtual void simple_name(simple_name ast, bool lvalue) {
if (ast.sym == null || ast.sym is Type)
return;
if (ast.sym.IsInstance)
this_access();
if (lvalue)
EmitLoadAddress(ast.sym);
else
EmitLoad(ast.sym);
}
public virtual void simple_name(simple_name ast, expression rhs) {
if (ast.sym == null || ast.sym is Type)
return;
if (ast.sym.IsInstance)
this_access();
else if (ast.sym is Formal && ((Formal)ast.sym).modifier != null)
EmitLoadAddress(ast.sym);
expression(rhs);
EmitStore(ast.sym);
}
public virtual void sizeof_expression(sizeof_expression ast) {
Emit(OpCodes.Sizeof, ast.ty.sym);
}
public virtual void stackalloc_initializer(stackalloc_initializer ast) {
Emit(OpCodes.Sizeof, ast.ty.sym);
expression(ast.expr);
Emit(OpCodes.Mul);
Emit(OpCodes.Localloc);
}
public virtual void statement(statement ast) {
asts.Push(ast);
if (ast is block_statement) block_statement((block_statement)ast);
else if (ast is break_statement) break_statement((break_statement)ast);
else if (ast is checked_statement) checked_statement((checked_statement)ast);
else if (ast is const_statement) const_statement((const_statement)ast);
else if (ast is continue_statement) continue_statement((continue_statement)ast);
else if (ast is do_statement) do_statement((do_statement)ast);
else if (ast is empty_statement) empty_statement((empty_statement)ast);
else if (ast is expression_statement) expression_statement((expression_statement)ast);
else if (ast is fixed_statement) fixed_statement((fixed_statement)ast);
else if (ast is for_statement) for_statement((for_statement)ast);
else if (ast is foreach_statement) foreach_statement((foreach_statement)ast);
else if (ast is goto_case_statement) goto_case_statement((goto_case_statement)ast);
else if (ast is goto_default_statement) goto_default_statement((goto_default_statement)ast);
else if (ast is goto_statement) goto_statement((goto_statement)ast);
else if (ast is if_statement) if_statement((if_statement)ast);
else if (ast is labeled_statement) labeled_statement((labeled_statement)ast);
else if (ast is local_statement) local_statement((local_statement)ast);
else if (ast is lock_statement) lock_statement((lock_statement)ast);
else if (ast is return_statement) return_statement((return_statement)ast);
else if (ast is switch_statement) switch_statement((switch_statement)ast);
else if (ast is throw_statement) throw_statement((throw_statement)ast);
else if (ast is try_statement) try_statement((try_statement)ast);
else if (ast is unchecked_statement) unchecked_statement((unchecked_statement)ast);
else if (ast is unsafe_statement) statement(((unsafe_statement)ast).block);
else if (ast is using_statement) using_statement((using_statement)ast);
else if (ast is while_statement) while_statement((while_statement)ast);
else throw new ArgumentException();
asts.Pop();
}
public virtual void statement(statement ast, Method m) {
if (m.Type != T.Void) {
retlab = ast.lab = genLabel(1);
retvar = newLocal(m.Type);
}
statement(ast);
if (m.Type != T.Void) {
defLabel(retlab);
EmitLoad(retvar);
}
Emit(OpCodes.Ret);
}
public virtual void string_literal(string_literal ast) {
Emit(OpCodes.Ldstr, (string)ast.value);
}
public virtual void switch_search(switch_expressionList values, int lb, int ub, int temp) {
for (int i = lb; i <= ub; i++) {
EmitLoad(temp);
if (values[i].expr is string_literal)
string_literal((string_literal)values[i].expr);
else
Emit(OpCodes.Ldc_I4, (int)(uint)values[i].expr.value);
gotoLabel(OpCodes.Beq, ((switch_section)values[i].parent).lab);
}
}
public virtual void switch_section(switch_section ast) {
asts.Push(ast);
defLabel(ast.lab);
foreach (statement x in ast.stmts)
statement(x);
asts.Pop();
}
public virtual void switch_section(switch_section ast, int dlab, ref bool hasdefault) {
foreach (switch_label x in ast.labels)
if (x is switch_default) {
hasdefault = true;
ast.lab = dlab;
return;
}
ast.lab = genLabel(1);
}
public virtual void switch_statement(switch_statement ast) {
ast.lab = genLabel(3);
bool hasdefault = false;
foreach (switch_section s in ast.sections)
switch_section(s, ast.lab, ref hasdefault);
expression(ast.expr);
int temp = newLocal(ast.typ);
EmitStore(temp);
if (ast.typ == T.String) {
EmitLoad(temp);
gotoLabel(OpCodes.Brfalse, ast.lab);
EmitLoad(temp);
EmitCall(T.String.FindMethod("Intern", T.String));
EmitStore(temp);
switch_search(ast.values, 0, ast.values.Count - 1, temp);
gotoLabel(ast.lab);
} else if (ast.typ == T.Long || ast.typ == T.ULong) {
switch_search(ast.values, 0, ast.values.Count - 1, temp);
gotoLabel(ast.lab);
} else if (ast.values.Count > 0) {
int i, j;
for (i = 0; i < ast.values.Count; i = j) {
for (j = i + 1; j < ast.values.Count; j++)
if (((uint)ast.values[j].expr.value - (uint)ast.values[i].expr.value + 1)/(j - i + 1) > 2)
break;
if (j - i < 2)
switch_search(ast.values, i, j - 1, temp);
else
switch_table(ast.values, i, j - 1, temp, ast.lab);
}
gotoLabel(ast.lab);
}
foreach (switch_section s in ast.sections)
switch_section(s);
if (!hasdefault)
defLabel(ast.lab);
defLabel(ast.lab + 1);
defLabel(ast.lab + 2);
}
public virtual void switch_table(switch_expressionList values, int lb, int ub, int temp, int dlab) {
EmitLoad(temp);
uint n = (uint)values[lb].expr.value;
if (n > 0) {
Emit(OpCodes.Ldc_I4, (int)n);
Emit(OpCodes.Sub);
}
int[] labels = new int[(uint)values[ub].expr.value-n+1];
int j = 0;
for (int i = lb; i <= ub; i++) {
for ( ; n < (uint)values[i].expr.value; n++)
labels[j++] = dlab;
labels[j++] = ((switch_section)values[i].parent).lab;
n++;
}
Debug.Assert(j == labels.Length);
EmitSwitch(labels);
}
public virtual void temporary(temporary ast) {
EmitLoad(ast.var);
}
public virtual void this_access() {
Emit(OpCodes.Ldarg_0);
}
public virtual void this_initializer(this_initializer ast) {
this_access();
EmitArgumentList(ast.method, ast.args);
EmitCall(ast.method);
}
public virtual void throw_statement(throw_statement ast) {
if (ast.expr != null) {
expression(ast.expr);
Emit(OpCodes.Throw);
} else
Emit(OpCodes.Rethrow);
}
public virtual void try_statement(try_statement ast) {
object handle1 = null, handle2 = null;
ast.lab = genLabel(1);
if (ast.finally_block != null)
handle1 = BeginTry();
if (ast.catches != null)
handle2 = BeginTry();
statement(ast.block);
if (ast.catches != null) {
catch_clauses(ast.catches, handle2);
EndTry(handle2);
}
if (ast.finally_block != null) {
handle1 = BeginFinally(handle1);
statement(ast.finally_block.block);
EndTry(handle1);
}
defLabel(ast.lab);
}
public virtual void typeof_expression(typeof_expression ast) {
Emit(OpCodes.Ldtoken, ast.ty.sym);
EmitCall(T.Type.FindMethod("GetTypeFromHandle", T.RuntimeTypeHandle));
}
public virtual void unary_expression(unary_expression ast, int trueLabel, int falseLabel) {
switch (ast.op.str) {
case "!":
if (trueLabel != 0 || falseLabel != 0)
expression(ast.expr, falseLabel, trueLabel);
else {
expression(ast.expr);
Emit(OpCodes.Ldc_I4_1);
Emit(OpCodes.Xor);
}
return;
}
switch (ast.op.str) {
case "-":
if (checking && (ast.typ.IsSigned || ast.typ.IsUnsigned)) {
Emit(OpCodes.Ldc_I4_0);
expression(ast.expr);
if (ast.expr.typ.IsUnsigned)
Emit(OpCodes.Sub_Ovf_Un);
else
Emit(OpCodes.Sub_Ovf);
break;
}
expression(ast.expr);
Emit(OpCodes.Neg);
break;
case "+": expression(ast.expr); break;
case "~": expression(ast.expr); Emit(OpCodes.Not); break;
case "*": msg.Error("indirection not implemented"); break;
}
}
public virtual void unchecked_expression(unchecked_expression ast, bool lvalue) {
bool save = checking;
checking = true;
expression(ast.expr, lvalue);
checking = save;
}
public virtual void unchecked_expression(unchecked_expression ast, expression rhs) {
bool save = checking;
checking = true;
expression(ast.expr, rhs);
checking = save;
}
public virtual void unchecked_statement(unchecked_statement ast) {
bool save = checking;
checking = true;
statement(ast.stmt);
checking = save;
}
public virtual void using_statement(using_statement ast) {
ast.lab = genLabel(1);
if (ast.r is resource_expr)
resource_expr((resource_expr)ast.r, ast);
else
resource_decl((resource_decl)ast.r, ast);
defLabel(ast.lab);
}
public virtual void variable_initializer(variable_initializer ast) {
if (ast is array_initializer) array_initializer((array_initializer)ast);
else if (ast is expr_initializer) expr_initializer((expr_initializer)ast);
else if (ast is stackalloc_initializer) stackalloc_initializer((stackalloc_initializer)ast);
else throw new ArgumentException();
}
public virtual void while_statement(while_statement ast) {
ast.lab = genLabel(3);
gotoLabel(ast.lab + 1);
defLabel(ast.lab);
statement(ast.body);
defLabel(ast.lab + 1);
expression(ast.expr, ast.lab, 0);
defLabel(ast.lab + 2);
}
}