static Expression ExprClassFromMemberInfo (MemberInfo mi)
{
if (mi is EventInfo){
- // FIXME: Implement
- return null;
+ return new EventExpr ((EventInfo) mi);
} else if (mi is FieldInfo){
return new FieldExpr ((FieldInfo) mi);
} else if (mi is PropertyInfo){
//
// Return values:
// If the return value is an Array, then it is an array of
- // MethodInfos
+ // MethodBases
//
// If the return value is an MemberInfo, it is anything, but a Method
//
//
// This is so we can catch correctly attempts to invoke instance methods
// from a static body (scan for error 120 in ResolveSimpleName).
- //
- protected static Expression MemberLookup (Report r, Type t, string name, bool same_type)
- {
- MemberTypes mt =
- // MemberTypes.Constructor |
- MemberTypes.Event |
- MemberTypes.Field |
- MemberTypes.Method |
- MemberTypes.NestedType |
- MemberTypes.Property;
-
- BindingFlags bf =
- BindingFlags.Public |
- BindingFlags.Static |
- BindingFlags.Instance;
-
+ //
+ 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 = t.FindMembers (mt, bf, Type.FilterName, name);
+ MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
- if (mi.Length == 1 && !(mi [0] is MethodInfo))
+ 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 MethodInfo)){
- r.Error (-5, "Do not know how to reproduce this case: Methods and non-Method with the same name, report this please");
-
+ 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
switch (left_e.ExprClass){
case ExprClass.Type:
- return MemberLookup (tc.RootContext.Report,
+ return MemberLookup (tc.RootContext,
left_e.Type, right,
left_e.Type == tc.TypeBuilder);
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 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 Expression Resolve (TypeContainer tc)
- {
- // FIXME: implement me
- return this;
+
+ // <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 ();
}
- public override void Emit (EmitContext ec)
+ Expression ForceConversion (Expression expr, Type target_type)
{
- }
- }
+ if (expr.Type == target_type)
+ return expr;
- public class Conditional : Expression {
- Expression expr, trueExpr, falseExpr;
+ return ConvertImplicit (expr, target_type);
+ }
- public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
+ //
+ // 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)
{
- this.expr = expr;
- this.trueExpr = trueExpr;
- this.falseExpr = falseExpr;
- }
+ 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);
- public Expression Expr {
- get {
- return expr;
+ 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;
}
}
- public Expression TrueExpr {
- get {
- return trueExpr;
- }
+ 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;
- public Expression FalseExpr {
- get {
- return falseExpr;
+ e = ForceConversion (right, TypeManager.int32_type);
+ if (e == null){
+ error19 (tc);
+ return null;
}
- }
+ right = e;
- public override Expression Resolve (TypeContainer tc)
- {
- // FIXME: Implement;
- return this;
- }
+ 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;
- public override void Emit (EmitContext ec)
- {
+ return this;
+ }
+ error19 (tc);
+ return null;
}
- }
-
- public class SimpleName : Expression {
- string name;
- public SimpleName (string name)
+ Expression ResolveOperator (TypeContainer tc)
{
- this.name = name;
- }
+ Type l = left.Type;
+ Type r = right.Type;
- public string Name {
- get {
- return name;
+ //
+ // 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;
}
- }
- //
- // Checks whether we are trying to access an instance
- // property, method or field from a static body.
- //
- Expression MemberStaticCheck (Report r, Expression e)
- {
- if (e is FieldExpr){
- FieldInfo fi = ((FieldExpr) e).FieldInfo;
+ 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 (!fi.IsStatic){
- r.Error (120,
- "An object reference is required " +
- "for the non-static field `"+name+"'");
- return null;
+ if (left_expr != null) {
+ left_set = (MethodGroupExpr) left_expr;
+ length1 = left_set.Methods.Length;
}
- } 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+"'");
+
+ 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;
}
}
- return e;
+ 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 class Conditional : Expression {
+ Expression expr, trueExpr, falseExpr;
+
+ public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
+ {
+ this.expr = expr;
+ this.trueExpr = trueExpr;
+ this.falseExpr = falseExpr;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ public Expression TrueExpr {
+ get {
+ return trueExpr;
+ }
+ }
+
+ public Expression FalseExpr {
+ get {
+ return falseExpr;
+ }
+ }
+
+ public override Expression Resolve (TypeContainer tc)
+ {
+ // FIXME: Implement;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ }
+ }
+
+ public class SimpleName : Expression {
+ string name;
+
+ public SimpleName (string name)
+ {
+ this.name = name;
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ //
+ // Checks whether we are trying to access an instance
+ // property, method or field from a static body.
+ //
+ Expression MemberStaticCheck (Report r, Expression e)
+ {
+ 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;
}
//
Expression e;
Report r = tc.RootContext.Report;
- e = MemberLookup (tc.RootContext.Report, tc.TypeBuilder, name, true);
+ e = MemberLookup (tc.RootContext, tc.TypeBuilder, name, true);
if (e != null){
if (e is TypeExpr)
return e;
public VariableInfo VariableInfo {
get {
- return (VariableInfo) Block.GetVariableInfo (Name);
+ return Block.GetVariableInfo (Name);
}
}
public override Expression Resolve (TypeContainer tc)
{
+ VariableInfo vi = Block.GetVariableInfo (Name);
+
+ type = vi.VariableType;
return this;
}
public override void Emit (EmitContext ec)
{
- Console.WriteLine ("Internal compiler error, LocalVariableReference should not be emitted");
+ 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 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);
}
}
public bool Resolve (TypeContainer tc)
{
expr = expr.Resolve (tc);
+
return expr != null;
}
public class Invocation : Expression {
public readonly ArrayList Arguments;
Expression expr;
- MethodInfo method = null;
+ 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.
/// -1 represents a type mismatch.
/// -2 represents a ref/out mismatch.
/// </summary>
- static int Badness (Argument a, ParameterInfo pi)
+ static int Badness (Argument a, Type t)
{
- if (pi.ParameterType == a.Expr.Type)
+ 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;
}
-
- public override Expression Resolve (TypeContainer tc)
+
+ // <summary>
+ // Returns the Parameters (a ParameterData interface) for the
+ // Method `mb'
+ // </summary>
+ static ParameterData GetParameterData (MethodBase mb)
{
- //
- // First, resolve the expression that is used to
- // trigger the invocation
- //
- this.expr = expr.Resolve (tc);
- if (this.expr == null)
- return null;
+ object pd = method_parameter_cache [mb];
- if (!(this.expr is MethodGroupExpr)){
- tc.RootContext.Report.Error (118,
- "Denotes an " + this.expr.ExprClass + " while a method was expected");
- return null;
- }
+ if (pd != null)
+ return (ParameterData) pd;
- //
- // 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 (mb is MethodBuilder || mb is ConstructorBuilder){
+ MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
- if (!a.Resolve (tc))
- return null;
- }
- }
+ InternalParameters ip = mc.ParameterInfo;
+ method_parameter_cache [mb] = ip;
- //
- // Find the Applicable Function Members (7.4.2.1)
- //
- MethodGroupExpr me = (MethodGroupExpr) this.expr;
+ 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--;
- ParameterInfo [] pi = me.Methods [i].GetParameters ();
+ 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 (pi.Length == Arguments.Count){
+ if (pd.Count == argument_count){
int badness = 0;
- for (int j = Arguments.Count; j > 0;){
+ for (int j = argument_count; j > 0;){
int x;
j--;
-
+
Argument a = (Argument) Arguments [j];
- x = Badness (a, pi [j]);
-
+ x = Badness (a, pd.ParameterType (j));
+
if (x < 0){
- // FIXME: report nice error.
- } else
- badness += x;
+ badness = best_match;
+ continue;
+ }
+
+ badness += x;
}
-
+
if (badness < best_match){
best_match = badness;
method = me.Methods [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;
}
- Console.WriteLine ("Found a method! " + method);
+ if (method is MethodInfo)
+ type = ((MethodInfo)method).ReturnType;
return this;
}
- public override void Emit (EmitContext ec)
+ public static void EmitArguments (EmitContext ec, ArrayList Arguments)
{
- int top = Arguments.Count;
+ 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);
+ }
- ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
}
}
public readonly ArrayList Indices;
public readonly ArrayList Initializers;
+ MethodBase method = null;
public New (string requested_type, ArrayList arguments)
{
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);
}
}
public class MemberAccess : Expression {
public readonly string Identifier;
Expression expr;
+ Expression member_lookup;
public MemberAccess (Expression expr, string id)
{
public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
- return this;
+ 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.
+ //
+ Console.WriteLine ("FIXME: Horrible way of figuring if something is an isntance");
+
+ if (expr is LocalVariableReference)
+ mg.InstanceExpression = 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 null;
}
public override 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;
+
+ public BuiltinTypeAccess (string type, string method)
+ {
+ System.Console.WriteLine ("DUDE! This type should be fully resolved!");
+ AccessBase = type;
+ Method = method;
+ }
+
+ 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 {
{
FieldInfo = fi;
eclass = ExprClass.Variable;
+ type = fi.FieldType;
}
override public Expression Resolve (TypeContainer tc)
eclass = ExprClass.PropertyAccess;
IsStatic = false;
- MethodInfo [] acc = pi.GetAccessors ();
+ 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)
}
// <summary>
- // Fully resolved expression that evaluates to a type
+ // Fully resolved expression that evaluates to a Property
// </summary>
- public class MethodGroupExpr : Expression {
- public readonly MethodInfo [] Methods;
+ public class EventExpr : Expression {
+ public readonly EventInfo EventInfo;
- public MethodGroupExpr (MemberInfo [] mi)
+ public EventExpr (EventInfo ei)
{
- Methods = new MethodInfo [mi.Length];
- mi.CopyTo (Methods, 0);
- eclass = ExprClass.MethodGroup;
+ 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 BuiltinTypeAccess : Expression {
- public readonly string AccessBase;
- public readonly string Method;
+ 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 BuiltinTypeAccess (string type, string method)
+ }
+
+ public class UnCheckedExpr : Expression {
+
+ public readonly Expression Expr;
+
+ public UnCheckedExpr (Expression e)
{
- System.Console.WriteLine ("DUDE! This type should be fully resolved!");
- AccessBase = type;
- Method = method;
+ Expr = e;
}
public override Expression Resolve (TypeContainer tc)
{
- // FIXME: Implement;
+ // 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)
+ {
+ }
+ }
}