using System.Collections;
using System.Diagnostics;
using System;
+ using System.Reflection;
+ using System.Reflection.Emit;
// <remarks>
// The ExprClass class contains the is used to pass the
}
}
- public abstract void Resolve (TypeContainer tc);
- public abstract void Emit (EmitContext ec);
+ public abstract Expression Resolve (TypeContainer tc);
+ public abstract void Emit (EmitContext ec);
// <summary>
// Protected constructor. Only derivate types should
eclass = ExprClass.Invalid;
type = null;
}
+
+ //
+ // Returns a fully formed expression after a MemberLookup
+ //
+ static Expression ExprClassFromMemberInfo (MemberInfo mi)
+ {
+ if (mi is EventInfo){
+ return new EventExpr ((EventInfo) mi);
+ } else if (mi is FieldInfo){
+ return new FieldExpr ((FieldInfo) mi);
+ } else if (mi is PropertyInfo){
+ return new PropertyExpr ((PropertyInfo) mi);
+ } else if (mi is Type)
+ return new TypeExpr ((Type) mi);
+
+ return null;
+ }
+
+ //
+ // FIXME: Probably implement a cache for (t,name,current_access_set)?
+ //
+ // FIXME: We need to cope with access permissions here, or this wont
+ // work!
+ //
+ // This code could use some optimizations, but we need to do some
+ // measurements. For example, we could use a delegate to `flag' when
+ // something can not any longer be a method-group (because it is something
+ // else).
+ //
+ // Return values:
+ // If the return value is an Array, then it is an array of
+ // MethodBases
+ //
+ // If the return value is an MemberInfo, it is anything, but a Method
+ //
+ // null on error.
+ //
+ // FIXME: When calling MemberLookup inside an `Invocation', we should pass
+ // the arguments here and have MemberLookup return only the methods that
+ // match the argument count/type, unlike we are doing now (we delay this
+ // decision).
+ //
+ // This is so we can catch correctly attempts to invoke instance methods
+ // from a static body (scan for error 120 in ResolveSimpleName).
+ //
+ public static Expression MemberLookup (RootContext rc, Type t, string name,
+ bool same_type, MemberTypes mt, BindingFlags bf)
+ {
+ if (same_type)
+ bf |= BindingFlags.NonPublic;
+
+ MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
+
+ if (mi == null)
+ return null;
+
+ if (mi.Length == 1 && !(mi [0] is MethodBase))
+ return Expression.ExprClassFromMemberInfo (mi [0]);
+
+ for (int i = 0; i < mi.Length; i++)
+ if (!(mi [i] is MethodBase)){
+ rc.Report.Error (-5, "Do not know how to reproduce this case: " +
+ "Methods and non-Method with the same name, report this please");
+
+ for (i = 0; i < mi.Length; i++){
+ Type tt = mi [i].GetType ();
+
+ Console.WriteLine (i + ": " + mi [i]);
+ while (tt != TypeManager.object_type){
+ Console.WriteLine (tt);
+ tt = tt.BaseType;
+ }
+ }
+ }
+
+ return new MethodGroupExpr (mi);
+ }
+
+ public const MemberTypes AllMemberTypes =
+ MemberTypes.Constructor |
+ MemberTypes.Event |
+ MemberTypes.Field |
+ MemberTypes.Method |
+ MemberTypes.NestedType |
+ MemberTypes.Property;
+
+ public const BindingFlags AllBindingsFlags =
+ BindingFlags.Public |
+ BindingFlags.Static |
+ BindingFlags.Instance;
+
+ public static Expression MemberLookup (RootContext rc, Type t, string name,
+ bool same_type)
+ {
+ return MemberLookup (rc, t, name, same_type, AllMemberTypes, AllBindingsFlags);
+ }
+
+ // <summary>
+ // Resolves the E in `E.I' side for a member_access
+ //
+ // This is suboptimal and should be merged with ResolveMemberAccess
+ static Expression ResolvePrimary (TypeContainer tc, string name)
+ {
+ int dot_pos = name.LastIndexOf (".");
+
+ if (tc.RootContext.IsNamespace (name))
+ return new NamespaceExpr (name);
+
+ if (dot_pos != -1){
+ } else {
+ Type t = tc.LookupType (name, false);
+
+ if (t != null)
+ return new TypeExpr (t);
+ }
+
+ return null;
+ }
+
+ static public Expression ResolveMemberAccess (TypeContainer tc, string name)
+ {
+ Expression left_e;
+ int dot_pos = name.LastIndexOf (".");
+ string left = name.Substring (0, dot_pos);
+ string right = name.Substring (dot_pos + 1);
+
+ left_e = ResolvePrimary (tc, left);
+ if (left_e == null)
+ return null;
+
+ switch (left_e.ExprClass){
+ case ExprClass.Type:
+ return MemberLookup (tc.RootContext,
+ left_e.Type, right,
+ left_e.Type == tc.TypeBuilder);
+
+ case ExprClass.Namespace:
+ case ExprClass.PropertyAccess:
+ case ExprClass.IndexerAccess:
+ case ExprClass.Variable:
+ case ExprClass.Value:
+ case ExprClass.Nothing:
+ case ExprClass.EventAccess:
+ case ExprClass.MethodGroup:
+ case ExprClass.Invalid:
+ tc.RootContext.Report.Error (-1000,
+ "Internal compiler error, should have " +
+ "got these handled before");
+ break;
+ }
+
+ return null;
+ }
+
+ static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ if (target_type == TypeManager.object_type) {
+ if (expr_type.IsClass)
+ return new EmptyCast (expr, target_type);
+ if (expr_type.IsValueType)
+ return new BoxedCast (expr, target_type);
+ } else if (expr_type.IsSubclassOf (target_type))
+ return new EmptyCast (expr, target_type);
+ else
+ // FIXME: missing implicit reference conversions:
+ //
+ // from any class-type S to any interface-type T.
+ // from any interface type S to interface-type T.
+ // from an array-type S to an array-type of type T
+ // from an array-type to System.Array
+ // from any delegate type to System.Delegate
+ // from any array-type or delegate type into System.ICloneable.
+ // from the null type to any reference-type.
+
+ return null;
+
+ return null;
+ }
+
+ // <summary>
+ // Converts implicitly the resolved expression `expr' into the
+ // `target_type'. It returns a new expression that can be used
+ // in a context that expects a `target_type'.
+ // </summary>
+ static public Expression ConvertImplicit (Expression expr, Type target_type)
+ {
+ Type expr_type = expr.Type;
+
+ if (expr_type == target_type){
+ Console.WriteLine ("Hey, ConvertImplicit was called with no job to do");
+ return expr;
+ }
+
+ //
+ // Step 1: Perform implicit conversions as found on expr.Type
+ //
+
+ //
+ // Step 2: Built-in conversions.
+ //
+ if (expr_type == TypeManager.sbyte_type){
+ //
+ // From sbyte to short, int, long, float, double.
+ //
+ if (target_type == TypeManager.int32_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (target_type == TypeManager.short_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
+ } else if (expr_type == TypeManager.byte_type){
+ //
+ // From byte to short, ushort, int, uint, long, ulong, float, double
+ //
+ if ((target_type == TypeManager.short_type) ||
+ (target_type == TypeManager.ushort_type) ||
+ (target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.uint32_type))
+ return new EmptyCast (expr, target_type);
+
+ if (target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ } else if (expr_type == TypeManager.short_type){
+ //
+ // From short to int, long, float, double
+ //
+ if (target_type == TypeManager.int32_type)
+ return new EmptyCast (expr, target_type);
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ } else if (expr_type == TypeManager.ushort_type){
+ //
+ // From ushort to int, uint, long, ulong, float, double
+ //
+ if ((target_type == TypeManager.uint32_type) ||
+ (target_type == TypeManager.uint64_type))
+ return new EmptyCast (expr, target_type);
+
+ if (target_type == TypeManager.int32_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ } else if (expr_type == TypeManager.int32_type){
+ //
+ // From int to long, float, double
+ //
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ } else if (expr_type == TypeManager.uint32_type){
+ //
+ // From uint to long, ulong, float, double
+ //
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R4);
+ } else if ((expr_type == TypeManager.uint64_type) ||
+ (expr_type == TypeManager.int64_type)){
+ //
+ // From long to float, double
+ //
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
+ OpCodes.Conv_R4);
+ } else if (expr_type == TypeManager.char_type){
+ //
+ // From char to ushort, int, uint, long, ulong, float, double
+ //
+ if ((target_type == TypeManager.ushort_type) ||
+ (target_type == TypeManager.int32_type) ||
+ (target_type == TypeManager.uint32_type))
+ return new EmptyCast (expr, target_type);
+ if (target_type == TypeManager.uint64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
+ if (target_type == TypeManager.int64_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
+ if (target_type == TypeManager.float_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
+ if (target_type == TypeManager.double_type)
+ return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+ } else
+ return ImplicitReferenceConversion (expr, target_type);
+
+
+
+ //
+ // Could not find an implicit cast.
+ //
+ return null;
+ }
+
+ // <summary>
+ // Performs an explicit conversion of the expression `expr' whose
+ // type is expr.Type to `target_type'.
+ // </summary>
+ static public Expression ConvertExplicit (Expression expr, Type target_type)
+ {
+ return expr;
+ }
+
}
+ // <summary>
+ // This kind of cast is used to encapsulate the child
+ // whose type is child.Type into an expression that is
+ // reported to return "return_type". This is used to encapsulate
+ // expressions which have compatible types, but need to be dealt
+ // at higher levels with.
+ //
+ // For example, a "byte" expression could be encapsulated in one
+ // of these as an "unsigned int". The type for the expression
+ // would be "unsigned int".
+ //
+ // </summary>
+
+ public class EmptyCast : Expression {
+ protected Expression child;
+
+ public EmptyCast (Expression child, Type return_type)
+ {
+ ExprClass = child.ExprClass;
+ type = return_type;
+ this.child = child;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ child.Emit (ec);
+ }
+ }
+
+ public class BoxedCast : EmptyCast {
+
+ public BoxedCast (Expression expr, Type target_type)
+ : base (expr, target_type)
+ {
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ base.Emit (ec);
+ ec.ig.Emit (OpCodes.Box, child.Type);
+ }
+ }
+
+
+ // <summary>
+ // This kind of cast is used to encapsulate a child expression
+ // that can be trivially converted to a target type using one or
+ // two opcodes. The opcodes are passed as arguments.
+ // </summary>
+ public class OpcodeCast : EmptyCast {
+ OpCode op, op2;
+ bool second_valid;
+
+ public OpcodeCast (Expression child, Type return_type, OpCode op)
+ : base (child, return_type)
+
+ {
+ this.op = op;
+ second_valid = false;
+ }
+
+ public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
+ : base (child, return_type)
+
+ {
+ this.op = op;
+ this.op2 = op2;
+ second_valid = true;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ base.Emit (ec);
+ ec.ig.Emit (op);
+
+ if (second_valid)
+ ec.ig.Emit (op2);
+ }
+
+ }
+
public class Unary : Expression {
public enum Operator {
Plus, Minus, Negate, BitComplement,
}
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
// FIXME: Implement;
+ return this;
}
public override void Emit (EmitContext ec)
}
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
// FIXME: Implement;
+ return this;
}
public override void Emit (EmitContext ec)
}
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
// FIXME: Implement;
+ return this;
}
public override void Emit (EmitContext ec)
public class Binary : Expression {
public enum Operator {
Multiply, Divide, Modulo,
- Add, Substract,
+ Add, Subtract,
ShiftLeft, ShiftRight,
- LessThan, GreatherThan, LessOrEqual, GreatherOrEqual,
+ LessThan, GreaterThan, LessOrEqual, GreaterOrEqual,
Equal, NotEqual,
BitwiseAnd,
ExclusiveOr,
Operator oper;
Expression left, right;
+ MethodBase method;
+ ArrayList Arguments;
+
public Binary (Operator oper, Expression left, Expression right)
{
this.oper = oper;
}
}
- public override void Resolve (TypeContainer tc)
+
+ // <summary>
+ // Retruns a stringified representation of the Operator
+ // </summary>
+ string OperName ()
{
+ switch (oper){
+ case Operator.Multiply:
+ return "*";
+ case Operator.Divide:
+ return "/";
+ case Operator.Modulo:
+ return "%";
+ case Operator.Add:
+ return "+";
+ case Operator.Subtract:
+ return "-";
+ case Operator.ShiftLeft:
+ return "<<";
+ case Operator.ShiftRight:
+ return ">>";
+ case Operator.LessThan:
+ return "<";
+ case Operator.GreaterThan:
+ return ">";
+ case Operator.LessOrEqual:
+ return "<=";
+ case Operator.GreaterOrEqual:
+ return ">=";
+ case Operator.Equal:
+ return "==";
+ case Operator.NotEqual:
+ return "!=";
+ case Operator.BitwiseAnd:
+ return "&";
+ case Operator.BitwiseOr:
+ return "|";
+ case Operator.ExclusiveOr:
+ return "^";
+ case Operator.LogicalOr:
+ return "||";
+ case Operator.LogicalAnd:
+ return "&&";
+ }
+
+ return oper.ToString ();
}
+ Expression ForceConversion (Expression expr, Type target_type)
+ {
+ if (expr.Type == target_type)
+ return expr;
+
+ return ConvertImplicit (expr, target_type);
+ }
+
+ //
+ // Note that handling the case l == Decimal || r == Decimal
+ // is taken care of by the Step 1 Operator Overload resolution.
+ //
+ void DoNumericPromotions (TypeContainer tc, Type l, Type r)
+ {
+ if (l == TypeManager.double_type || r == TypeManager.double_type){
+ //
+ // If either operand is of type double, the other operand is
+ // conveted to type double.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (right, TypeManager.double_type);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (left, TypeManager.double_type);
+
+ type = TypeManager.double_type;
+ } else if (l == TypeManager.float_type || r == TypeManager.float_type){
+ //
+ // if either operand is of type float, th eother operand is
+ // converd to type float.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (right, TypeManager.float_type);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (left, TypeManager.float_type);
+ type = TypeManager.float_type;
+ } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
+ //
+ // If either operand is of type ulong, the other operand is
+ // converted to type ulong. or an error ocurrs if the other
+ // operand is of type sbyte, short, int or long
+ //
+ Type other = null;
+
+ if (l == TypeManager.uint64_type)
+ other = r;
+ else if (r == TypeManager.uint64_type)
+ other = l;
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type) ||
+ (other == TypeManager.int64_type)){
+ string oper = OperName ();
+
+ tc.RootContext.Report.Error (34, "Operator `" + OperName ()
+ + "' is ambiguous on operands of type `"
+ + TypeManager.CSharpName (l) + "' "
+ + "and `" + TypeManager.CSharpName (r)
+ + "'");
+ }
+ type = TypeManager.uint64_type;
+ } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
+ //
+ // If either operand is of type long, the other operand is converted
+ // to type long.
+ //
+ if (l != TypeManager.int64_type)
+ left = ConvertImplicit (left, TypeManager.int64_type);
+ if (r != TypeManager.int64_type)
+ right = ConvertImplicit (right, TypeManager.int64_type);
+
+ type = TypeManager.int64_type;
+ } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
+ //
+ // If either operand is of type uint, and the other
+ // operand is of type sbyte, short or int, othe operands are
+ // converted to type long.
+ //
+ Type other = null;
+
+ if (l == TypeManager.uint32_type)
+ other = r;
+ else if (r == TypeManager.uint32_type)
+ other = l;
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type)){
+ left = ForceConversion (left, TypeManager.int64_type);
+ right = ForceConversion (right, TypeManager.int64_type);
+ type = TypeManager.int64_type;
+ } else {
+ //
+ // if either operand is of type uint, the other
+ // operand is converd to type uint
+ //
+ left = ForceConversion (left, TypeManager.uint32_type);
+ right = ForceConversion (left, TypeManager.uint32_type);
+ type = TypeManager.uint32_type;
+ }
+ } else {
+ left = ForceConversion (left, TypeManager.int32_type);
+ right = ForceConversion (right, TypeManager.int32_type);
+ type = TypeManager.int32_type;
+ }
+ }
+
+ void error19 (TypeContainer tc)
+ {
+ tc.RootContext.Report.Error (
+ 19,
+ "Operator " + OperName () + " cannot be applied to operands of type `" +
+ TypeManager.CSharpName (left.Type) + "' and `" +
+ TypeManager.CSharpName (right.Type) + "'");
+
+ }
+
+ Expression CheckShiftArguments (TypeContainer tc)
+ {
+ Expression e;
+ Type l = left.Type;
+ Type r = right.Type;
+
+ e = ForceConversion (right, TypeManager.int32_type);
+ if (e == null){
+ error19 (tc);
+ return null;
+ }
+ right = e;
+
+ if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
+ ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
+ ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
+ ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
+ left = e;
+
+ return this;
+ }
+ error19 (tc);
+ return null;
+ }
+
+ Expression ResolveOperator (TypeContainer tc)
+ {
+ Type l = left.Type;
+ Type r = right.Type;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression left_expr, right_expr;
+
+ string op = "Operator" + oper;
+
+ left_expr = MemberLookup (tc.RootContext, l, op, false);
+
+ if (!(left_expr is MethodGroupExpr)){
+ // FIXME: Find proper error
+ tc.RootContext.Report.Error (118, "Did find something that is not a method");
+ return null;
+ }
+
+ right_expr = MemberLookup (tc.RootContext, r, op, false);
+
+ if (!(right_expr is MethodGroupExpr)){
+ // FIXME: Find proper error
+ tc.RootContext.Report.Error (118, "Did find something that is not a method");
+ return null;
+ }
+
+ if (left_expr != null || right_expr != null) {
+ //
+ // Now we need to form the union of these two sets and
+ // then call OverloadResolve on that.
+ //
+ MethodGroupExpr left_set = null, right_set = null;
+ int length1 = 0, length2 = 0;
+
+ if (left_expr != null) {
+ left_set = (MethodGroupExpr) left_expr;
+ length1 = left_set.Methods.Length;
+ }
+
+ if (right_expr != null) {
+ right_set = (MethodGroupExpr) right_expr;
+ length2 = right_set.Methods.Length;
+ }
+
+ MemberInfo [] mi = new MemberInfo [length1 + length2];
+ if (left_set != null)
+ left_set.Methods.CopyTo (mi, 0);
+ if (right_set != null)
+ right_set.Methods.CopyTo (mi, length1);
+
+ MethodGroupExpr union = new MethodGroupExpr (mi);
+
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ method = Invocation.OverloadResolve (union, Arguments);
+ if (method != null)
+ return this;
+
+ }
+
+ //
+ // Step 2: Default operations on CLI native types.
+ //
+
+ // Only perform numeric promotions on:
+ // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
+ //
+ if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){
+ return CheckShiftArguments (tc);
+ } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
+
+ if (l != TypeManager.bool_type || r != TypeManager.bool_type)
+ error19 (tc);
+ } else
+ DoNumericPromotions (tc, l, r);
+
+ if (left == null || right == null)
+ return null;
+
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ if (!((l == TypeManager.int32_type) ||
+ (l == TypeManager.uint32_type) ||
+ (l == TypeManager.int64_type) ||
+ (l == TypeManager.uint64_type))){
+ error19 (tc);
+ return null;
+ }
+ }
+
+ if (oper == Operator.Equal ||
+ oper == Operator.NotEqual ||
+ oper == Operator.LessOrEqual ||
+ oper == Operator.LessThan ||
+ oper == Operator.GreaterOrEqual ||
+ oper == Operator.GreaterThan){
+ type = TypeManager.bool_type;
+ }
+
+ return this;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ left = left.Resolve (tc);
+ right = right.Resolve (tc);
+
+ if (left == null || right == null)
+ return null;
+
+ return ResolveOperator (tc);
+ }
+
+ public bool IsBranchable ()
+ {
+ if (oper == Operator.Equal ||
+ oper == Operator.NotEqual ||
+ oper == Operator.LessThan ||
+ oper == Operator.GreaterThan ||
+ oper == Operator.LessOrEqual ||
+ oper == Operator.GreaterOrEqual){
+ return true;
+ } else
+ return false;
+ }
+
+ // <summary>
+ // This entry point is used by routines that might want
+ // to emit a brfalse/brtrue after an expression, and instead
+ // they could use a more compact notation.
+ //
+ // Typically the code would generate l.emit/r.emit, followed
+ // by the comparission and then a brtrue/brfalse. The comparissions
+ // are sometimes inneficient (there are not as complete as the branches
+ // look for the hacks in Emit using double ceqs).
+ //
+ // So for those cases we provide EmitBranchable that can emit the
+ // branch with the test
+ // </summary>
+ public void EmitBranchable (EmitContext ec, int target)
+ {
+ OpCode opcode;
+ bool close_target = false;
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ switch (oper){
+ case Operator.Equal:
+ if (close_target)
+ opcode = OpCodes.Beq_S;
+ else
+ opcode = OpCodes.Beq;
+ break;
+
+ case Operator.NotEqual:
+ if (close_target)
+ opcode = OpCodes.Bne_Un_S;
+ else
+ opcode = OpCodes.Bne_Un;
+ break;
+
+ case Operator.LessThan:
+ if (close_target)
+ opcode = OpCodes.Blt_S;
+ else
+ opcode = OpCodes.Blt;
+ break;
+
+ case Operator.GreaterThan:
+ if (close_target)
+ opcode = OpCodes.Bgt_S;
+ else
+ opcode = OpCodes.Bgt;
+ break;
+
+ case Operator.LessOrEqual:
+ if (close_target)
+ opcode = OpCodes.Ble_S;
+ else
+ opcode = OpCodes.Ble;
+ break;
+
+ case Operator.GreaterOrEqual:
+ if (close_target)
+ opcode = OpCodes.Bge_S;
+ else
+ opcode = OpCodes.Ble;
+ break;
+
+ default:
+ throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
+ + oper.ToString ());
+ }
+
+ ec.ig.Emit (opcode, target);
+ }
+
public override void Emit (EmitContext ec)
{
+ ILGenerator ig = ec.ig;
+ Type l = left.Type;
+ Type r = right.Type;
+ OpCode opcode;
+
+ if (method != null) {
+
+ bool is_static = method.IsStatic;
+
+ // FIXME : I am just not able to get this right !!
+ // There's something wrong with this part which causes
+ // an InvalidProgramException if this code is emitted
+
+ //if (Arguments != null)
+ // Invocation.EmitArguments (ec, Arguments);
+
+ //if (is_static){
+ // if (method is MethodInfo)
+ // ig.Emit (OpCodes.Call, (MethodInfo) method);
+ // else
+ // ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ //} else {
+ // if (method is MethodInfo)
+ // ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+ // else
+ // ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+ //}
+
+ //return;
+ }
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ switch (oper){
+ case Operator.Multiply:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Mul_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Mul_Ovf_Un;
+ else
+ opcode = OpCodes.Mul;
+ } else
+ opcode = OpCodes.Mul;
+
+ break;
+
+ case Operator.Divide:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ opcode = OpCodes.Div_Un;
+ else
+ opcode = OpCodes.Div;
+ break;
+
+ case Operator.Modulo:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ opcode = OpCodes.Rem_Un;
+ else
+ opcode = OpCodes.Rem;
+ break;
+
+ case Operator.Add:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Add_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Add_Ovf_Un;
+ else
+ opcode = OpCodes.Mul;
+ } else
+ opcode = OpCodes.Add;
+ break;
+
+ case Operator.Subtract:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Sub_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Sub_Ovf_Un;
+ else
+ opcode = OpCodes.Sub;
+ } else
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.ShiftRight:
+ opcode = OpCodes.Shr;
+ break;
+
+ case Operator.ShiftLeft:
+ opcode = OpCodes.Shl;
+ break;
+
+ case Operator.Equal:
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.NotEqual:
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.LessThan:
+ opcode = OpCodes.Clt;
+ break;
+
+ case Operator.GreaterThan:
+ opcode = OpCodes.Cgt;
+ break;
+
+ case Operator.LessOrEqual:
+ ec.ig.Emit (OpCodes.Cgt);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.GreaterOrEqual:
+ ec.ig.Emit (OpCodes.Clt);
+ ec.ig.Emit (OpCodes.Ldc_I4_1);
+
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.LogicalOr:
+ case Operator.BitwiseOr:
+ opcode = OpCodes.Or;
+ break;
+
+ case Operator.LogicalAnd:
+ case Operator.BitwiseAnd:
+ opcode = OpCodes.And;
+ break;
+
+ case Operator.ExclusiveOr:
+ opcode = OpCodes.Xor;
+ break;
+
+ default:
+ throw new Exception ("This should not happen: Operator = "
+ + oper.ToString ());
+ }
+
+ ec.ig.Emit (opcode);
}
}
}
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
// FIXME: Implement;
+ return this;
}
public override void Emit (EmitContext ec)
}
}
- public override void Resolve (TypeContainer tc)
+ //
+ // Checks whether we are trying to access an instance
+ // property, method or field from a static body.
+ //
+ Expression MemberStaticCheck (Report r, Expression e)
{
- // FIXME: Implement;
+ if (e is FieldExpr){
+ FieldInfo fi = ((FieldExpr) e).FieldInfo;
+
+ if (!fi.IsStatic){
+ r.Error (120,
+ "An object reference is required " +
+ "for the non-static field `"+name+"'");
+ return null;
+ }
+ } else if (e is MethodGroupExpr){
+ // FIXME: Pending reorganization of MemberLookup
+ // Basically at this point we should have the
+ // best match already selected for us, and
+ // we should only have to check a *single*
+ // Method for its static on/off bit.
+ return e;
+ } else if (e is PropertyExpr){
+ if (!((PropertyExpr) e).IsStatic){
+ r.Error (120,
+ "An object reference is required " +
+ "for the non-static property access `"+
+ name+"'");
+ return null;
+ }
+ }
+
+ return e;
+ }
+
+ //
+ // 7.5.2: Simple Names.
+ //
+ // Local Variables and Parameters are handled at
+ // parse time, so they never occur as SimpleNames.
+ //
+ Expression ResolveSimpleName (TypeContainer tc)
+ {
+ Expression e;
+ Report r = tc.RootContext.Report;
+
+ e = MemberLookup (tc.RootContext, tc.TypeBuilder, name, true);
+ if (e != null){
+ if (e is TypeExpr)
+ return e;
+ else if (e is FieldExpr){
+ FieldExpr fe = (FieldExpr) e;
+
+ if (!fe.FieldInfo.IsStatic)
+ fe.Instance = new This ();
+ }
+
+ if ((tc.ModFlags & Modifiers.STATIC) != 0)
+ return MemberStaticCheck (r, e);
+ else
+ return e;
+ }
+
+ //
+ // Do step 3 of the Simple Name resolution.
+ //
+ // FIXME: implement me.
+
+ return this;
+ }
+
+ //
+ // SimpleName needs to handle a multitude of cases:
+ //
+ // simple_names and qualified_identifiers are placed on
+ // the tree equally.
+ //
+ public override Expression Resolve (TypeContainer tc)
+ {
+ if (name.IndexOf (".") != -1)
+ return ResolveMemberAccess (tc, name);
+ else
+ return ResolveSimpleName (tc);
}
public override void Emit (EmitContext ec)
}
public class LocalVariableReference : Expression {
- string name;
- Block block;
+ public readonly string Name;
+ public readonly Block Block;
public LocalVariableReference (Block block, string name)
{
- this.block = block;
- this.name = name;
+ Block = block;
+ Name = name;
+ eclass = ExprClass.Variable;
}
- public Block Block {
+ public VariableInfo VariableInfo {
get {
- return block;
+ return Block.GetVariableInfo (Name);
}
}
-
- public string Name {
- get {
- return name;
- }
- }
-
- public override void Resolve (TypeContainer tc)
+
+ public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ VariableInfo vi = Block.GetVariableInfo (Name);
+
+ type = vi.VariableType;
+ return this;
}
public override void Emit (EmitContext ec)
{
+ VariableInfo vi = VariableInfo;
+ ILGenerator ig = ec.ig;
+ int idx = vi.Idx;
+
+ switch (idx){
+ case 0:
+ ig.Emit (OpCodes.Ldloc_0);
+ break;
+
+ case 1:
+ ig.Emit (OpCodes.Ldloc_1);
+ break;
+
+ case 2:
+ ig.Emit (OpCodes.Ldloc_2);
+ break;
+
+ case 3:
+ ig.Emit (OpCodes.Ldloc_3);
+ break;
+
+ default:
+ if (idx < 255)
+ ig.Emit (OpCodes.Ldloc_S, idx);
+ else
+ ig.Emit (OpCodes.Ldloc, idx);
+ break;
+ }
}
}
public class ParameterReference : Expression {
- Parameters pars;
- string name;
+ public readonly Parameters Pars;
+ public readonly String Name;
+ public readonly int Idx;
- public ParameterReference (Parameters pars, string name)
+ public ParameterReference (Parameters pars, int idx, string name)
{
- this.pars = pars;
- this.name = name;
+ Pars = pars;
+ Idx = idx;
+ Name = name;
}
- public string Name {
- get {
- return name;
- }
- }
-
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ Type [] types = Pars.GetParameterInfo (tc);
+
+ type = types [Idx];
+
+ return this;
}
public override void Emit (EmitContext ec)
{
+ if (Idx < 255)
+ ec.ig.Emit (OpCodes.Ldarg_S, Idx);
+ else
+ ec.ig.Emit (OpCodes.Ldarg, Idx);
}
}
return expr;
}
}
+
+ public bool Resolve (TypeContainer tc)
+ {
+ expr = expr.Resolve (tc);
+
+ return expr != null;
+ }
+
+ public void Emit (EmitContext ec)
+ {
+ expr.Emit (ec);
+ }
}
// <summary>
public class Invocation : Expression {
public readonly ArrayList Arguments;
Expression expr;
+ MethodBase method = null;
+
+ static Hashtable method_parameter_cache;
+ static Invocation ()
+ {
+ method_parameter_cache = new Hashtable ();
+ }
+
//
// arguments is an ArrayList, but we do not want to typecast,
// as it might be null.
}
}
- public override void Resolve (TypeContainer tc)
+ /// <summary>
+ /// Computes whether Argument `a' and the ParameterInfo `pi' are
+ /// compatible, and if so, how good is the match (in terms of
+ /// "better conversions" (7.4.2.3).
+ ///
+ /// 0 is the best possible match.
+ /// -1 represents a type mismatch.
+ /// -2 represents a ref/out mismatch.
+ /// </summary>
+ static int Badness (Argument a, Type t)
{
- // FIXME: Implement;
+ if (a.Expr.Type == null){
+ throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
+ }
+
+ if (t == a.Expr.Type)
+ return 0;
+
+ // FIXME: Implement implicit conversions here.
+ // FIXME: Implement better conversion here.
+
+ return -1;
}
+ // <summary>
+ // Returns the Parameters (a ParameterData interface) for the
+ // Method `mb'
+ // </summary>
+ static ParameterData GetParameterData (MethodBase mb)
+ {
+ object pd = method_parameter_cache [mb];
+
+ if (pd != null)
+ return (ParameterData) pd;
+
+ if (mb is MethodBuilder || mb is ConstructorBuilder){
+ MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
+
+ InternalParameters ip = mc.ParameterInfo;
+ method_parameter_cache [mb] = ip;
+
+ return (ParameterData) ip;
+ } else {
+ ParameterInfo [] pi = mb.GetParameters ();
+ ReflectionParameters rp = new ReflectionParameters (pi);
+ method_parameter_cache [mb] = rp;
+
+ return (ParameterData) rp;
+ }
+ }
+
+ // <summary>
+ // Find the Applicable Function Members (7.4.2.1)
+ //
+ // me: Method Group expression with the members to select.
+ // it might contain constructors or methods (or anything
+ // that maps to a method).
+ //
+ // Arguments: ArrayList containing resolved Argument objects.
+ //
+ // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+ // that is the best match of me on Arguments.
+ //
+ // </summary>
+ public static MethodBase OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
+ {
+ ArrayList afm = new ArrayList ();
+ int best_match = 10000;
+ int best_match_idx = -1;
+ MethodBase method = null;
+ int argument_count;
+
+ if (Arguments == null)
+ argument_count = 0;
+ else
+ argument_count = Arguments.Count;
+
+ for (int i = me.Methods.Length; i > 0; ){
+ i--;
+ MethodBase mb = me.Methods [i];
+ ParameterData pd;
+
+ pd = GetParameterData (mb);
+
+ // If this is the case, we have a method with no args - presumably
+ if (pd == null && argument_count == 0)
+ return me.Methods [0];
+
+ //
+ // Compute how good this is
+ //
+ if (pd.Count == argument_count){
+ int badness = 0;
+
+ for (int j = argument_count; j > 0;){
+ int x;
+ j--;
+
+ Argument a = (Argument) Arguments [j];
+
+ x = Badness (a, pd.ParameterType (j));
+
+ if (x < 0){
+ badness = best_match;
+ continue;
+ }
+
+ badness += x;
+ }
+
+ if (badness < best_match){
+ best_match = badness;
+ method = me.Methods [i];
+ best_match_idx = i;
+ }
+ }
+ }
+
+ if (best_match_idx == -1)
+ return null;
+
+ return method;
+ }
+
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ //
+ // First, resolve the expression that is used to
+ // trigger the invocation
+ //
+ this.expr = expr.Resolve (tc);
+ if (this.expr == null)
+ return null;
+
+ if (!(this.expr is MethodGroupExpr)){
+ tc.RootContext.Report.Error (118,
+ "Denotes a non-method (Detail: ExprClass=" + this.expr.ExprClass+")");
+ return null;
+ }
+
+ //
+ // Next, evaluate all the expressions in the argument list
+ //
+ if (Arguments != null){
+ for (int i = Arguments.Count; i > 0;){
+ --i;
+ Argument a = (Argument) Arguments [i];
+
+ if (!a.Resolve (tc))
+ return null;
+ }
+ }
+
+ method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
+
+ if (method == null){
+ tc.RootContext.Report.Error (-6,
+ "Figure out error: Can not find a good function for this argument list");
+ return null;
+ }
+
+ if (method is MethodInfo)
+ type = ((MethodInfo)method).ReturnType;
+
+ return this;
+ }
+
+ public static void EmitArguments (EmitContext ec, ArrayList Arguments)
+ {
+ int top;
+
+ if (Arguments != null)
+ top = Arguments.Count;
+ else
+ top = 0;
+
+ for (int i = 0; i < top; i++){
+ Argument a = (Argument) Arguments [i];
+
+ a.Emit (ec);
+ }
+ }
+
public override void Emit (EmitContext ec)
{
+ bool is_static = method.IsStatic;
+
+ if (!is_static){
+ MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+
+ if (mg.InstanceExpression == null){
+ Console.WriteLine ("Internal compiler error. Should check in the method groups for static/instance");
+ }
+
+ mg.InstanceExpression.Emit (ec);
+ }
+
+ if (Arguments != null)
+ EmitArguments (ec, Arguments);
+
+ if (is_static){
+ if (method is MethodInfo)
+ ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ } else {
+ if (method is MethodInfo)
+ ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+ else
+ ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+ }
+
}
}
public readonly ArrayList Indices;
public readonly ArrayList Initializers;
+ MethodBase method = null;
public New (string requested_type, ArrayList arguments)
{
NewType = NType.Array;
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ type = tc.LookupType (RequestedType, false);
+
+ if (type == null)
+ return null;
+
+ Expression ml;
+
+ ml = MemberLookup (tc.RootContext, type, ".ctor", false,
+ MemberTypes.Constructor, AllBindingsFlags);
+
+ if (! (ml is MethodGroupExpr)){
+ //
+ // FIXME: Find proper error
+ //
+ tc.RootContext.Report.Error (118, "Did find something that is not a method");
+ return null;
+ }
+
+ if (Arguments != null){
+ for (int i = Arguments.Count; i > 0;){
+ --i;
+ Argument a = (Argument) Arguments [i];
+
+ if (!a.Resolve (tc))
+ return null;
+ }
+ }
+
+ method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments);
+
+ if (method == null) {
+ tc.RootContext.Report.Error (-6,
+ "New invocation: Can not find a constructor for this argument list");
+ return null;
+ }
+
+ return this;
}
public override void Emit (EmitContext ec)
{
+ Invocation.EmitArguments (ec, Arguments);
+ ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
}
}
+ //
+ // Represents the `this' construct
+ //
public class This : Expression {
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ eclass = ExprClass.Variable;
+ type = tc.TypeBuilder;
+
+ return this;
}
public override void Emit (EmitContext ec)
{
+ ec.ig.Emit (OpCodes.Ldarg_0);
}
}
QueriedType = queried_type;
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ type = tc.LookupType (QueriedType, false);
+
+ if (type == null)
+ return null;
+
+ eclass = ExprClass.Type;
+ return this;
}
public override void Emit (EmitContext ec)
{
+ // FIXME: Implement.
}
}
this.QueriedType = queried_type;
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
// FIXME: Implement;
+ return this;
}
public override void Emit (EmitContext ec)
public class MemberAccess : Expression {
public readonly string Identifier;
Expression expr;
+ Expression member_lookup;
public MemberAccess (Expression expr, string id)
{
}
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ Expression new_expression = expr.Resolve (tc);
+
+ if (new_expression == null)
+ return null;
+
+ Console.WriteLine ("This is what I figured: " + expr.Type + "/" + expr.ExprClass);
+
+ member_lookup = MemberLookup (tc.RootContext, expr.Type, Identifier, false);
+
+ if (member_lookup is MethodGroupExpr){
+ MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
+
+ //
+ // Bind the instance expression to it
+ //
+ // FIXME: This is a horrible way of detecting if it is
+ // an instance expression. Figure out how to fix this.
+ //
+
+ if (expr is LocalVariableReference ||
+ expr is ParameterReference ||
+ expr is FieldExpr)
+ mg.InstanceExpression = expr;
+
+ return member_lookup;
+ } else if (member_lookup is FieldExpr){
+ FieldExpr fe = (FieldExpr) member_lookup;
+
+ fe.Instance = expr;
+
+ return member_lookup;
+ } else
+ //
+ // FIXME: This should generate the proper node
+ // ie, for a Property Access, it should like call it
+ // and stuff.
+
+ return member_lookup;
}
public override void Emit (EmitContext ec)
}
+ // <summary>
+ // Nodes of type Namespace are created during the semantic
+ // analysis to resolve member_access/qualified_identifier/simple_name
+ // accesses.
+ //
+ // They are born `resolved'.
+ // </summary>
+ public class NamespaceExpr : Expression {
+ public readonly string Name;
+
+ public NamespaceExpr (string name)
+ {
+ Name = name;
+ eclass = ExprClass.Namespace;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ }
+ }
+
+ // <summary>
+ // Fully resolved expression that evaluates to a type
+ // </summary>
+ public class TypeExpr : Expression {
+ public TypeExpr (Type t)
+ {
+ Type = t;
+ eclass = ExprClass.Type;
+ }
+
+ override public Expression Resolve (TypeContainer tc)
+ {
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+
+ }
+ }
+
+ // <summary>
+ // MethodGroup Expression.
+ //
+ // This is a fully resolved expression that evaluates to a type
+ // </summary>
+ public class MethodGroupExpr : Expression {
+ public readonly MethodBase [] Methods;
+ Expression instance_expression = null;
+
+ public MethodGroupExpr (MemberInfo [] mi)
+ {
+ Methods = new MethodBase [mi.Length];
+ mi.CopyTo (Methods, 0);
+ eclass = ExprClass.MethodGroup;
+ }
+
+ //
+ // `A method group may have associated an instance expression'
+ //
+ public Expression InstanceExpression {
+ get {
+ return instance_expression;
+ }
+
+ set {
+ instance_expression = value;
+ }
+ }
+
+ override public Expression Resolve (TypeContainer tc)
+ {
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+
+ }
+ }
+
public class BuiltinTypeAccess : Expression {
public readonly string AccessBase;
public readonly string Method;
Method = method;
}
- public override void Resolve (TypeContainer tc)
+ public override Expression Resolve (TypeContainer tc)
{
// FIXME: Implement;
+ return this;
}
public override void Emit (EmitContext ec)
{
}
}
-}
+ // Fully resolved expression that evaluates to a Field
+ // </summary>
+ public class FieldExpr : Expression {
+ public readonly FieldInfo FieldInfo;
+ public Expression Instance;
+
+ public FieldExpr (FieldInfo fi)
+ {
+ FieldInfo = fi;
+ eclass = ExprClass.Variable;
+ type = fi.FieldType;
+ }
+
+ override public Expression Resolve (TypeContainer tc)
+ {
+ if (!FieldInfo.IsStatic){
+ if (Instance == null){
+ throw new Exception ("non-static FieldExpr without instance var\n" +
+ "You have to assign the Instance variable\n" +
+ "Of the FieldExpr to set this\n");
+ }
+
+ Instance = Instance.Resolve (tc);
+ if (Instance == null)
+ return null;
+
+ }
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (FieldInfo.IsStatic)
+ ig.Emit (OpCodes.Ldsfld, FieldInfo);
+ else {
+ Instance.Emit (ec);
+
+ ig.Emit (OpCodes.Ldfld, FieldInfo);
+ }
+ }
+ }
+
+ // <summary>
+ // Fully resolved expression that evaluates to a Property
+ // </summary>
+ public class PropertyExpr : Expression {
+ public readonly PropertyInfo PropertyInfo;
+ public readonly bool IsStatic;
+
+ public PropertyExpr (PropertyInfo pi)
+ {
+ PropertyInfo = pi;
+ eclass = ExprClass.PropertyAccess;
+ IsStatic = false;
+
+ MethodBase [] acc = pi.GetAccessors ();
+
+ for (int i = 0; i < acc.Length; i++)
+ if (acc [i].IsStatic)
+ IsStatic = true;
+
+ type = pi.PropertyType;
+ }
+
+ override public Expression Resolve (TypeContainer tc)
+ {
+ // We are born in resolved state.
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ // FIXME: Implement.
+ }
+ }
+
+ // <summary>
+ // Fully resolved expression that evaluates to a Property
+ // </summary>
+ public class EventExpr : Expression {
+ public readonly EventInfo EventInfo;
+
+ public EventExpr (EventInfo ei)
+ {
+ EventInfo = ei;
+ eclass = ExprClass.EventAccess;
+ }
+
+ override public Expression Resolve (TypeContainer tc)
+ {
+ // We are born in resolved state.
+ return this;
+ }
+
+ override public void Emit (EmitContext ec)
+ {
+ // FIXME: Implement.
+ }
+ }
+
+ public class CheckedExpr : Expression {
+
+ public readonly Expression Expr;
+
+ public CheckedExpr (Expression e)
+ {
+ Expr = e;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // FIXME : Implement !
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ }
+
+ }
+ public class UnCheckedExpr : Expression {
+ public readonly Expression Expr;
+ public UnCheckedExpr (Expression e)
+ {
+ Expr = e;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // FIXME : Implement !
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ }
+
+ }
+
+ public class ElementAccess : Expression {
+
+ public readonly ArrayList Arguments;
+ public readonly Expression Expr;
+
+ public ElementAccess (Expression e, ArrayList e_list)
+ {
+ Expr = e;
+ Arguments = e_list;
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // FIXME : Implement
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ // FIXME : Implement !
+ }
+
+ }
+
+ public class BaseAccess : Expression {
+
+ public enum BaseAccessType {
+ Member,
+ Indexer
+ };
+
+ public readonly BaseAccessType BAType;
+ public readonly string Member;
+ public readonly ArrayList Arguments;
+
+ public BaseAccess (BaseAccessType t, string member, ArrayList args)
+ {
+ BAType = t;
+ Member = member;
+ Arguments = args;
+
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // FIXME : Implement !
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ }
+ }
+}