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 (RootContext rc, 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;
133 MemberInfo [] mi = rc.TypeManager.FindMembers (t, mt, bf, Type.FilterName, name);
138 if (mi.Length == 1 && !(mi [0] is MethodInfo))
139 return Expression.ExprClassFromMemberInfo (mi [0]);
141 for (int i = 0; i < mi.Length; i++)
142 if (!(mi [i] is MethodInfo)){
143 rc.Report.Error (-5, "Do not know how to reproduce this case: " +
144 "Methods and non-Method with the same name, report this please");
148 return new MethodGroupExpr (mi);
152 // Resolves the E in `E.I' side for a member_access
154 // This is suboptimal and should be merged with ResolveMemberAccess
155 static Expression ResolvePrimary (TypeContainer tc, string name)
157 int dot_pos = name.LastIndexOf (".");
159 if (tc.RootContext.IsNamespace (name))
160 return new NamespaceExpr (name);
164 Type t = tc.LookupType (name, false);
167 return new TypeExpr (t);
173 static public Expression ResolveMemberAccess (TypeContainer tc, string name)
176 int dot_pos = name.LastIndexOf (".");
177 string left = name.Substring (0, dot_pos);
178 string right = name.Substring (dot_pos + 1);
180 left_e = ResolvePrimary (tc, left);
184 switch (left_e.ExprClass){
186 return MemberLookup (tc.RootContext,
188 left_e.Type == tc.TypeBuilder);
190 case ExprClass.Namespace:
191 case ExprClass.PropertyAccess:
192 case ExprClass.IndexerAccess:
193 case ExprClass.Variable:
194 case ExprClass.Value:
195 case ExprClass.Nothing:
196 case ExprClass.EventAccess:
197 case ExprClass.MethodGroup:
198 case ExprClass.Invalid:
199 tc.RootContext.Report.Error (-1000,
200 "Internal compiler error, should have " +
201 "got these handled before");
208 static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
210 Type expr_type = expr.Type;
212 if (target_type == TypeManager.object_type) {
213 if (expr_type.IsClass)
214 return new EmptyCast (expr, target_type);
215 if (expr_type.IsValueType)
216 return new BoxedCast (expr, target_type);
217 } else if (expr_type.IsSubclassOf (target_type))
218 return new EmptyCast (expr, target_type);
220 // FIXME: missing implicit reference conversions:
222 // from any class-type S to any interface-type T.
223 // from any interface type S to interface-type T.
224 // from an array-type S to an array-type of type T
225 // from an array-type to System.Array
226 // from any delegate type to System.Delegate
227 // from any array-type or delegate type into System.ICloneable.
228 // from the null type to any reference-type.
236 // Converts implicitly the resolved expression `expr' into the
237 // `target_type'. It returns a new expression that can be used
238 // in a context that expects a `target_type'.
240 static public Expression ConvertImplicit (Expression expr, Type target_type)
242 Type expr_type = expr.Type;
244 if (expr_type == target_type){
245 Console.WriteLine ("Hey, ConvertImplicit was called with no job to do");
250 // Step 1: Perform implicit conversions as found on expr.Type
254 // Step 2: Built-in conversions.
256 if (expr_type == TypeManager.sbyte_type){
258 // From sbyte to short, int, long, float, double.
260 if (target_type == TypeManager.int32_type)
261 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
262 if (target_type == TypeManager.int64_type)
263 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
264 if (target_type == TypeManager.double_type)
265 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
266 if (target_type == TypeManager.float_type)
267 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
268 if (target_type == TypeManager.short_type)
269 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2);
270 } else if (expr_type == TypeManager.byte_type){
272 // From byte to short, ushort, int, uint, long, ulong, float, double
274 if ((target_type == TypeManager.short_type) ||
275 (target_type == TypeManager.ushort_type) ||
276 (target_type == TypeManager.int32_type) ||
277 (target_type == TypeManager.uint32_type))
278 return new EmptyCast (expr, target_type);
280 if (target_type == TypeManager.uint64_type)
281 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
282 if (target_type == TypeManager.int64_type)
283 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
285 if (target_type == TypeManager.float_type)
286 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
287 if (target_type == TypeManager.double_type)
288 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
289 } else if (expr_type == TypeManager.short_type){
291 // From short to int, long, float, double
293 if (target_type == TypeManager.int32_type)
294 return new EmptyCast (expr, target_type);
295 if (target_type == TypeManager.int64_type)
296 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
297 if (target_type == TypeManager.double_type)
298 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
299 if (target_type == TypeManager.float_type)
300 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
301 } else if (expr_type == TypeManager.ushort_type){
303 // From ushort to int, uint, long, ulong, float, double
305 if ((target_type == TypeManager.uint32_type) ||
306 (target_type == TypeManager.uint64_type))
307 return new EmptyCast (expr, target_type);
309 if (target_type == TypeManager.int32_type)
310 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4);
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.int32_type){
319 // From int to long, float, double
321 if (target_type == TypeManager.int64_type)
322 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
323 if (target_type == TypeManager.double_type)
324 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
325 if (target_type == TypeManager.float_type)
326 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
327 } else if (expr_type == TypeManager.uint32_type){
329 // From uint to long, ulong, float, double
331 if (target_type == TypeManager.int64_type)
332 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
333 if (target_type == TypeManager.uint64_type)
334 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
335 if (target_type == TypeManager.double_type)
336 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
338 if (target_type == TypeManager.float_type)
339 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
341 } else if ((expr_type == TypeManager.uint64_type) ||
342 (expr_type == TypeManager.int64_type)){
344 // From long to float, double
346 if (target_type == TypeManager.double_type)
347 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
349 if (target_type == TypeManager.float_type)
350 return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
352 } else if (expr_type == TypeManager.char_type){
354 // From char to ushort, int, uint, long, ulong, float, double
356 if ((target_type == TypeManager.ushort_type) ||
357 (target_type == TypeManager.int32_type) ||
358 (target_type == TypeManager.uint32_type))
359 return new EmptyCast (expr, target_type);
360 if (target_type == TypeManager.uint64_type)
361 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
362 if (target_type == TypeManager.int64_type)
363 return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
364 if (target_type == TypeManager.float_type)
365 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);
366 if (target_type == TypeManager.double_type)
367 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
369 return ImplicitReferenceConversion (expr, target_type);
374 // Could not find an implicit cast.
380 // Performs an explicit conversion of the expression `expr' whose
381 // type is expr.Type to `target_type'.
383 static public Expression ConvertExplicit (Expression expr, Type target_type)
391 // This kind of cast is used to encapsulate the child
392 // whose type is child.Type into an expression that is
393 // reported to return "return_type". This is used to encapsulate
394 // expressions which have compatible types, but need to be dealt
395 // at higher levels with.
397 // For example, a "byte" expression could be encapsulated in one
398 // of these as an "unsigned int". The type for the expression
399 // would be "unsigned int".
403 public class EmptyCast : Expression {
404 protected Expression child;
406 public EmptyCast (Expression child, Type return_type)
408 ExprClass = child.ExprClass;
413 public override Expression Resolve (TypeContainer tc)
415 // This should never be invoked, we are born in fully
416 // initialized state.
421 public override void Emit (EmitContext ec)
427 public class BoxedCast : EmptyCast {
429 public BoxedCast (Expression expr, Type target_type)
430 : base (expr, target_type)
434 public override Expression Resolve (TypeContainer tc)
436 // This should never be invoked, we are born in fully
437 // initialized state.
442 public override void Emit (EmitContext ec)
445 ec.ig.Emit (OpCodes.Box, child.Type);
451 // This kind of cast is used to encapsulate a child expression
452 // that can be trivially converted to a target type using one or
453 // two opcodes. The opcodes are passed as arguments.
455 public class OpcodeCast : EmptyCast {
458 public OpcodeCast (Expression child, Type return_type, OpCode op)
459 : base (child, return_type)
463 this.op2 = OpCodes.Nop;
466 public OpcodeCast (Expression child, Type return_type, OpCode op, OpCode op2)
467 : base (child, return_type)
474 public override Expression Resolve (TypeContainer tc)
476 // This should never be invoked, we are born in fully
477 // initialized state.
482 public override void Emit (EmitContext ec)
487 if (!op2.Equals (OpCodes.Nop))
493 public class Unary : Expression {
494 public enum Operator {
495 Plus, Minus, Negate, BitComplement,
496 Indirection, AddressOf, PreIncrement,
497 PreDecrement, PostIncrement, PostDecrement
503 public Unary (Operator op, Expression expr)
509 public Expression Expr {
519 public Operator Oper {
529 public override Expression Resolve (TypeContainer tc)
535 public override void Emit (EmitContext ec)
540 public class Probe : Expression {
545 public enum Operator {
549 public Probe (Operator oper, Expression expr, string probe_type)
552 this.probe_type = probe_type;
556 public Operator Oper {
562 public Expression Expr {
568 public string ProbeType {
574 public override Expression Resolve (TypeContainer tc)
580 public override void Emit (EmitContext ec)
585 public class Cast : Expression {
589 public Cast (string cast_type, Expression expr)
591 this.target_type = target_type;
595 public string TargetType {
601 public Expression Expr {
610 public override Expression Resolve (TypeContainer tc)
616 public override void Emit (EmitContext ec)
621 public class Binary : Expression {
622 public enum Operator {
623 Multiply, Divide, Modulo,
625 ShiftLeft, ShiftRight,
626 LessThan, GreatherThan, LessOrEqual, GreatherOrEqual,
636 Expression left, right;
638 public Binary (Operator oper, Expression left, Expression right)
645 public Operator Oper {
654 public Expression Left {
663 public Expression Right {
674 // Retruns a stringified representation of the Operator
679 case Operator.Multiply:
681 case Operator.Divide:
683 case Operator.Modulo:
687 case Operator.Substract:
689 case Operator.ShiftLeft:
691 case Operator.ShiftRight:
693 case Operator.LessThan:
695 case Operator.GreatherThan:
697 case Operator.LessOrEqual:
699 case Operator.GreatherOrEqual:
703 case Operator.NotEqual:
705 case Operator.BitwiseAnd:
707 case Operator.BitwiseOr:
709 case Operator.ExclusiveOr:
711 case Operator.LogicalOr:
713 case Operator.LogicalAnd:
717 return oper.ToString ();
720 Expression ForceConversion (Expression expr, Type target_type)
722 if (expr.Type == target_type)
725 return ConvertImplicit (expr, target_type);
729 // Note that handling the case l == Decimal || r == Decimal
730 // is taken care of by the Step 1 Operator Overload resolution.
732 void DoNumericPromotions (TypeContainer tc, Type l, Type r)
734 if (l == TypeManager.double_type || r == TypeManager.double_type){
736 // If either operand is of type double, the other operand is
737 // conveted to type double.
739 if (r != TypeManager.double_type)
740 right = ConvertImplicit (right, TypeManager.double_type);
741 if (l != TypeManager.double_type)
742 left = ConvertImplicit (left, TypeManager.double_type);
744 type = TypeManager.double_type;
745 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
747 // if either operand is of type float, th eother operand is
748 // converd to type float.
750 if (r != TypeManager.double_type)
751 right = ConvertImplicit (right, TypeManager.float_type);
752 if (l != TypeManager.double_type)
753 left = ConvertImplicit (left, TypeManager.float_type);
754 type = TypeManager.float_type;
755 } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
757 // If either operand is of type ulong, the other operand is
758 // converted to type ulong. or an error ocurrs if the other
759 // operand is of type sbyte, short, int or long
763 if (l == TypeManager.uint64_type)
765 else if (r == TypeManager.uint64_type)
768 if ((other == TypeManager.sbyte_type) ||
769 (other == TypeManager.short_type) ||
770 (other == TypeManager.int32_type) ||
771 (other == TypeManager.int64_type)){
772 string oper = OperName ();
774 tc.RootContext.Report.Error (34, "Operator `" + OperName ()
775 + "' is ambiguous on operands of type `"
776 + TypeManager.CSharpName (l) + "' "
777 + "and `" + TypeManager.CSharpName (r)
780 type = TypeManager.uint64_type;
781 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
783 // If either operand is of type long, the other operand is converted
786 if (l != TypeManager.int64_type)
787 left = ConvertImplicit (left, TypeManager.int64_type);
788 if (r != TypeManager.int64_type)
789 right = ConvertImplicit (right, TypeManager.int64_type);
791 type = TypeManager.int64_type;
792 } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
794 // If either operand is of type uint, and the other
795 // operand is of type sbyte, short or int, othe operands are
796 // converted to type long.
800 if (l == TypeManager.uint32_type)
802 else if (r == TypeManager.uint32_type)
805 if ((other == TypeManager.sbyte_type) ||
806 (other == TypeManager.short_type) ||
807 (other == TypeManager.int32_type)){
808 left = ForceConversion (left, TypeManager.int64_type);
809 right = ForceConversion (right, TypeManager.int64_type);
810 type = TypeManager.int64_type;
813 // if either operand is of type uint, the other
814 // operand is converd to type uint
816 left = ForceConversion (left, TypeManager.uint32_type);
817 right = ForceConversion (left, TypeManager.uint32_type);
818 type = TypeManager.uint32_type;
821 left = ForceConversion (left, TypeManager.int32_type);
822 right = ForceConversion (right, TypeManager.int32_type);
826 void error19 (TypeContainer tc)
828 tc.RootContext.Report.Error (
830 "Operator " + OperName () + " cannot be applied to operands of type `" +
831 TypeManager.CSharpName (left.Type) + "' and `" +
832 TypeManager.CSharpName (right.Type) + "'");
836 Expression CheckShiftArguments (TypeContainer tc)
842 e = ForceConversion (right, TypeManager.int32_type);
849 if (((e = ConvertImplicit (left, TypeManager.int32_type)) != null) ||
850 ((e = ConvertImplicit (left, TypeManager.uint32_type)) != null) ||
851 ((e = ConvertImplicit (left, TypeManager.int64_type)) != null) ||
852 ((e = ConvertImplicit (left, TypeManager.uint64_type)) != null)){
861 Expression ResolveOperator (TypeContainer tc)
867 // Step 1: Perform Operator Overload location
872 // Step 2: Default operations on CLI native types.
875 // Only perform numeric promotions on:
876 // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
878 if (oper == Operator.ShiftLeft || oper == Operator.ShiftRight){
879 return CheckShiftArguments (tc);
880 } else if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
882 if (l != TypeManager.bool_type || r != TypeManager.bool_type)
885 DoNumericPromotions (tc, l, r);
887 if (oper == Operator.BitwiseAnd ||
888 oper == Operator.BitwiseOr ||
889 oper == Operator.ExclusiveOr){
890 if (!((l == TypeManager.int32_type) ||
891 (l == TypeManager.uint32_type) ||
892 (l == TypeManager.int64_type) ||
893 (l == TypeManager.uint64_type))){
899 if (left == null || right == null)
905 public override Expression Resolve (TypeContainer tc)
907 left = left.Resolve (tc);
908 right = right.Resolve (tc);
910 if (left == null || right == null)
913 return ResolveOperator (tc);
916 public bool IsBranchable ()
918 if (oper == Operator.Equal ||
919 oper == Operator.NotEqual ||
920 oper == Operator.LessThan ||
921 oper == Operator.GreatherThan ||
922 oper == Operator.LessOrEqual ||
923 oper == Operator.GreatherOrEqual){
930 // This entry point is used by routines that might want
931 // to emit a brfalse/brtrue after an expression, and instead
932 // they could use a more compact notation.
934 // Typically the code would generate l.emit/r.emit, followed
935 // by the comparission and then a brtrue/brfalse. The comparissions
936 // are sometimes inneficient (there are not as complete as the branches
937 // look for the hacks in Emit using double ceqs).
939 // So for those cases we provide EmitBranchable that can emit the
940 // branch with the test
942 public void EmitBranchable (EmitContext ec, int target)
945 bool close_target = false;
953 opcode = OpCodes.Beq_S;
955 opcode = OpCodes.Beq;
958 case Operator.NotEqual:
960 opcode = OpCodes.Bne_Un_S;
962 opcode = OpCodes.Bne_Un;
965 case Operator.LessThan:
967 opcode = OpCodes.Blt_S;
969 opcode = OpCodes.Blt;
972 case Operator.GreatherThan:
974 opcode = OpCodes.Bgt_S;
976 opcode = OpCodes.Bgt;
979 case Operator.LessOrEqual:
981 opcode = OpCodes.Ble_S;
983 opcode = OpCodes.Ble;
986 case Operator.GreatherOrEqual:
988 opcode = OpCodes.Bge_S;
990 opcode = OpCodes.Ble;
994 Console.WriteLine ("EmitBranchable called for non-EmitBranchable operator: "
996 opcode = OpCodes.Nop;
1000 ec.ig.Emit (opcode, target);
1003 public override void Emit (EmitContext ec)
1005 ILGenerator ig = ec.ig;
1007 Type r = right.Type;
1014 case Operator.Multiply:
1016 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1017 opcode = OpCodes.Mul_Ovf;
1018 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1019 opcode = OpCodes.Mul_Ovf_Un;
1021 opcode = OpCodes.Mul;
1023 opcode = OpCodes.Mul;
1027 case Operator.Divide:
1028 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1029 opcode = OpCodes.Div_Un;
1031 opcode = OpCodes.Div;
1034 case Operator.Modulo:
1035 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
1036 opcode = OpCodes.Rem_Un;
1038 opcode = OpCodes.Rem;
1043 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1044 opcode = OpCodes.Add_Ovf;
1045 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1046 opcode = OpCodes.Add_Ovf_Un;
1048 opcode = OpCodes.Mul;
1050 opcode = OpCodes.Add;
1053 case Operator.Substract:
1055 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
1056 opcode = OpCodes.Sub_Ovf;
1057 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
1058 opcode = OpCodes.Sub_Ovf_Un;
1060 opcode = OpCodes.Sub;
1062 opcode = OpCodes.Sub;
1065 case Operator.ShiftRight:
1066 opcode = OpCodes.Shr;
1069 case Operator.ShiftLeft:
1070 opcode = OpCodes.Shl;
1073 case Operator.Equal:
1074 opcode = OpCodes.Ceq;
1077 case Operator.NotEqual:
1078 ec.ig.Emit (OpCodes.Ceq);
1079 ec.ig.Emit (OpCodes.Ldc_I4_0);
1081 opcode = OpCodes.Ceq;
1084 case Operator.LessThan:
1085 opcode = OpCodes.Clt;
1088 case Operator.GreatherThan:
1089 opcode = OpCodes.Cgt;
1092 case Operator.LessOrEqual:
1093 ec.ig.Emit (OpCodes.Cgt);
1094 ec.ig.Emit (OpCodes.Ldc_I4_0);
1096 opcode = OpCodes.Ceq;
1099 case Operator.GreatherOrEqual:
1100 ec.ig.Emit (OpCodes.Clt);
1101 ec.ig.Emit (OpCodes.Ldc_I4_1);
1103 opcode = OpCodes.Sub;
1106 case Operator.LogicalOr:
1107 case Operator.BitwiseOr:
1108 opcode = OpCodes.Or;
1111 case Operator.LogicalAnd:
1112 case Operator.BitwiseAnd:
1113 opcode = OpCodes.And;
1116 case Operator.ExclusiveOr:
1117 opcode = OpCodes.Xor;
1121 Console.WriteLine ("This should not happen: Operator = " + oper.ToString ());
1122 opcode = OpCodes.Nop;
1126 ec.ig.Emit (opcode);
1130 public class Conditional : Expression {
1131 Expression expr, trueExpr, falseExpr;
1133 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr)
1136 this.trueExpr = trueExpr;
1137 this.falseExpr = falseExpr;
1140 public Expression Expr {
1146 public Expression TrueExpr {
1152 public Expression FalseExpr {
1158 public override Expression Resolve (TypeContainer tc)
1160 // FIXME: Implement;
1164 public override void Emit (EmitContext ec)
1169 public class SimpleName : Expression {
1172 public SimpleName (string name)
1177 public string Name {
1184 // Checks whether we are trying to access an instance
1185 // property, method or field from a static body.
1187 Expression MemberStaticCheck (Report r, Expression e)
1189 if (e is FieldExpr){
1190 FieldInfo fi = ((FieldExpr) e).FieldInfo;
1194 "An object reference is required " +
1195 "for the non-static field `"+name+"'");
1198 } else if (e is MethodGroupExpr){
1199 // FIXME: Pending reorganization of MemberLookup
1200 // Basically at this point we should have the
1201 // best match already selected for us, and
1202 // we should only have to check a *single*
1203 // Method for its static on/off bit.
1205 } else if (e is PropertyExpr){
1206 if (!((PropertyExpr) e).IsStatic){
1208 "An object reference is required " +
1209 "for the non-static property access `"+
1219 // 7.5.2: Simple Names.
1221 // Local Variables and Parameters are handled at
1222 // parse time, so they never occur as SimpleNames.
1224 Expression ResolveSimpleName (TypeContainer tc)
1227 Report r = tc.RootContext.Report;
1229 e = MemberLookup (tc.RootContext, tc.TypeBuilder, name, true);
1233 if ((tc.ModFlags & Modifiers.STATIC) != 0)
1234 return MemberStaticCheck (r, e);
1240 // Do step 3 of the Simple Name resolution.
1242 // FIXME: implement me.
1248 // SimpleName needs to handle a multitude of cases:
1250 // simple_names and qualified_identifiers are placed on
1251 // the tree equally.
1253 public override Expression Resolve (TypeContainer tc)
1255 if (name.IndexOf (".") != -1)
1256 return ResolveMemberAccess (tc, name);
1258 return ResolveSimpleName (tc);
1261 public override void Emit (EmitContext ec)
1266 public class LocalVariableReference : Expression {
1267 public readonly string Name;
1268 public readonly Block Block;
1270 public LocalVariableReference (Block block, string name)
1274 eclass = ExprClass.Variable;
1277 public VariableInfo VariableInfo {
1279 return (VariableInfo) Block.GetVariableInfo (Name);
1283 public override Expression Resolve (TypeContainer tc)
1288 public override void Emit (EmitContext ec)
1290 Console.WriteLine ("Internal compiler error, LocalVariableReference should not be emitted");
1294 public class ParameterReference : Expression {
1295 public readonly Parameters Pars;
1296 public readonly String Name;
1297 public readonly int Idx;
1299 public ParameterReference (Parameters pars, int idx, string name)
1306 public override Expression Resolve (TypeContainer tc)
1308 // FIXME: Implement;
1312 public override void Emit (EmitContext ec)
1318 // Used for arguments to New(), Invocation()
1320 public class Argument {
1327 public readonly AType Type;
1330 public Argument (Expression expr, AType type)
1336 public Expression Expr {
1342 public bool Resolve (TypeContainer tc)
1344 expr = expr.Resolve (tc);
1345 return expr != null;
1348 public void Emit (EmitContext ec)
1355 // Invocation of methods or delegates.
1357 public class Invocation : Expression {
1358 public readonly ArrayList Arguments;
1360 MethodInfo method = null;
1363 // arguments is an ArrayList, but we do not want to typecast,
1364 // as it might be null.
1366 // FIXME: only allow expr to be a method invocation or a
1367 // delegate invocation (7.5.5)
1369 public Invocation (Expression expr, ArrayList arguments)
1372 Arguments = arguments;
1375 public Expression Expr {
1382 /// Computes whether Argument `a' and the ParameterInfo `pi' are
1383 /// compatible, and if so, how good is the match (in terms of
1384 /// "better conversions" (7.4.2.3).
1386 /// 0 is the best possible match.
1387 /// -1 represents a type mismatch.
1388 /// -2 represents a ref/out mismatch.
1390 static int Badness (Argument a, ParameterInfo pi)
1392 if (pi.ParameterType == a.Expr.Type)
1395 // FIXME: Implement implicit conversions here.
1396 // FIXME: Implement better conversion here.
1402 // Find the Applicable Function Members (7.4.2.1)
1404 static MethodInfo OverloadResolve (MethodGroupExpr me, ArrayList Arguments)
1406 ArrayList afm = new ArrayList ();
1407 int best_match = 10000;
1408 int best_match_idx = -1;
1409 MethodInfo method = null;
1411 for (int i = me.Methods.Length; i > 0; ){
1413 ParameterInfo [] pi = me.Methods [i].GetParameters ();
1416 // Compute how good this is
1418 if (pi.Length == Arguments.Count){
1421 for (int j = Arguments.Count; j > 0;){
1425 Argument a = (Argument) Arguments [j];
1427 x = Badness (a, pi [j]);
1430 // FIXME: report nice error.
1435 if (badness < best_match){
1436 best_match = badness;
1437 method = me.Methods [i];
1443 if (best_match_idx == -1)
1450 public override Expression Resolve (TypeContainer tc)
1453 // First, resolve the expression that is used to
1454 // trigger the invocation
1456 this.expr = expr.Resolve (tc);
1457 if (this.expr == null)
1460 if (!(this.expr is MethodGroupExpr)){
1461 tc.RootContext.Report.Error (118,
1462 "Denotes an " + this.expr.ExprClass + " while a method was expected");
1467 // Next, evaluate all the expressions in the argument list
1469 if (Arguments != null){
1470 for (int i = Arguments.Count; i > 0;){
1472 Argument a = (Argument) Arguments [i];
1474 if (!a.Resolve (tc))
1479 method = OverloadResolve ((MethodGroupExpr) this.expr, Arguments);
1481 if (method == null){
1482 tc.RootContext.Report.Error (-6,
1483 "Figure out error: Can not find a good function for this argument list");
1487 Console.WriteLine ("Found a method! " + method);
1492 public override void Emit (EmitContext ec)
1494 int top = Arguments.Count;
1496 for (int i = 0; i < top; i++){
1497 Argument a = (Argument) Arguments [i];
1502 ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
1506 public class New : Expression {
1513 public readonly NType NewType;
1514 public readonly ArrayList Arguments;
1515 public readonly string RequestedType;
1516 // These are for the case when we have an array
1517 public readonly string Rank;
1518 public readonly ArrayList Indices;
1519 public readonly ArrayList Initializers;
1522 public New (string requested_type, ArrayList arguments)
1524 RequestedType = requested_type;
1525 Arguments = arguments;
1526 NewType = NType.Object;
1529 public New (string requested_type, ArrayList exprs, string rank, ArrayList initializers)
1531 RequestedType = requested_type;
1534 Initializers = initializers;
1535 NewType = NType.Array;
1538 public override Expression Resolve (TypeContainer tc)
1540 // FIXME: Implement;
1544 public override void Emit (EmitContext ec)
1549 public class This : Expression {
1550 public override Expression Resolve (TypeContainer tc)
1552 // FIXME: Implement;
1556 public override void Emit (EmitContext ec)
1561 public class TypeOf : Expression {
1562 public readonly string QueriedType;
1564 public TypeOf (string queried_type)
1566 QueriedType = queried_type;
1569 public override Expression Resolve (TypeContainer tc)
1571 // FIXME: Implement;
1575 public override void Emit (EmitContext ec)
1580 public class SizeOf : Expression {
1581 public readonly string QueriedType;
1583 public SizeOf (string queried_type)
1585 this.QueriedType = queried_type;
1588 public override Expression Resolve (TypeContainer tc)
1590 // FIXME: Implement;
1594 public override void Emit (EmitContext ec)
1599 public class MemberAccess : Expression {
1600 public readonly string Identifier;
1603 public MemberAccess (Expression expr, string id)
1609 public Expression Expr {
1615 public override Expression Resolve (TypeContainer tc)
1617 // FIXME: Implement;
1621 public override void Emit (EmitContext ec)
1628 // Nodes of type Namespace are created during the semantic
1629 // analysis to resolve member_access/qualified_identifier/simple_name
1632 // They are born `resolved'.
1634 public class NamespaceExpr : Expression {
1635 public readonly string Name;
1637 public NamespaceExpr (string name)
1640 eclass = ExprClass.Namespace;
1643 public override Expression Resolve (TypeContainer tc)
1648 public override void Emit (EmitContext ec)
1654 // Fully resolved expression that evaluates to a type
1656 public class TypeExpr : Expression {
1657 public TypeExpr (Type t)
1660 eclass = ExprClass.Type;
1663 override public Expression Resolve (TypeContainer tc)
1668 override public void Emit (EmitContext ec)
1675 // Fully resolved expression that evaluates to a type
1677 public class MethodGroupExpr : Expression {
1678 public readonly MethodInfo [] Methods;
1680 public MethodGroupExpr (MemberInfo [] mi)
1682 Methods = new MethodInfo [mi.Length];
1683 mi.CopyTo (Methods, 0);
1684 eclass = ExprClass.MethodGroup;
1687 override public Expression Resolve (TypeContainer tc)
1692 override public void Emit (EmitContext ec)
1698 public class BuiltinTypeAccess : Expression {
1699 public readonly string AccessBase;
1700 public readonly string Method;
1702 public BuiltinTypeAccess (string type, string method)
1704 System.Console.WriteLine ("DUDE! This type should be fully resolved!");
1709 public override Expression Resolve (TypeContainer tc)
1711 // FIXME: Implement;
1715 public override void Emit (EmitContext ec)
1721 // Fully resolved expression that evaluates to a Field
1723 public class FieldExpr : Expression {
1724 public readonly FieldInfo FieldInfo;
1726 public FieldExpr (FieldInfo fi)
1729 eclass = ExprClass.Variable;
1732 override public Expression Resolve (TypeContainer tc)
1734 // We are born in resolved state.
1738 override public void Emit (EmitContext ec)
1740 // FIXME: Assert that this should not be reached?
1745 // Fully resolved expression that evaluates to a Property
1747 public class PropertyExpr : Expression {
1748 public readonly PropertyInfo PropertyInfo;
1749 public readonly bool IsStatic;
1751 public PropertyExpr (PropertyInfo pi)
1754 eclass = ExprClass.PropertyAccess;
1757 MethodInfo [] acc = pi.GetAccessors ();
1759 for (int i = 0; i < acc.Length; i++)
1760 if (acc [i].IsStatic)
1764 override public Expression Resolve (TypeContainer tc)
1766 // We are born in resolved state.
1770 override public void Emit (EmitContext ec)
1772 // FIXME: Implement.
1777 // Fully resolved expression that evaluates to a Property
1779 public class EventExpr : Expression {
1780 public readonly EventInfo EventInfo;
1782 public EventExpr (EventInfo ei)
1785 eclass = ExprClass.EventAccess;
1788 override public Expression Resolve (TypeContainer tc)
1790 // We are born in resolved state.
1794 override public void Emit (EmitContext ec)
1796 // FIXME: Implement.
1800 public class CheckedExpr : Expression {
1802 public readonly Expression Expr;
1804 public CheckedExpr (Expression e)
1809 public override Expression Resolve (TypeContainer tc)
1811 // FIXME : Implement !
1815 public override void Emit (EmitContext ec)
1821 public class UnCheckedExpr : Expression {
1823 public readonly Expression Expr;
1825 public UnCheckedExpr (Expression e)
1830 public override Expression Resolve (TypeContainer tc)
1832 // FIXME : Implement !
1836 public override void Emit (EmitContext ec)
1842 public class ElementAccess : Expression {
1844 public readonly ArrayList Arguments;
1845 public readonly Expression Expr;
1847 public ElementAccess (Expression e, ArrayList e_list)
1853 public override Expression Resolve (TypeContainer tc)
1855 // FIXME : Implement
1859 public override void Emit (EmitContext ec)
1861 // FIXME : Implement !
1866 public class BaseAccess : Expression {
1868 public enum BaseAccessType {
1873 public readonly BaseAccessType BAType;
1874 public readonly string Member;
1875 public readonly ArrayList Arguments;
1877 public BaseAccess (BaseAccessType t, string member, ArrayList args)
1885 public override Expression Resolve (TypeContainer tc)
1887 // FIXME : Implement !
1891 public override void Emit (EmitContext ec)