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 public static Expression MemberLookup (RootContext rc, Type t, string name,
116 bool same_type, MemberTypes mt, BindingFlags bf)
119 bf |= BindingFlags.NonPublic;
121 MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
126 if (mi.Length == 1 && !(mi [0] is MethodBase))
127 return Expression.ExprClassFromMemberInfo (mi [0]);
129 for (int i = 0; i < mi.Length; i++)
130 if (!(mi [i] is MethodBase)){
131 rc.Report.Error (-5, "Do not know how to reproduce this case: " +
132 "Methods and non-Method with the same name, report this please");
134 for (i = 0; i < mi.Length; i++){
135 Type tt = mi [i].GetType ();
137 Console.WriteLine (i + ": " + mi [i]);
138 while (tt != TypeManager.object_type){
139 Console.WriteLine (tt);
145 return new MethodGroupExpr (mi);
148 public const MemberTypes AllMemberTypes =
149 MemberTypes.Constructor |
153 MemberTypes.NestedType |
154 MemberTypes.Property;
156 public const BindingFlags AllBindingsFlags =
157 BindingFlags.Public |
158 BindingFlags.Static |
159 BindingFlags.Instance;
161 public static Expression MemberLookup (RootContext rc, Type t, string name,
164 return MemberLookup (rc, t, name, same_type, AllMemberTypes, AllBindingsFlags);
168 // Resolves the E in `E.I' side for a member_access
170 // This is suboptimal and should be merged with ResolveMemberAccess
171 static Expression ResolvePrimary (TypeContainer tc, string name)
173 int dot_pos = name.LastIndexOf (".");
175 if (tc.RootContext.IsNamespace (name))
176 return new NamespaceExpr (name);
180 Type t = tc.LookupType (name, false);
183 return new TypeExpr (t);
189 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
192 int dot_pos = name.LastIndexOf (".");
193 string left = name.Substring (0, dot_pos);
194 string right = name.Substring (dot_pos + 1);
196 left_e = ResolvePrimary (tc, left);
200 switch (left_e.ExprClass){
202 return MemberLookup (tc.RootContext,
204 left_e.Type == tc.TypeBuilder);
206 case ExprClass.Namespace:
207 case ExprClass.PropertyAccess:
208 case ExprClass.IndexerAccess:
209 case ExprClass.Variable:
210 case ExprClass.Value:
211 case ExprClass.Nothing:
212 case ExprClass.EventAccess:
213 case ExprClass.MethodGroup:
214 case ExprClass.Invalid:
215 tc.RootContext.Report.Error (-1000,
216 "Internal compiler error, should have " +
217 "got these handled before");
224 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
226 Type expr_type = expr.Type;
228 if (target_type == TypeManager.object_type) {
229 if (expr_type.IsClass)
230 return new EmptyCast (expr, target_type);
231 if (expr_type.IsValueType)
232 return new BoxedCast (expr, target_type);
233 } else if (expr_type.IsSubclassOf (target_type))
234 return new EmptyCast (expr, target_type);
236 // FIXME: missing implicit reference conversions:
238 // from any class-type S to any interface-type T.
239 // from any interface type S to interface-type T.
240 // from an array-type S to an array-type of type T
241 // from an array-type to System.Array
242 // from any delegate type to System.Delegate
243 // from any array-type or delegate type into System.ICloneable.
244 // from the null type to any reference-type.
252 // Converts implicitly the resolved expression `expr' into the
253 // `target_type'. It returns a new expression that can be used
254 // in a context that expects a `target_type'.
256 static public Expression ConvertImplicit (Expression expr, Type target_type)
258 Type expr_type = expr.Type;
260 if (expr_type == target_type){
261 Console.WriteLine ("Hey, ConvertImplicit was called with no job to do");
266 // Step 1: Perform implicit conversions as found on expr.Type
270 // Step 2: Built-in conversions.
272 if (expr_type == TypeManager.sbyte_type){
274 // From sbyte to short, int, long, float, double.
276 if (target_type == TypeManager.int32_type)
277 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
278 if (target_type == TypeManager.int64_type)
279 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
280 if (target_type == TypeManager.double_type)
281 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
282 if (target_type == TypeManager.float_type)
283 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
284 if (target_type == TypeManager.short_type)
285 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
286 } else if (expr_type == TypeManager.byte_type){
288 // From byte to short, ushort, int, uint, long, ulong, float, double
290 if ((target_type == TypeManager.short_type) ||
291 (target_type == TypeManager.ushort_type) ||
292 (target_type == TypeManager.int32_type) ||
293 (target_type == TypeManager.uint32_type))
294 return new EmptyCast (expr, target_type);
296 if (target_type == TypeManager.uint64_type)
297 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
298 if (target_type == TypeManager.int64_type)
299 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
301 if (target_type == TypeManager.float_type)
302 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
303 if (target_type == TypeManager.double_type)
304 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
305 } else if (expr_type == TypeManager.short_type){
307 // From short to int, long, float, double
309 if (target_type == TypeManager.int32_type)
310 return new EmptyCast (expr, target_type);
311 if (target_type == TypeManager.int64_type)
312 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
313 if (target_type == TypeManager.double_type)
314 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
315 if (target_type == TypeManager.float_type)
316 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
317 } else if (expr_type == TypeManager.ushort_type){
319 // From ushort to int, uint, long, ulong, float, double
321 if ((target_type == TypeManager.uint32_type) ||
322 (target_type == TypeManager.uint64_type))
323 return new EmptyCast (expr, target_type);
325 if (target_type == TypeManager.int32_type)
326 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
327 if (target_type == TypeManager.int64_type)
328 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
329 if (target_type == TypeManager.double_type)
330 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
331 if (target_type == TypeManager.float_type)
332 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
333 } else if (expr_type == TypeManager.int32_type){
335 // From int to long, float, double
337 if (target_type == TypeManager.int64_type)
338 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
339 if (target_type == TypeManager.double_type)
340 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
341 if (target_type == TypeManager.float_type)
342 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
343 } else if (expr_type == TypeManager.uint32_type){
345 // From uint to long, ulong, float, double
347 if (target_type == TypeManager.int64_type)
348 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
349 if (target_type == TypeManager.uint64_type)
350 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
351 if (target_type == TypeManager.double_type)
352 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
354 if (target_type == TypeManager.float_type)
355 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
357 } else if ((expr_type == TypeManager.uint64_type) ||
358 (expr_type == TypeManager.int64_type)){
360 // From long to float, double
362 if (target_type == TypeManager.double_type)
363 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
365 if (target_type == TypeManager.float_type)
366 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
368 } else if (expr_type == TypeManager.char_type){
370 // From char to ushort, int, uint, long, ulong, float, double
372 if ((target_type == TypeManager.ushort_type) ||
373 (target_type == TypeManager.int32_type) ||
374 (target_type == TypeManager.uint32_type))
375 return new EmptyCast (expr, target_type);
376 if (target_type == TypeManager.uint64_type)
377 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
378 if (target_type == TypeManager.int64_type)
379 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
380 if (target_type == TypeManager.float_type)
381 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
382 if (target_type == TypeManager.double_type)
383 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
385 return ImplicitReferenceConversion (expr, target_type);
390 // Could not find an implicit cast.
396 // Performs an explicit conversion of the expression `expr' whose
397 // type is expr.Type to `target_type'.
399 static public Expression ConvertExplicit (Expression expr, Type target_type)
407 // This kind of cast is used to encapsulate the child
408 // whose type is child.Type into an expression that is
409 // reported to return "return_type". This is used to encapsulate
410 // expressions which have compatible types, but need to be dealt
411 // at higher levels with.
413 // For example, a "byte" expression could be encapsulated in one
414 // of these as an "unsigned int". The type for the expression
415 // would be "unsigned int".
419 public class EmptyCast : Expression {
420 protected Expression child;
422 public EmptyCast (Expression child, Type return_type)
424 ExprClass = child.ExprClass;
429 public override Expression Resolve (TypeContainer tc)
431 // This should never be invoked, we are born in fully
432 // initialized state.
437 public override void Emit (EmitContext ec)
443 public class BoxedCast : EmptyCast {
445 public BoxedCast (Expression expr, Type target_type)
446 : base (expr, target_type)
450 public override Expression Resolve (TypeContainer tc)
452 // This should never be invoked, we are born in fully
453 // initialized state.
458 public override void Emit (EmitContext ec)
461 ec.ig.Emit (OpCodes.Box, child.Type);
467 // This kind of cast is used to encapsulate a child expression
468 // that can be trivially converted to a target type using one or
469 // two opcodes. The opcodes are passed as arguments.
471 public class OpcodeCast : EmptyCast {
475 public OpcodeCast (Expression child, Type return_type, OpCode op)
476 : base (child, return_type)
480 second_valid = false;
483 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
484 : base (child, return_type)
492 public override Expression Resolve (TypeContainer tc)
494 // This should never be invoked, we are born in fully
495 // initialized state.
500 public override void Emit (EmitContext ec)
511 public class Unary : Expression {
512 public enum Operator {
513 Add, Subtract, Negate, BitComplement,
514 Indirection, AddressOf, PreIncrement,
515 PreDecrement, PostIncrement, PostDecrement
523 public Unary (Operator op, Expression expr)
529 public Expression Expr {
539 public Operator Oper {
550 // Returns a stringified representation of the Operator
557 case Operator.Subtract:
559 case Operator.Negate:
561 case Operator.BitComplement:
563 case Operator.AddressOf:
565 case Operator.Indirection:
567 case Operator.PreIncrement : case Operator.PostIncrement :
569 case Operator.PreDecrement : case Operator.PostDecrement :
573 return oper.ToString ();
576 Expression ForceConversion (Expression expr, Type target_type)
578 if (expr.Type == target_type)
581 return ConvertImplicit (expr, target_type);
584 Expression ResolveOperator (TypeContainer tc)
586 Type expr_type = expr.Type;
589 // Step 1: Perform Operator Overload location
594 if (oper == Operator.PostIncrement || oper == Operator.PreIncrement)
595 op_name = "op_Increment";
596 else if (oper == Operator.PostDecrement || oper == Operator.PreDecrement)
597 op_name = "op_Decrement";
599 op_name = "op_" + oper;
601 mg = MemberLookup (tc.RootContext, expr_type, op_name, false);
604 Arguments = new ArrayList ();
605 Arguments.Add (new Argument (expr, Argument.AType.Expression));
607 method = Invocation.OverloadResolve ((MethodGroupExpr) mg, Arguments);
613 // Step 2: Default operations on CLI native types.
616 // Only perform numeric promotions on:
619 if (expr_type == null)
622 if (oper == Operator.Negate && expr_type != TypeManager.bool_type) {
623 tc.RootContext.Report.Error (
625 "Operator " + OperName () + " cannot be applied to operands of type `" +
626 TypeManager.CSharpName (expr.Type) + "'");
629 expr = ForceConversion (expr, TypeManager.int32_type);
630 type = TypeManager.int32_type;
633 if (oper == Operator.BitComplement) {
634 if (!((expr_type == TypeManager.int32_type) ||
635 (expr_type == TypeManager.uint32_type) ||
636 (expr_type == TypeManager.int64_type) ||
637 (expr_type == TypeManager.uint64_type))){
638 tc.RootContext.Report.Error (
640 "Operator " + OperName () + " cannot be applied to operands of type `" +
641 TypeManager.CSharpName (expr.Type) + "'");
647 // A plus in front of something is just a no-op
649 if (oper == Operator.Add)
653 // Fold -Constant into a negative constant
655 if (oper == Operator.Subtract){
658 if (expr is IntLiteral)
659 e = new IntLiteral (-((IntLiteral) expr).Value);
660 else if (expr is LongLiteral)
661 e = new LongLiteral (-((LongLiteral) expr).Value);
662 else if (expr is FloatLiteral)
663 e = new FloatLiteral (-((FloatLiteral) expr).Value);
671 // FIXME : Are we supposed to check that we have an object type
672 // for & and * operators ?
678 public override Expression Resolve (TypeContainer tc)
680 expr = expr.Resolve (tc);
685 return ResolveOperator (tc);
688 public override void Emit (EmitContext ec)
691 ILGenerator ig = ec.ig;
692 Type expr_type = expr.Type;
694 if (method != null) {
696 // Note that operators are static anyway
698 if (Arguments != null)
699 Invocation.EmitArguments (ec, method, Arguments);
701 if (method is MethodInfo)
702 ig.Emit (OpCodes.Call, (MethodInfo) method);
704 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
709 // FIXME : This is commented out for now
714 throw new Exception ("This should be caught by Resolve");
716 case Operator.Subtract:
721 case Operator.Negate:
725 case Operator.BitComplement:
729 case Operator.AddressOf :
733 case Operator.Indirection :
737 case Operator.PreIncrement : case Operator.PostIncrement :
741 case Operator.PreDecrement : case Operator.PostDecrement :
746 throw new Exception ("This should not happen: Operator = "
750 // FIXME : Commented out for now.
756 public class Probe : Expression {
761 public enum Operator {
765 public Probe (Operator oper, Expression expr, string probe_type)
768 this.probe_type = probe_type;
772 public Operator Oper {
778 public Expression Expr {
784 public string ProbeType {
790 public override Expression Resolve (TypeContainer tc)
793 throw new Exception ("Unimplemented");
797 public override void Emit (EmitContext ec)
802 public class Cast : Expression {
806 public Cast (string cast_type, Expression expr)
808 this.target_type = target_type;
812 public string TargetType {
818 public Expression Expr {
827 public override Expression Resolve (TypeContainer tc)
829 type = tc.LookupType (target_type, false);
830 eclass = ExprClass.Value;
835 // FIXME: Finish this.
839 public override void Emit (EmitContext ec)
844 public class Binary : Expression {
845 public enum Operator {
846 Multiply, Divide, Modulo,
848 ShiftLeft, ShiftRight,
849 LessThan, GreaterThan, LessOrEqual, GreaterOrEqual,
859 Expression left, right;
864 public Binary (Operator oper, Expression left, Expression right)
871 public Operator Oper {
880 public Expression Left {
889 public Expression Right {
900 // Returns a stringified representation of the Operator
905 case Operator.Multiply:
907 case Operator.Divide:
909 case Operator.Modulo:
913 case Operator.Subtract:
915 case Operator.ShiftLeft:
917 case Operator.ShiftRight:
919 case Operator.LessThan:
921 case Operator.GreaterThan:
923 case Operator.LessOrEqual:
925 case Operator.GreaterOrEqual:
929 case Operator.NotEqual:
931 case Operator.BitwiseAnd:
933 case Operator.BitwiseOr:
935 case Operator.ExclusiveOr:
937 case Operator.LogicalOr:
939 case Operator.LogicalAnd:
943 return oper.ToString ();
946 Expression ForceConversion (Expression expr, Type target_type)
948 if (expr.Type == target_type)
951 return ConvertImplicit (expr, target_type);
955 // Note that handling the case l == Decimal || r == Decimal
956 // is taken care of by the Step 1 Operator Overload resolution.
958 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
960 if (l == TypeManager.double_type || r == TypeManager.double_type){
962 // If either operand is of type double, the other operand is
963 // conveted to type double.
965 if (r != TypeManager.double_type)
966 right = ConvertImplicit (right, TypeManager.double_type);
967 if (l != TypeManager.double_type)
968 left = ConvertImplicit (left, TypeManager.double_type);
970 type = TypeManager.double_type;
971 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
973 // if either operand is of type float, th eother operand is
974 // converd to type float.
976 if (r != TypeManager.double_type)
977 right = ConvertImplicit (right, TypeManager.float_type);
978 if (l != TypeManager.double_type)
979 left = ConvertImplicit (left, TypeManager.float_type);
980 type = TypeManager.float_type;
981 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
983 // If either operand is of type ulong, the other operand is
984 // converted to type ulong. or an error ocurrs if the other
985 // operand is of type sbyte, short, int or long
989 if (l == TypeManager.uint64_type)
991 else if (r == TypeManager.uint64_type)
994 if ((other == TypeManager.sbyte_type) ||
995 (other == TypeManager.short_type) ||
996 (other == TypeManager.int32_type) ||
997 (other == TypeManager.int64_type)){
998 string oper = OperName ();
1000 tc.RootContext.Report.Error (34, "Operator `" + OperName ()
1001 + "' is ambiguous on operands of type `"
1002 + TypeManager.CSharpName (l) + "' "
1003 + "and `" + TypeManager.CSharpName (r)
1006 type = TypeManager.uint64_type;
1007 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1009 // If either operand is of type long, the other operand is converted
1012 if (l != TypeManager.int64_type)
1013 left = ConvertImplicit (left, TypeManager.int64_type);
1014 if (r != TypeManager.int64_type)
1015 right = ConvertImplicit (right, TypeManager.int64_type);
1017 type = TypeManager.int64_type;
1018 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
1020 // If either operand is of type uint, and the other
1021 // operand is of type sbyte, short or int, othe operands are
1022 // converted to type long.
1026 if (l == TypeManager.uint32_type)
1028 else if (r == TypeManager.uint32_type)
1031 if ((other == TypeManager.sbyte_type) ||
1032 (other == TypeManager.short_type) ||
1033 (other == TypeManager.int32_type)){
1034 left = ForceConversion (left, TypeManager.int64_type);
1035 right = ForceConversion (right, TypeManager.int64_type);
1036 type = TypeManager.int64_type;
1039 // if either operand is of type uint, the other
1040 // operand is converd to type uint
1042 left = ForceConversion (left, TypeManager.uint32_type);
1043 right = ForceConversion (left, TypeManager.uint32_type);
1044 type = TypeManager.uint32_type;
1047 left = ForceConversion (left, TypeManager.int32_type);
1048 right = ForceConversion (right, TypeManager.int32_type);
1049 type = TypeManager.int32_type;
1053 void error19 (TypeContainer tc)
1055 tc.RootContext.Report.Error (
1057 "Operator " + OperName () + " cannot be applied to operands of type `" +
1058 TypeManager.CSharpName (left.Type) + "' and `" +
1059 TypeManager.CSharpName (right.Type) + "'");
1063 Expression CheckShiftArguments (TypeContainer tc)
1067 Type r = right.Type;
1069 e = ForceConversion (right, TypeManager.int32_type);
1076 if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
1077 ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
1078 ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
1079 ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
1088 Expression ResolveOperator (TypeContainer tc)
1091 Type r = right.Type;
1094 // Step 1: Perform Operator Overload location
1096 Expression left_expr, right_expr;
1098 string op = "op_" + oper;
1100 left_expr = MemberLookup (tc.RootContext, l, op, false);
1102 right_expr = MemberLookup (tc.RootContext, r, op, false);
1104 if (left_expr != null || right_expr != null) {
1106 // Now we need to form the union of these two sets and
1107 // then call OverloadResolve on that.
1109 MethodGroupExpr left_set = null, right_set = null;
1110 int length1 = 0, length2 = 0;
1112 if (left_expr != null) {
1113 left_set = (MethodGroupExpr) left_expr;
1114 length1 = left_set.Methods.Length;
1117 if (right_expr != null) {
1118 right_set = (MethodGroupExpr) right_expr;
1119 length2 = right_set.Methods.Length;
1122 MemberInfo [] mi = new MemberInfo [length1 + length2];
1123 if (left_set != null)
1124 left_set.Methods.CopyTo (mi, 0);
1125 if (right_set != null)
1126 right_set.Methods.CopyTo (mi, length1);
1128 MethodGroupExpr union = new MethodGroupExpr (mi);
1130 Arguments = new ArrayList ();
1131 Arguments.Add (new Argument (left, Argument.AType.Expression));
1132 Arguments.Add (new Argument (right, Argument.AType.Expression));
1135 method = Invocation.OverloadResolve (union, Arguments);
1141 // Step 2: Default operations on CLI native types.
1144 // Only perform numeric promotions on:
1145 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
1147 if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){
1148 return CheckShiftArguments (tc);
1149 } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
1151 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
1154 DoNumericPromotions (tc, l, r);
1156 if (left == null || right == null)
1159 if (oper == Operator.BitwiseAnd ||
1160 oper == Operator.BitwiseOr ||
1161 oper == Operator.ExclusiveOr){
1162 if (!((l == TypeManager.int32_type) ||
1163 (l == TypeManager.uint32_type) ||
1164 (l == TypeManager.int64_type) ||
1165 (l == TypeManager.uint64_type))){
1171 if (oper == Operator.Equal ||
1172 oper == Operator.NotEqual ||
1173 oper == Operator.LessOrEqual ||
1174 oper == Operator.LessThan ||
1175 oper == Operator.GreaterOrEqual ||
1176 oper == Operator.GreaterThan){
1177 type = TypeManager.bool_type;
1183 public override Expression Resolve (TypeContainer tc)
1185 left = left.Resolve (tc);
1186 right = right.Resolve (tc);
1188 if (left == null || right == null)
1191 return ResolveOperator (tc);
1194 public bool IsBranchable ()
1196 if (oper == Operator.Equal ||
1197 oper == Operator.NotEqual ||
1198 oper == Operator.LessThan ||
1199 oper == Operator.GreaterThan ||
1200 oper == Operator.LessOrEqual ||
1201 oper == Operator.GreaterOrEqual){
1208 // This entry point is used by routines that might want
1209 // to emit a brfalse/brtrue after an expression, and instead
1210 // they could use a more compact notation.
1212 // Typically the code would generate l.emit/r.emit, followed
1213 // by the comparission and then a brtrue/brfalse. The comparissions
1214 // are sometimes inneficient (there are not as complete as the branches
1215 // look for the hacks in Emit using double ceqs).
1217 // So for those cases we provide EmitBranchable that can emit the
1218 // branch with the test
1220 public void EmitBranchable (EmitContext ec, int target)
1223 bool close_target = false;
1229 case Operator.Equal:
1231 opcode = OpCodes.Beq_S;
1233 opcode = OpCodes.Beq;
1236 case Operator.NotEqual:
1238 opcode = OpCodes.Bne_Un_S;
1240 opcode = OpCodes.Bne_Un;
1243 case Operator.LessThan:
1245 opcode = OpCodes.Blt_S;
1247 opcode = OpCodes.Blt;
1250 case Operator.GreaterThan:
1252 opcode = OpCodes.Bgt_S;
1254 opcode = OpCodes.Bgt;
1257 case Operator.LessOrEqual:
1259 opcode = OpCodes.Ble_S;
1261 opcode = OpCodes.Ble;
1264 case Operator.GreaterOrEqual:
1266 opcode = OpCodes.Bge_S;
1268 opcode = OpCodes.Ble;
1272 throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "
1273 + oper.ToString ());
1276 ec.ig.Emit (opcode, target);
1279 public override void Emit (EmitContext ec)
1281 ILGenerator ig = ec.ig;
1283 Type r = right.Type;
1286 if (method != null) {
1288 // Note that operators are static anyway
1290 if (Arguments != null)
1291 Invocation.EmitArguments (ec, method, Arguments);
1293 if (method is MethodInfo)
1294 ig.Emit (OpCodes.Call, (MethodInfo) method);
1296 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1305 case Operator.Multiply:
1307 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1308 opcode = OpCodes.Mul_Ovf;
1309 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1310 opcode = OpCodes.Mul_Ovf_Un;
1312 opcode = OpCodes.Mul;
1314 opcode = OpCodes.Mul;
1318 case Operator.Divide:
1319 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1320 opcode = OpCodes.Div_Un;
1322 opcode = OpCodes.Div;
1325 case Operator.Modulo:
1326 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1327 opcode = OpCodes.Rem_Un;
1329 opcode = OpCodes.Rem;
1334 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1335 opcode = OpCodes.Add_Ovf;
1336 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1337 opcode = OpCodes.Add_Ovf_Un;
1339 opcode = OpCodes.Mul;
1341 opcode = OpCodes.Add;
1344 case Operator.Subtract:
1346 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1347 opcode = OpCodes.Sub_Ovf;
1348 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1349 opcode = OpCodes.Sub_Ovf_Un;
1351 opcode = OpCodes.Sub;
1353 opcode = OpCodes.Sub;
1356 case Operator.ShiftRight:
1357 opcode = OpCodes.Shr;
1360 case Operator.ShiftLeft:
1361 opcode = OpCodes.Shl;
1364 case Operator.Equal:
1365 opcode = OpCodes.Ceq;
1368 case Operator.NotEqual:
1369 ec.ig.Emit (OpCodes.Ceq);
1370 ec.ig.Emit (OpCodes.Ldc_I4_0);
1372 opcode = OpCodes.Ceq;
1375 case Operator.LessThan:
1376 opcode = OpCodes.Clt;
1379 case Operator.GreaterThan:
1380 opcode = OpCodes.Cgt;
1383 case Operator.LessOrEqual:
1384 ec.ig.Emit (OpCodes.Cgt);
1385 ec.ig.Emit (OpCodes.Ldc_I4_0);
1387 opcode = OpCodes.Ceq;
1390 case Operator.GreaterOrEqual:
1391 ec.ig.Emit (OpCodes.Clt);
1392 ec.ig.Emit (OpCodes.Ldc_I4_1);
1394 opcode = OpCodes.Sub;
1397 case Operator.LogicalOr:
1398 case Operator.BitwiseOr:
1399 opcode = OpCodes.Or;
1402 case Operator.LogicalAnd:
1403 case Operator.BitwiseAnd:
1404 opcode = OpCodes.And;
1407 case Operator.ExclusiveOr:
1408 opcode = OpCodes.Xor;
1412 throw new Exception ("This should not happen: Operator = "
1413 + oper.ToString ());
1420 public class Conditional : Expression {
1421 Expression expr, trueExpr, falseExpr;
1423 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
1426 this.trueExpr = trueExpr;
1427 this.falseExpr = falseExpr;
1430 public Expression Expr {
1436 public Expression TrueExpr {
1442 public Expression FalseExpr {
1448 public override Expression Resolve (TypeContainer tc)
1450 // FIXME: Implement;
1451 throw new Exception ("Unimplemented");
1455 public override void Emit (EmitContext ec)
1460 public class SimpleName : Expression {
1461 public readonly string Name;
1462 public readonly Location Location;
1464 public SimpleName (string name, Location l)
1471 // Checks whether we are trying to access an instance
1472 // property, method or field from a static body.
1474 Expression MemberStaticCheck (Report r, Expression e)
1476 if (e is FieldExpr){
1477 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1481 "An object reference is required " +
1482 "for the non-static field `"+Name+"'");
1485 } else if (e is MethodGroupExpr){
1486 // FIXME: Pending reorganization of MemberLookup
1487 // Basically at this point we should have the
1488 // best match already selected for us, and
1489 // we should only have to check a *single*
1490 // Method for its static on/off bit.
1492 } else if (e is PropertyExpr){
1493 if (!((PropertyExpr) e).IsStatic){
1495 "An object reference is required " +
1496 "for the non-static property access `"+
1506 // 7.5.2: Simple Names.
1508 // Local Variables and Parameters are handled at
1509 // parse time, so they never occur as SimpleNames.
1511 Expression ResolveSimpleName (TypeContainer tc)
1514 Report r = tc.RootContext.Report;
1516 e = MemberLookup (tc.RootContext, tc.TypeBuilder, Name, true);
1520 else if (e is FieldExpr){
1521 FieldExpr fe = (FieldExpr) e;
1523 if (!fe.FieldInfo.IsStatic)
1524 fe.Instance = new This ();
1527 if ((tc.ModFlags & Modifiers.STATIC) != 0)
1528 return MemberStaticCheck (r, e);
1534 // Do step 3 of the Simple Name resolution.
1536 // FIXME: implement me.
1538 r.Error (103, Location, "The name `" + Name + "' does not exist in the class `" +
1545 // SimpleName needs to handle a multitude of cases:
1547 // simple_names and qualified_identifiers are placed on
1548 // the tree equally.
1550 public override Expression Resolve (TypeContainer tc)
1552 if (Name.IndexOf (".") != -1)
1553 return ResolveMemberAccess (tc, Name);
1555 return ResolveSimpleName (tc);
1558 public override void Emit (EmitContext ec)
1563 public class LocalVariableReference : Expression {
1564 public readonly string Name;
1565 public readonly Block Block;
1567 public LocalVariableReference (Block block, string name)
1571 eclass = ExprClass.Variable;
1574 public VariableInfo VariableInfo {
1576 return Block.GetVariableInfo (Name);
1580 public override Expression Resolve (TypeContainer tc)
1582 VariableInfo vi = Block.GetVariableInfo (Name);
1584 type = vi.VariableType;
1588 public override void Emit (EmitContext ec)
1590 VariableInfo vi = VariableInfo;
1591 ILGenerator ig = ec.ig;
1594 Console.WriteLine ("Variable: " + vi);
1597 ig.Emit (OpCodes.Ldloc_0);
1601 ig.Emit (OpCodes.Ldloc_1);
1605 ig.Emit (OpCodes.Ldloc_2);
1609 ig.Emit (OpCodes.Ldloc_3);
1614 ig.Emit (OpCodes.Ldloc_S, idx);
1616 ig.Emit (OpCodes.Ldloc, idx);
1622 public class ParameterReference : Expression {
1623 public readonly Parameters Pars;
1624 public readonly String Name;
1625 public readonly int Idx;
1627 public ParameterReference (Parameters pars, int idx, string name)
1634 public override Expression Resolve (TypeContainer tc)
1636 Type [] types = Pars.GetParameterInfo (tc);
1643 public override void Emit (EmitContext ec)
1646 ec.ig.Emit (OpCodes.Ldarg_S, Idx);
1648 ec.ig.Emit (OpCodes.Ldarg, Idx);
1653 // Used for arguments to New(), Invocation()
1655 public class Argument {
1662 public readonly AType Type;
1665 public Argument (Expression expr, AType type)
1671 public Expression Expr {
1677 public bool Resolve (TypeContainer tc)
1679 expr = expr.Resolve (tc);
1681 return expr != null;
1684 public void Emit (EmitContext ec)
1691 // Invocation of methods or delegates.
1693 public class Invocation : Expression {
1694 public readonly ArrayList Arguments;
1695 public readonly Location Location;
1698 MethodBase method = null;
1700 static Hashtable method_parameter_cache;
1702 static Invocation ()
1704 method_parameter_cache = new Hashtable ();
1708 // arguments is an ArrayList, but we do not want to typecast,
1709 // as it might be null.
1711 // FIXME: only allow expr to be a method invocation or a
1712 // delegate invocation (7.5.5)
1714 public Invocation (Expression expr, ArrayList arguments, Location l)
1717 Arguments = arguments;
1721 public Expression Expr {
1728 /// Computes whether Argument `a' and the Type t of the ParameterInfo `pi' are
1729 /// compatible, and if so, how good is the match (in terms of
1730 /// "better conversions" (7.4.2.3).
1732 /// 0 is the best possible match.
1733 /// -1 represents a type mismatch.
1734 /// -2 represents a ref/out mismatch.
1736 static int Badness (Argument a, Type t)
1738 Expression argument_expr = a.Expr;
1739 Type argument_type = argument_expr.Type;
1741 if (argument_type == null){
1742 throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
1745 if (t == argument_type)
1749 // Now probe whether an implicit constant expression conversion
1752 // An implicit constant expression conversion permits the following
1755 // * A constant-expression of type `int' can be converted to type
1756 // sbyte, byute, short, ushort, uint, ulong provided the value of
1757 // of the expression is withing the range of the destination type.
1759 // * A constant-expression of type long can be converted to type
1760 // ulong, provided the value of the constant expression is not negative
1762 // FIXME: Note that this assumes that constant folding has
1763 // taken place. We dont do constant folding yet.
1766 if (argument_type == TypeManager.int32_type && argument_expr is IntLiteral){
1767 IntLiteral ei = (IntLiteral) argument_expr;
1768 int value = ei.Value;
1770 if (t == TypeManager.sbyte_type){
1771 if (value >= SByte.MinValue && value <= SByte.MaxValue)
1773 } else if (t == TypeManager.byte_type){
1774 if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
1776 } else if (t == TypeManager.short_type){
1777 if (value >= Int16.MinValue && value <= Int16.MaxValue)
1779 } else if (t == TypeManager.ushort_type){
1780 if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
1782 } else if (t == TypeManager.uint32_type){
1784 // we can optimize this case: a positive int32
1785 // always fits on a uint32
1789 } else if (t == TypeManager.uint64_type){
1791 // we can optimize this case: a positive int32
1792 // always fits on a uint64
1797 } else if (argument_type == TypeManager.int64_type && argument_expr is LongLiteral){
1798 LongLiteral ll = (LongLiteral) argument_expr;
1800 if (t == TypeManager.uint64_type){
1806 // FIXME: Implement user-defined implicit conversions here.
1807 // FIXME: Implement better conversion here.
1813 // Returns the Parameters (a ParameterData interface) for the
1816 static ParameterData GetParameterData (MethodBase mb)
1818 object pd = method_parameter_cache [mb];
1821 return (ParameterData) pd;
1823 if (mb is MethodBuilder || mb is ConstructorBuilder){
1824 MethodCore mc = TypeContainer.LookupMethodByBuilder (mb);
1826 InternalParameters ip = mc.ParameterInfo;
1827 method_parameter_cache [mb] = ip;
1829 return (ParameterData) ip;
1831 ParameterInfo [] pi = mb.GetParameters ();
1832 ReflectionParameters rp = new ReflectionParameters (pi);
1833 method_parameter_cache [mb] = rp;
1835 return (ParameterData) rp;
1840 // Find the Applicable Function Members (7.4.2.1)
1842 // me: Method Group expression with the members to select.
1843 // it might contain constructors or methods (or anything
1844 // that maps to a method).
1846 // Arguments: ArrayList containing resolved Argument objects.
1848 // Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
1849 // that is the best match of me on Arguments.
1852 public static MethodBase OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
1854 ArrayList afm = new ArrayList ();
1855 int best_match = 10000;
1856 int best_match_idx = -1;
1857 MethodBase method = null;
1860 if (Arguments == null)
1863 argument_count = Arguments.Count;
1865 for (int i = me.Methods.Length; i > 0; ){
1867 MethodBase mb = me.Methods [i];
1870 pd = GetParameterData (mb);
1872 // If this is the case, we have a method with no args - presumably
1873 if (pd == null && argument_count == 0)
1874 return me.Methods [0];
1877 // Compute how good this is
1879 if (pd.Count == argument_count){
1882 for (int j = argument_count; j > 0;){
1886 Argument a = (Argument) Arguments [j];
1888 x = Badness (a, pd.ParameterType (j));
1891 badness = best_match;
1898 if (badness < best_match){
1899 best_match = badness;
1900 method = me.Methods [i];
1906 if (best_match_idx == -1)
1913 public override Expression Resolve (TypeContainer tc)
1916 // First, resolve the expression that is used to
1917 // trigger the invocation
1919 this.expr = expr.Resolve (tc);
1920 if (this.expr == null)
1923 if (!(this.expr is MethodGroupExpr)){
1924 tc.RootContext.Report.Error (118,
1925 "Denotes a non-method (Detail: ExprClass=" + this.expr.ExprClass+")");
1930 // Next, evaluate all the expressions in the argument list
1932 if (Arguments != null){
1933 for (int i = Arguments.Count; i > 0;){
1935 Argument a = (Argument) Arguments [i];
1937 if (!a.Resolve (tc))
1942 method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
1944 if (method == null){
1945 tc.RootContext.Report.Error (-6, Location,
1946 "Figure out error: Can not find a good function for this argument list");
1950 if (method is MethodInfo)
1951 type = ((MethodInfo)method).ReturnType;
1956 public static void EmitArguments (EmitContext ec, MethodBase method, ArrayList Arguments)
1960 if (Arguments != null)
1961 top = Arguments.Count;
1965 for (int i = 0; i < top; i++){
1966 Argument a = (Argument) Arguments [i];
1968 Console.WriteLine ("Perform the actual type widening of arguments here for things like: void fn (sbyte s); ... fn (1)");
1974 public override void Emit (EmitContext ec)
1976 bool is_static = method.IsStatic;
1979 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
1981 if (mg.InstanceExpression == null){
1982 Console.WriteLine ("Internal compiler error. Should check in the method groups for static/instance");
1985 mg.InstanceExpression.Emit (ec);
1988 if (Arguments != null)
1989 EmitArguments (ec, method, Arguments);
1992 if (method is MethodInfo)
1993 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
1995 ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1997 if (method is MethodInfo)
1998 ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
2000 ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
2006 public class New : Expression {
2013 public readonly NType NewType;
2014 public readonly ArrayList Arguments;
2015 public readonly string RequestedType;
2016 // These are for the case when we have an array
2017 public readonly string Rank;
2018 public readonly ArrayList Indices;
2019 public readonly ArrayList Initializers;
2021 MethodBase method = null;
2023 public New (string requested_type, ArrayList arguments)
2025 RequestedType = requested_type;
2026 Arguments = arguments;
2027 NewType = NType.Object;
2030 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
2032 RequestedType = requested_type;
2035 Initializers = initializers;
2036 NewType = NType.Array;
2039 public override Expression Resolve (TypeContainer tc)
2041 type = tc.LookupType (RequestedType, false);
2048 ml = MemberLookup (tc.RootContext, type, ".ctor", false,
2049 MemberTypes.Constructor, AllBindingsFlags);
2051 if (! (ml is MethodGroupExpr)){
2053 // FIXME: Find proper error
2055 tc.RootContext.Report.Error (118, "Did find something that is not a method");
2059 if (Arguments != null){
2060 for (int i = Arguments.Count; i > 0;){
2062 Argument a = (Argument) Arguments [i];
2064 if (!a.Resolve (tc))
2069 method = Invocation.OverloadResolve ((MethodGroupExpr) ml, Arguments);
2071 if (method == null) {
2072 tc.RootContext.Report.Error (-6,
2073 "New invocation: Can not find a constructor for this argument list");
2080 public override void Emit (EmitContext ec)
2082 Invocation.EmitArguments (ec, method, Arguments);
2083 ec.ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
2088 // Represents the `this' construct
2090 public class This : Expression {
2091 public override Expression Resolve (TypeContainer tc)
2093 eclass = ExprClass.Variable;
2094 type = tc.TypeBuilder;
2099 public override void Emit (EmitContext ec)
2101 ec.ig.Emit (OpCodes.Ldarg_0);
2105 public class TypeOf : Expression {
2106 public readonly string QueriedType;
2108 public TypeOf (string queried_type)
2110 QueriedType = queried_type;
2113 public override Expression Resolve (TypeContainer tc)
2115 type = tc.LookupType (QueriedType, false);
2120 eclass = ExprClass.Type;
2124 public override void Emit (EmitContext ec)
2126 // FIXME: Implement.
2130 public class SizeOf : Expression {
2131 public readonly string QueriedType;
2133 public SizeOf (string queried_type)
2135 this.QueriedType = queried_type;
2138 public override Expression Resolve (TypeContainer tc)
2140 // FIXME: Implement;
2141 throw new Exception ("Unimplemented");
2145 public override void Emit (EmitContext ec)
2150 public class MemberAccess : Expression {
2151 public readonly string Identifier;
2153 Expression member_lookup;
2155 public MemberAccess (Expression expr, string id)
2161 public Expression Expr {
2167 public override Expression Resolve (TypeContainer tc)
2169 Expression new_expression = expr.Resolve (tc);
2171 if (new_expression == null)
2174 Console.WriteLine ("This is what I figured: " + expr.Type + "/" + expr.ExprClass);
2176 member_lookup = MemberLookup (tc.RootContext, expr.Type, Identifier, false);
2178 if (member_lookup is MethodGroupExpr){
2179 MethodGroupExpr mg = (MethodGroupExpr) member_lookup;
2182 // Bind the instance expression to it
2184 // FIXME: This is a horrible way of detecting if it is
2185 // an instance expression. Figure out how to fix this.
2188 if (expr is LocalVariableReference ||
2189 expr is ParameterReference ||
2191 mg.InstanceExpression = expr;
2193 return member_lookup;
2194 } else if (member_lookup is FieldExpr){
2195 FieldExpr fe = (FieldExpr) member_lookup;
2199 return member_lookup;
2202 // FIXME: This should generate the proper node
2203 // ie, for a Property Access, it should like call it
2206 return member_lookup;
2209 public override void Emit (EmitContext ec)
2216 // Nodes of type Namespace are created during the semantic
2217 // analysis to resolve member_access/qualified_identifier/simple_name
2220 // They are born `resolved'.
2222 public class NamespaceExpr : Expression {
2223 public readonly string Name;
2225 public NamespaceExpr (string name)
2228 eclass = ExprClass.Namespace;
2231 public override Expression Resolve (TypeContainer tc)
2236 public override void Emit (EmitContext ec)
2242 // Fully resolved expression that evaluates to a type
2244 public class TypeExpr : Expression {
2245 public TypeExpr (Type t)
2248 eclass = ExprClass.Type;
2251 override public Expression Resolve (TypeContainer tc)
2256 override public void Emit (EmitContext ec)
2263 // MethodGroup Expression.
2265 // This is a fully resolved expression that evaluates to a type
2267 public class MethodGroupExpr : Expression {
2268 public readonly MethodBase [] Methods;
2269 Expression instance_expression = null;
2271 public MethodGroupExpr (MemberInfo [] mi)
2273 Methods = new MethodBase [mi.Length];
2274 mi.CopyTo (Methods, 0);
2275 eclass = ExprClass.MethodGroup;
2279 // `A method group may have associated an instance expression'
2281 public Expression InstanceExpression {
2283 return instance_expression;
2287 instance_expression = value;
2291 override public Expression Resolve (TypeContainer tc)
2296 override public void Emit (EmitContext ec)
2302 public class BuiltinTypeAccess : Expression {
2303 public readonly string AccessBase;
2304 public readonly string Method;
2306 public BuiltinTypeAccess (string type, string method)
2308 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
2313 public override Expression Resolve (TypeContainer tc)
2315 // FIXME: Implement;
2316 throw new Exception ("Unimplemented");
2320 public override void Emit (EmitContext ec)
2326 // Fully resolved expression that evaluates to a Field
2328 public class FieldExpr : Expression {
2329 public readonly FieldInfo FieldInfo;
2330 public Expression Instance;
2332 public FieldExpr (FieldInfo fi)
2335 eclass = ExprClass.Variable;
2336 type = fi.FieldType;
2339 override public Expression Resolve (TypeContainer tc)
2341 if (!FieldInfo.IsStatic){
2342 if (Instance == null){
2343 throw new Exception ("non-static FieldExpr without instance var\n" +
2344 "You have to assign the Instance variable\n" +
2345 "Of the FieldExpr to set this\n");
2348 Instance = Instance.Resolve (tc);
2349 if (Instance == null)
2356 override public void Emit (EmitContext ec)
2358 ILGenerator ig = ec.ig;
2360 if (FieldInfo.IsStatic)
2361 ig.Emit (OpCodes.Ldsfld, FieldInfo);
2365 ig.Emit (OpCodes.Ldfld, FieldInfo);
2371 // Fully resolved expression that evaluates to a Property
2373 public class PropertyExpr : Expression {
2374 public readonly PropertyInfo PropertyInfo;
2375 public readonly bool IsStatic;
2377 public PropertyExpr (PropertyInfo pi)
2380 eclass = ExprClass.PropertyAccess;
2383 MethodBase [] acc = pi.GetAccessors ();
2385 for (int i = 0; i < acc.Length; i++)
2386 if (acc [i].IsStatic)
2389 type = pi.PropertyType;
2392 override public Expression Resolve (TypeContainer tc)
2394 // We are born in resolved state.
2398 override public void Emit (EmitContext ec)
2400 // FIXME: Implement;
2401 throw new Exception ("Unimplemented");
2406 // Fully resolved expression that evaluates to a Property
2408 public class EventExpr : Expression {
2409 public readonly EventInfo EventInfo;
2411 public EventExpr (EventInfo ei)
2414 eclass = ExprClass.EventAccess;
2417 override public Expression Resolve (TypeContainer tc)
2419 // We are born in resolved state.
2423 override public void Emit (EmitContext ec)
2425 // FIXME: Implement.
2429 public class CheckedExpr : Expression {
2431 public Expression Expr;
2433 public CheckedExpr (Expression e)
2438 public override Expression Resolve (TypeContainer tc)
2440 Expr = Expr.Resolve (tc);
2445 eclass = Expr.ExprClass;
2450 public override void Emit (EmitContext ec)
2452 bool last_check = ec.CheckState;
2454 ec.CheckState = true;
2458 ec.CheckState = last_check;
2463 public class UnCheckedExpr : Expression {
2465 public Expression Expr;
2467 public UnCheckedExpr (Expression e)
2472 public override Expression Resolve (TypeContainer tc)
2474 Expr = Expr.Resolve (tc);
2479 eclass = Expr.ExprClass;
2484 public override void Emit (EmitContext ec)
2486 bool last_check = ec.CheckState;
2488 ec.CheckState = false;
2492 ec.CheckState = last_check;
2497 public class ElementAccess : Expression {
2499 public readonly ArrayList Arguments;
2500 public readonly Expression Expr;
2502 public ElementAccess (Expression e, ArrayList e_list)
2508 public override Expression Resolve (TypeContainer tc)
2510 // FIXME: Implement;
2511 throw new Exception ("Unimplemented");
2515 public override void Emit (EmitContext ec)
2517 // FIXME : Implement !
2522 public class BaseAccess : Expression {
2524 public enum BaseAccessType {
2529 public readonly BaseAccessType BAType;
2530 public readonly string Member;
2531 public readonly ArrayList Arguments;
2533 public BaseAccess (BaseAccessType t, string member, ArrayList args)
2541 public override Expression Resolve (TypeContainer tc)
2543 // FIXME: Implement;
2544 throw new Exception ("Unimplemented");
2548 public override void Emit (EmitContext ec)