1463 lines
50 KiB
C#
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);
|
||
|
}
|
||
|
}
|