2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
7 // (C) 2001 Ximian, Inc.
10 using System.Collections;
11 using System.Diagnostics;
13 using System.Reflection;
14 using System.Reflection.Emit;
17 // The ExprClass class contains the is used to pass the
18 // classification of an expression (value, variable, namespace,
19 // type, method group, property access, event access, indexer access,
22 public enum ExprClass {
25 Value, Variable, Namespace, Type,
26 MethodGroup, PropertyAccess,
27 EventAccess, IndexerAccess, Nothing,
31 // Base class for expressions
33 public abstract class Expression {
34 protected ExprClass eclass;
47 public ExprClass ExprClass {
57 public abstract Expression Resolve (TypeContainer tc);
58 public abstract void Emit (EmitContext ec);
61 // Protected constructor. Only derivate types should
62 // be able to be created
65 protected Expression ()
67 eclass = ExprClass.Invalid;
72 // Returns a fully formed expression after a MemberLookup
74 static Expression ExprClassFromMemberInfo (MemberInfo mi)
79 } else if (mi is FieldInfo){
80 return new FieldExpr ((FieldInfo) mi);
81 } else if (mi is PropertyInfo){
82 return new PropertyExpr ((PropertyInfo) mi);
83 } else if (mi is Type)
84 return new TypeExpr ((Type) mi);
90 // FIXME: Probably implement a cache for (t,name,current_access_set)?
92 // FIXME: We need to cope with access permissions here, or this wont
95 // This code could use some optimizations, but we need to do some
96 // measurements. For example, we could use a delegate to `flag' when
97 // something can not any longer be a method-group (because it is something
101 // If the return value is an Array, then it is an array of
104 // If the return value is an MemberInfo, it is anything, but a Method
108 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
109 // the arguments here and have MemberLookup return only the methods that
110 // match the argument count/type, unlike we are doing now (we delay this
113 // This is so we can catch correctly attempts to invoke instance methods
114 // from a static body (scan for error 120 in ResolveSimpleName).
116 protected static Expression MemberLookup (Report r, Type t, string name, bool same_type)
119 // MemberTypes.Constructor |
123 MemberTypes.NestedType |
124 MemberTypes.Property;
127 BindingFlags.Public |
128 BindingFlags.Static |
129 BindingFlags.Instance;
132 bf |= BindingFlags.NonPublic;
135 MemberInfo [] mi = t.FindMembers (mt, bf, Type.FilterName, name);
137 if (mi.Length == 1 && !(mi [0] is MethodInfo))
138 return Expression.ExprClassFromMemberInfo (mi [0]);
140 for (int i = 0; i < mi.Length; i++)
141 if (!(mi [i] is MethodInfo)){
142 r.Error (-5, "Do not know how to reproduce this case: Methods and non-Method with the same name, report this please");
146 return new MethodGroupExpr (mi);
150 // Resolves the E in `E.I' side for a member_access
152 // This is suboptimal and should be merged with ResolveMemberAccess
153 static Expression ResolvePrimary (TypeContainer tc, string name)
155 int dot_pos = name.LastIndexOf (".");
157 if (tc.RootContext.IsNamespace (name))
158 return new NamespaceExpr (name);
162 Type t = tc.LookupType (name, false);
165 return new TypeExpr (t);
171 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
174 int dot_pos = name.LastIndexOf (".");
175 string left = name.Substring (0, dot_pos);
176 string right = name.Substring (dot_pos + 1);
178 left_e = ResolvePrimary (tc, left);
182 switch (left_e.ExprClass){
184 return MemberLookup (tc.RootContext.Report,
186 left_e.Type == tc.TypeBuilder);
188 case ExprClass.Namespace:
189 case ExprClass.PropertyAccess:
190 case ExprClass.IndexerAccess:
191 case ExprClass.Variable:
192 case ExprClass.Value:
193 case ExprClass.Nothing:
194 case ExprClass.EventAccess:
195 case ExprClass.MethodGroup:
196 case ExprClass.Invalid:
197 tc.RootContext.Report.Error (-1000,
198 "Internal compiler error, should have " +
199 "got these handled before");
208 public class Unary : Expression {
209 public enum Operator {
210 Plus, Minus, Negate, BitComplement,
211 Indirection, AddressOf, PreIncrement,
212 PreDecrement, PostIncrement, PostDecrement
218 public Unary (Operator op, Expression expr)
224 public Expression Expr {
234 public Operator Oper {
244 public override Expression Resolve (TypeContainer tc)
250 public override void Emit (EmitContext ec)
255 public class Probe : Expression {
260 public enum Operator {
264 public Probe (Operator oper, Expression expr, string probe_type)
267 this.probe_type = probe_type;
271 public Operator Oper {
277 public Expression Expr {
283 public string ProbeType {
289 public override Expression Resolve (TypeContainer tc)
295 public override void Emit (EmitContext ec)
300 public class Cast : Expression {
304 public Cast (string cast_type, Expression expr)
306 this.target_type = target_type;
310 public string TargetType {
316 public Expression Expr {
325 public override Expression Resolve (TypeContainer tc)
331 public override void Emit (EmitContext ec)
336 public class Binary : Expression {
337 public enum Operator {
338 Multiply, Divide, Modulo,
340 ShiftLeft, ShiftRight,
341 LessThan, GreatherThan, LessOrEqual, GreatherOrEqual,
351 Expression left, right;
353 public Binary (Operator oper, Expression left, Expression right)
360 public Operator Oper {
369 public Expression Left {
378 public Expression Right {
387 public override Expression Resolve (TypeContainer tc)
389 // FIXME: implement me
393 public override void Emit (EmitContext ec)
398 public class Conditional : Expression {
399 Expression expr, trueExpr, falseExpr;
401 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
404 this.trueExpr = trueExpr;
405 this.falseExpr = falseExpr;
408 public Expression Expr {
414 public Expression TrueExpr {
420 public Expression FalseExpr {
426 public override Expression Resolve (TypeContainer tc)
432 public override void Emit (EmitContext ec)
437 public class SimpleName : Expression {
440 public SimpleName (string name)
452 // Checks whether we are trying to access an instance
453 // property, method or field from a static body.
455 Expression MemberStaticCheck (Report r, Expression e)
458 FieldInfo fi = ((FieldExpr) e).FieldInfo;
462 "An object reference is required " +
463 "for the non-static field `"+name+"'");
466 } else if (e is MethodGroupExpr){
467 // FIXME: Pending reorganization of MemberLookup
468 // Basically at this point we should have the
469 // best match already selected for us, and
470 // we should only have to check a *single*
471 // Method for its static on/off bit.
473 } else if (e is PropertyExpr){
474 if (!((PropertyExpr) e).IsStatic){
476 "An object reference is required " +
477 "for the non-static property access `"+
487 // 7.5.2: Simple Names.
489 // Local Variables and Parameters are handled at
490 // parse time, so they never occur as SimpleNames.
492 Expression ResolveSimpleName (TypeContainer tc)
495 Report r = tc.RootContext.Report;
497 e = MemberLookup (tc.RootContext.Report, tc.TypeBuilder, name, true);
501 if ((tc.ModFlags & Modifiers.STATIC) != 0)
502 return MemberStaticCheck (r, e);
508 // Do step 3 of the Simple Name resolution.
510 // FIXME: implement me.
516 // SimpleName needs to handle a multitude of cases:
518 // simple_names and qualified_identifiers are placed on
521 public override Expression Resolve (TypeContainer tc)
523 if (name.IndexOf (".") != -1)
524 return ResolveMemberAccess (tc, name);
526 return ResolveSimpleName (tc);
529 public override void Emit (EmitContext ec)
534 public class LocalVariableReference : Expression {
535 public readonly string Name;
536 public readonly Block Block;
538 public LocalVariableReference (Block block, string name)
542 eclass = ExprClass.Variable;
545 public VariableInfo VariableInfo {
547 return (VariableInfo) Block.GetVariableInfo (Name);
551 public override Expression Resolve (TypeContainer tc)
556 public override void Emit (EmitContext ec)
558 Console.WriteLine ("Internal compiler error, LocalVariableReference should not be emitted");
562 public class ParameterReference : Expression {
563 public readonly Parameters Pars;
564 public readonly String Name;
565 public readonly int Idx;
567 public ParameterReference (Parameters pars, int idx, string name)
574 public override Expression Resolve (TypeContainer tc)
580 public override void Emit (EmitContext ec)
586 // Used for arguments to New(), Invocation()
588 public class Argument {
595 public readonly AType Type;
598 public Argument (Expression expr, AType type)
604 public Expression Expr {
610 public bool Resolve (TypeContainer tc)
612 expr = expr.Resolve (tc);
616 public void Emit (EmitContext ec)
623 // Invocation of methods or delegates.
625 public class Invocation : Expression {
626 public readonly ArrayList Arguments;
628 MethodInfo method = null;
631 // arguments is an ArrayList, but we do not want to typecast,
632 // as it might be null.
634 // FIXME: only allow expr to be a method invocation or a
635 // delegate invocation (7.5.5)
637 public Invocation (Expression expr, ArrayList arguments)
640 Arguments = arguments;
643 public Expression Expr {
650 /// Computes whether Argument `a' and the ParameterInfo `pi' are
651 /// compatible, and if so, how good is the match (in terms of
652 /// "better conversions" (7.4.2.3).
654 /// 0 is the best possible match.
655 /// -1 represents a type mismatch.
656 /// -2 represents a ref/out mismatch.
658 static int Badness (Argument a, ParameterInfo pi)
660 if (pi.ParameterType == a.Expr.Type)
663 // FIXME: Implement implicit conversions here.
664 // FIXME: Implement better conversion here.
669 public override Expression Resolve (TypeContainer tc)
672 // First, resolve the expression that is used to
673 // trigger the invocation
675 this.expr = expr.Resolve (tc);
676 if (this.expr == null)
679 if (!(this.expr is MethodGroupExpr)){
680 tc.RootContext.Report.Error (118,
681 "Denotes an " + this.expr.ExprClass + " while a method was expected");
686 // Next, evaluate all the expressions in the argument list
688 if (Arguments != null){
689 for (int i = Arguments.Count; i > 0;){
691 Argument a = (Argument) Arguments [i];
699 // Find the Applicable Function Members (7.4.2.1)
701 MethodGroupExpr me = (MethodGroupExpr) this.expr;
702 ArrayList afm = new ArrayList ();
703 int best_match = 10000;
704 int best_match_idx = -1;
706 for (int i = me.Methods.Length; i > 0; ){
708 ParameterInfo [] pi = me.Methods [i].GetParameters ();
711 // Compute how good this is
713 if (pi.Length == Arguments.Count){
716 for (int j = Arguments.Count; j > 0;){
720 Argument a = (Argument) Arguments [j];
722 x = Badness (a, pi [j]);
725 // FIXME: report nice error.
730 if (badness < best_match){
731 best_match = badness;
732 method = me.Methods [i];
739 tc.RootContext.Report.Error (-6,
740 "Figure out error: Can not find a good function for this argument list");
744 Console.WriteLine ("Found a method! " + method);
749 public override void Emit (EmitContext ec)
751 int top = Arguments.Count;
753 for (int i = 0; i < top; i++){
754 Argument a = (Argument) Arguments [i];
759 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
763 public class New : Expression {
770 public readonly NType NewType;
771 public readonly ArrayList Arguments;
772 public readonly string RequestedType;
773 // These are for the case when we have an array
774 public readonly string Rank;
775 public readonly ArrayList Indices;
776 public readonly ArrayList Initializers;
779 public New (string requested_type, ArrayList arguments)
781 RequestedType = requested_type;
782 Arguments = arguments;
783 NewType = NType.Object;
786 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
788 RequestedType = requested_type;
791 Initializers = initializers;
792 NewType = NType.Array;
795 public override Expression Resolve (TypeContainer tc)
801 public override void Emit (EmitContext ec)
806 public class This : Expression {
807 public override Expression Resolve (TypeContainer tc)
813 public override void Emit (EmitContext ec)
818 public class TypeOf : Expression {
819 public readonly string QueriedType;
821 public TypeOf (string queried_type)
823 QueriedType = queried_type;
826 public override Expression Resolve (TypeContainer tc)
832 public override void Emit (EmitContext ec)
837 public class SizeOf : Expression {
838 public readonly string QueriedType;
840 public SizeOf (string queried_type)
842 this.QueriedType = queried_type;
845 public override Expression Resolve (TypeContainer tc)
851 public override void Emit (EmitContext ec)
856 public class MemberAccess : Expression {
857 public readonly string Identifier;
860 public MemberAccess (Expression expr, string id)
866 public Expression Expr {
872 public override Expression Resolve (TypeContainer tc)
878 public override void Emit (EmitContext ec)
885 // Nodes of type Namespace are created during the semantic
886 // analysis to resolve member_access/qualified_identifier/simple_name
889 // They are born `resolved'.
891 public class NamespaceExpr : Expression {
892 public readonly string Name;
894 public NamespaceExpr (string name)
897 eclass = ExprClass.Namespace;
900 public override Expression Resolve (TypeContainer tc)
905 public override void Emit (EmitContext ec)
911 // Fully resolved expression that evaluates to a type
913 public class TypeExpr : Expression {
914 public TypeExpr (Type t)
917 eclass = ExprClass.Type;
920 override public Expression Resolve (TypeContainer tc)
925 override public void Emit (EmitContext ec)
932 // Fully resolved expression that evaluates to a type
934 public class MethodGroupExpr : Expression {
935 public readonly MethodInfo [] Methods;
937 public MethodGroupExpr (MemberInfo [] mi)
939 Methods = new MethodInfo [mi.Length];
940 mi.CopyTo (Methods, 0);
941 eclass = ExprClass.MethodGroup;
944 override public Expression Resolve (TypeContainer tc)
949 override public void Emit (EmitContext ec)
955 public class BuiltinTypeAccess : Expression {
956 public readonly string AccessBase;
957 public readonly string Method;
959 public BuiltinTypeAccess (string type, string method)
961 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
966 public override Expression Resolve (TypeContainer tc)
972 public override void Emit (EmitContext ec)
978 // Fully resolved expression that evaluates to a Field
980 public class FieldExpr : Expression {
981 public readonly FieldInfo FieldInfo;
983 public FieldExpr (FieldInfo fi)
986 eclass = ExprClass.Variable;
989 override public Expression Resolve (TypeContainer tc)
991 // We are born in resolved state.
995 override public void Emit (EmitContext ec)
997 // FIXME: Assert that this should not be reached?
1002 // Fully resolved expression that evaluates to a Property
1004 public class PropertyExpr : Expression {
1005 public readonly PropertyInfo PropertyInfo;
1006 public readonly bool IsStatic;
1008 public PropertyExpr (PropertyInfo pi)
1011 eclass = ExprClass.PropertyAccess;
1014 MethodInfo [] acc = pi.GetAccessors ();
1016 for (int i = 0; i < acc.Length; i++)
1017 if (acc [i].IsStatic)
1021 override public Expression Resolve (TypeContainer tc)
1023 // We are born in resolved state.
1027 override public void Emit (EmitContext ec)
1029 // FIXME: Implement.
1033 public class CheckedExpr : Expression {
1035 public readonly Expression Expr;
1037 public CheckedExpr (Expression e)
1042 public override Expression Resolve (TypeContainer tc)
1044 // FIXME : Implement !
1048 public override void Emit (EmitContext ec)
1054 public class UnCheckedExpr : Expression {
1056 public readonly Expression Expr;
1058 public UnCheckedExpr (Expression e)
1063 public override Expression Resolve (TypeContainer tc)
1065 // FIXME : Implement !
1069 public override void Emit (EmitContext ec)
1075 public class ElementAccess : Expression {
1077 public readonly ArrayList Arguments;
1078 public readonly Expression Expr;
1080 public ElementAccess (Expression e, ArrayList e_list)
1086 public override Expression Resolve (TypeContainer tc)
1088 // FIXME : Implement
1092 public override void Emit (EmitContext ec)
1094 // FIXME : Implement !
1099 public class BaseAccess : Expression {
1101 public enum BaseAccessType {
1106 public readonly BaseAccessType BAType;
1107 public readonly string Member;
1108 public readonly ArrayList Arguments;
1110 public BaseAccess (BaseAccessType t, string member, ArrayList args)
1118 public override Expression Resolve (TypeContainer tc)
1120 // FIXME : Implement !
1124 public override void Emit (EmitContext ec)