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); } }