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)
77 return new EventExpr ((EventInfo) mi);
78 } else if (mi is FieldInfo){
79 return new FieldExpr ((FieldInfo) mi);
80 } else if (mi is PropertyInfo){
81 return new PropertyExpr ((PropertyInfo) mi);
82 } else if (mi is Type)
83 return new TypeExpr ((Type) mi);
89 // FIXME: Probably implement a cache for (t,name,current_access_set)?
91 // FIXME: We need to cope with access permissions here, or this wont
94 // This code could use some optimizations, but we need to do some
95 // measurements. For example, we could use a delegate to `flag' when
96 // something can not any longer be a method-group (because it is something
100 // If the return value is an Array, then it is an array of
103 // If the return value is an MemberInfo, it is anything, but a Method
107 // FIXME: When calling MemberLookup inside an `Invocation', we should pass
108 // the arguments here and have MemberLookup return only the methods that
109 // match the argument count/type, unlike we are doing now (we delay this
112 // This is so we can catch correctly attempts to invoke instance methods
113 // from a static body (scan for error 120 in ResolveSimpleName).
115 protected static Expression MemberLookup (Report r, Type t, string name, bool same_type)
118 // MemberTypes.Constructor |
122 MemberTypes.NestedType |
123 MemberTypes.Property;
126 BindingFlags.Public |
127 BindingFlags.Static |
128 BindingFlags.Instance;
131 bf |= BindingFlags.NonPublic;
134 MemberInfo [] mi = t.FindMembers (mt, bf, Type.FilterName, name);
136 if (mi.Length == 1 && !(mi [0] is MethodInfo))
137 return Expression.ExprClassFromMemberInfo (mi [0]);
139 for (int i = 0; i < mi.Length; i++)
140 if (!(mi [i] is MethodInfo)){
141 r.Error (-5, "Do not know how to reproduce this case: Methods and non-Method with the same name, report this please");
145 return new MethodGroupExpr (mi);
149 // Resolves the E in `E.I' side for a member_access
151 // This is suboptimal and should be merged with ResolveMemberAccess
152 static Expression ResolvePrimary (TypeContainer tc, string name)
154 int dot_pos = name.LastIndexOf (".");
156 if (tc.RootContext.IsNamespace (name))
157 return new NamespaceExpr (name);
161 Type t = tc.LookupType (name, false);
164 return new TypeExpr (t);
170 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
173 int dot_pos = name.LastIndexOf (".");
174 string left = name.Substring (0, dot_pos);
175 string right = name.Substring (dot_pos + 1);
177 left_e = ResolvePrimary (tc, left);
181 switch (left_e.ExprClass){
183 return MemberLookup (tc.RootContext.Report,
185 left_e.Type == tc.TypeBuilder);
187 case ExprClass.Namespace:
188 case ExprClass.PropertyAccess:
189 case ExprClass.IndexerAccess:
190 case ExprClass.Variable:
191 case ExprClass.Value:
192 case ExprClass.Nothing:
193 case ExprClass.EventAccess:
194 case ExprClass.MethodGroup:
195 case ExprClass.Invalid:
196 tc.RootContext.Report.Error (-1000,
197 "Internal compiler error, should have " +
198 "got these handled before");
207 public class Unary : Expression {
208 public enum Operator {
209 Plus, Minus, Negate, BitComplement,
210 Indirection, AddressOf, PreIncrement,
211 PreDecrement, PostIncrement, PostDecrement
217 public Unary (Operator op, Expression expr)
223 public Expression Expr {
233 public Operator Oper {
243 public override Expression Resolve (TypeContainer tc)
249 public override void Emit (EmitContext ec)
254 public class Probe : Expression {
259 public enum Operator {
263 public Probe (Operator oper, Expression expr, string probe_type)
266 this.probe_type = probe_type;
270 public Operator Oper {
276 public Expression Expr {
282 public string ProbeType {
288 public override Expression Resolve (TypeContainer tc)
294 public override void Emit (EmitContext ec)
299 public class Cast : Expression {
303 public Cast (string cast_type, Expression expr)
305 this.target_type = target_type;
309 public string TargetType {
315 public Expression Expr {
324 public override Expression Resolve (TypeContainer tc)
330 public override void Emit (EmitContext ec)
335 public class Binary : Expression {
336 public enum Operator {
337 Multiply, Divide, Modulo,
339 ShiftLeft, ShiftRight,
340 LessThan, GreatherThan, LessOrEqual, GreatherOrEqual,
350 Expression left, right;
352 OpCode opcode, opcode_check;
354 public Binary (Operator oper, Expression left, Expression right)
361 public Operator Oper {
370 public Expression Left {
379 public Expression Right {
388 Expression ResolveOperator (Operator oper, Type l, Type r)
391 // Step 1: Perform Operator Overload location
395 // Step 2: Default operations
398 case Operator.Multiply:
399 opcode = OpCodes.Mul;
400 if (l == TypeManager.int32_type)
401 opcode_check = OpCodes.Mul_Ovf;
402 else if (l == TypeManager.uint32_type)
403 opcode_check = OpCodes.Mul_Ovf_Un;
404 else if (l == TypeManager.uint64_type)
405 opcode_check = OpCodes.Mul_Ovf_Un;
406 else if (l == TypeManager.int64_type)
407 opcode_check = OpCodes.Mul_Ovf;
409 opcode_check = OpCodes.Mul;
416 public override Expression Resolve (TypeContainer tc)
418 left = left.Resolve (tc);
419 right = right.Resolve (tc);
421 if (left == null || right == null)
424 return ResolveOperator (oper, left.Type, right.Type);
427 public override void Emit (EmitContext ec)
429 ILGenerator ig = ec.ig;
435 ec.ig.Emit (opcode_check);
441 public class Conditional : Expression {
442 Expression expr, trueExpr, falseExpr;
444 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
447 this.trueExpr = trueExpr;
448 this.falseExpr = falseExpr;
451 public Expression Expr {
457 public Expression TrueExpr {
463 public Expression FalseExpr {
469 public override Expression Resolve (TypeContainer tc)
475 public override void Emit (EmitContext ec)
480 public class SimpleName : Expression {
483 public SimpleName (string name)
495 // Checks whether we are trying to access an instance
496 // property, method or field from a static body.
498 Expression MemberStaticCheck (Report r, Expression e)
501 FieldInfo fi = ((FieldExpr) e).FieldInfo;
505 "An object reference is required " +
506 "for the non-static field `"+name+"'");
509 } else if (e is MethodGroupExpr){
510 // FIXME: Pending reorganization of MemberLookup
511 // Basically at this point we should have the
512 // best match already selected for us, and
513 // we should only have to check a *single*
514 // Method for its static on/off bit.
516 } else if (e is PropertyExpr){
517 if (!((PropertyExpr) e).IsStatic){
519 "An object reference is required " +
520 "for the non-static property access `"+
530 // 7.5.2: Simple Names.
532 // Local Variables and Parameters are handled at
533 // parse time, so they never occur as SimpleNames.
535 Expression ResolveSimpleName (TypeContainer tc)
538 Report r = tc.RootContext.Report;
540 e = MemberLookup (tc.RootContext.Report, tc.TypeBuilder, name, true);
544 if ((tc.ModFlags & Modifiers.STATIC) != 0)
545 return MemberStaticCheck (r, e);
551 // Do step 3 of the Simple Name resolution.
553 // FIXME: implement me.
559 // SimpleName needs to handle a multitude of cases:
561 // simple_names and qualified_identifiers are placed on
564 public override Expression Resolve (TypeContainer tc)
566 if (name.IndexOf (".") != -1)
567 return ResolveMemberAccess (tc, name);
569 return ResolveSimpleName (tc);
572 public override void Emit (EmitContext ec)
577 public class LocalVariableReference : Expression {
578 public readonly string Name;
579 public readonly Block Block;
581 public LocalVariableReference (Block block, string name)
585 eclass = ExprClass.Variable;
588 public VariableInfo VariableInfo {
590 return (VariableInfo) Block.GetVariableInfo (Name);
594 public override Expression Resolve (TypeContainer tc)
599 public override void Emit (EmitContext ec)
601 Console.WriteLine ("Internal compiler error, LocalVariableReference should not be emitted");
605 public class ParameterReference : Expression {
606 public readonly Parameters Pars;
607 public readonly String Name;
608 public readonly int Idx;
610 public ParameterReference (Parameters pars, int idx, string name)
617 public override Expression Resolve (TypeContainer tc)
623 public override void Emit (EmitContext ec)
629 // Used for arguments to New(), Invocation()
631 public class Argument {
638 public readonly AType Type;
641 public Argument (Expression expr, AType type)
647 public Expression Expr {
653 public bool Resolve (TypeContainer tc)
655 expr = expr.Resolve (tc);
659 public void Emit (EmitContext ec)
666 // Invocation of methods or delegates.
668 public class Invocation : Expression {
669 public readonly ArrayList Arguments;
671 MethodInfo method = null;
674 // arguments is an ArrayList, but we do not want to typecast,
675 // as it might be null.
677 // FIXME: only allow expr to be a method invocation or a
678 // delegate invocation (7.5.5)
680 public Invocation (Expression expr, ArrayList arguments)
683 Arguments = arguments;
686 public Expression Expr {
693 /// Computes whether Argument `a' and the ParameterInfo `pi' are
694 /// compatible, and if so, how good is the match (in terms of
695 /// "better conversions" (7.4.2.3).
697 /// 0 is the best possible match.
698 /// -1 represents a type mismatch.
699 /// -2 represents a ref/out mismatch.
701 static int Badness (Argument a, ParameterInfo pi)
703 if (pi.ParameterType == a.Expr.Type)
706 // FIXME: Implement implicit conversions here.
707 // FIXME: Implement better conversion here.
713 // Find the Applicable Function Members (7.4.2.1)
715 static MethodInfo OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
717 ArrayList afm = new ArrayList ();
718 int best_match = 10000;
719 int best_match_idx = -1;
720 MethodInfo method = null;
722 for (int i = me.Methods.Length; i > 0; ){
724 ParameterInfo [] pi = me.Methods [i].GetParameters ();
727 // Compute how good this is
729 if (pi.Length == Arguments.Count){
732 for (int j = Arguments.Count; j > 0;){
736 Argument a = (Argument) Arguments [j];
738 x = Badness (a, pi [j]);
741 // FIXME: report nice error.
746 if (badness < best_match){
747 best_match = badness;
748 method = me.Methods [i];
754 if (best_match_idx == -1)
761 public override Expression Resolve (TypeContainer tc)
764 // First, resolve the expression that is used to
765 // trigger the invocation
767 this.expr = expr.Resolve (tc);
768 if (this.expr == null)
771 if (!(this.expr is MethodGroupExpr)){
772 tc.RootContext.Report.Error (118,
773 "Denotes an " + this.expr.ExprClass + " while a method was expected");
778 // Next, evaluate all the expressions in the argument list
780 if (Arguments != null){
781 for (int i = Arguments.Count; i > 0;){
783 Argument a = (Argument) Arguments [i];
790 method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
793 tc.RootContext.Report.Error (-6,
794 "Figure out error: Can not find a good function for this argument list");
798 Console.WriteLine ("Found a method! " + method);
803 public override void Emit (EmitContext ec)
805 int top = Arguments.Count;
807 for (int i = 0; i < top; i++){
808 Argument a = (Argument) Arguments [i];
813 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
817 public class New : Expression {
824 public readonly NType NewType;
825 public readonly ArrayList Arguments;
826 public readonly string RequestedType;
827 // These are for the case when we have an array
828 public readonly string Rank;
829 public readonly ArrayList Indices;
830 public readonly ArrayList Initializers;
833 public New (string requested_type, ArrayList arguments)
835 RequestedType = requested_type;
836 Arguments = arguments;
837 NewType = NType.Object;
840 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
842 RequestedType = requested_type;
845 Initializers = initializers;
846 NewType = NType.Array;
849 public override Expression Resolve (TypeContainer tc)
855 public override void Emit (EmitContext ec)
860 public class This : Expression {
861 public override Expression Resolve (TypeContainer tc)
867 public override void Emit (EmitContext ec)
872 public class TypeOf : Expression {
873 public readonly string QueriedType;
875 public TypeOf (string queried_type)
877 QueriedType = queried_type;
880 public override Expression Resolve (TypeContainer tc)
886 public override void Emit (EmitContext ec)
891 public class SizeOf : Expression {
892 public readonly string QueriedType;
894 public SizeOf (string queried_type)
896 this.QueriedType = queried_type;
899 public override Expression Resolve (TypeContainer tc)
905 public override void Emit (EmitContext ec)
910 public class MemberAccess : Expression {
911 public readonly string Identifier;
914 public MemberAccess (Expression expr, string id)
920 public Expression Expr {
926 public override Expression Resolve (TypeContainer tc)
932 public override void Emit (EmitContext ec)
939 // Nodes of type Namespace are created during the semantic
940 // analysis to resolve member_access/qualified_identifier/simple_name
943 // They are born `resolved'.
945 public class NamespaceExpr : Expression {
946 public readonly string Name;
948 public NamespaceExpr (string name)
951 eclass = ExprClass.Namespace;
954 public override Expression Resolve (TypeContainer tc)
959 public override void Emit (EmitContext ec)
965 // Fully resolved expression that evaluates to a type
967 public class TypeExpr : Expression {
968 public TypeExpr (Type t)
971 eclass = ExprClass.Type;
974 override public Expression Resolve (TypeContainer tc)
979 override public void Emit (EmitContext ec)
986 // Fully resolved expression that evaluates to a type
988 public class MethodGroupExpr : Expression {
989 public readonly MethodInfo [] Methods;
991 public MethodGroupExpr (MemberInfo [] mi)
993 Methods = new MethodInfo [mi.Length];
994 mi.CopyTo (Methods, 0);
995 eclass = ExprClass.MethodGroup;
998 override public Expression Resolve (TypeContainer tc)
1003 override public void Emit (EmitContext ec)
1009 public class BuiltinTypeAccess : Expression {
1010 public readonly string AccessBase;
1011 public readonly string Method;
1013 public BuiltinTypeAccess (string type, string method)
1015 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
1020 public override Expression Resolve (TypeContainer tc)
1022 // FIXME: Implement;
1026 public override void Emit (EmitContext ec)
1032 // Fully resolved expression that evaluates to a Field
1034 public class FieldExpr : Expression {
1035 public readonly FieldInfo FieldInfo;
1037 public FieldExpr (FieldInfo fi)
1040 eclass = ExprClass.Variable;
1043 override public Expression Resolve (TypeContainer tc)
1045 // We are born in resolved state.
1049 override public void Emit (EmitContext ec)
1051 // FIXME: Assert that this should not be reached?
1056 // Fully resolved expression that evaluates to a Property
1058 public class PropertyExpr : Expression {
1059 public readonly PropertyInfo PropertyInfo;
1060 public readonly bool IsStatic;
1062 public PropertyExpr (PropertyInfo pi)
1065 eclass = ExprClass.PropertyAccess;
1068 MethodInfo [] acc = pi.GetAccessors ();
1070 for (int i = 0; i < acc.Length; i++)
1071 if (acc [i].IsStatic)
1075 override public Expression Resolve (TypeContainer tc)
1077 // We are born in resolved state.
1081 override public void Emit (EmitContext ec)
1083 // FIXME: Implement.
1088 // Fully resolved expression that evaluates to a Property
1090 public class EventExpr : Expression {
1091 public readonly EventInfo EventInfo;
1093 public EventExpr (EventInfo ei)
1096 eclass = ExprClass.EventAccess;
1099 override public Expression Resolve (TypeContainer tc)
1101 // We are born in resolved state.
1105 override public void Emit (EmitContext ec)
1107 // FIXME: Implement.
1111 public class CheckedExpr : Expression {
1113 public readonly Expression Expr;
1115 public CheckedExpr (Expression e)
1120 public override Expression Resolve (TypeContainer tc)
1122 // FIXME : Implement !
1126 public override void Emit (EmitContext ec)
1132 public class UnCheckedExpr : Expression {
1134 public readonly Expression Expr;
1136 public UnCheckedExpr (Expression e)
1141 public override Expression Resolve (TypeContainer tc)
1143 // FIXME : Implement !
1147 public override void Emit (EmitContext ec)
1153 public class ElementAccess : Expression {
1155 public readonly ArrayList Arguments;
1156 public readonly Expression Expr;
1158 public ElementAccess (Expression e, ArrayList e_list)
1164 public override Expression Resolve (TypeContainer tc)
1166 // FIXME : Implement
1170 public override void Emit (EmitContext ec)
1172 // FIXME : Implement !
1177 public class BaseAccess : Expression {
1179 public enum BaseAccessType {
1184 public readonly BaseAccessType BAType;
1185 public readonly string Member;
1186 public readonly ArrayList Arguments;
1188 public BaseAccess (BaseAccessType t, string member, ArrayList args)
1196 public override Expression Resolve (TypeContainer tc)
1198 // FIXME : Implement !
1202 public override void Emit (EmitContext ec)