2 // expression.cs: Expression representation for the IL tree.
5 // Miguel de Icaza (miguel@ximian.com)
6 // Manjula GHM (mmanjula@novell.com)
7 // Satya Sudha K (ksathyasudha@novell.com)
9 // (C) 2001 Ximian, Inc.
14 namespace Mono.MonoBASIC {
16 using System.Collections;
17 using System.Reflection;
18 using System.Reflection.Emit;
22 /// This is just a helper class, it is generated by Unary, UnaryMutator
23 /// when an overloaded method has been found. It just emits the code for a
26 public class StaticCallExpr : ExpressionStatement {
30 StaticCallExpr (MethodInfo m, ArrayList a, Location l)
36 eclass = ExprClass.Value;
40 public override Expression DoResolve (EmitContext ec)
43 // We are born fully resolved
48 public override void Emit (EmitContext ec)
51 Invocation.EmitArguments (ec, mi, args);
53 ec.ig.Emit (OpCodes.Call, mi);
57 static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
58 Expression e, Location loc)
63 args = new ArrayList (1);
64 args.Add (new Argument (e, Argument.AType.Expression));
65 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
70 return new StaticCallExpr ((MethodInfo) method, args, loc);
73 public override void EmitStatement (EmitContext ec)
76 if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
77 ec.ig.Emit (OpCodes.Pop);
82 /// Unary expressions.
86 /// Unary implements unary expressions. It derives from
87 /// ExpressionStatement becuase the pre/post increment/decrement
88 /// operators can be used in a statement context.
90 public class Unary : Expression {
91 public enum Operator : byte {
92 UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
93 Indirection, AddressOf, TOP
97 public Expression Expr;
99 public Unary (Operator op, Expression expr, Location loc)
107 /// Returns a stringified representation of the Operator
109 static public string OperName (Operator oper)
112 case Operator.UnaryPlus:
114 case Operator.UnaryNegation:
116 case Operator.LogicalNot:
118 case Operator.OnesComplement:
120 case Operator.AddressOf:
122 case Operator.Indirection:
126 return oper.ToString ();
129 static string [] oper_names;
133 oper_names = new string [(int)Operator.TOP];
135 oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
136 oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
137 oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
138 oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
139 oper_names [(int) Operator.Indirection] = "op_Indirection";
140 oper_names [(int) Operator.AddressOf] = "op_AddressOf";
143 void Error23 (Type t)
146 30311, "Operator " + OperName (Oper) +
147 " cannot be applied to operand of type '" +
148 TypeManager.MonoBASIC_Name (t) + "'");
152 /// The result has been already resolved:
154 /// FIXME: a minus constant -128 sbyte cant be turned into a
157 static Expression TryReduceNegative (Constant expr)
161 if (expr is IntConstant)
162 e = new IntConstant (-((IntConstant) expr).Value);
163 else if (expr is UIntConstant){
164 uint value = ((UIntConstant) expr).Value;
166 if (value < 2147483649)
167 return new IntConstant (-(int)value);
169 e = new LongConstant (value);
171 else if (expr is LongConstant)
172 e = new LongConstant (-((LongConstant) expr).Value);
173 else if (expr is ULongConstant){
174 ulong value = ((ULongConstant) expr).Value;
176 if (value < 9223372036854775809)
177 return new LongConstant(-(long)value);
179 else if (expr is FloatConstant)
180 e = new FloatConstant (-((FloatConstant) expr).Value);
181 else if (expr is DoubleConstant)
182 e = new DoubleConstant (-((DoubleConstant) expr).Value);
183 else if (expr is DecimalConstant)
184 e = new DecimalConstant (-((DecimalConstant) expr).Value);
185 else if (expr is ShortConstant)
186 e = new IntConstant (-((ShortConstant) expr).Value);
187 else if (expr is UShortConstant)
188 e = new IntConstant (-((UShortConstant) expr).Value);
193 // This routine will attempt to simplify the unary expression when the
194 // argument is a constant. The result is returned in 'result' and the
195 // function returns true or false depending on whether a reduction
196 // was performed or not
198 bool Reduce (EmitContext ec, Constant e, out Expression result)
200 Type expr_type = e.Type;
203 case Operator.UnaryPlus:
207 case Operator.UnaryNegation:
208 result = TryReduceNegative (e);
211 case Operator.LogicalNot:
212 if (expr_type != TypeManager.bool_type) {
218 BoolConstant b = (BoolConstant) e;
219 result = new BoolConstant (!(b.Value));
222 case Operator.OnesComplement:
223 if (!((expr_type == TypeManager.int32_type) ||
224 (expr_type == TypeManager.uint32_type) ||
225 (expr_type == TypeManager.int64_type) ||
226 (expr_type == TypeManager.uint64_type) ||
227 (expr_type.IsSubclassOf (TypeManager.enum_type)))){
233 if (e is EnumConstant){
234 EnumConstant enum_constant = (EnumConstant) e;
237 if (Reduce (ec, enum_constant.Child, out reduced)){
238 result = new EnumConstant ((Constant) reduced, enum_constant.Type);
246 if (expr_type == TypeManager.int32_type){
247 result = new IntConstant (~ ((IntConstant) e).Value);
248 } else if (expr_type == TypeManager.uint32_type){
249 result = new UIntConstant (~ ((UIntConstant) e).Value);
250 } else if (expr_type == TypeManager.int64_type){
251 result = new LongConstant (~ ((LongConstant) e).Value);
252 } else if (expr_type == TypeManager.uint64_type){
253 result = new ULongConstant (~ ((ULongConstant) e).Value);
261 case Operator.AddressOf:
265 case Operator.Indirection:
269 throw new Exception ("Can not constant fold: " + Oper.ToString());
272 Expression ResolveOperator (EmitContext ec)
274 Type expr_type = Expr.Type;
278 if (Oper == Operator.LogicalNot && expr_type != TypeManager.bool_type)
279 Oper = Operator.OnesComplement;
282 if ((expr_type == TypeManager.string_type) &&
283 (Oper == Operator.UnaryPlus ||
284 Oper == Operator.UnaryNegation)) {
286 Expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
291 expr_type = Expr.Type;
295 // Step 1: Perform Operator Overload location
297 op_name = oper_names [(int) Oper];
299 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
302 Expression e = StaticCallExpr.MakeSimpleCall (
303 ec, (MethodGroupExpr) mg, Expr, loc);
313 // Only perform numeric promotions on:
316 if (expr_type == null)
320 // Step 2: Default operations on CLI native types.
323 // Attempt to use a constant folding operation.
324 if (Expr is Constant){
327 if (Reduce (ec, (Constant) Expr, out result))
332 case Operator.LogicalNot:
333 if (expr_type != TypeManager.bool_type) {
338 type = TypeManager.bool_type;
341 case Operator.OnesComplement:
342 if (expr_type == TypeManager.string_type ||
343 expr_type == TypeManager.decimal_type ||
344 expr_type == TypeManager.double_type ||
345 expr_type == TypeManager.float_type) {
346 if ((Expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc)) == null) {
350 expr_type = Expr.Type;
353 if (expr_type == TypeManager.int64_type) {
357 if (expr_type == TypeManager.byte_type ||
358 expr_type == TypeManager.short_type ||
359 expr_type == TypeManager.int32_type) {
360 type = TypeManager.int32_type;
364 if (expr_type == TypeManager.object_type) {
365 Expression etmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.ObjectType.NotObj", Location.Null);
366 ArrayList arguments = new ArrayList ();
367 arguments.Add (new Argument (Expr, Argument.AType.Expression));
368 Expression e = new Invocation (etmp, arguments, loc);
369 return e.Resolve (ec);
373 case Operator.AddressOf:
374 // Not required in VB ??
375 if (Expr.eclass != ExprClass.Variable){
376 Error (211, "Cannot take the address of non-variables");
385 if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
389 string ptr_type_name = Expr.Type.FullName + "*";
390 type = TypeManager.LookupType (ptr_type_name);
394 case Operator.Indirection:
400 if (!expr_type.IsPointer){
403 "The * or -> operator can only be applied to pointers");
408 // We create an Indirection expression, because
409 // it can implement the IMemoryLocation.
411 return new Indirection (Expr, loc);
413 case Operator.UnaryPlus:
415 // A plus in front of something is just a no-op, so return the child.
417 if (expr_type == TypeManager.string_type) {
418 Expression e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
420 type = TypeManager.double_type;
425 if (expr_type == TypeManager.bool_type) {
426 Expression e = ConvertImplicit (ec, Expr, TypeManager.short_type, loc);
428 type = TypeManager.int32_type;
435 case Operator.UnaryNegation:
437 // Deals with -literals
438 // int operator- (int x)
439 // long operator- (long x)
440 // float operator- (float f)
441 // double operator- (double d)
442 // decimal operator- (decimal d)
446 // transform - - expr into expr
449 Unary unary = (Unary) Expr;
451 if (unary.Oper == Operator.UnaryNegation)
456 // perform numeric promotions to int,
460 // The following is inneficient, because we call
461 // ConvertImplicit too many times.
463 // It is also not clear if we should convert to Float
464 // or Double initially.
466 if (expr_type == TypeManager.string_type) {
467 Expression e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
470 type = TypeManager.double_type;
475 if (expr_type == TypeManager.bool_type) {
476 Expression e = ConvertImplicit (ec, Expr, TypeManager.short_type, loc);
479 type = TypeManager.int32_type;
484 if (expr_type == TypeManager.float_type ||
485 expr_type == TypeManager.double_type) {
490 if (expr_type == TypeManager.short_type ||
491 expr_type == TypeManager.byte_type) {
492 type = TypeManager.int32_type;
496 if (expr_type == TypeManager.int32_type ||
497 expr_type == TypeManager.int64_type) {
498 Expression e = new Binary (Binary.Operator.Subtraction, new IntLiteral (0), Expr, loc);
499 return e.Resolve (ec);
506 Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
507 TypeManager.MonoBASIC_Name (expr_type) + "'");
511 public override Expression DoResolve (EmitContext ec)
513 if (Oper == Operator.AddressOf)
514 Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
516 Expr = Expr.Resolve (ec);
521 Type init_type = Expr.Type;
523 eclass = ExprClass.Value;
524 Expression etmp = ResolveOperator (ec);
525 // Convert the result to byte/short if operands are of type byte/short/boolean
526 if (etmp.Type != init_type &&
527 (init_type == TypeManager.byte_type ||
528 init_type == TypeManager.short_type ||
529 init_type == TypeManager.bool_type)) {
530 Expression conv_exp = null;
531 if (init_type == TypeManager.byte_type && Oper != Operator.UnaryNegation) {
532 return new OpcodeCast (etmp, TypeManager.byte_type, OpCodes.Conv_U1);
535 conv_exp = ConvertImplicit (ec, etmp, TypeManager.short_type, loc);
537 if (conv_exp != null)
543 public override void Emit (EmitContext ec)
545 ILGenerator ig = ec.ig;
548 case Operator.UnaryPlus:
549 throw new Exception ("This should be caught by Resolve");
551 case Operator.UnaryNegation:
553 ig.Emit (OpCodes.Neg);
556 case Operator.LogicalNot:
558 ig.Emit (OpCodes.Ldc_I4_0);
559 ig.Emit (OpCodes.Ceq);
562 case Operator.OnesComplement:
564 ig.Emit (OpCodes.Not);
567 case Operator.AddressOf:
568 ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
572 throw new Exception ("This should not happen: Operator = "
578 /// This will emit the child expression for 'ec' avoiding the logical
579 /// not. The parent will take care of changing brfalse/brtrue
581 public void EmitLogicalNot (EmitContext ec)
583 if (Oper != Operator.LogicalNot)
584 throw new Exception ("EmitLogicalNot can only be called with !expr");
589 public override string ToString ()
591 return "Unary (" + Oper + ", " + Expr + ")";
597 // Unary operators are turned into Indirection expressions
598 // after semantic analysis (this is so we can take the address
599 // of an indirection).
601 public class Indirection : Expression, IMemoryLocation, IAssignMethod {
603 LocalTemporary temporary;
606 public Indirection (Expression expr, Location l)
609 this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
610 eclass = ExprClass.Variable;
614 void LoadExprValue (EmitContext ec)
618 public override void Emit (EmitContext ec)
620 ILGenerator ig = ec.ig;
622 if (temporary != null){
628 ec.ig.Emit (OpCodes.Dup);
629 temporary.Store (ec);
630 have_temporary = true;
634 LoadFromPtr (ig, Type);
637 public void EmitAssign (EmitContext ec, Expression source)
639 if (temporary != null){
645 ec.ig.Emit (OpCodes.Dup);
646 temporary.Store (ec);
647 have_temporary = true;
652 StoreFromPtr (ec.ig, type);
655 public void AddressOf (EmitContext ec, AddressOp Mode)
657 if (temporary != null){
663 ec.ig.Emit (OpCodes.Dup);
664 temporary.Store (ec);
665 have_temporary = true;
670 public override Expression DoResolve (EmitContext ec)
673 // Born fully resolved
678 public new void CacheTemporaries (EmitContext ec)
680 temporary = new LocalTemporary (ec, type);
685 /// Unary Mutator expressions (pre and post ++ and --)
689 /// UnaryMutator implements ++ and -- expressions. It derives from
690 /// ExpressionStatement becuase the pre/post increment/decrement
691 /// operators can be used in a statement context.
693 /// FIXME: Idea, we could split this up in two classes, one simpler
694 /// for the common case, and one with the extra fields for more complex
695 /// classes (indexers require temporary access; overloaded require method)
697 /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
698 /// PostDecrement, that way we could save the 'Mode' byte as well.
700 public class UnaryMutator : ExpressionStatement {
701 public enum Mode : byte {
702 PreIncrement, PreDecrement, PostIncrement, PostDecrement
707 LocalTemporary temp_storage;
710 // This is expensive for the simplest case.
714 public UnaryMutator (Mode m, Expression e, Location l)
721 static string OperName (Mode mode)
723 return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
728 /// Returns whether an object of type 't' can be incremented
729 /// or decremented with add/sub (ie, basically whether we can
730 /// use pre-post incr-decr operations on it, but it is not a
731 /// System.Decimal, which we require operator overloading to catch)
733 static bool IsIncrementableNumber (Type t)
735 return (t == TypeManager.sbyte_type) ||
736 (t == TypeManager.byte_type) ||
737 (t == TypeManager.short_type) ||
738 (t == TypeManager.ushort_type) ||
739 (t == TypeManager.int32_type) ||
740 (t == TypeManager.uint32_type) ||
741 (t == TypeManager.int64_type) ||
742 (t == TypeManager.uint64_type) ||
743 (t == TypeManager.char_type) ||
744 (t.IsSubclassOf (TypeManager.enum_type)) ||
745 (t == TypeManager.float_type) ||
746 (t == TypeManager.double_type) ||
747 (t.IsPointer && t != TypeManager.void_ptr_type);
750 Expression ResolveOperator (EmitContext ec)
752 Type expr_type = expr.Type;
755 // Step 1: Perform Operator Overload location
760 if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
761 op_name = "op_Increment";
763 op_name = "op_Decrement";
765 mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
767 if (mg == null && expr_type.BaseType != null)
768 mg = MemberLookup (ec, expr_type.BaseType, op_name,
769 MemberTypes.Method, AllBindingFlags, loc);
772 method = StaticCallExpr.MakeSimpleCall (
773 ec, (MethodGroupExpr) mg, expr, loc);
780 // The operand of the prefix/postfix increment decrement operators
781 // should be an expression that is classified as a variable,
782 // a property access or an indexer access
785 if (expr.eclass == ExprClass.Variable){
786 if (IsIncrementableNumber (expr_type) ||
787 expr_type == TypeManager.decimal_type){
790 } else if (expr.eclass == ExprClass.IndexerAccess){
791 IndexerAccess ia = (IndexerAccess) expr;
793 temp_storage = new LocalTemporary (ec, expr.Type);
795 expr = ia.ResolveLValue (ec, temp_storage);
800 } else if (expr.eclass == ExprClass.PropertyAccess){
801 PropertyExpr pe = (PropertyExpr) expr;
803 if (pe.VerifyAssignable ())
808 expr.Error118 ("variable, indexer or property access");
812 Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
813 TypeManager.MonoBASIC_Name (expr_type) + "'");
817 public override Expression DoResolve (EmitContext ec)
819 expr = expr.Resolve (ec);
824 eclass = ExprClass.Value;
825 return ResolveOperator (ec);
828 static int PtrTypeSize (Type t)
830 return GetTypeSize (t.GetElementType ());
834 // Loads the proper "1" into the stack based on the type
836 static void LoadOne (ILGenerator ig, Type t)
838 if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
839 ig.Emit (OpCodes.Ldc_I8, 1L);
840 else if (t == TypeManager.double_type)
841 ig.Emit (OpCodes.Ldc_R8, 1.0);
842 else if (t == TypeManager.float_type)
843 ig.Emit (OpCodes.Ldc_R4, 1.0F);
844 else if (t.IsPointer){
845 int n = PtrTypeSize (t);
848 ig.Emit (OpCodes.Sizeof, t);
850 IntConstant.EmitInt (ig, n);
852 ig.Emit (OpCodes.Ldc_I4_1);
857 // FIXME: We need some way of avoiding the use of temp_storage
858 // for some types of storage (parameters, local variables,
859 // static fields) and single-dimension array access.
861 void EmitCode (EmitContext ec, bool is_expr)
863 ILGenerator ig = ec.ig;
864 IAssignMethod ia = (IAssignMethod) expr;
865 Type expr_type = expr.Type;
867 if (temp_storage == null)
868 temp_storage = new LocalTemporary (ec, expr_type);
870 ia.CacheTemporaries (ec);
871 ig.Emit (OpCodes.Nop);
873 case Mode.PreIncrement:
874 case Mode.PreDecrement:
878 LoadOne (ig, expr_type);
881 // Select the opcode based on the check state (then the type)
882 // and the actual operation
885 if (expr_type == TypeManager.int32_type ||
886 expr_type == TypeManager.int64_type){
887 if (mode == Mode.PreDecrement)
888 ig.Emit (OpCodes.Sub_Ovf);
890 ig.Emit (OpCodes.Add_Ovf);
891 } else if (expr_type == TypeManager.uint32_type ||
892 expr_type == TypeManager.uint64_type){
893 if (mode == Mode.PreDecrement)
894 ig.Emit (OpCodes.Sub_Ovf_Un);
896 ig.Emit (OpCodes.Add_Ovf_Un);
898 if (mode == Mode.PreDecrement)
899 ig.Emit (OpCodes.Sub_Ovf);
901 ig.Emit (OpCodes.Add_Ovf);
904 if (mode == Mode.PreDecrement)
905 ig.Emit (OpCodes.Sub);
907 ig.Emit (OpCodes.Add);
912 temp_storage.Store (ec);
913 ia.EmitAssign (ec, temp_storage);
915 temp_storage.Emit (ec);
918 case Mode.PostIncrement:
919 case Mode.PostDecrement:
927 ig.Emit (OpCodes.Dup);
929 LoadOne (ig, expr_type);
932 if (expr_type == TypeManager.int32_type ||
933 expr_type == TypeManager.int64_type){
934 if (mode == Mode.PostDecrement)
935 ig.Emit (OpCodes.Sub_Ovf);
937 ig.Emit (OpCodes.Add_Ovf);
938 } else if (expr_type == TypeManager.uint32_type ||
939 expr_type == TypeManager.uint64_type){
940 if (mode == Mode.PostDecrement)
941 ig.Emit (OpCodes.Sub_Ovf_Un);
943 ig.Emit (OpCodes.Add_Ovf_Un);
945 if (mode == Mode.PostDecrement)
946 ig.Emit (OpCodes.Sub_Ovf);
948 ig.Emit (OpCodes.Add_Ovf);
951 if (mode == Mode.PostDecrement)
952 ig.Emit (OpCodes.Sub);
954 ig.Emit (OpCodes.Add);
960 temp_storage.Store (ec);
961 ia.EmitAssign (ec, temp_storage);
966 public override void Emit (EmitContext ec)
972 public override void EmitStatement (EmitContext ec)
974 EmitCode (ec, false);
980 /// Base class for the 'Is' and 'As' classes.
984 /// FIXME: Split this in two, and we get to save the 'Operator' Oper
987 public abstract class Probe : Expression {
988 public readonly Expression ProbeType;
989 protected Expression expr;
990 protected Type probe_type;
992 public Probe (Expression expr, Expression probe_type, Location l)
994 ProbeType = probe_type;
999 public Expression Expr {
1005 public override Expression DoResolve (EmitContext ec)
1007 probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
1009 if (probe_type == null)
1012 expr = expr.Resolve (ec);
1019 /// Implementation of the 'is' operator.
1021 public class Is : Probe {
1022 public Is (Expression expr, Expression probe_type, Location l)
1023 : base (expr, probe_type, l)
1028 AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
1033 public override void Emit (EmitContext ec)
1035 ILGenerator ig = ec.ig;
1040 case Action.AlwaysFalse:
1041 ig.Emit (OpCodes.Pop);
1042 IntConstant.EmitInt (ig, 0);
1044 case Action.AlwaysTrue:
1045 ig.Emit (OpCodes.Pop);
1046 ig.Emit (OpCodes.Nop);
1047 IntConstant.EmitInt (ig, 1);
1049 case Action.LeaveOnStack:
1050 // the 'e != null' rule.
1053 ig.Emit (OpCodes.Isinst, probe_type);
1054 ig.Emit (OpCodes.Ldnull);
1055 ig.Emit (OpCodes.Cgt_Un);
1058 throw new Exception ("never reached");
1061 public override Expression DoResolve (EmitContext ec)
1063 Expression e = base.DoResolve (ec);
1065 if ((e == null) || (expr == null))
1068 Type etype = expr.Type;
1069 bool warning_always_matches = false;
1070 bool warning_never_matches = false;
1072 type = TypeManager.bool_type;
1073 eclass = ExprClass.Value;
1076 // First case, if at compile time, there is an implicit conversion
1077 // then e != null (objects) or true (value types)
1079 e = ConvertImplicitStandard (ec, expr, probe_type, loc);
1082 if (etype.IsValueType)
1083 action = Action.AlwaysTrue;
1085 action = Action.LeaveOnStack;
1087 warning_always_matches = true;
1088 } else if (ExplicitReferenceConversionExists (etype, probe_type)){
1090 // Second case: explicit reference convresion
1092 if (expr is NullLiteral)
1093 action = Action.AlwaysFalse;
1095 action = Action.Probe;
1097 action = Action.AlwaysFalse;
1098 warning_never_matches = true;
1101 if (RootContext.WarningLevel >= 1){
1102 if (warning_always_matches)
1105 "The expression is always of type '" +
1106 TypeManager.MonoBASIC_Name (probe_type) + "'");
1107 else if (warning_never_matches){
1108 if (!(probe_type.IsInterface || expr.Type.IsInterface))
1111 "The expression is never of type '" +
1112 TypeManager.MonoBASIC_Name (probe_type) + "'");
1121 /// Implementation of the 'as' operator.
1123 public class As : Probe {
1124 public As (Expression expr, Expression probe_type, Location l)
1125 : base (expr, probe_type, l)
1129 bool do_isinst = false;
1131 public override void Emit (EmitContext ec)
1133 ILGenerator ig = ec.ig;
1138 ig.Emit (OpCodes.Isinst, probe_type);
1141 static void Error_CannotConvertType (Type source, Type target, Location loc)
1144 39, loc, "as operator can not convert from '" +
1145 TypeManager.MonoBASIC_Name (source) + "' to '" +
1146 TypeManager.MonoBASIC_Name (target) + "'");
1149 public override Expression DoResolve (EmitContext ec)
1151 Expression e = base.DoResolve (ec);
1157 eclass = ExprClass.Value;
1158 Type etype = expr.Type;
1160 if (TypeManager.IsValueType (probe_type)){
1161 Report.Error (77, loc, "The as operator should be used with a reference type only (" +
1162 TypeManager.MonoBASIC_Name (probe_type) + " is a value type)");
1167 e = ConvertImplicit (ec, expr, probe_type, loc);
1174 if (ExplicitReferenceConversionExists (etype, probe_type)){
1179 Error_CannotConvertType (etype, probe_type, loc);
1185 /// This represents a typecast in the source language.
1187 /// FIXME: Cast expressions have an unusual set of parsing
1188 /// rules, we need to figure those out.
1190 public class Cast : Expression {
1191 Expression target_type;
1195 public Cast (Expression cast_type, Expression expr, Location loc)
1197 this.target_type = cast_type;
1200 runtime_cast = false;
1203 public Expression TargetType {
1209 public Expression Expr {
1218 public bool IsRuntimeCast
1221 return runtime_cast;
1224 runtime_cast = value;
1229 /// Attempts to do a compile-time folding of a constant cast.
1231 Expression TryReduce (EmitContext ec, Type target_type)
1233 if (expr is ByteConstant){
1234 byte v = ((ByteConstant) expr).Value;
1236 if (target_type == TypeManager.sbyte_type)
1237 return new SByteConstant ((sbyte) v);
1238 if (target_type == TypeManager.short_type)
1239 return new ShortConstant ((short) v);
1240 if (target_type == TypeManager.ushort_type)
1241 return new UShortConstant ((ushort) v);
1242 if (target_type == TypeManager.int32_type)
1243 return new IntConstant ((int) v);
1244 if (target_type == TypeManager.uint32_type)
1245 return new UIntConstant ((uint) v);
1246 if (target_type == TypeManager.int64_type)
1247 return new LongConstant ((long) v);
1248 if (target_type == TypeManager.uint64_type)
1249 return new ULongConstant ((ulong) v);
1250 if (target_type == TypeManager.float_type)
1251 return new FloatConstant ((float) v);
1252 if (target_type == TypeManager.double_type)
1253 return new DoubleConstant ((double) v);
1254 if (target_type == TypeManager.char_type)
1255 return new CharConstant ((char) v);
1256 if (target_type == TypeManager.decimal_type)
1257 return new DecimalConstant ((decimal) v);
1259 if (expr is SByteConstant){
1260 sbyte v = ((SByteConstant) expr).Value;
1262 if (target_type == TypeManager.byte_type)
1263 return new ByteConstant ((byte) v);
1264 if (target_type == TypeManager.short_type)
1265 return new ShortConstant ((short) v);
1266 if (target_type == TypeManager.ushort_type)
1267 return new UShortConstant ((ushort) v);
1268 if (target_type == TypeManager.int32_type)
1269 return new IntConstant ((int) v);
1270 if (target_type == TypeManager.uint32_type)
1271 return new UIntConstant ((uint) v);
1272 if (target_type == TypeManager.int64_type)
1273 return new LongConstant ((long) v);
1274 if (target_type == TypeManager.uint64_type)
1275 return new ULongConstant ((ulong) v);
1276 if (target_type == TypeManager.float_type)
1277 return new FloatConstant ((float) v);
1278 if (target_type == TypeManager.double_type)
1279 return new DoubleConstant ((double) v);
1280 if (target_type == TypeManager.char_type)
1281 return new CharConstant ((char) v);
1282 if (target_type == TypeManager.decimal_type)
1283 return new DecimalConstant ((decimal) v);
1285 if (expr is ShortConstant){
1286 short v = ((ShortConstant) expr).Value;
1288 if (target_type == TypeManager.byte_type)
1289 return new ByteConstant ((byte) v);
1290 if (target_type == TypeManager.sbyte_type)
1291 return new SByteConstant ((sbyte) v);
1292 if (target_type == TypeManager.ushort_type)
1293 return new UShortConstant ((ushort) v);
1294 if (target_type == TypeManager.int32_type)
1295 return new IntConstant ((int) v);
1296 if (target_type == TypeManager.uint32_type)
1297 return new UIntConstant ((uint) v);
1298 if (target_type == TypeManager.int64_type)
1299 return new LongConstant ((long) v);
1300 if (target_type == TypeManager.uint64_type)
1301 return new ULongConstant ((ulong) v);
1302 if (target_type == TypeManager.float_type)
1303 return new FloatConstant ((float) v);
1304 if (target_type == TypeManager.double_type)
1305 return new DoubleConstant ((double) v);
1306 if (target_type == TypeManager.char_type)
1307 return new CharConstant ((char) v);
1308 if (target_type == TypeManager.decimal_type)
1309 return new DecimalConstant ((decimal) v);
1311 if (expr is UShortConstant){
1312 ushort v = ((UShortConstant) expr).Value;
1314 if (target_type == TypeManager.byte_type)
1315 return new ByteConstant ((byte) v);
1316 if (target_type == TypeManager.sbyte_type)
1317 return new SByteConstant ((sbyte) v);
1318 if (target_type == TypeManager.short_type)
1319 return new ShortConstant ((short) v);
1320 if (target_type == TypeManager.int32_type)
1321 return new IntConstant ((int) v);
1322 if (target_type == TypeManager.uint32_type)
1323 return new UIntConstant ((uint) v);
1324 if (target_type == TypeManager.int64_type)
1325 return new LongConstant ((long) v);
1326 if (target_type == TypeManager.uint64_type)
1327 return new ULongConstant ((ulong) v);
1328 if (target_type == TypeManager.float_type)
1329 return new FloatConstant ((float) v);
1330 if (target_type == TypeManager.double_type)
1331 return new DoubleConstant ((double) v);
1332 if (target_type == TypeManager.char_type)
1333 return new CharConstant ((char) v);
1334 if (target_type == TypeManager.decimal_type)
1335 return new DecimalConstant ((decimal) v);
1337 if (expr is IntConstant){
1338 int v = ((IntConstant) expr).Value;
1340 if (target_type == TypeManager.byte_type)
1341 return new ByteConstant ((byte) v);
1342 if (target_type == TypeManager.sbyte_type)
1343 return new SByteConstant ((sbyte) v);
1344 if (target_type == TypeManager.short_type)
1345 return new ShortConstant ((short) v);
1346 if (target_type == TypeManager.ushort_type)
1347 return new UShortConstant ((ushort) v);
1348 if (target_type == TypeManager.uint32_type)
1349 return new UIntConstant ((uint) v);
1350 if (target_type == TypeManager.int64_type)
1351 return new LongConstant ((long) v);
1352 if (target_type == TypeManager.uint64_type)
1353 return new ULongConstant ((ulong) v);
1354 if (target_type == TypeManager.float_type)
1355 return new FloatConstant ((float) v);
1356 if (target_type == TypeManager.double_type)
1357 return new DoubleConstant ((double) v);
1358 if (target_type == TypeManager.char_type)
1359 return new CharConstant ((char) v);
1360 if (target_type == TypeManager.decimal_type)
1361 return new DecimalConstant ((decimal) v);
1363 if (expr is UIntConstant){
1364 uint v = ((UIntConstant) expr).Value;
1366 if (target_type == TypeManager.byte_type)
1367 return new ByteConstant ((byte) v);
1368 if (target_type == TypeManager.sbyte_type)
1369 return new SByteConstant ((sbyte) v);
1370 if (target_type == TypeManager.short_type)
1371 return new ShortConstant ((short) v);
1372 if (target_type == TypeManager.ushort_type)
1373 return new UShortConstant ((ushort) v);
1374 if (target_type == TypeManager.int32_type)
1375 return new IntConstant ((int) v);
1376 if (target_type == TypeManager.int64_type)
1377 return new LongConstant ((long) v);
1378 if (target_type == TypeManager.uint64_type)
1379 return new ULongConstant ((ulong) v);
1380 if (target_type == TypeManager.float_type)
1381 return new FloatConstant ((float) v);
1382 if (target_type == TypeManager.double_type)
1383 return new DoubleConstant ((double) v);
1384 if (target_type == TypeManager.char_type)
1385 return new CharConstant ((char) v);
1386 if (target_type == TypeManager.decimal_type)
1387 return new DecimalConstant ((decimal) v);
1389 if (expr is LongConstant){
1390 long v = ((LongConstant) expr).Value;
1392 if (target_type == TypeManager.byte_type)
1393 return new ByteConstant ((byte) v);
1394 if (target_type == TypeManager.sbyte_type)
1395 return new SByteConstant ((sbyte) v);
1396 if (target_type == TypeManager.short_type)
1397 return new ShortConstant ((short) v);
1398 if (target_type == TypeManager.ushort_type)
1399 return new UShortConstant ((ushort) v);
1400 if (target_type == TypeManager.int32_type)
1401 return new IntConstant ((int) v);
1402 if (target_type == TypeManager.uint32_type)
1403 return new UIntConstant ((uint) v);
1404 if (target_type == TypeManager.uint64_type)
1405 return new ULongConstant ((ulong) v);
1406 if (target_type == TypeManager.float_type)
1407 return new FloatConstant ((float) v);
1408 if (target_type == TypeManager.double_type)
1409 return new DoubleConstant ((double) v);
1410 if (target_type == TypeManager.char_type)
1411 return new CharConstant ((char) v);
1412 if (target_type == TypeManager.decimal_type)
1413 return new DecimalConstant ((decimal) v);
1415 if (expr is ULongConstant){
1416 ulong v = ((ULongConstant) expr).Value;
1418 if (target_type == TypeManager.byte_type)
1419 return new ByteConstant ((byte) v);
1420 if (target_type == TypeManager.sbyte_type)
1421 return new SByteConstant ((sbyte) v);
1422 if (target_type == TypeManager.short_type)
1423 return new ShortConstant ((short) v);
1424 if (target_type == TypeManager.ushort_type)
1425 return new UShortConstant ((ushort) v);
1426 if (target_type == TypeManager.int32_type)
1427 return new IntConstant ((int) v);
1428 if (target_type == TypeManager.uint32_type)
1429 return new UIntConstant ((uint) v);
1430 if (target_type == TypeManager.int64_type)
1431 return new LongConstant ((long) v);
1432 if (target_type == TypeManager.float_type)
1433 return new FloatConstant ((float) v);
1434 if (target_type == TypeManager.double_type)
1435 return new DoubleConstant ((double) v);
1436 if (target_type == TypeManager.char_type)
1437 return new CharConstant ((char) v);
1438 if (target_type == TypeManager.decimal_type)
1439 return new DecimalConstant ((decimal) v);
1441 if (expr is FloatConstant){
1442 float v = ((FloatConstant) expr).Value;
1444 if (target_type == TypeManager.byte_type)
1445 return new ByteConstant ((byte) v);
1446 if (target_type == TypeManager.sbyte_type)
1447 return new SByteConstant ((sbyte) v);
1448 if (target_type == TypeManager.short_type)
1449 return new ShortConstant ((short) v);
1450 if (target_type == TypeManager.ushort_type)
1451 return new UShortConstant ((ushort) v);
1452 if (target_type == TypeManager.int32_type)
1453 return new IntConstant ((int) v);
1454 if (target_type == TypeManager.uint32_type)
1455 return new UIntConstant ((uint) v);
1456 if (target_type == TypeManager.int64_type)
1457 return new LongConstant ((long) v);
1458 if (target_type == TypeManager.uint64_type)
1459 return new ULongConstant ((ulong) v);
1460 if (target_type == TypeManager.double_type)
1461 return new DoubleConstant ((double) v);
1462 if (target_type == TypeManager.char_type)
1463 return new CharConstant ((char) v);
1464 if (target_type == TypeManager.decimal_type)
1465 return new DecimalConstant ((decimal) v);
1467 if (expr is DoubleConstant){
1468 double v = ((DoubleConstant) expr).Value;
1470 if (target_type == TypeManager.byte_type)
1471 return new ByteConstant ((byte) v);
1472 if (target_type == TypeManager.sbyte_type)
1473 return new SByteConstant ((sbyte) v);
1474 if (target_type == TypeManager.short_type)
1475 return new ShortConstant ((short) v);
1476 if (target_type == TypeManager.ushort_type)
1477 return new UShortConstant ((ushort) v);
1478 if (target_type == TypeManager.int32_type)
1479 return new IntConstant ((int) v);
1480 if (target_type == TypeManager.uint32_type)
1481 return new UIntConstant ((uint) v);
1482 if (target_type == TypeManager.int64_type)
1483 return new LongConstant ((long) v);
1484 if (target_type == TypeManager.uint64_type)
1485 return new ULongConstant ((ulong) v);
1486 if (target_type == TypeManager.float_type)
1487 return new FloatConstant ((float) v);
1488 if (target_type == TypeManager.char_type)
1489 return new CharConstant ((char) v);
1490 if (target_type == TypeManager.decimal_type)
1491 return new DecimalConstant ((decimal) v);
1497 public override Expression DoResolve (EmitContext ec)
1499 expr = expr.Resolve (ec);
1503 type = ec.DeclSpace.ResolveType (target_type, false, Location);
1508 eclass = ExprClass.Value;
1510 if (expr is Constant){
1511 Expression e = TryReduce (ec, type);
1517 expr = ConvertExplicit (ec, expr, type, runtime_cast, loc);
1521 public override void Emit (EmitContext ec)
1524 // This one will never happen
1526 throw new Exception ("Should not happen");
1530 public class StringConcat : Expression {
1532 Expression left, right;
1533 ArrayList Arguments;
1534 protected MethodBase method;
1536 public StringConcat(Location loc, Expression left, Expression right) {
1542 public override Expression DoResolve (EmitContext ec)
1544 left = left.Resolve (ec);
1545 right = right.Resolve (ec);
1547 if (left == null || right == null)
1550 if (left.Type == null)
1551 throw new Exception (
1552 "Resolve returned non null, but did not set the type! (" +
1553 left + ") at Line: " + loc.Row);
1554 if (right.Type == null)
1555 throw new Exception (
1556 "Resolve returned non null, but did not set the type! (" +
1557 right + ") at Line: "+ loc.Row);
1559 eclass = ExprClass.Value;
1560 if (left is StringConstant && right is StringConstant){
1561 return new StringConstant (
1562 ((StringConstant) left).Value +
1563 ((StringConstant) right).Value);
1567 Type r = right.Type;
1569 if (l == TypeManager.string_type && r == TypeManager.string_type) {
1570 type = TypeManager.string_type;
1571 method = TypeManager.string_concat_string_string;
1572 Arguments = new ArrayList ();
1573 Arguments.Add (new Argument (left, Argument.AType.Expression));
1574 Arguments.Add (new Argument (right, Argument.AType.Expression));
1578 if (l != TypeManager.string_type) {
1579 method = TypeManager.string_concat_object_object;
1580 left = ConvertImplicit (ec, left, TypeManager.string_type, loc);
1582 Error_OperatorCannotBeApplied (loc, "&", l, r);
1586 type = TypeManager.string_type;
1587 Arguments = new ArrayList ();
1588 Arguments.Add (new Argument (left, Argument.AType.Expression));
1589 Arguments.Add (new Argument (right, Argument.AType.Expression));
1593 if (r != TypeManager.string_type) {
1594 method = TypeManager.string_concat_object_object;
1595 right = ConvertImplicit (ec, right, TypeManager.string_type, loc);
1597 Error_OperatorCannotBeApplied (loc, "&", l, r);
1601 type = TypeManager.string_type;
1602 Arguments = new ArrayList ();
1603 Arguments.Add (new Argument (left, Argument.AType.Expression));
1604 Arguments.Add (new Argument (right, Argument.AType.Expression));
1610 public override void Emit (EmitContext ec)
1612 ILGenerator ig = ec.ig;
1613 if (method != null) {
1614 // Note that operators are static anyway
1615 if (Arguments != null)
1616 Invocation.EmitArguments (ec, method, Arguments);
1617 if (method is MethodInfo)
1618 ig.Emit (OpCodes.Call, (MethodInfo) method);
1620 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
1626 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1628 Report.Error (19, loc,
1629 "Operator " + name + " cannot be applied to operands of type '" +
1630 TypeManager.MonoBASIC_Name (l) + "' and '" +
1631 TypeManager.MonoBASIC_Name (r) + "'");
1638 /// Binary operators
1640 public class Binary : Expression {
1641 public enum Operator : byte {
1643 Multiply, Division, IntDivision, Modulus,
1644 Addition, Subtraction,
1645 LeftShift, RightShift,
1646 LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
1647 Equality, Inequality,
1659 Expression left, right;
1662 // After resolution, method might contain the operator overload
1665 protected MethodBase method;
1666 ArrayList Arguments;
1668 bool DelegateOperation;
1670 // This must be kept in sync with Operator!!!
1671 static string [] oper_names;
1675 oper_names = new string [(int) Operator.TOP];
1677 oper_names [(int) Operator.Multiply] = "op_Multiply";
1678 oper_names [(int) Operator.Division] = "op_Division";
1679 oper_names [(int) Operator.IntDivision] = "op_Division";
1680 oper_names [(int) Operator.Modulus] = "op_Modulus";
1681 oper_names [(int) Operator.Addition] = "op_Addition";
1682 oper_names [(int) Operator.Subtraction] = "op_Subtraction";
1683 oper_names [(int) Operator.LeftShift] = "op_LeftShift";
1684 oper_names [(int) Operator.RightShift] = "op_RightShift";
1685 oper_names [(int) Operator.LessThan] = "op_LessThan";
1686 oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
1687 oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
1688 oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
1689 oper_names [(int) Operator.Equality] = "op_Equality";
1690 oper_names [(int) Operator.Inequality] = "op_Inequality";
1691 oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
1692 oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
1693 oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
1694 oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
1695 oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
1696 oper_names [(int) Operator.Is] = "op_Is";
1699 public Binary (Operator oper, Expression left, Expression right, Location loc)
1701 left = Parser.SetValueRequiredFlag (left);
1702 right = Parser.SetValueRequiredFlag (right);
1709 public Operator Oper {
1718 public Expression Left {
1727 public Expression Right {
1738 /// Returns a stringified representation of the Operator
1740 static string OperName (Operator oper)
1743 case Operator.Exponentiation:
1745 case Operator.Multiply:
1747 case Operator.Division:
1749 case Operator.IntDivision:
1751 case Operator.Modulus:
1753 case Operator.Addition:
1755 case Operator.Subtraction:
1757 case Operator.LeftShift:
1759 case Operator.RightShift:
1761 case Operator.LessThan:
1763 case Operator.GreaterThan:
1765 case Operator.LessThanOrEqual:
1767 case Operator.GreaterThanOrEqual:
1769 case Operator.Equality:
1771 case Operator.Inequality:
1773 case Operator.BitwiseAnd:
1775 case Operator.BitwiseOr:
1777 case Operator.ExclusiveOr:
1779 case Operator.LogicalOr:
1781 case Operator.LogicalAnd:
1787 return oper.ToString ();
1790 public override string ToString ()
1792 return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
1793 right.ToString () + ")";
1796 Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
1798 if (expr.Type == target_type)
1801 return ConvertImplicit (ec, expr, target_type, Location.Null);
1804 public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
1807 34, loc, "Operator '" + OperName (oper)
1808 + "' is ambiguous on operands of type '"
1809 + TypeManager.MonoBASIC_Name (l) + "' "
1810 + "and '" + TypeManager.MonoBASIC_Name (r)
1815 // Handles boolean types also
1817 bool DoNumericPromotions (EmitContext ec, Type l, Type r, Operator oper)
1820 Type conv_left_as = null;
1821 Type conv_right_as = null;
1822 if (left is NullLiteral)
1824 if (right is NullLiteral)
1827 // Need not do anything for shift operators, as this will be handled by the
1828 // 'CheckShiftArguments' method
1829 if (oper == Operator.LeftShift || oper == Operator.RightShift)
1831 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
1832 if (IsArithmaticOperator (oper) && oper != Operator.Division) {
1833 type = TypeManager.int32_type;
1834 conv_left_as = conv_right_as = TypeManager.short_type;
1838 if (IsBitwiseOperator (oper)) {
1840 if (l == TypeManager.decimal_type ||
1841 l == TypeManager.double_type ||
1842 l == TypeManager.float_type) {
1843 conv_left_as = type = TypeManager.int64_type;
1846 if (r == TypeManager.decimal_type ||
1847 r == TypeManager.double_type ||
1848 r == TypeManager.float_type) {
1849 conv_right_as = type = TypeManager.int64_type;
1854 if (oper == Operator.IntDivision) {
1855 if (l == TypeManager.decimal_type || r == TypeManager.decimal_type ||
1856 l == TypeManager.float_type || r == TypeManager.float_type ||
1857 l == TypeManager.double_type || r == TypeManager.double_type)
1858 conv_left_as = conv_right_as = TypeManager.int64_type;
1859 l = r = TypeManager.int64_type;
1862 if (IsLogicalOperator (oper)) {
1863 if (l == TypeManager.decimal_type)
1864 conv_left_as = TypeManager.bool_type;
1865 else if (r == TypeManager.decimal_type)
1866 conv_right_as = TypeManager.bool_type;
1867 } else if ((l == TypeManager.double_type || r == TypeManager.double_type) ||
1868 (oper == Operator.Exponentiation) ||
1869 (oper == Operator.Division &&
1870 !(l == TypeManager.decimal_type || r == TypeManager.decimal_type))) {
1872 // If either operand is of type double, the other operand is
1873 // conveted to type double.
1875 type = conv_left_as = conv_right_as = TypeManager.double_type;
1877 } else if (l == TypeManager.float_type || r == TypeManager.float_type){
1879 // if either operand is of type float, the other operand is
1880 // converted to type float.
1882 type = conv_left_as = conv_right_as = TypeManager.float_type;
1883 } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
1884 type = conv_left_as = conv_right_as = TypeManager.decimal_type;
1885 } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
1887 // If either operand is of type long, the other operand is converted
1890 type = conv_left_as = conv_right_as = TypeManager.int64_type;
1891 } else if (l == TypeManager.int32_type || r == TypeManager.int32_type){
1892 type = conv_left_as = conv_right_as = TypeManager.int32_type;
1893 } else if (l == TypeManager.short_type || r == TypeManager.short_type){
1894 conv_left_as = conv_right_as = TypeManager.short_type;
1895 type = TypeManager.int32_type;
1897 type = TypeManager.int32_type;
1900 if (conv_left_as != null)
1901 left = ConvertImplicit (ec, left, conv_left_as, loc);
1902 if (conv_right_as != null)
1903 right = ConvertImplicit (ec, right, conv_right_as, loc);
1905 return (left != null) && (right != null);
1908 static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
1910 Report.Error (19, loc,
1911 "Operator '" + name + "' cannot be applied to operands of type '" +
1912 TypeManager.MonoBASIC_Name (l) + "' and '" +
1913 TypeManager.MonoBASIC_Name (r) + "'");
1916 void Error_OperatorCannotBeApplied ()
1918 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1921 static bool is_32_or_64 (Type t)
1923 return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
1924 t == TypeManager.int64_type || t == TypeManager.uint64_type);
1927 static bool is_unsigned (Type t)
1929 return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
1930 t == TypeManager.short_type || t == TypeManager.byte_type);
1933 Expression CheckShiftArguments (EmitContext ec)
1937 e = ForceConversion (ec, right, TypeManager.int32_type);
1939 Error_OperatorCannotBeApplied ();
1944 if (left is NullLiteral) {
1946 if (right.Type != TypeManager.bool_type) {
1947 left = ConvertImplicit (ec, left, right.Type, loc);
1949 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1956 if (type == TypeManager.bool_type) {
1957 left = ConvertImplicit (ec, left, TypeManager.short_type, loc);
1959 Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
1966 if ( type == TypeManager.byte_type)
1968 else if (type == TypeManager.short_type || type == TypeManager.bool_type)
1970 else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
1975 right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (mask), loc);
1976 right = right.DoResolve (ec);
1979 if (type == TypeManager.byte_type ||
1980 type == TypeManager.short_type ||
1981 type == TypeManager.int32_type) {
1982 type = TypeManager.int32_type;
1986 if (type == TypeManager.int64_type)
1988 if ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) {
1990 type = TypeManager.int64_type;
1994 Error_OperatorCannotBeApplied ();
1998 bool IsRelationalOperator (Binary.Operator oper) {
1999 return (oper == Operator.Equality ||
2000 oper == Operator.Inequality ||
2001 oper == Operator.LessThan ||
2002 oper == Operator.LessThanOrEqual ||
2003 oper == Operator.GreaterThan ||
2004 oper == Operator.GreaterThanOrEqual);
2007 bool IsArithmaticOperator (Binary.Operator oper) {
2008 return (oper == Operator.Addition ||
2009 oper == Operator.Subtraction ||
2010 oper == Operator.Multiply ||
2011 oper == Operator.Division ||
2012 oper == Operator.IntDivision ||
2013 oper == Operator.Exponentiation ||
2014 oper == Operator.Modulus);
2017 bool IsShiftOperator (Binary.Operator oper) {
2018 return (oper == Operator.LeftShift ||
2019 oper == Operator.RightShift);
2022 bool IsLogicalOperator (Binary.Operator oper) {
2023 return (oper == Operator.LogicalOr ||
2024 oper == Operator.LogicalAnd);
2027 bool IsBitwiseOperator (Binary.Operator oper) {
2028 return (oper == Operator.BitwiseOr ||
2029 oper == Operator.BitwiseAnd ||
2030 oper == Operator.ExclusiveOr);
2033 Expression ResolveOperator (EmitContext ec)
2036 Type r = right.Type;
2038 Expression left_expr, right_expr;
2039 left_expr = right_expr = null;
2041 if (oper == Operator.Addition && right is Unary) {
2042 Unary unary_right = (Unary) right;
2043 if (unary_right.Oper == Unary.Operator.UnaryNegation) {
2044 oper = Operator.Subtraction;
2045 right = unary_right.Expr;
2050 if (TypeManager.IsEnumType (l))
2051 l = TypeManager.EnumToUnderlying (l);
2052 if (TypeManager.IsEnumType (r))
2053 r = TypeManager.EnumToUnderlying (r);
2055 Type conv_left_as = null;
2056 Type conv_right_as = null;
2058 if (left is NullLiteral && (r.IsValueType || r == TypeManager.string_type)) {
2059 // Just treat nothing as the other type, implicit conversion
2060 // will return the default value
2065 if (right is NullLiteral && (l.IsValueType || l == TypeManager.string_type)) {
2066 // Just treat nothing as the other type, implicit conversion
2067 // will return the default value
2072 // deal with objects and reference types first
2073 if (l == TypeManager.object_type || r == TypeManager.object_type) {
2076 // operator != (object a, object b)
2077 // operator == (object a, object b)
2079 // For this to be used, both arguments have to be reference-types.
2080 // Read the rationale on the spec (14.9.6)
2082 // Also, if at compile time we know that the classes do not inherit
2083 // one from the other, then we catch the error there.
2085 // If other type is a value type, convert it to object
2086 if (r == TypeManager.object_type &&
2087 (l.IsValueType || l == TypeManager.string_type))
2088 left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
2089 if (l == TypeManager.object_type &&
2090 (r.IsValueType || r == TypeManager.string_type))
2091 right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
2092 if (left == null || right == null) {
2093 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2100 if (l == TypeManager.object_type && r == TypeManager.object_type) {
2103 case Operator.Addition :
2104 fqn = "ObjectType.AddObj";
2106 case Operator.Subtraction :
2107 fqn = "ObjectType.SubObj";
2109 case Operator.Multiply :
2110 fqn = "ObjectType.MulObj";
2112 case Operator.Division :
2113 fqn = "ObjectType.DivObj";
2115 case Operator.IntDivision :
2116 fqn = "ObjectType.IDivObj";
2118 case Operator.Modulus :
2119 fqn = "ObjectType.ModObj";
2121 case Operator.Exponentiation :
2122 fqn = "ObjectType.PowObj";
2124 case Operator.Like :
2125 fqn = "ObjectType.LikeObj";
2127 case Operator.Equality :
2128 case Operator.Inequality :
2129 case Operator.LessThan :
2130 case Operator.LessThanOrEqual :
2131 case Operator.GreaterThan :
2132 case Operator.GreaterThanOrEqual :
2133 fqn = "ObjectType.ObjTst";
2135 case Operator.BitwiseAnd:
2136 fqn = "ObjectType.BitAndObj";
2138 case Operator.BitwiseOr:
2139 fqn = "ObjectType.BitOrObj";
2141 case Operator.ExclusiveOr:
2142 fqn = "ObjectType.BitXorObj";
2144 case Operator.LeftShift:
2145 fqn = "ObjectType.ShiftLeftObj";
2147 case Operator.RightShift:
2148 fqn = "ObjectType.ShiftRightObj";
2151 eclass = ExprClass.Value;
2152 type = TypeManager.bool_type;
2157 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2161 if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2162 right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
2163 if (right == null) {
2164 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2169 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (
2170 "Microsoft.VisualBasic.CompilerServices." + fqn,
2173 ArrayList args = new ArrayList ();
2174 args.Add (new Argument (left, Argument.AType.Expression));
2175 args.Add (new Argument (right, Argument.AType.Expression));
2176 if (IsRelationalOperator (oper))
2177 args.Add (new Argument (new BoolConstant (false), Argument.AType.Expression));
2178 if (oper == Operator.Like)
2179 args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
2180 Expression e = new Invocation (etmp, args, loc);
2181 if (IsRelationalOperator (oper)) {
2182 e = new Binary (oper, e.Resolve(ec), new IntConstant (0), loc);
2184 return e.Resolve (ec);
2185 } else if (!l.IsValueType || !r.IsValueType) {
2187 // If one of the operands are reference types and other is object, support for 'Is' operator
2188 if (oper == Operator.Is) {
2189 eclass = ExprClass.Value;
2190 type = TypeManager.bool_type;
2196 } else if (!l.IsValueType || !r.IsValueType) {
2198 if (!l.IsValueType && !r.IsValueType) {
2199 // If both the operands are reference types, support for 'Is' operator
2200 if (oper == Operator.Is) {
2201 eclass = ExprClass.Value;
2202 type = TypeManager.bool_type;
2206 // Either of the operands are reference types
2207 if (l.IsSubclassOf (TypeManager.delegate_type) &&
2208 r.IsSubclassOf (TypeManager.delegate_type)) {
2209 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2210 Arguments = new ArrayList ();
2211 Arguments.Add (new Argument (left, Argument.AType.Expression));
2212 Arguments.Add (new Argument (right, Argument.AType.Expression));
2214 if (oper == Operator.Addition)
2215 method = TypeManager.delegate_combine_delegate_delegate;
2217 method = TypeManager.delegate_remove_delegate_delegate;
2220 Error_OperatorCannotBeApplied ();
2224 DelegateOperation = true;
2229 if (oper != Operator.Equality) {
2230 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2235 bool left_is_string = (left.Type == TypeManager.string_type);
2236 bool right_is_string = (right.Type == TypeManager.string_type);
2238 if (left_is_string || right_is_string) {
2240 if (left is NullLiteral) {
2241 left_is_string = true;
2244 if (right is NullLiteral) {
2245 right_is_string = true;
2248 if (left_is_string && right_is_string) {
2249 if (oper == Operator.Addition) {
2250 // Both operands are string
2251 Expression e = new StringConcat (loc, left, right);
2252 return e.Resolve(ec);
2255 if (IsRelationalOperator (oper)) {
2257 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrCmp", Location.Null);
2258 eclass = ExprClass.Value;
2259 type = TypeManager.bool_type;
2260 ArrayList args = new ArrayList ();
2261 args.Add (new Argument(left, Argument.AType.Expression));
2262 args.Add (new Argument(right, Argument.AType.Expression));
2263 args.Add (new Argument(new BoolConstant(false), Argument.AType.Expression));
2264 Expression e = (Expression) new Invocation (etmp, args, loc);
2265 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2266 return e.Resolve(ec);
2269 if (oper == Operator.Like) {
2270 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrLike", Location.Null);
2271 type = TypeManager.bool_type;
2272 ArrayList args = new ArrayList ();
2273 args.Add (new Argument(left, Argument.AType.Expression));
2274 args.Add (new Argument(right, Argument.AType.Expression));
2275 args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
2276 Expression e = (Expression) new Invocation (etmp, args, loc);
2277 return e.Resolve (ec);
2281 Expression other = right_is_string ? left: right;
2282 Type other_type = other.Type;
2285 // Disallow arithmatic / shift / logical operators on dates and characters
2287 if (other_type == TypeManager.date_type || other_type == TypeManager.char_type) {
2288 if (!(oper == Operator.Addition || IsRelationalOperator (oper) || oper == Operator.Like)) {
2289 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2294 if (oper == Operator.Addition) {
2295 if (other_type == TypeManager.void_type) {
2296 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2299 if (other_type == TypeManager.date_type ||
2300 other_type == TypeManager.char_type ||
2301 other_type == typeof (System.Char[])) {
2302 conv_left_as = conv_right_as = TypeManager.string_type;
2303 type = TypeManager.string_type;
2306 conv_right_as = conv_left_as = TypeManager.double_type;
2307 type = TypeManager.double_type;
2309 } else if (IsRelationalOperator (oper)) {
2310 if (other_type == TypeManager.char_type || other_type == typeof (System.Char[])) {
2311 conv_left_as = conv_right_as = TypeManager.string_type;
2312 } else if (other_type == TypeManager.date_type) {
2313 conv_right_as = conv_left_as = other_type;
2314 } else if (other_type == TypeManager.bool_type) {
2315 conv_right_as = conv_left_as = other_type;
2316 } else if (! other_type.IsValueType) {
2317 // Do Nothing, just return
2318 type = TypeManager.bool_type;
2321 conv_right_as = conv_left_as = TypeManager.double_type;
2323 type = TypeManager.bool_type;
2325 } else if (oper == Operator.Like) {
2326 conv_left_as = conv_right_as = TypeManager.string_type;
2327 } else if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2329 conv_left_as = TypeManager.int64_type;
2330 conv_right_as = TypeManager.int32_type;
2331 type = TypeManager.int64_type;
2333 } else if ( IsLogicalOperator (oper)) {
2334 type = conv_right_as = conv_left_as = TypeManager.bool_type;
2335 } else if ( IsBitwiseOperator (oper)) {
2337 if (other_type == TypeManager.bool_type) {
2338 conv_right_as = conv_left_as = TypeManager.bool_type;
2339 type = TypeManager.bool_type;
2341 conv_left_as = conv_right_as = TypeManager.int64_type;
2342 type = TypeManager.int64_type;
2344 } else if (oper == Operator.Exponentiation) {
2345 conv_left_as = conv_right_as = TypeManager.double_type;
2346 } else if (oper == Operator.IntDivision) {
2347 conv_left_as = conv_right_as = TypeManager.int64_type;
2349 // Arithmatic operators
2350 conv_right_as = conv_left_as = TypeManager.double_type;
2351 type = TypeManager.double_type;
2354 // Both are not of type string
2355 if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is) {
2356 if (l.IsValueType || r.IsValueType) {
2357 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2360 type = TypeManager.bool_type;
2363 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2367 } else if (l == TypeManager.date_type || r == TypeManager.date_type) {
2368 // Date with string operations handled above
2369 // Only other possiblity is date with date
2370 if (oper == Operator.Like) {
2371 conv_right_as = conv_left_as = TypeManager.string_type;
2372 type = TypeManager.bool_type;
2373 } else if (l == TypeManager.date_type && r == TypeManager.date_type) {
2374 if (oper == Operator.Addition) {
2375 conv_left_as = conv_right_as = TypeManager.string_type;
2376 } else if (IsRelationalOperator (oper)) {
2377 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.DateTime.Compare", Location.Null);
2378 eclass = ExprClass.Value;
2379 type = TypeManager.bool_type;
2380 ArrayList args = new ArrayList ();
2381 args.Add (new Argument(left, Argument.AType.Expression));
2382 args.Add (new Argument(right, Argument.AType.Expression));
2383 Expression e = (Expression) new Invocation (etmp, args, loc);
2384 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2385 return e.Resolve(ec);
2387 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2391 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2394 } else if (l == TypeManager.char_type || r == TypeManager.char_type) {
2395 // char op string handled above
2396 if (oper == Operator.Like) {
2397 conv_right_as = conv_left_as = TypeManager.string_type;
2398 type = TypeManager.bool_type;
2399 } else if (l == TypeManager.char_type && r == TypeManager.char_type) {
2400 if (oper == Operator.Addition)
2401 conv_left_as = conv_right_as = TypeManager.string_type;
2402 else if (IsRelationalOperator (oper)) {
2403 type = TypeManager.bool_type;
2405 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2409 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2412 } else if (l.IsPointer || r.IsPointer) {
2413 if (oper == Operator.Addition || oper == Operator.Subtraction) {
2415 if (r.IsPointer && oper == Operator.Subtraction){
2417 return new PointerArithmetic (
2418 false, left, right, TypeManager.int64_type,
2420 } else if (is_32_or_64 (r))
2421 return new PointerArithmetic (
2422 oper == Operator.Addition, left, right, l, loc);
2423 } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
2424 return new PointerArithmetic (
2425 true, right, left, r, loc);
2429 // Pointer comparison
2431 if (l.IsPointer && r.IsPointer){
2432 if (oper == Operator.Equality || oper == Operator.Inequality ||
2433 oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
2434 oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
2435 type = TypeManager.bool_type;
2439 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2442 } else if (oper == Operator.Like) {
2443 conv_left_as = conv_right_as = TypeManager.string_type;
2447 DoNumericPromotions (ec, l, r, oper);
2448 if (left == null || right == null) {
2449 Error_OperatorCannotBeApplied (loc, OperName(oper), l, r);
2455 // Required conversions done by 'DoNumericPromotions' method
2456 // So Reset 'conv_left_as', 'conv_right_as'
2457 conv_left_as = conv_right_as = null;
2459 if (l == TypeManager.decimal_type && r == TypeManager.decimal_type) {
2460 if (IsRelationalOperator (oper)) {
2461 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.Decimal.Compare", Location.Null);
2462 eclass = ExprClass.Value;
2463 type = TypeManager.bool_type;
2464 ArrayList args = new ArrayList ();
2465 args.Add (new Argument(left, Argument.AType.Expression));
2466 args.Add (new Argument(right, Argument.AType.Expression));
2467 Expression e = (Expression) new Invocation (etmp, args, loc);
2468 e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
2469 return e.Resolve(ec);
2470 } else if (IsArithmaticOperator (oper)) {
2472 if (oper == Operator.Addition)
2473 fqn = "System.Decimal.Add";
2474 else if (oper == Operator.Subtraction)
2475 fqn = "System.Decimal.Subtract";
2476 else if (oper == Operator.Multiply)
2477 fqn = "System.Decimal.Multiply";
2478 else if (oper == Operator.Division)
2479 fqn = "System.Decimal.Divide";
2480 else if (oper == Operator.Modulus)
2481 fqn = "System.Decimal.Remainder";
2484 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (fqn, Location.Null);
2485 eclass = ExprClass.Value;
2486 type = TypeManager.decimal_type;
2487 ArrayList args = new ArrayList ();
2488 args.Add (new Argument(left, Argument.AType.Expression));
2489 args.Add (new Argument(right, Argument.AType.Expression));
2490 Expression e = (Expression) new Invocation (etmp, args, loc);
2491 return e.Resolve (ec);
2497 bool conv_done = false;
2498 if (conv_left_as != null && conv_left_as != l) {
2500 left = ConvertImplicit (ec, left, conv_left_as, loc);
2502 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2508 if (conv_right_as != null && conv_right_as != r) {
2510 right = ConvertImplicit (ec, right, conv_right_as, loc);
2511 if (right == null) {
2512 Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
2519 return ResolveOperator (ec);
2522 if (oper == Operator.Exponentiation) {
2523 Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI("System.Math.Pow", loc);
2524 ArrayList args = new ArrayList();
2525 args.Add (new Argument (left, Argument.AType.Expression));
2526 args.Add (new Argument (right, Argument.AType.Expression));
2527 Expression e = (Expression) new Invocation (etmp, args, loc);
2528 return e.Resolve(ec);
2531 bool overload_failed = false;
2532 string op = oper_names [(int) oper];
2533 MethodGroupExpr union = null;
2534 left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
2536 right_expr = MemberLookup (
2537 ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
2538 union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
2540 union = (MethodGroupExpr) left_expr;
2542 if (union != null) {
2543 Arguments = new ArrayList ();
2544 Arguments.Add (new Argument (left, Argument.AType.Expression));
2545 Arguments.Add (new Argument (right, Argument.AType.Expression));
2547 method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
2548 if (method != null) {
2549 MethodInfo mi = (MethodInfo) method;
2551 type = mi.ReturnType;
2554 overload_failed = true;
2558 if (overload_failed) {
2559 Error_OperatorCannotBeApplied ();
2563 if (IsRelationalOperator (oper)) {
2564 type = TypeManager.bool_type;
2565 if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
2566 // Reverse the operator - to make it consistent with vbc
2567 if (oper == Operator.LessThan)
2568 oper = Operator.GreaterThan;
2569 else if (oper == Operator.GreaterThan)
2570 oper = Operator.LessThan;
2571 else if (oper == Operator.LessThanOrEqual)
2572 oper = Operator.GreaterThanOrEqual;
2573 else if (oper == Operator.GreaterThanOrEqual)
2574 oper = Operator.LessThanOrEqual;
2578 if (IsLogicalOperator (oper))
2579 type = TypeManager.bool_type;
2580 if (IsBitwiseOperator (oper)) {
2582 if (l == TypeManager.byte_type ||
2583 l == TypeManager.short_type ||
2584 l == TypeManager.bool_type ||
2585 l == TypeManager.int32_type ||
2586 l == TypeManager.int64_type)
2589 Error_OperatorCannotBeApplied();
2593 Error_OperatorCannotBeApplied();
2598 if (oper == Operator.LeftShift || oper == Operator.RightShift) {
2599 return CheckShiftArguments (ec);
2606 public override Expression DoResolve (EmitContext ec)
2608 left = left.Resolve (ec);
2609 right = right.Resolve (ec);
2611 if (left == null || right == null)
2614 if (left.Type == null)
2615 throw new Exception (
2616 "Resolve returned non null, but did not set the type! (" +
2617 left + ") at Line: " + loc.Row);
2618 if (right.Type == null)
2619 throw new Exception (
2620 "Resolve returned non null, but did not set the type! (" +
2621 right + ") at Line: "+ loc.Row);
2623 eclass = ExprClass.Value;
2625 // To support 'Or' argument of AttributeTargets in AttributeUsage
2627 if (left is EnumConstant && oper != Operator.BitwiseOr) {
2628 left = ((EnumConstant) left).WidenToCompilerConstant();
2631 if (right is EnumConstant && oper != Operator.BitwiseOr) {
2632 right = ((EnumConstant) right).WidenToCompilerConstant();
2635 if (left is Constant && right is Constant){
2636 Expression e = ConstantFold.BinaryFold (
2637 ec, oper, (Constant) left, (Constant) right, loc);
2642 Expression etmp = ResolveOperator (ec);
2645 // if the operands are of type byte/short, convert the result back to short/byte
2646 if (l == TypeManager.bool_type || l == TypeManager.short_type || l == TypeManager.byte_type) {
2647 if (l == TypeManager.bool_type)
2648 l = TypeManager.short_type;
2649 if (IsArithmaticOperator (oper) && oper != Operator.Division) {
2650 Expression conv_exp = ConvertImplicit (ec, etmp, l, loc);
2651 if (conv_exp != null)
2654 if (IsShiftOperator (oper)) {
2655 // No overflow checks are needed
2656 if (l == TypeManager.byte_type)
2657 return new OpcodeCast (etmp, l, OpCodes.Conv_U1);
2659 return new OpcodeCast (etmp, l, OpCodes.Conv_I2);
2667 /// EmitBranchable is called from Statement.EmitBoolExpression in the
2668 /// context of a conditional bool expression. This function will return
2669 /// false if it is was possible to use EmitBranchable, or true if it was.
2671 /// The expression's code is generated, and we will generate a branch to 'target'
2672 /// if the resulting expression value is equal to isTrue
2674 public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
2679 ILGenerator ig = ec.ig;
2682 // This is more complicated than it looks, but its just to avoid
2683 // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
2684 // but on top of that we want for == and != to use a special path
2685 // if we are comparing against null
2687 if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is){
2688 bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
2690 if (left is NullLiteral){
2693 ig.Emit (OpCodes.Brtrue, target);
2695 ig.Emit (OpCodes.Brfalse, target);
2697 } else if (right is NullLiteral){
2700 ig.Emit (OpCodes.Brtrue, target);
2702 ig.Emit (OpCodes.Brfalse, target);
2705 } else if (!(oper == Operator.LessThan ||
2706 oper == Operator.GreaterThan ||
2707 oper == Operator.LessThanOrEqual ||
2708 oper == Operator.GreaterThanOrEqual ||
2709 oper == Operator.Is))
2717 bool isUnsigned = is_unsigned (left.Type);
2720 case Operator.Equality:
2722 ig.Emit (OpCodes.Beq, target);
2724 ig.Emit (OpCodes.Bne_Un, target);
2727 case Operator.Inequality:
2729 ig.Emit (OpCodes.Bne_Un, target);
2731 ig.Emit (OpCodes.Beq, target);
2734 case Operator.LessThan:
2737 ig.Emit (OpCodes.Blt_Un, target);
2739 ig.Emit (OpCodes.Blt, target);
2742 ig.Emit (OpCodes.Bge_Un, target);
2744 ig.Emit (OpCodes.Bge, target);
2747 case Operator.GreaterThan:
2750 ig.Emit (OpCodes.Bgt_Un, target);
2752 ig.Emit (OpCodes.Bgt, target);
2755 ig.Emit (OpCodes.Ble_Un, target);
2757 ig.Emit (OpCodes.Ble, target);
2760 case Operator.LessThanOrEqual:
2763 ig.Emit (OpCodes.Ble_Un, target);
2765 ig.Emit (OpCodes.Ble, target);
2768 ig.Emit (OpCodes.Bgt_Un, target);
2770 ig.Emit (OpCodes.Bgt, target);
2774 case Operator.GreaterThanOrEqual:
2777 ig.Emit (OpCodes.Bge_Un, target);
2779 ig.Emit (OpCodes.Bge, target);
2782 ig.Emit (OpCodes.Blt_Un, target);
2784 ig.Emit (OpCodes.Blt, target);
2789 ig.Emit (OpCodes.Beq, target); //Check this
2791 ig.Emit (OpCodes.Bne_Un_S, target);
2801 public override void Emit (EmitContext ec)
2803 ILGenerator ig = ec.ig;
2805 Type r = right.Type;
2806 //Type r = right.Type;
2809 if (method != null) {
2811 // Note that operators are static anyway
2813 if (Arguments != null)
2814 Invocation.EmitArguments (ec, method, Arguments);
2816 if (method is MethodInfo)
2817 ig.Emit (OpCodes.Call, (MethodInfo) method);
2819 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
2821 if (DelegateOperation)
2822 ig.Emit (OpCodes.Castclass, type);
2828 // Handle short-circuit operators differently
2831 if (IsLogicalOperator (oper)) {
2832 Label load_zero = ig.DefineLabel ();
2833 Label load_one = ig.DefineLabel ();
2834 Label end = ig.DefineLabel ();
2837 if (l != TypeManager.bool_type) {
2838 if (l == TypeManager.int64_type) {
2839 ec.ig.Emit (OpCodes.Ldc_I8, 0L);
2840 ec.ig.Emit (OpCodes.Cgt_Un);
2841 } else if (l == TypeManager.float_type) {
2842 ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
2843 ec.ig.Emit (OpCodes.Ceq);
2844 ec.ig.Emit (OpCodes.Ldc_I4_0);
2845 ec.ig.Emit (OpCodes.Ceq);
2846 } else if (l == TypeManager.double_type) {
2847 ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
2848 ec.ig.Emit (OpCodes.Ceq);
2849 ec.ig.Emit (OpCodes.Ldc_I4_0);
2850 ec.ig.Emit (OpCodes.Ceq);
2852 ec.ig.Emit (OpCodes.Ldc_I4_0);
2853 ec.ig.Emit (OpCodes.Cgt_Un);
2856 if (oper == Operator.LogicalAnd)
2857 ig.Emit (OpCodes.Brfalse, load_zero);
2859 ig.Emit (OpCodes.Brtrue, load_one);
2862 if (r != TypeManager.bool_type) {
2863 if (r == TypeManager.int64_type) {
2864 ec.ig.Emit (OpCodes.Ldc_I8, 0L);
2865 ec.ig.Emit (OpCodes.Cgt_Un);
2866 } else if (r == TypeManager.float_type) {
2867 ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
2868 ec.ig.Emit (OpCodes.Ceq);
2869 ec.ig.Emit (OpCodes.Ldc_I4_0);
2870 ec.ig.Emit (OpCodes.Ceq);
2871 } else if (r == TypeManager.double_type) {
2872 ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
2873 ec.ig.Emit (OpCodes.Ceq);
2874 ec.ig.Emit (OpCodes.Ldc_I4_0);
2875 ec.ig.Emit (OpCodes.Ceq);
2877 ec.ig.Emit (OpCodes.Ldc_I4_0);
2878 ec.ig.Emit (OpCodes.Cgt_Un);
2881 ig.Emit (OpCodes.Brtrue, load_one);
2882 ig.MarkLabel (load_zero);
2883 ig.Emit (OpCodes.Ldc_I4_0);
2884 ig.Emit (OpCodes.Br, end);
2885 ig.MarkLabel (load_one);
2886 ig.Emit (OpCodes.Ldc_I4_1);
2895 case Operator.Multiply:
2897 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2898 opcode = OpCodes.Mul_Ovf;
2899 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2900 opcode = OpCodes.Mul_Ovf_Un;
2902 opcode = OpCodes.Mul;
2904 opcode = OpCodes.Mul;
2908 case Operator.Division:
2909 case Operator.IntDivision:
2910 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2911 opcode = OpCodes.Div_Un;
2913 opcode = OpCodes.Div;
2916 case Operator.Modulus:
2917 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2918 opcode = OpCodes.Rem_Un;
2920 opcode = OpCodes.Rem;
2923 case Operator.Addition:
2925 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2926 opcode = OpCodes.Add_Ovf;
2927 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2928 opcode = OpCodes.Add_Ovf_Un;
2930 opcode = OpCodes.Add;
2932 opcode = OpCodes.Add;
2935 case Operator.Subtraction:
2937 if (l == TypeManager.int32_type || l == TypeManager.int64_type)
2938 opcode = OpCodes.Sub_Ovf;
2939 else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
2940 opcode = OpCodes.Sub_Ovf_Un;
2942 opcode = OpCodes.Sub;
2944 opcode = OpCodes.Sub;
2947 case Operator.RightShift:
2948 if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
2949 opcode = OpCodes.Shr_Un;
2951 opcode = OpCodes.Shr;
2954 case Operator.LeftShift:
2955 opcode = OpCodes.Shl;
2958 case Operator.Equality:
2960 opcode = OpCodes.Ceq;
2963 case Operator.Inequality:
2964 ec.ig.Emit (OpCodes.Ceq);
2965 ec.ig.Emit (OpCodes.Ldc_I4_0);
2967 opcode = OpCodes.Ceq;
2970 case Operator.LessThan:
2971 opcode = OpCodes.Clt;
2974 case Operator.GreaterThan:
2975 opcode = OpCodes.Cgt;
2978 case Operator.LessThanOrEqual:
2979 ec.ig.Emit (OpCodes.Cgt);
2980 ec.ig.Emit (OpCodes.Ldc_I4_0);
2982 opcode = OpCodes.Ceq;
2985 case Operator.GreaterThanOrEqual:
2986 ec.ig.Emit (OpCodes.Clt);
2987 ec.ig.Emit (OpCodes.Ldc_I4_1);
2989 opcode = OpCodes.Sub;
2992 case Operator.BitwiseOr:
2993 opcode = OpCodes.Or;
2996 case Operator.BitwiseAnd:
2997 opcode = OpCodes.And;
3000 case Operator.ExclusiveOr:
3001 opcode = OpCodes.Xor;
3005 throw new Exception ("This should not happen: Operator = "
3006 + oper.ToString ());
3012 public bool IsBuiltinOperator {
3014 return method == null;
3019 public class PointerArithmetic : Expression {
3020 Expression left, right;
3024 // We assume that 'l' is always a pointer
3026 public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
3030 eclass = ExprClass.Variable;
3034 is_add = is_addition;
3037 public override Expression DoResolve (EmitContext ec)
3040 // We are born fully resolved
3045 public override void Emit (EmitContext ec)
3047 Type op_type = left.Type;
3048 ILGenerator ig = ec.ig;
3049 int size = GetTypeSize (op_type.GetElementType ());
3051 if (right.Type.IsPointer){
3053 // handle (pointer - pointer)
3057 ig.Emit (OpCodes.Sub);
3061 ig.Emit (OpCodes.Sizeof, op_type);
3063 IntLiteral.EmitInt (ig, size);
3064 ig.Emit (OpCodes.Div);
3066 ig.Emit (OpCodes.Conv_I8);
3069 // handle + and - on (pointer op int)
3072 ig.Emit (OpCodes.Conv_I);
3076 ig.Emit (OpCodes.Sizeof, op_type);
3078 IntLiteral.EmitInt (ig, size);
3079 ig.Emit (OpCodes.Mul);
3082 ig.Emit (OpCodes.Add);
3084 ig.Emit (OpCodes.Sub);
3090 /// Implements the ternary conditional operator (?:)
3092 public class Conditional : Expression {
3093 Expression expr, trueExpr, falseExpr;
3095 public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
3098 this.trueExpr = trueExpr;
3099 this.falseExpr = falseExpr;
3103 public Expression Expr {
3109 public Expression TrueExpr {
3115 public Expression FalseExpr {
3121 public override Expression DoResolve (EmitContext ec)
3123 expr = expr.Resolve (ec);
3128 if (expr.Type != TypeManager.bool_type)
3129 expr = Expression.ConvertImplicitRequired (
3130 ec, expr, TypeManager.bool_type, loc);
3132 trueExpr = trueExpr.Resolve (ec);
3133 falseExpr = falseExpr.Resolve (ec);
3135 if (trueExpr == null || falseExpr == null)
3138 eclass = ExprClass.Value;
3139 if (trueExpr.Type == falseExpr.Type)
3140 type = trueExpr.Type;
3143 Type true_type = trueExpr.Type;
3144 Type false_type = falseExpr.Type;
3146 if (trueExpr is NullLiteral){
3149 } else if (falseExpr is NullLiteral){
3155 // First, if an implicit conversion exists from trueExpr
3156 // to falseExpr, then the result type is of type falseExpr.Type
3158 conv = ConvertImplicit (ec, trueExpr, false_type, loc);
3161 // Check if both can convert implicitl to each other's type
3163 if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
3165 "Can not compute type of conditional expression " +
3166 "as '" + TypeManager.MonoBASIC_Name (trueExpr.Type) +
3167 "' and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) +
3168 "' convert implicitly to each other");
3173 } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
3177 Error (173, "The type of the conditional expression can " +
3178 "not be computed because there is no implicit conversion" +
3179 " from '" + TypeManager.MonoBASIC_Name (trueExpr.Type) + "'" +
3180 " and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) + "'");
3185 if (expr is BoolConstant){
3186 BoolConstant bc = (BoolConstant) expr;
3197 public override void Emit (EmitContext ec)
3199 ILGenerator ig = ec.ig;
3200 Label false_target = ig.DefineLabel ();
3201 Label end_target = ig.DefineLabel ();
3203 Statement.EmitBoolExpression (ec, expr, false_target, false);
3205 ig.Emit (OpCodes.Br, end_target);
3206 ig.MarkLabel (false_target);
3207 falseExpr.Emit (ec);
3208 ig.MarkLabel (end_target);
3216 public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3217 public readonly string Name;
3218 public readonly Block Block;
3219 VariableInfo variable_info;
3222 public LocalVariableReference (Block block, string name, Location l)
3227 eclass = ExprClass.Variable;
3230 // Setting 'is_readonly' to false will allow you to create a writable
3231 // reference to a read-only variable. This is used by foreach and using.
3232 public LocalVariableReference (Block block, string name, Location l,
3233 VariableInfo variable_info, bool is_readonly)
3234 : this (block, name, l)
3236 this.variable_info = variable_info;
3237 this.is_readonly = is_readonly;
3240 public VariableInfo VariableInfo {
3242 if (variable_info == null) {
3243 variable_info = Block.GetVariableInfo (Name);
3244 is_readonly = variable_info.ReadOnly;
3246 return variable_info;
3250 public bool IsAssigned (EmitContext ec, Location loc)
3252 return VariableInfo.IsAssigned (ec, loc);
3255 public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
3257 return VariableInfo.IsFieldAssigned (ec, name, loc);
3260 public void SetAssigned (EmitContext ec)
3262 VariableInfo.SetAssigned (ec);
3265 public void SetFieldAssigned (EmitContext ec, string name)
3267 VariableInfo.SetFieldAssigned (ec, name);
3270 public bool IsReadOnly {
3272 if (variable_info == null) {
3273 variable_info = Block.GetVariableInfo (Name);
3274 is_readonly = variable_info.ReadOnly;
3280 public override Expression DoResolve (EmitContext ec)
3282 VariableInfo vi = VariableInfo;
3284 if (Block.IsConstant (Name)) {
3285 Expression e = Block.GetConstantExpression (Name);
3291 if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3294 type = vi.VariableType;
3298 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3300 VariableInfo vi = VariableInfo;
3302 if (ec.DoFlowAnalysis)
3303 ec.SetVariableAssigned (vi);
3305 Expression e = DoResolve (ec);
3311 Error (1604, "cannot assign to '" + Name + "' because it is readonly");
3318 public override void Emit (EmitContext ec)
3320 VariableInfo vi = VariableInfo;
3321 ILGenerator ig = ec.ig;
3323 ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
3327 public void EmitAssign (EmitContext ec, Expression source)
3329 ILGenerator ig = ec.ig;
3330 VariableInfo vi = VariableInfo;
3336 ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
3339 public void AddressOf (EmitContext ec, AddressOp mode)
3341 VariableInfo vi = VariableInfo;
3343 ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
3348 /// This represents a reference to a parameter in the intermediate
3351 public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
3355 public Parameter.Modifier mod;
3356 public bool is_ref, is_out;
3358 public ParameterReference (Parameters pars, int idx, string name, Location loc)
3364 eclass = ExprClass.Variable;
3367 public bool IsAssigned (EmitContext ec, Location loc)
3369 if (!is_out || !ec.DoFlowAnalysis)
3372 if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
3373 Report.Error (165, loc,
3374 "Use of unassigned local variable '" + name + "'");
3381 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
3383 if (!is_out || !ec.DoFlowAnalysis)
3386 if (ec.CurrentBranching.IsParameterAssigned (idx))
3389 if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
3390 Report.Error (170, loc,
3391 "Use of possibly unassigned field '" + field_name + "'");
3398 public void SetAssigned (EmitContext ec)
3400 if (is_out && ec.DoFlowAnalysis)
3401 ec.CurrentBranching.SetParameterAssigned (idx);
3404 public void SetFieldAssigned (EmitContext ec, string field_name)
3406 if (is_out && ec.DoFlowAnalysis)
3407 ec.CurrentBranching.SetParameterAssigned (idx, field_name);
3411 // Notice that for ref/out parameters, the type exposed is not the
3412 // same type exposed externally.
3415 // externally we expose "int&"
3416 // here we expose "int".
3418 // We record this in "is_ref". This means that the type system can treat
3419 // the type as it is expected, but when we generate the code, we generate
3420 // the alternate kind of code.
3422 public override Expression DoResolve (EmitContext ec)
3424 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3425 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3426 // is_out = (mod & Parameter.Modifier.OUT) != 0;
3427 eclass = ExprClass.Variable;
3429 /* if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
3435 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
3437 type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
3438 is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
3439 // is_out = (mod & Parameter.Modifier.OUT) != 0;
3440 eclass = ExprClass.Variable;
3442 if (is_out && ec.DoFlowAnalysis)
3443 ec.SetParameterAssigned (idx);
3448 static void EmitLdArg (ILGenerator ig, int x)
3452 case 0: ig.Emit (OpCodes.Ldarg_0); break;
3453 case 1: ig.Emit (OpCodes.Ldarg_1); break;
3454 case 2: ig.Emit (OpCodes.Ldarg_2); break;
3455 case 3: ig.Emit (OpCodes.Ldarg_3); break;
3456 default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
3459 ig.Emit (OpCodes.Ldarg, x);
3463 // This method is used by parameters that are references, that are
3464 // being passed as references: we only want to pass the pointer (that
3465 // is already stored in the parameter, not the address of the pointer,
3466 // and not the value of the variable).
3468 public void EmitLoad (EmitContext ec)
3470 ILGenerator ig = ec.ig;
3476 EmitLdArg (ig, arg_idx);
3479 public override void Emit (EmitContext ec)
3481 ILGenerator ig = ec.ig;
3487 EmitLdArg (ig, arg_idx);
3493 // If we are a reference, we loaded on the stack a pointer
3494 // Now lets load the real value
3496 LoadFromPtr (ig, type);
3499 public void EmitAssign (EmitContext ec, Expression source)
3501 ILGenerator ig = ec.ig;
3508 EmitLdArg (ig, arg_idx);
3513 StoreFromPtr (ig, type);
3516 ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
3518 ig.Emit (OpCodes.Starg, arg_idx);
3522 public void AddressOf (EmitContext ec, AddressOp mode)
3531 ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
3533 ec.ig.Emit (OpCodes.Ldarg, arg_idx);
3536 ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
3538 ec.ig.Emit (OpCodes.Ldarga, arg_idx);
3545 /// Invocation of methods or delegates.
3547 public class Invocation : ExpressionStatement {
3548 public ArrayList Arguments;
3550 public Expression expr;
3551 MethodBase method = null;
3553 bool is_latebinding;
3554 bool is_left_hand; // Needed for late bound calls
3555 bool is_retval_required; // Needed for late bound calls
3556 static Hashtable method_parameter_cache;
3557 static MemberFilter CompareName;
3559 static ArrayList tempvars; // For ByRef - different parameter and argument type
3560 static bool is_byref_conversion = false; //For ByRef when it is converted
3561 static string errorMsg = "";
3563 static Invocation ()
3565 method_parameter_cache = new PtrHashtable ();
3569 // arguments is an ArrayList, but we do not want to typecast,
3570 // as it might be null.
3572 // FIXME: only allow expr to be a method invocation or a
3573 // delegate invocation (7.5.5)
3575 public Invocation (Expression expr, ArrayList arguments, Location l)
3578 if (this.expr is MemberAccess) {
3579 ((MemberAccess) this.expr).IsInvocation = true;
3581 this.is_retval_required = false;
3582 this.is_left_hand = false;
3583 Arguments = arguments;
3585 CompareName = new MemberFilter (compare_name_filter);
3588 public Expression Expr {
3594 public bool IsLeftHand {
3596 return is_left_hand;
3599 is_left_hand = value;
3603 public bool IsRetvalRequired {
3605 return is_retval_required;
3608 is_retval_required = value;
3612 public bool IsLateBinding {
3614 return is_latebinding;
3617 is_latebinding = value;
3622 /// Returns the Parameters (a ParameterData interface) for the
3625 public static ParameterData GetParameterData (MethodBase mb)
3627 object pd = method_parameter_cache [mb];
3631 return (ParameterData) pd;
3634 ip = TypeManager.LookupParametersByBuilder (mb);
3636 method_parameter_cache [mb] = ip;
3638 return (ParameterData) ip;
3640 ParameterInfo [] pi = mb.GetParameters ();
3642 ReflectionParameters rp = new ReflectionParameters (pi);
3643 method_parameter_cache [mb] = rp;
3645 return (ParameterData) rp;
3649 enum Applicability { Same, Better, Worse };
3652 /// Determines "Better function"
3655 /// and returns an integer indicating :
3656 /// 0 if candidate ain't better
3657 /// 1 if candidate is better than the current best match
3659 static Applicability BetterFunction (EmitContext ec, ArrayList args,
3660 MethodBase candidate, MethodBase best,
3661 bool expanded_form, Location loc)
3663 ParameterData candidate_pd = GetParameterData (candidate);
3664 ParameterData best_pd;
3670 argument_count = args.Count;
3672 int cand_count = candidate_pd.Count;
3674 if (cand_count == 0 && argument_count == 0)
3675 return Applicability.Same;
3677 if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
3678 if (cand_count != argument_count)
3679 return Applicability.Worse;
3681 best_pd = GetParameterData (best);
3683 Applicability res = Applicability.Same;
3685 for (int j = 0; j < argument_count; ++j) {
3687 //Argument a = (Argument) args [j];
3689 Type ct = candidate_pd.ParameterType (j);
3690 Type bt = best_pd.ParameterType (j);
3692 if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3694 ct = ct.GetElementType ();
3696 if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
3698 bt = bt.GetElementType ();
3701 if (!WideningConversionExists (ct, bt))
3702 return Applicability.Worse;
3703 res = Applicability.Better;
3707 if (res == Applicability.Same)
3708 if (candidate_pd.Count < best_pd.Count)
3709 res = Applicability.Better;
3710 else if (candidate_pd.Count > best_pd.Count)
3711 res = Applicability.Worse;
3716 public static string FullMethodDesc (MethodBase mb)
3718 string ret_type = "";
3720 if (mb is MethodInfo)
3721 ret_type = TypeManager.MonoBASIC_Name (((MethodInfo) mb).ReturnType) + " ";
3723 StringBuilder sb = new StringBuilder (ret_type + mb.Name);
3724 ParameterData pd = GetParameterData (mb);
3726 int count = pd.Count;
3729 for (int i = count; i > 0; ) {
3732 sb.Append (pd.ParameterDesc (count - i - 1));
3738 return sb.ToString ();
3741 public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
3743 MemberInfo [] miset;
3744 MethodGroupExpr union;
3749 return (MethodGroupExpr) mg2;
3752 return (MethodGroupExpr) mg1;
3755 MethodGroupExpr left_set = null, right_set = null;
3756 int length1 = 0, length2 = 0;
3758 left_set = (MethodGroupExpr) mg1;
3759 length1 = left_set.Methods.Length;
3761 right_set = (MethodGroupExpr) mg2;
3762 length2 = right_set.Methods.Length;
3764 ArrayList common = new ArrayList ();
3766 foreach (MethodBase l in left_set.Methods){
3767 foreach (MethodBase r in right_set.Methods){
3775 miset = new MemberInfo [length1 + length2 - common.Count];
3776 left_set.Methods.CopyTo (miset, 0);
3780 foreach (MemberInfo mi in right_set.Methods){
3781 if (!common.Contains (mi))
3785 union = new MethodGroupExpr (miset, loc);
3791 protected enum ConversionType { None, Widening, Narrowing };
3793 static ConversionType CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
3795 if (a.ArgType == Argument.AType.NoArg) {
3796 return ConversionType.Widening;
3799 Parameter.Modifier a_mod = a.GetParameterModifier () &
3800 ~(Parameter.Modifier.REF);
3801 Parameter.Modifier p_mod = pd.ParameterModifier (i) &
3802 ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
3804 if (a_mod == p_mod ||
3805 (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
3806 // if (a_mod == Parameter.Modifier.NONE) {
3807 if (! WideningConversionExists (a.Expr, ptype) ) {
3809 if (! NarrowingConversionExists (ec, a.Expr, ptype) )
3810 return ConversionType.None;
3812 return ConversionType.Narrowing;
3814 return ConversionType.Widening;
3817 if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
3818 Type pt = pd.ParameterType (i);
3821 pt = TypeManager.LookupType (pt.FullName + "&");
3824 return ConversionType.None;
3826 return ConversionType.Widening;
3828 return ConversionType.None;
3831 static bool HasArrayParameter (ParameterData pd)
3834 return c > 0 && (pd.ParameterModifier (c - 1) & Parameter.Modifier.PARAMS) != 0;
3837 static int CountStandardParams (ParameterData pd)
3839 int count = pd.Count;
3840 for (int i = 0; i < count; i++) {
3841 Parameter.Modifier pm = pd.ParameterModifier (i);
3842 if ((pm & (Parameter.Modifier.OPTIONAL | Parameter.Modifier.PARAMS)) != 0)
3849 /// Determines if the candidate method is applicable (section 14.4.2.1)
3850 /// to the given set of arguments
3852 static ConversionType IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate, out bool expanded)
3859 if (arguments == null)
3862 arg_count = arguments.Count;
3864 ParameterData pd = GetParameterData (candidate);
3865 int ps_count = CountStandardParams (pd);
3866 int pd_count = pd.Count;
3868 // Validate argument count
3869 if (ps_count == pd_count) {
3870 if (arg_count != pd_count)
3871 return ConversionType.None;
3874 if (arg_count < ps_count)
3875 return ConversionType.None;
3876 if (!HasArrayParameter (pd) && arg_count > pd_count)
3877 return ConversionType.None;
3880 ConversionType result = ConversionType.Widening;
3881 if (arg_count > 0) {
3882 result = ConversionType.None;
3883 int array_param_index = -1;
3884 for (int i = 0; i < arg_count; ++i) {
3885 Argument a = (Argument) arguments [i];
3886 param_type = pd.ParameterType (i);
3887 Parameter.Modifier mod = pd.ParameterModifier (i);
3888 if (array_param_index < 0 && (mod & Parameter.Modifier.PARAMS) != 0)
3889 array_param_index = i;
3891 bool IsDelegate = TypeManager.IsDelegateType (param_type);
3894 if (a.ArgType == Argument.AType.AddressOf) {
3895 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
3896 ArrayList args = new ArrayList();
3898 string param_name = pd.ParameterDesc(i).Replace('+', '.');
3899 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
3901 New temp_new = new New ((Expression)pname, args, Location.Null);
3902 Expression del_temp = temp_new.DoResolve(ec);
3904 if (del_temp == null)
3905 return ConversionType.None;
3907 a = new Argument (del_temp, Argument.AType.Expression);
3908 if (!a.Resolve(ec, Location.Null))
3909 return ConversionType.None;
3913 if (a.ArgType == Argument.AType.AddressOf)
3914 return ConversionType.None;
3917 if (a.ArgType != Argument.AType.NoArg && (mod & Parameter.Modifier.REF) != 0) {
3918 a = new Argument (a.Expr, Argument.AType.Ref);
3919 if (!a.Resolve(ec,Location.Null))
3920 return ConversionType.None;
3923 ConversionType match = ConversionType.None;
3924 if (i == array_param_index)
3925 match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
3926 if (match == ConversionType.None && array_param_index >= 0 && i >= array_param_index) {
3928 param_type = param_type.GetElementType ();
3930 if (match == ConversionType.None)
3931 match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
3932 if (match == ConversionType.None)
3933 return ConversionType.None;
3934 if (result == ConversionType.None)
3936 else if (match == ConversionType.Narrowing)
3937 result = ConversionType.Narrowing;
3944 internal static ArrayList ReorderArguments (MethodBase mb,
3945 ArrayList Arguments,
3946 CaseInsensitiveHashtable namedArgs,
3950 ArrayList orderedArgs = new ArrayList ();
3951 ParameterData pd = GetParameterData (mb);
3953 for (int index = 0; index < pd.Count; index ++) {
3954 string paramName = pd.ParameterName (index);
3955 if (namedArgs.Contains (paramName)) {
3956 if ((pd.ParameterModifier (index) & Parameter.Modifier.PARAMS) == Parameter.Modifier.PARAMS) {
3958 ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': Named argument cannot match a ParamArray parameter";
3961 int argIndex = (int) namedArgs [paramName];
3962 orderedArgs.Add (Arguments [argIndex]);
3964 Parameter.Modifier p_mod = pd.ParameterModifier (index) & Parameter.Modifier.OPTIONAL;
3965 if (p_mod == Parameter.Modifier.OPTIONAL)
3966 orderedArgs.Add (new Argument (pd.ParameterName (index), new EmptyExpression (), Argument.AType.NoArg));
3969 ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': Argument not specified for parameter '" + paramName + "'";
3974 if (Arguments.Count > orderedArgs.Count) {
3975 for (int argIndex = 0; argIndex < Arguments.Count; argIndex ++) {
3976 string argName = ((Argument) Arguments [argIndex]).ParamName;
3978 for (int paramIndex = 0; paramIndex < pd.Count; paramIndex ++) {
3979 string paramName = pd.ParameterName (paramIndex);
3980 if (String.Compare (argName, paramName, true) == 0) {
3987 ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': '" + argName + "' is not a parameter";
3996 static bool compare_name_filter (MemberInfo m, object filterCriteria)
3998 return (m.Name == ((string) filterCriteria));
4001 // We need an overload for OverloadResolve because Invocation.DoResolve
4002 // must pass Arguments by reference, since a later call to IsApplicable
4003 // can change the argument list if optional parameters are defined
4004 // in the method declaration
4005 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4006 ArrayList Arguments, Location loc)
4008 ArrayList a = Arguments;
4009 return OverloadResolve (ec, me, ref a, loc);
4012 static string ToString(MethodBase mbase)
4017 if (mbase is MethodBuilder)
4019 MethodBuilder mb = (MethodBuilder) mbase;
4020 String res = mb.ReturnType + " (";
4021 ParameterInfo [] parms = mb.GetParameters();
4022 for (int i = 0; i < parms.Length; i++) {
4025 res += parms[i].ParameterType;
4031 return mbase.ToString();
4035 /// Find the Applicable Function Members (7.4.2.1)
4037 /// me: Method Group expression with the members to select.
4038 /// it might contain constructors or methods (or anything
4039 /// that maps to a method).
4041 /// Arguments: ArrayList containing resolved Argument objects.
4043 /// loc: The location if we want an error to be reported, or a Null
4044 /// location for "probing" purposes.
4046 /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
4047 /// that is the best match of me on Arguments.
4050 public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
4051 ref ArrayList Arguments, Location loc)
4053 MethodBase method = null;
4055 ArrayList candidates = new ArrayList ();
4056 Hashtable expanded_candidates = new Hashtable();
4057 int narrow_count = 0;
4058 bool narrowing_candidate = false;
4060 CaseInsensitiveHashtable namedArgs = new CaseInsensitiveHashtable ();
4062 if (Arguments == null)
4065 argument_count = Arguments.Count;
4067 if (!CheckNamedArguments (Arguments, loc))
4070 if (!GetNamedArgPos (Arguments, ref namedArgs, loc))
4073 ArrayList newarglist = Arguments;
4074 foreach (MethodBase candidate in me.Methods){
4075 bool candidate_expanded;
4076 newarglist = Arguments;
4077 if (argument_count > 0 && namedArgs.Count != 0) {
4078 newarglist = ReorderArguments (candidate, Arguments, namedArgs, ref errorMsg, loc);
4079 if (newarglist == null)
4083 ConversionType m = IsApplicable (ec, newarglist, candidate, out candidate_expanded);
4084 if (candidate_expanded)
4085 expanded_candidates [candidate] = candidate;
4086 if (m == ConversionType.None)
4088 else if (m == ConversionType.Narrowing) {
4089 if (method == null) {
4091 narrowing_candidate = true;
4094 } else if (m == ConversionType.Widening) {
4095 if (method == null || narrowing_candidate) {
4097 narrowing_candidate = false;
4099 Applicability res = BetterFunction (ec, Arguments, candidate, method, true, loc);
4100 if (res == Applicability.Same)
4101 continue; // should check it overrides?
4102 if (res == Applicability.Better)
4105 candidates.Add (candidate);
4109 if (candidates.Count == 0) {
4110 if (narrow_count > 1)
4112 else if (narrow_count == 1)
4114 } else if (candidates.Count == 1) {
4115 method = (MethodBase)candidates [0];
4120 if (method == null) {
4122 // Okay so we have failed to find anything so we
4123 // return by providing info about the closest match
4125 for (int i = 0; i < me.Methods.Length; ++i) {
4127 MethodBase c = (MethodBase) me.Methods [i];
4128 ParameterData pd = GetParameterData (c);
4130 if (pd.Count != argument_count)
4134 if (narrow_count != 0) {
4135 if (IsApplicable (ec, Arguments, c, out dummy) == ConversionType.None)
4137 Report.Error (1502, loc,
4138 "Overloaded match for method '" +
4139 FullMethodDesc (c) +
4140 "' requires narrowing conversionss");
4143 VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
4151 // Now check that there are no ambiguities i.e the selected method
4152 // should be better than all the others
4155 if (candidates != null) {
4156 foreach (MethodBase candidate in candidates){
4157 if (candidate == method)
4161 if (BetterFunction (ec, Arguments, candidate, method,
4162 false, loc) == Applicability.Better) {
4165 "Ambiguous call of '" + me.Name + "' when selecting function due to implicit casts");
4172 // And now check if the arguments are all compatible, perform conversions
4173 // if necessary etc. and return if everything is all right
4178 bool chose_params_expanded = expanded_candidates.Contains (method);
4180 newarglist = Arguments;
4181 if (argument_count > 0 && namedArgs.Count != 0) {
4183 newarglist = ReorderArguments (method, Arguments, namedArgs, ref err, loc);
4184 if (newarglist == null)
4188 Arguments = ConstructArgumentList(ec, newarglist, namedArgs, method);
4189 if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
4190 chose_params_expanded, null, loc))
4198 internal static bool CheckNamedArguments (ArrayList Arguments, Location loc)
4200 if (Arguments == null || Arguments.Count == 0)
4203 bool namedArgFound = false;
4204 for (int index = 0; index < Arguments.Count; index ++) {
4205 Argument a = (Argument) Arguments [index];
4206 if (a.ParamName == null || a.ParamName == "") {
4207 if (namedArgFound) {
4208 Report.Error (30241, loc,
4209 "Named argument expected");
4213 namedArgFound = true;
4219 internal static bool GetNamedArgPos (ArrayList Arguments, ref CaseInsensitiveHashtable namedArgs, Location loc)
4222 if (Arguments == null || Arguments.Count == 0)
4224 for (int index = 0; index < Arguments.Count; index ++) {
4225 Argument a = (Argument) Arguments [index];
4226 if (a.ParamName == null || a.ParamName == "")
4227 // none of the args are named
4229 if (namedArgs.Contains (a.ParamName)) {
4230 Report.Error (30274, loc, "Parameter '" + a.ParamName +"'already has a matching argument");
4233 namedArgs.Add (a.ParamName, index);
4238 public static ArrayList ConstructArgumentList (EmitContext ec, ArrayList Arguments, CaseInsensitiveHashtable namedArgs, MethodBase method)
4240 ArrayList newarglist = new ArrayList();
4241 int arg_count = Arguments == null ? 0 : Arguments.Count;
4243 ParameterData pd = GetParameterData (method);
4244 bool argNamesGiven = (namedArgs.Count > 0);
4245 for (int i = 0; i < arg_count; i++) {
4246 Argument a = (Argument) Arguments [i];
4247 Type param_type = pd.ParameterType (i);
4249 bool IsDelegate = TypeManager.IsDelegateType (param_type);
4250 if (a.ArgType == Argument.AType.NoArg) {
4252 a = new Argument (pd.ParameterName (i), pd.DefaultValue (i), Argument.AType.Expression);
4254 a = new Argument (pd.DefaultValue (i), Argument.AType.Expression);
4255 a.Resolve (ec, Location.Null);
4259 if (a.ArgType == Argument.AType.AddressOf) {
4260 a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
4261 ArrayList args = new ArrayList();
4263 string param_name = pd.ParameterDesc(i).Replace('+', '.');
4264 Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
4266 New temp_new = new New ((Expression)pname, args, Location.Null);
4267 Expression del_temp = temp_new.DoResolve(ec);
4268 a = new Argument (del_temp, Argument.AType.Expression);
4269 a.Resolve(ec, Location.Null);
4272 if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0) {
4273 a.ArgType = Argument.AType.Ref;
4274 a.Resolve(ec, Location.Null);
4280 if (HasArrayParameter (pd) && arg_count == pd.Count - 1)
4283 for (int i = arg_count; i < pd.Count; i++) {
4284 Expression e = pd.DefaultValue (i);
4287 a = new Argument (e, Argument.AType.Expression);
4289 a = new Argument (pd.ParameterName (i), e, Argument.AType.Expression);
4290 if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0)
4291 a.ArgType = Argument.AType.Ref;
4293 a.Resolve (ec, Location.Null);
4300 public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
4303 bool chose_params_expanded,
4307 return (VerifyArgumentsCompat (ec, Arguments, argument_count,
4308 method, chose_params_expanded, delegate_type, loc, null));
4311 public static bool VerifyArgumentsCompat (EmitContext ec,
4312 ArrayList Arguments,
4315 bool chose_params_expanded,
4318 string InvokingProperty)
4320 ParameterData pd = GetParameterData (method);
4321 int pd_count = pd.Count;
4323 for (int j = 0; j < argument_count; j++) {
4324 Argument a = (Argument) Arguments [j];
4325 Expression a_expr = a.Expr;
4326 Type parameter_type = pd.ParameterType(j);
4328 if (parameter_type == null)
4330 Error_WrongNumArguments(loc, (InvokingProperty == null)?((delegate_type == null)?FullMethodDesc (method):delegate_type.ToString ()):InvokingProperty, argument_count);
4333 if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
4334 chose_params_expanded)
4335 parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
4336 // By pass conversion for foll. case and handle it in EmitArguments()
4338 if (a.ArgType != Argument.AType.Ref && a.Type != parameter_type){
4341 conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
4344 if (!Location.IsNull (loc)) {
4345 if (delegate_type == null)
4346 if (InvokingProperty == null)
4347 Report.Error (1502, loc,
4348 "The best overloaded match for method '" +
4349 FullMethodDesc (method) +
4350 "' has some invalid arguments");
4352 Report.Error (1502, loc,
4355 "' has some invalid arguments");
4357 Report.Error (1594, loc,
4358 "Delegate '" + delegate_type.ToString () +
4359 "' has some invalid arguments.");
4360 Report.Error (1503, loc,
4361 "Argument " + (j+1) +
4362 ": Cannot convert from '" + Argument.FullDesc (a)
4363 + "' to '" + pd.ParameterDesc (j) + "'");
4370 // Update the argument with the implicit conversion
4376 Parameter.Modifier a_mod = a.GetParameterModifier () &
4377 ~(Parameter.Modifier.REF);
4378 Parameter.Modifier p_mod = pd.ParameterModifier (j) &
4379 ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
4381 if (a_mod != p_mod &&
4382 pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
4383 if (!Location.IsNull (loc)) {
4384 Report.Error (1502, loc,
4385 "The best overloaded match for method '" + FullMethodDesc (method)+
4386 "' has some invalid arguments");
4387 Report.Error (1503, loc,
4388 "Argument " + (j+1) +
4389 ": Cannot convert from '" + Argument.FullDesc (a)
4390 + "' to '" + pd.ParameterDesc (j) + "'");
4400 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
4402 this.is_left_hand = true;
4403 Expression expr_to_return = DoResolve (ec);
4405 if (expr_to_return is IndexerAccess) {
4406 IndexerAccess ia = expr_to_return as IndexerAccess;
4407 expr_to_return = ia.DoResolveLValue (ec, right_side);
4409 return expr_to_return;
4412 public override Expression DoResolve (EmitContext ec)
4415 // First, resolve the expression that is used to
4416 // trigger the invocation
4418 Expression expr_to_return = null;
4419 Expression temp = null;
4421 if (expr is BaseAccess)
4425 if ((ec.ReturnType != null) && (expr.ToString() == ec.BlockName)) {
4426 ec.InvokingOwnOverload = true;
4427 flags = ResolveFlags.MethodGroup;
4428 temp = expr.Resolve (ec, flags);
4429 ec.InvokingOwnOverload = false;
4433 ec.InvokingOwnOverload = false;
4434 flags = ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup;
4435 temp = expr.Resolve (ec, flags);
4442 if (expr is MemberAccess) {
4443 MemberAccess m = expr as MemberAccess;
4444 if (m.Expr.Type == TypeManager.object_type) {
4445 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4446 loc, expr, Arguments,
4447 is_retval_required, is_left_hand);
4448 if (!etmp.ResolveArguments (ec))
4450 etmp.GenerateLateBindingStatements();
4451 this.is_latebinding = true;
4452 return etmp.Resolve (ec);
4460 if (expr is Invocation) {
4461 // FIXME Calls which return an Array are not resolved (here or in the grammar)
4462 expr = expr.Resolve(ec);
4465 if (!(expr is MethodGroupExpr))
4467 Type expr_type = expr.Type;
4469 if (expr_type != null)
4471 bool IsDelegate = TypeManager.IsDelegateType (expr_type);
4473 return (new DelegateInvocation (
4474 this.expr, Arguments, loc)).Resolve (ec);
4479 // Next, evaluate all the expressions in the argument list
4481 if (Arguments != null)
4483 foreach (Argument a in Arguments)
4485 if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
4486 Report.Error (999, "This item cannot have empty arguments");
4488 if (!a.Resolve (ec, loc))
4493 if (expr is MethodGroupExpr)
4495 MethodGroupExpr mg = (MethodGroupExpr) expr;
4496 method = OverloadResolve (ec, mg, ref Arguments, loc);
4500 "Could not find any applicable function to invoke for this argument list" + errorMsg);
4504 if ((method as MethodInfo) != null)
4506 MethodInfo mi = method as MethodInfo;
4507 type = TypeManager.TypeToCoreType (mi.ReturnType);
4508 if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4509 SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
4512 if ((method as ConstructorInfo) != null)
4514 ConstructorInfo ci = method as ConstructorInfo;
4515 type = TypeManager.void_type;
4516 if (!ci.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
4517 SimpleName.Error_ObjectRefRequired (ec, loc, ci.Name);
4528 eclass = ExprClass.Value;
4529 expr_to_return = this;
4530 return expr_to_return;
4533 if (expr is PropertyExpr)
4535 PropertyExpr pe = ((PropertyExpr) expr);
4536 if (pe.PropertyArgs != null)
4537 goto skip_already_resolved_property;
4538 pe.PropertyArgs = (ArrayList) Arguments;
4539 MethodBase mi = pe.PropertyInfo.GetGetMethod(true);
4541 bool expanded = false;
4542 if (IsApplicable(ec, pe.PropertyArgs, mi, out expanded) != ConversionType.None) {
4543 if(VerifyArgumentsCompat (ec, pe.PropertyArgs,
4544 pe.PropertyArgs.Count, mi, expanded, null, loc, pe.Name))
4546 expr_to_return = pe.DoResolve (ec);
4547 expr_to_return.eclass = ExprClass.PropertyAccess;
4548 Arguments = new ArrayList ();
4549 return expr_to_return;
4553 throw new Exception("Error resolving Property Access expression\n" + pe.ToString());
4556 pe.PropertyArgs = new ArrayList ();
4557 if (VerifyArgumentsCompat (ec, pe.PropertyArgs,
4558 0, mi, false, null, loc, pe.Name)) {
4559 expr = pe.DoResolve (ec);
4560 expr.eclass = ExprClass.PropertyAccess;
4562 throw new Exception("Error resolving Property Access expression\n" + pe.ToString());
4567 skip_already_resolved_property:
4568 if (expr.Type.IsArray) {
4569 // If we are here, expr must be an ArrayAccess
4570 ArrayList idxs = new ArrayList();
4571 foreach (Argument a in Arguments)
4575 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
4576 ArrayAccess aa = new ArrayAccess (ea, expr.Location);
4577 expr_to_return = aa.DoResolve(ec);
4578 expr_to_return.eclass = ExprClass.Variable;
4581 // check whether this is a indexer
4583 ArrayList idxs = new ArrayList();
4584 foreach (Argument a in Arguments) {
4587 ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
4588 IndexerAccess ia = new IndexerAccess (ea, expr.Location);
4590 expr_to_return = ia.DoResolve(ec);
4592 expr_to_return = ia.DoResolve(ec);
4594 // Since all the above are failed we need to do
4597 if (expr_to_return == null) {
4599 // We can't resolve now, but we
4600 // have to try to access the array with a call
4601 // to LateIndexGet/Set in the runtime
4602 if (! is_left_hand) {
4603 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
4606 if (!etmp.ResolveArguments (ec))
4608 etmp.GenerateLateBindingStatements();
4609 return etmp.Resolve (ec);
4615 return expr_to_return;
4618 static void Error_WrongNumArguments (Location loc, String name, int arg_count)
4620 Report.Error (1501, loc, "No overload for method `" + name + "' takes `" +
4621 arg_count + "' arguments");
4625 // Emits the list of arguments as an array
4627 static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
4629 ILGenerator ig = ec.ig;
4630 int count = arguments.Count - idx;
4631 Argument a = (Argument) arguments [idx];
4632 Type t = a.Expr.Type;
4633 string array_type = t.FullName + "[]";
4636 array = ig.DeclareLocal (TypeManager.LookupType (array_type));
4637 IntConstant.EmitInt (ig, count);
4638 ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
4639 ig.Emit (OpCodes.Stloc, array);
4641 int top = arguments.Count;
4642 for (int j = idx; j < top; j++){
4643 a = (Argument) arguments [j];
4645 ig.Emit (OpCodes.Ldloc, array);
4646 IntConstant.EmitInt (ig, j - idx);
4649 ArrayAccess.EmitStoreOpcode (ig, t);
4651 ig.Emit (OpCodes.Ldloc, array);
4655 /// Emits a list of resolved Arguments that are in the arguments
4658 public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
4660 ParameterData pd = GetParameterData (mb);
4663 // If we are calling a params method with no arguments, special case it
4665 if (arguments == null){
4667 pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
4668 ILGenerator ig = ec.ig;
4670 IntConstant.EmitInt (ig, 0);
4671 ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
4676 int top = arguments.Count;
4678 for (int i = 0; i < top; i++){
4679 Argument a = (Argument) arguments [i];
4680 Type parameter_type = pd.ParameterType(i);
4681 Type argtype = a.Type;
4682 Type arg_expr_type = a.Expr.Type;
4684 if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
4686 // Special case if we are passing the same data as the
4687 // params argument, do not put it in an array.
4689 if (pd.ParameterType (i) == a.Type)
4692 EmitParams (ec, i, arguments);
4695 if ((a.ArgType == Argument.AType.Ref ) &&
4696 (parameter_type != arg_expr_type ||
4697 ! (a.Expr is IMemoryLocation))) {
4699 LocalTemporary localtmp = new LocalTemporary (ec, parameter_type );
4701 if((arg_expr_type != parameter_type) && (a.ArgType == Argument.AType.Ref)) {
4702 Expression e = ConvertImplicit (ec, a.Expr, parameter_type, Location.Null);
4703 is_byref_conversion = true;
4710 if (tempvars == null)
4711 tempvars = new ArrayList ();
4712 if (a.Expr is IMemoryLocation && is_byref_conversion ) {
4715 argtype = argtype.GetElementType();
4716 conv = ConvertImplicit (ec, localtmp, argtype, Location.Null);
4717 tempvars.Add (new Assign (a.Expr, conv, Location.Null));
4720 localtmp.Store (ec);
4721 a = new Argument (localtmp, a.ArgType);
4728 if (pd.Count > top &&
4729 pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
4730 ILGenerator ig = ec.ig;
4732 IntConstant.EmitInt (ig, 0);
4733 ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
4738 /// is_base tells whether we want to force the use of the 'call'
4739 /// opcode instead of using callvirt. Call is required to call
4740 /// a specific method, while callvirt will always use the most
4741 /// recent method in the vtable.
4743 /// is_static tells whether this is an invocation on a static method
4745 /// instance_expr is an expression that represents the instance
4746 /// it must be non-null if is_static is false.
4748 /// method is the method to invoke.
4750 /// Arguments is the list of arguments to pass to the method or constructor.
4752 public static void EmitCall (EmitContext ec, bool is_base,
4753 bool is_static, Expression instance_expr,
4754 MethodBase method, ArrayList Arguments, Location loc)
4756 EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);
4759 public static void EmitCall (EmitContext ec, bool is_base,
4760 bool is_static, Expression instance_expr,
4761 MethodBase method, ArrayList Arguments, ArrayList prop_args, Location loc)
4763 ILGenerator ig = ec.ig;
4764 bool struct_call = false;
4765 bool is_myclass = false;
4767 if (instance_expr is This && ((This) instance_expr).AccessType == This.TypeOfAccess.MyClass)
4770 Type decl_type = method.DeclaringType;
4772 if (!RootContext.StdLib)
4774 // Replace any calls to the system's System.Array type with calls to
4775 // the newly created one.
4776 if (method == TypeManager.system_int_array_get_length)
4777 method = TypeManager.int_array_get_length;
4778 else if (method == TypeManager.system_int_array_get_rank)
4779 method = TypeManager.int_array_get_rank;
4780 else if (method == TypeManager.system_object_array_clone)
4781 method = TypeManager.object_array_clone;
4782 else if (method == TypeManager.system_int_array_get_length_int)
4783 method = TypeManager.int_array_get_length_int;
4784 else if (method == TypeManager.system_int_array_get_lower_bound_int)
4785 method = TypeManager.int_array_get_lower_bound_int;
4786 else if (method == TypeManager.system_int_array_get_upper_bound_int)
4787 method = TypeManager.int_array_get_upper_bound_int;
4788 else if (method == TypeManager.system_void_array_copyto_array_int)
4789 method = TypeManager.void_array_copyto_array_int;
4793 // This checks the 'ConditionalAttribute' on the method, and the
4794 // ObsoleteAttribute
4796 TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
4797 if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
4799 if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
4804 if (decl_type.IsValueType)
4807 // If this is ourselves, push "this"
4809 if (instance_expr == null)
4811 ig.Emit (OpCodes.Ldarg_0);
4816 // Push the instance expression
4818 if (instance_expr.Type.IsValueType)
4821 // Special case: calls to a function declared in a
4822 // reference-type with a value-type argument need
4823 // to have their value boxed.
4826 if (decl_type.IsValueType)
4829 // If the expression implements IMemoryLocation, then
4830 // we can optimize and use AddressOf on the
4833 // If not we have to use some temporary storage for
4835 if (instance_expr is IMemoryLocation)
4837 ((IMemoryLocation)instance_expr).
4838 AddressOf (ec, AddressOp.LoadStore);
4842 Type t = instance_expr.Type;
4844 instance_expr.Emit (ec);
4845 LocalBuilder temp = ig.DeclareLocal (t);
4846 ig.Emit (OpCodes.Stloc, temp);
4847 ig.Emit (OpCodes.Ldloca, temp);
4852 instance_expr.Emit (ec);
4853 ig.Emit (OpCodes.Box, instance_expr.Type);
4857 instance_expr.Emit (ec);
4861 if (prop_args != null && prop_args.Count > 0)
4863 if (Arguments == null)
4864 Arguments = new ArrayList();
4866 for (int i = prop_args.Count-1; i >=0 ; i--)
4868 Arguments.Insert (0,prop_args[i]);
4873 EmitArguments (ec, method, Arguments);
4875 if (is_static || struct_call || is_base || is_myclass)
4877 if (method is MethodInfo)
4879 ig.Emit (OpCodes.Call, (MethodInfo) method);
4882 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
4886 if (method is MethodInfo)
4887 ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
4889 ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
4893 static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
4895 int top = prop_args.Count;
4897 for (int i = 0; i < top; i++)
4899 Argument a = (Argument) prop_args [i];
4904 public override void Emit (EmitContext ec)
4906 MethodGroupExpr mg = (MethodGroupExpr) this.expr;
4909 ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
4912 public override void EmitStatement (EmitContext ec)
4917 // Pop the return value if there is one
4919 if (method is MethodInfo){
4920 Type ret = ((MethodInfo)method).ReturnType;
4921 if ((TypeManager.TypeToCoreType (ret) != TypeManager.void_type) && !this.is_latebinding) {
4922 ec.ig.Emit (OpCodes.Pop);
4924 if (tempvars != null) {
4925 foreach (ExpressionStatement s in tempvars)
4926 s.EmitStatement (ec);
4936 // This class is used to "disable" the code generation for the
4937 // temporary variable when initializing value types.
4939 class EmptyAddressOf : EmptyExpression, IMemoryLocation {
4940 public void AddressOf (EmitContext ec, AddressOp Mode)
4947 /// Implements the new expression
4949 public class New : ExpressionStatement {
4950 public readonly ArrayList Arguments;
4951 public readonly Expression RequestedType;
4953 MethodBase method = null;
4956 // If set, the new expression is for a value_target, and
4957 // we will not leave anything on the stack.
4959 Expression value_target;
4960 bool value_target_set = false;
4961 public bool isDelegate = false;
4963 public New (Expression requested_type, ArrayList arguments, Location l)
4965 RequestedType = requested_type;
4966 Arguments = arguments;
4970 public Expression ValueTypeVariable {
4972 return value_target;
4976 value_target = value;
4977 value_target_set = true;
4982 // This function is used to disable the following code sequence for
4983 // value type initialization:
4985 // AddressOf (temporary)
4989 // Instead the provide will have provided us with the address on the
4990 // stack to store the results.
4992 static Expression MyEmptyExpression;
4994 public void DisableTemporaryValueType ()
4996 if (MyEmptyExpression == null)
4997 MyEmptyExpression = new EmptyAddressOf ();
5000 // To enable this, look into:
5001 // test-34 and test-89 and self bootstrapping.
5003 // For instance, we can avoid a copy by using 'newobj'
5004 // instead of Call + Push-temp on value types.
5005 // value_target = MyEmptyExpression;
5008 public override Expression DoResolve (EmitContext ec)
5010 if (this.isDelegate) {
5011 // if its a delegate resolve the type of RequestedType first
5012 Expression dtype = RequestedType.Resolve(ec);
5013 string ts = (dtype.Type.ToString()).Replace ('+','.');
5014 dtype = Mono.MonoBASIC.Parser.DecomposeQI (ts, Location.Null);
5016 type = ec.DeclSpace.ResolveType (dtype, false, loc);
5019 type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
5024 bool IsDelegate = TypeManager.IsDelegateType (type);
5027 return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
5029 if (type.IsInterface || type.IsAbstract){
5031 30376, "It is not possible to create instances of Interfaces " +
5032 "or classes marked as MustInherit");
5036 bool is_struct = false;
5037 is_struct = type.IsValueType;
5038 eclass = ExprClass.Value;
5041 // SRE returns a match for .ctor () on structs (the object constructor),
5042 // so we have to manually ignore it.
5044 if (is_struct && Arguments == null)
5048 ml = MemberLookupFinal (ec, type, ".ctor",
5049 MemberTypes.Constructor,
5050 AllBindingFlags | BindingFlags.Public, loc);
5055 if (! (ml is MethodGroupExpr)){
5057 ml.Error118 ("method group");
5063 if (Arguments != null){
5064 foreach (Argument a in Arguments){
5065 if (!a.Resolve (ec, loc))
5070 method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
5075 if (method == null) {
5076 if (!is_struct || Arguments.Count > 0) {
5078 "New invocation: Can not find a constructor for " +
5079 "this argument list");
5087 // This DoEmit can be invoked in two contexts:
5088 // * As a mechanism that will leave a value on the stack (new object)
5089 // * As one that wont (init struct)
5091 // You can control whether a value is required on the stack by passing
5092 // need_value_on_stack. The code *might* leave a value on the stack
5093 // so it must be popped manually
5095 // If we are dealing with a ValueType, we have a few
5096 // situations to deal with:
5098 // * The target is a ValueType, and we have been provided
5099 // the instance (this is easy, we are being assigned).
5101 // * The target of New is being passed as an argument,
5102 // to a boxing operation or a function that takes a
5105 // In this case, we need to create a temporary variable
5106 // that is the argument of New.
5108 // Returns whether a value is left on the stack
5110 bool DoEmit (EmitContext ec, bool need_value_on_stack)
5112 bool is_value_type = type.IsValueType;
5113 ILGenerator ig = ec.ig;
5118 // Allow DoEmit() to be called multiple times.
5119 // We need to create a new LocalTemporary each time since
5120 // you can't share LocalBuilders among ILGeneators.
5121 if (!value_target_set)
5122 value_target = new LocalTemporary (ec, type);
5124 ml = (IMemoryLocation) value_target;
5125 ml.AddressOf (ec, AddressOp.Store);
5129 Invocation.EmitArguments (ec, method, Arguments);
5133 ig.Emit (OpCodes.Initobj, type);
5135 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
5136 if (need_value_on_stack){
5137 value_target.Emit (ec);
5142 ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
5147 public override void Emit (EmitContext ec)
5152 public override void EmitStatement (EmitContext ec)
5154 if (DoEmit (ec, false))
5155 ec.ig.Emit (OpCodes.Pop);
5160 /// 14.5.10.2: Represents an array creation expression.
5164 /// There are two possible scenarios here: one is an array creation
5165 /// expression that specifies the dimensions and optionally the
5166 /// initialization data and the other which does not need dimensions
5167 /// specified but where initialization data is mandatory.
5169 public class ArrayCreation : ExpressionStatement {
5170 Expression requested_base_type;
5171 ArrayList initializers;
5174 // The list of Argument types.
5175 // This is used to construct the 'newarray' or constructor signature
5177 ArrayList arguments;
5180 // Method used to create the array object.
5182 MethodBase new_method = null;
5184 Type array_element_type;
5185 Type underlying_type;
5186 bool is_one_dimensional = false;
5187 bool is_builtin_type = false;
5188 bool expect_initializers = false;
5189 int num_arguments = 0;
5193 ArrayList array_data;
5198 // The number of array initializers that we can handle
5199 // via the InitializeArray method - through EmitStaticInitializers
5201 int num_automatic_initializers;
5203 public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
5205 this.requested_base_type = requested_base_type;
5206 this.initializers = initializers;
5210 arguments = new ArrayList ();
5212 foreach (Expression e in exprs) {
5213 arguments.Add (new Argument (e, Argument.AType.Expression));
5218 public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
5220 this.requested_base_type = requested_base_type;
5221 this.initializers = initializers;
5225 //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
5227 //string tmp = rank.Substring (rank.LastIndexOf ("["));
5229 //dimensions = tmp.Length - 1;
5230 expect_initializers = true;
5233 public Expression FormArrayType (Expression base_type, int idx_count, string rank)
5235 StringBuilder sb = new StringBuilder (rank);
5238 for (int i = 1; i < idx_count; i++)
5243 return new ComposedCast (base_type, sb.ToString (), loc);
5246 void Error_IncorrectArrayInitializer ()
5248 Error (30567, "Incorrectly structured array initializer");
5251 public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
5253 if (specified_dims) {
5254 Argument a = (Argument) arguments [idx];
5256 if (!a.Resolve (ec, loc))
5259 if (!(a.Expr is Constant)) {
5260 Error (150, "A constant value is expected");
5264 int value = (int) ((Constant) a.Expr).GetValue ();
5266 if (value != probe.Count) {
5267 Error_IncorrectArrayInitializer ();
5271 bounds [idx] = value;
5274 int child_bounds = -1;
5275 foreach (object o in probe) {
5276 if (o is ArrayList) {
5277 int current_bounds = ((ArrayList) o).Count;
5279 if (child_bounds == -1)
5280 child_bounds = current_bounds;
5282 else if (child_bounds != current_bounds){
5283 Error_IncorrectArrayInitializer ();
5286 bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
5290 if (child_bounds != -1){
5291 Error_IncorrectArrayInitializer ();
5295 Expression tmp = (Expression) o;
5296 tmp = tmp.Resolve (ec);
5300 // Console.WriteLine ("I got: " + tmp);
5301 // Handle initialization from vars, fields etc.
5303 Expression conv = ConvertImplicitRequired (
5304 ec, tmp, underlying_type, loc);
5309 if (conv is StringConstant)
5310 array_data.Add (conv);
5311 else if (conv is Constant) {
5312 array_data.Add (conv);
5313 num_automatic_initializers++;
5315 array_data.Add (conv);
5322 public void UpdateIndices (EmitContext ec)
5325 for (ArrayList probe = initializers; probe != null;) {
5326 if (probe.Count > 0 && probe [0] is ArrayList) {
5327 Expression e = new IntConstant (probe.Count);
5328 arguments.Add (new Argument (e, Argument.AType.Expression));
5330 bounds [i++] = probe.Count;
5332 probe = (ArrayList) probe [0];
5335 Expression e = new IntConstant (probe.Count);
5336 arguments.Add (new Argument (e, Argument.AType.Expression));
5338 bounds [i++] = probe.Count;
5345 public bool ValidateInitializers (EmitContext ec, Type array_type)
5347 if (initializers == null) {
5348 if (expect_initializers)
5354 if (underlying_type == null)
5358 // We use this to store all the date values in the order in which we
5359 // will need to store them in the byte blob later
5361 array_data = new ArrayList ();
5362 bounds = new Hashtable ();
5366 if (arguments != null) {
5367 ret = CheckIndices (ec, initializers, 0, true);
5370 arguments = new ArrayList ();
5372 ret = CheckIndices (ec, initializers, 0, false);
5379 if (arguments.Count != dimensions) {
5380 Error_IncorrectArrayInitializer ();
5388 void Error_NegativeArrayIndex ()
5390 Error (284, "Can not create array with a negative size");
5394 // Converts 'source' to an int, uint, long or ulong.
5396 Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
5400 bool old_checked = ec.CheckState;
5401 ec.CheckState = true;
5403 target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
5404 if (target == null){
5405 target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
5406 if (target == null){
5407 target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
5408 if (target == null){
5409 target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
5411 Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
5415 ec.CheckState = old_checked;
5418 // Only positive constants are allowed at compile time
5420 if (target is Constant){
5421 if (target is IntConstant){
5422 if (((IntConstant) target).Value < 0){
5423 Error_NegativeArrayIndex ();
5428 if (target is LongConstant){
5429 if (((LongConstant) target).Value < 0){
5430 Error_NegativeArrayIndex ();
5441 // Creates the type of the array
5443 bool LookupType (EmitContext ec)
5445 StringBuilder array_qualifier = new StringBuilder (rank);
5448 // 'In the first form allocates an array instace of the type that results
5449 // from deleting each of the individual expression from the expression list'
5451 if (num_arguments > 0) {
5452 array_qualifier.Append ("[");
5453 for (int i = num_arguments-1; i > 0; i--)
5454 array_qualifier.Append (",");
5455 array_qualifier.Append ("]");
5461 Expression array_type_expr;
5462 array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
5463 type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
5468 underlying_type = type;
5469 if (underlying_type.IsArray)
5470 underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
5471 dimensions = type.GetArrayRank ();
5476 public override Expression DoResolve (EmitContext ec)
5480 if (!LookupType (ec))
5484 // First step is to validate the initializers and fill
5485 // in any missing bits
5487 if (!ValidateInitializers (ec, type))
5490 if (arguments == null)
5493 arg_count = arguments.Count;
5494 foreach (Argument a in arguments){
5495 if (!a.Resolve (ec, loc))
5498 Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
5499 if (real_arg == null)
5506 array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
5508 if (arg_count == 1) {
5509 is_one_dimensional = true;
5510 eclass = ExprClass.Value;
5514 is_builtin_type = TypeManager.IsBuiltinType (type);
5516 if (is_builtin_type) {
5519 ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
5520 AllBindingFlags, loc);
5522 if (!(ml is MethodGroupExpr)) {
5523 ml.Error118 ("method group");
5528 Error (-6, "New invocation: Can not find a constructor for " +
5529 "this argument list");
5533 new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
5535 if (new_method == null) {
5536 Error (-6, "New invocation: Can not find a constructor for " +
5537 "this argument list");
5541 eclass = ExprClass.Value;
5544 ModuleBuilder mb = CodeGen.ModuleBuilder;
5545 ArrayList args = new ArrayList ();
5547 if (arguments != null) {
5548 for (int i = 0; i < arg_count; i++)
5549 args.Add (TypeManager.int32_type);
5552 Type [] arg_types = null;
5555 arg_types = new Type [args.Count];
5557 args.CopyTo (arg_types, 0);
5559 new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
5562 if (new_method == null) {
5563 Error (-6, "New invocation: Can not find a constructor for " +
5564 "this argument list");
5568 eclass = ExprClass.Value;
5573 public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
5578 int count = array_data.Count;
5580 if (underlying_type.IsEnum)
5581 underlying_type = TypeManager.EnumToUnderlying (underlying_type);
5583 factor = GetTypeSize (underlying_type);
5585 throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
5587 data = new byte [(count * factor + 4) & ~3];
5590 for (int i = 0; i < count; ++i) {
5591 object v = array_data [i];
5593 if (v is EnumConstant)
5594 v = ((EnumConstant) v).Child;
5596 if (v is Constant && !(v is StringConstant))
5597 v = ((Constant) v).GetValue ();
5603 if (underlying_type == TypeManager.int64_type){
5604 if (!(v is Expression)){
5605 long val = (long) v;
5607 for (int j = 0; j < factor; ++j) {
5608 data [idx + j] = (byte) (val & 0xFF);
5612 } else if (underlying_type == TypeManager.uint64_type){
5613 if (!(v is Expression)){
5614 ulong val = (ulong) v;
5616 for (int j = 0; j < factor; ++j) {
5617 data [idx + j] = (byte) (val & 0xFF);
5621 } else if (underlying_type == TypeManager.float_type) {
5622 if (!(v is Expression)){
5623 element = BitConverter.GetBytes ((float) v);
5625 for (int j = 0; j < factor; ++j)
5626 data [idx + j] = element [j];
5628 } else if (underlying_type == TypeManager.double_type) {
5629 if (!(v is Expression)){
5630 element = BitConverter.GetBytes ((double) v);
5632 for (int j = 0; j < factor; ++j)
5633 data [idx + j] = element [j];
5635 } else if (underlying_type == TypeManager.char_type){
5636 if (!(v is Expression)){
5637 int val = (int) ((char) v);
5639 data [idx] = (byte) (val & 0xff);
5640 data [idx+1] = (byte) (val >> 8);
5642 } else if (underlying_type == TypeManager.short_type){
5643 if (!(v is Expression)){
5644 int val = (int) ((short) v);
5646 data [idx] = (byte) (val & 0xff);
5647 data [idx+1] = (byte) (val >> 8);
5649 } else if (underlying_type == TypeManager.ushort_type){
5650 if (!(v is Expression)){
5651 int val = (int) ((ushort) v);
5653 data [idx] = (byte) (val & 0xff);
5654 data [idx+1] = (byte) (val >> 8);
5656 } else if (underlying_type == TypeManager.int32_type) {
5657 if (!(v is Expression)){
5660 data [idx] = (byte) (val & 0xff);
5661 data [idx+1] = (byte) ((val >> 8) & 0xff);
5662 data [idx+2] = (byte) ((val >> 16) & 0xff);
5663 data [idx+3] = (byte) (val >> 24);
5665 } else if (underlying_type == TypeManager.uint32_type) {
5666 if (!(v is Expression)){
5667 uint val = (uint) v;
5669 data [idx] = (byte) (val & 0xff);
5670 data [idx+1] = (byte) ((val >> 8) & 0xff);
5671 data [idx+2] = (byte) ((val >> 16) & 0xff);
5672 data [idx+3] = (byte) (val >> 24);
5674 } else if (underlying_type == TypeManager.sbyte_type) {
5675 if (!(v is Expression)){
5676 sbyte val = (sbyte) v;
5677 data [idx] = (byte) val;
5679 } else if (underlying_type == TypeManager.byte_type) {
5680 if (!(v is Expression)){
5681 byte val = (byte) v;
5682 data [idx] = (byte) val;
5684 } else if (underlying_type == TypeManager.bool_type) {
5685 if (!(v is Expression)){
5686 bool val = (bool) v;
5687 data [idx] = (byte) (val ? 1 : 0);
5689 } else if (underlying_type == TypeManager.decimal_type){
5690 if (!(v is Expression)){
5691 int [] bits = Decimal.GetBits ((decimal) v);
5694 for (int j = 0; j < 4; j++){
5695 data [p++] = (byte) (bits [j] & 0xff);
5696 data [p++] = (byte) ((bits [j] >> 8) & 0xff);
5697 data [p++] = (byte) ((bits [j] >> 16) & 0xff);
5698 data [p++] = (byte) (bits [j] >> 24);
5702 throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
5711 // Emits the initializers for the array
5713 void EmitStaticInitializers (EmitContext ec, bool is_expression)
5716 // First, the static data
5719 ILGenerator ig = ec.ig;
5721 byte [] data = MakeByteBlob (array_data, underlying_type, loc);
5723 fb = RootContext.MakeStaticData (data);
5726 ig.Emit (OpCodes.Dup);
5727 ig.Emit (OpCodes.Ldtoken, fb);
5728 ig.Emit (OpCodes.Call,
5729 TypeManager.void_initializearray_array_fieldhandle);
5733 // Emits pieces of the array that can not be computed at compile
5734 // time (variables and string locations).
5736 // This always expect the top value on the stack to be the array
5738 void EmitDynamicInitializers (EmitContext ec, bool is_expression)
5740 ILGenerator ig = ec.ig;
5741 int dims = bounds.Count;
5742 int [] current_pos = new int [dims];
5743 int top = array_data.Count;
5744 LocalBuilder temp = ig.DeclareLocal (type);
5746 ig.Emit (OpCodes.Stloc, temp);
5748 MethodInfo set = null;
5752 ModuleBuilder mb = null;
5753 mb = CodeGen.ModuleBuilder;
5754 args = new Type [dims + 1];
5757 for (j = 0; j < dims; j++)
5758 args [j] = TypeManager.int32_type;
5760 args [j] = array_element_type;
5762 set = mb.GetArrayMethod (
5764 CallingConventions.HasThis | CallingConventions.Standard,
5765 TypeManager.void_type, args);
5768 for (int i = 0; i < top; i++){
5770 Expression e = null;
5772 if (array_data [i] is Expression)
5773 e = (Expression) array_data [i];
5777 // Basically we do this for string literals and
5778 // other non-literal expressions
5780 if (e is StringConstant || !(e is Constant) ||
5781 num_automatic_initializers <= 2) {
5782 Type etype = e.Type;
5784 ig.Emit (OpCodes.Ldloc, temp);
5786 for (int idx = 0; idx < dims; idx++)
5787 IntConstant.EmitInt (ig, current_pos [idx]);
5790 // If we are dealing with a struct, get the
5791 // address of it, so we can store it.
5794 etype.IsSubclassOf (TypeManager.value_type) &&
5795 (!TypeManager.IsBuiltinType (etype) ||
5796 etype == TypeManager.decimal_type)) {
5801 // Let new know that we are providing
5802 // the address where to store the results
5804 n.DisableTemporaryValueType ();
5807 ig.Emit (OpCodes.Ldelema, etype);
5813 ArrayAccess.EmitStoreOpcode (ig, array_element_type);
5815 ig.Emit (OpCodes.Call, set);
5822 for (int j = dims - 1; j >= 0; j--){
5824 if (current_pos [j] < (int) bounds [j])
5826 current_pos [j] = 0;
5831 ig.Emit (OpCodes.Ldloc, temp);
5834 void EmitArrayArguments (EmitContext ec)
5836 ILGenerator ig = ec.ig;
5838 foreach (Argument a in arguments) {
5839 Type atype = a.Type;
5842 if (atype == TypeManager.uint64_type)
5843 ig.Emit (OpCodes.Conv_Ovf_U4);
5844 else if (atype == TypeManager.int64_type)
5845 ig.Emit (OpCodes.Conv_Ovf_I4);
5849 void DoEmit (EmitContext ec, bool is_statement)
5851 ILGenerator ig = ec.ig;
5853 EmitArrayArguments (ec);
5854 if (is_one_dimensional)
5855 ig.Emit (OpCodes.Newarr, array_element_type);
5857 if (is_builtin_type)
5858 ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
5860 ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
5863 if (initializers != null){
5865 // FIXME: Set this variable correctly.
5867 bool dynamic_initializers = true;
5869 if (underlying_type != TypeManager.string_type &&
5870 underlying_type != TypeManager.object_type) {
5871 if (num_automatic_initializers > 2)
5872 EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
5875 if (dynamic_initializers)
5876 EmitDynamicInitializers (ec, !is_statement);
5880 public override void Emit (EmitContext ec)
5885 public override void EmitStatement (EmitContext ec)
5893 /// Represents the 'this' construct
5895 public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
5897 public enum TypeOfAccess : byte {
5903 TypeOfAccess access_type;
5905 public This (TypeOfAccess access_type, Block block, Location loc)
5909 this.access_type = access_type;
5912 public This (Block block, Location loc)
5916 this.access_type = TypeOfAccess.Me;
5919 public This (Location loc)
5922 this.access_type = TypeOfAccess.Me;
5925 public TypeOfAccess AccessType {
5926 get { return access_type; }
5929 public bool IsAssigned (EmitContext ec, Location loc)
5934 return vi.IsAssigned (ec, loc);
5937 public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
5942 return vi.IsFieldAssigned (ec, field_name, loc);
5945 public void SetAssigned (EmitContext ec)
5948 vi.SetAssigned (ec);
5951 public void SetFieldAssigned (EmitContext ec, string field_name)
5954 vi.SetFieldAssigned (ec, field_name);
5957 public override Expression DoResolve (EmitContext ec)
5959 eclass = ExprClass.Variable;
5960 type = ec.ContainerType;
5963 Error (26, "Keyword this not valid in static code");
5968 vi = block.ThisVariable;
5973 override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
5977 VariableInfo vi = ec.CurrentBlock.ThisVariable;
5979 vi.SetAssigned (ec);
5981 if (ec.TypeContainer is Class){
5982 Error (1604, "Cannot assign to 'this'");
5989 public override void Emit (EmitContext ec)
5991 ILGenerator ig = ec.ig;
5993 ig.Emit (OpCodes.Ldarg_0);
5994 if (ec.TypeContainer is Struct)
5995 ig.Emit (OpCodes.Ldobj, type);
5998 public void EmitAssign (EmitContext ec, Expression source)
6000 ILGenerator ig = ec.ig;
6002 if (ec.TypeContainer is Struct){
6003 ig.Emit (OpCodes.Ldarg_0);
6005 ig.Emit (OpCodes.Stobj, type);
6008 ig.Emit (OpCodes.Starg, 0);
6012 public void AddressOf (EmitContext ec, AddressOp mode)
6014 ec.ig.Emit (OpCodes.Ldarg_0);
6017 // FIGURE OUT WHY LDARG_S does not work
6019 // consider: struct X { int val; int P { set { val = value; }}}
6021 // Yes, this looks very bad. Look at 'NOTAS' for
6023 // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
6028 /// Implements the typeof operator
6030 public class TypeOf : Expression {
6031 public readonly Expression QueriedType;
6034 public TypeOf (Expression queried_type, Location l)
6036 QueriedType = queried_type;
6040 public override Expression DoResolve (EmitContext ec)
6042 typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6044 if (typearg == null)
6047 type = TypeManager.type_type;
6048 eclass = ExprClass.Type;
6052 public override void Emit (EmitContext ec)
6054 ec.ig.Emit (OpCodes.Ldtoken, typearg);
6055 ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
6058 public Type TypeArg {
6059 get { return typearg; }
6064 /// Implements the sizeof expression
6066 public class SizeOf : Expression {
6067 public readonly Expression QueriedType;
6070 public SizeOf (Expression queried_type, Location l)
6072 this.QueriedType = queried_type;
6076 public override Expression DoResolve (EmitContext ec)
6079 Error (233, "Sizeof may only be used in an unsafe context " +
6080 "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
6084 type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
6085 if (type_queried == null)
6088 if (!TypeManager.IsUnmanagedType (type_queried)){
6089 Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.MonoBASIC_Name (type_queried) + ")");
6093 type = TypeManager.int32_type;
6094 eclass = ExprClass.Value;
6098 public override void Emit (EmitContext ec)
6100 int size = GetTypeSize (type_queried);
6103 ec.ig.Emit (OpCodes.Sizeof, type_queried);
6105 IntConstant.EmitInt (ec.ig, size);
6110 /// Implements the member access expression
6112 public class MemberAccess : Expression, ITypeExpression {
6113 public readonly string Identifier;
6115 Expression member_lookup;
6119 public MemberAccess (Expression expr, string id, Location l)
6126 public MemberAccess (Expression expr, string id, Location l, bool isInvocation)
6131 is_invocation = isInvocation;
6134 public bool IsInvocation {
6136 return is_invocation;
6139 is_invocation = value;
6143 public bool IsLeftHand {
6145 return is_left_hand;
6148 is_left_hand = value;
6152 public Expression Expr {
6158 static void error176 (Location loc, string name)
6160 Report.Error (176, loc, "Static member '" +
6161 name + "' cannot be accessed " +
6162 "with an instance reference, qualify with a " +
6163 "type name instead");
6166 static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
6168 if (left_original == null)
6171 if (!(left_original is SimpleName))
6174 SimpleName sn = (SimpleName) left_original;
6176 Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
6183 public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
6184 Expression left, Location loc,
6185 Expression left_original)
6187 bool left_is_type, left_is_explicit;
6190 // If 'left' is null, then we're called from SimpleNameResolve and this is
6191 // a member in the currently defining class.
6193 left_is_type = ec.IsStatic || ec.IsFieldInitializer;
6194 left_is_explicit = false;
6196 // Implicitly default to 'this' unless we're static.
6197 if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
6200 left_is_type = left is TypeExpr;
6201 left_is_explicit = true;
6204 if (member_lookup is FieldExpr){
6205 FieldExpr fe = (FieldExpr) member_lookup;
6206 FieldInfo fi = fe.FieldInfo;
6207 Type decl_type = fi.DeclaringType;
6209 if (fi is FieldBuilder) {
6210 Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
6213 if (!c.LookupConstantValue (out o, ec))
6216 object real_value = ((Constant) c.Expr).GetValue ();
6217 Expression exp = Constantify (real_value, fi.FieldType);
6223 // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
6225 if (fi.IsInitOnly && !(fi is FieldBuilder) && fi.FieldType == TypeManager.decimal_type) {
6226 object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
6227 if (attrs.Length == 1)
6228 return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
6234 Type t = fi.FieldType;
6238 if (fi is FieldBuilder)
6239 o = TypeManager.GetValue ((FieldBuilder) fi);
6241 o = fi.GetValue (fi);
6243 if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
6244 if (left_is_explicit && !left_is_type &&
6245 !IdenticalNameAndTypeName (ec, left_original, loc)) {
6246 error176 (loc, fe.FieldInfo.Name);
6250 Expression enum_member = MemberLookup (
6251 ec, decl_type, "value__", MemberTypes.Field,
6252 AllBindingFlags, loc);
6254 Enum en = TypeManager.LookupEnum (decl_type);
6258 c = Constantify (o, en.UnderlyingType);
6260 c = Constantify (o, enum_member.Type);
6262 return new EnumConstant (c, decl_type);
6265 Expression exp = Constantify (o, t);
6267 if (left_is_explicit && !left_is_type) {
6268 error176 (loc, fe.FieldInfo.Name);
6275 if (fi.FieldType.IsPointer && !ec.InUnsafe){
6282 if (member_lookup is IMemberExpr) {
6283 IMemberExpr me = (IMemberExpr) member_lookup;
6286 MethodGroupExpr mg = me as MethodGroupExpr;
6287 if ((mg != null) && left_is_explicit && left.Type.IsInterface)
6288 mg.IsExplicitImpl = left_is_explicit;
6291 if (IdenticalNameAndTypeName (ec, left_original, loc))
6292 return member_lookup;
6294 SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
6299 if (!me.IsInstance){
6300 if (IdenticalNameAndTypeName (ec, left_original, loc))
6301 return member_lookup;
6303 /*if (left_is_explicit) {
6304 error176 (loc, me.Name);
6310 // Since we can not check for instance objects in SimpleName,
6311 // becaue of the rule that allows types and variables to share
6312 // the name (as long as they can be de-ambiguated later, see
6313 // IdenticalNameAndTypeName), we have to check whether left
6314 // is an instance variable in a static context
6316 // However, if the left-hand value is explicitly given, then
6317 // it is already our instance expression, so we aren't in
6321 if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
6322 IMemberExpr mexp = (IMemberExpr) left;
6324 if (!mexp.IsStatic){
6325 SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
6330 me.InstanceExpression = left;
6333 return member_lookup;
6336 if (member_lookup is TypeExpr){
6337 member_lookup.Resolve (ec, ResolveFlags.Type);
6338 return member_lookup;
6341 Console.WriteLine ("Left is: " + left);
6342 Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
6343 Environment.Exit (0);
6347 public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
6350 throw new Exception ();
6352 // Resolve the expression with flow analysis turned off, we'll do the definite
6353 // assignment checks later. This is because we don't know yet what the expression
6354 // will resolve to - it may resolve to a FieldExpr and in this case we must do the
6355 // definite assignment check on the actual field and not on the whole struct.
6358 Expression original = expr;
6359 expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
6364 if (expr is SimpleName){
6365 SimpleName child_expr = (SimpleName) expr;
6367 Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
6369 if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
6370 return new_expr.Resolve (ec, flags);
6372 return new_expr.Resolve (ec, flags | ResolveFlags.MethodGroup | ResolveFlags.VariableOrValue);
6375 int errors = Report.Errors;
6377 Type expr_type = expr.Type;
6379 if (expr is TypeExpr){
6380 //FIXME: add access level check
6381 //if (!ec.DeclSpace.CheckAccessLevel (expr_type)) {
6382 // Error (30390, "'" + TypeManager.MonoBASIC_Name (expr_type) + "' " +
6383 // "is inaccessible because of its protection level");
6387 if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
6388 Enum en = TypeManager.LookupEnum (expr_type);
6391 object value = en.LookupEnumValue (Identifier);
6394 Constant c = Constantify (value, en.UnderlyingType);
6395 return new EnumConstant (c, expr_type);
6397 Report.Error (30456, loc,
6398 Identifier + " is not found in member list of enum " + en.Name);
6404 if (expr_type.IsPointer){
6405 Error (30311, "The '.' operator can not be applied to pointer operands (" +
6406 TypeManager.MonoBASIC_Name (expr_type) + ")");
6410 member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
6412 if (member_lookup == null)
6414 // Error has already been reported.
6415 if (errors < Report.Errors)
6419 // Try looking the member up from the same type, if we find
6420 // it, we know that the error was due to limited visibility
6422 object lookup = TypeManager.MemberLookup (
6423 expr_type, expr_type, AllMemberTypes, AllBindingFlags |
6424 BindingFlags.NonPublic, Identifier);
6426 if (lookup == null) {
6427 if (expr_type != TypeManager.object_type)
6428 Error (30456, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
6429 // If this came as a part of Invocation,
6430 // Since argumets are not known, return null,
6431 // let Invocation's Resolve take care
6435 else if (! is_left_hand) {
6436 StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
6438 true, is_left_hand);
6439 etmp.GenerateLateBindingStatements();
6440 return etmp.Resolve (ec);
6443 // if the expression is a left hand side of an assignment,
6444 // return null, as we dont know the RHS
6445 // Let assign take care of Late Binding
6450 if ((expr_type != ec.ContainerType) &&
6451 ec.ContainerType.IsSubclassOf (expr_type))
6454 // Although a derived class can access protected members of
6455 // its base class it cannot do so through an instance of the
6456 // base class (CS1540). If the expr_type is a parent of the
6457 // ec.ContainerType and the lookup succeeds with the latter one,
6458 // then we are in this situation.
6460 lookup = TypeManager.MemberLookup(
6461 ec.ContainerType, ec.ContainerType, AllMemberTypes,
6462 AllBindingFlags, Identifier);
6465 Error (1540, "Cannot access protected member '" +
6466 expr_type + "." + Identifier + "' " +
6467 "via a qualifier of type '" + TypeManager.MonoBASIC_Name (expr_type) + "'; the " +
6468 "qualifier must be of type '" + TypeManager.MonoBASIC_Name (ec.ContainerType) + "' " +
6469 "(or derived from it)");
6471 Error (30390, "'" + expr_type + "." + Identifier + "' " +
6472 "is inaccessible because of its protection level");
6474 Error (30390, "'" + expr_type + "." + Identifier + "' " +
6475 "is inaccessible because of its protection level");
6480 if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))) {
6481 Enum en = TypeManager.LookupEnum (expr_type);
6484 object value = en.LookupEnumValue (Identifier);
6485 expr_type = TypeManager.int32_type;
6486 if (value != null) {
6487 Constant c = Constantify (value, en.UnderlyingType);
6488 return new EnumConstant (c, en.UnderlyingType);
6490 Report.Error (30456, loc,
6491 Identifier + " is not found in member list of enum " + en.Name);
6496 if (member_lookup is TypeExpr){
6497 member_lookup.Resolve (ec, ResolveFlags.Type);
6499 return member_lookup;
6500 } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
6503 member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
6504 if (member_lookup == null)
6507 // The following DoResolve/DoResolveLValue will do the definite assignment
6509 if (right_side != null)
6510 member_lookup = member_lookup.DoResolveLValue (ec, right_side);
6512 member_lookup = member_lookup.DoResolve (ec);
6514 return member_lookup;
6517 public override Expression DoResolve (EmitContext ec)
6519 return DoResolve (ec, null, ResolveFlags.VariableOrValue |
6520 ResolveFlags.SimpleName | ResolveFlags.Type);
6523 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6525 return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
6526 ResolveFlags.SimpleName | ResolveFlags.Type);
6529 public Expression DoResolveType (EmitContext ec)
6531 return DoResolve (ec, null, ResolveFlags.Type);
6534 public override void Emit (EmitContext ec)
6536 throw new Exception ("Should not happen");
6539 public override string ToString ()
6541 return expr + "." + Identifier;
6548 /// Implements checked expressions
6550 public class CheckedExpr : Expression {
6552 public Expression Expr;
6554 public CheckedExpr (Expression e, Location l)
6560 public override Expression DoResolve (EmitContext ec)
6562 bool last_const_check = ec.ConstantCheckState;
6564 ec.ConstantCheckState = true;
6565 Expr = Expr.Resolve (ec);
6566 ec.ConstantCheckState = last_const_check;
6571 if (Expr is Constant)
6574 eclass = Expr.eclass;
6579 public override void Emit (EmitContext ec)
6581 bool last_check = ec.CheckState;
6582 bool last_const_check = ec.ConstantCheckState;
6584 ec.CheckState = true;
6585 ec.ConstantCheckState = true;
6587 ec.CheckState = last_check;
6588 ec.ConstantCheckState = last_const_check;
6594 /// Implements the unchecked expression
6596 public class UnCheckedExpr : Expression {
6598 public Expression Expr;
6600 public UnCheckedExpr (Expression e, Location l)
6606 public override Expression DoResolve (EmitContext ec)
6608 bool last_const_check = ec.ConstantCheckState;
6610 ec.ConstantCheckState = false;
6611 Expr = Expr.Resolve (ec);
6612 ec.ConstantCheckState = last_const_check;
6617 if (Expr is Constant)
6620 eclass = Expr.eclass;
6625 public override void Emit (EmitContext ec)
6627 bool last_check = ec.CheckState;
6628 bool last_const_check = ec.ConstantCheckState;
6630 ec.CheckState = false;
6631 ec.ConstantCheckState = false;
6633 ec.CheckState = last_check;
6634 ec.ConstantCheckState = last_const_check;
6640 /// An Element Access expression.
6642 /// During semantic analysis these are transformed into
6643 /// IndexerAccess or ArrayAccess
6645 public class ElementAccess : Expression {
6646 public ArrayList Arguments;
6647 public Expression Expr;
6649 public ElementAccess (Expression e, ArrayList e_list, Location l)
6658 Arguments = new ArrayList ();
6659 foreach (Expression tmp in e_list)
6660 Arguments.Add (new Argument (tmp, Argument.AType.Expression));
6664 bool CommonResolve (EmitContext ec)
6666 Expr = Expr.Resolve (ec);
6671 if (Arguments == null)
6674 foreach (Argument a in Arguments){
6675 if (!a.Resolve (ec, loc))
6682 Expression MakePointerAccess ()
6686 if (t == TypeManager.void_ptr_type){
6689 "The array index operation is not valid for void pointers");
6692 if (Arguments.Count != 1){
6695 "A pointer must be indexed by a single value");
6698 Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,
6700 return new Indirection (p, loc);
6703 public override Expression DoResolve (EmitContext ec)
6705 if (!CommonResolve (ec))
6709 // We perform some simple tests, and then to "split" the emit and store
6710 // code we create an instance of a different class, and return that.
6712 // I am experimenting with this pattern.
6717 return (new ArrayAccess (this, loc)).Resolve (ec);
6718 else if (t.IsPointer)
6719 return MakePointerAccess ();
6721 return (new IndexerAccess (this, loc)).Resolve (ec);
6724 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
6726 if (!CommonResolve (ec))
6731 return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
6732 else if (t.IsPointer)
6733 return MakePointerAccess ();
6735 return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
6738 public override void Emit (EmitContext ec)
6740 throw new Exception ("Should never be reached");
6745 /// Implements array access
6747 public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
6749 // Points to our "data" repository
6753 LocalTemporary [] cached_locations;
6755 public ArrayAccess (ElementAccess ea_data, Location l)
6758 eclass = ExprClass.Variable;
6762 public override Expression DoResolve (EmitContext ec)
6764 //ExprClass eclass = ea.Expr.eclass;
6767 // As long as the type is valid
6768 if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
6769 eclass == ExprClass.Value)) {
6770 ea.Expr.Error118 ("variable or value");
6775 Type t = ea.Expr.Type;
6777 if (t == typeof (System.Object))
6779 // We can't resolve now, but we
6780 // have to try to access the array with a call
6781 // to LateIndexGet in the runtime
6783 Expression lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
6784 Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
6785 ArrayList adims = new ArrayList();
6787 ArrayList ainit = new ArrayList();
6788 foreach (Argument a in ea.Arguments)
6789 ainit.Add ((Expression) a.Expr);
6791 adims.Add ((Expression) new IntLiteral (ea.Arguments.Count));
6793 Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
6795 ArrayList args = new ArrayList();
6796 args.Add (new Argument(ea.Expr, Argument.AType.Expression));
6797 args.Add (new Argument(oace, Argument.AType.Expression));
6798 args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
6800 Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
6801 lig_call = lig_call.Resolve(ec);
6805 if (t.GetArrayRank () != ea.Arguments.Count){
6807 "Incorrect number of indexes for array " +
6808 " expected: " + t.GetArrayRank () + " got: " +
6809 ea.Arguments.Count);
6812 type = TypeManager.TypeToCoreType (t.GetElementType ());
6813 if (type.IsPointer && !ec.InUnsafe){
6814 UnsafeError (ea.Location);
6818 foreach (Argument a in ea.Arguments){
6819 Type argtype = a.Type;
6821 if (argtype == TypeManager.int32_type ||
6822 argtype == TypeManager.uint32_type ||
6823 argtype == TypeManager.int64_type ||
6824 argtype == TypeManager.uint64_type)
6828 // Mhm. This is strage, because the Argument.Type is not the same as
6829 // Argument.Expr.Type: the value changes depending on the ref/out setting.
6831 // Wonder if I will run into trouble for this.
6833 a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
6838 eclass = ExprClass.Variable;
6844 /// Emits the right opcode to load an object of Type 't'
6845 /// from an array of T
6847 static public void EmitLoadOpcode (ILGenerator ig, Type type)
6849 if (type == TypeManager.byte_type || type == TypeManager.bool_type)
6850 ig.Emit (OpCodes.Ldelem_U1);
6851 else if (type == TypeManager.sbyte_type)
6852 ig.Emit (OpCodes.Ldelem_I1);
6853 else if (type == TypeManager.short_type)
6854 ig.Emit (OpCodes.Ldelem_I2);
6855 else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
6856 ig.Emit (OpCodes.Ldelem_U2);
6857 else if (type == TypeManager.int32_type)
6858 ig.Emit (OpCodes.Ldelem_I4);
6859 else if (type == TypeManager.uint32_type)
6860 ig.Emit (OpCodes.Ldelem_U4);
6861 else if (type == TypeManager.uint64_type)
6862 ig.Emit (OpCodes.Ldelem_I8);
6863 else if (type == TypeManager.int64_type)
6864 ig.Emit (OpCodes.Ldelem_I8);
6865 else if (type == TypeManager.float_type)
6866 ig.Emit (OpCodes.Ldelem_R4);
6867 else if (type == TypeManager.double_type)
6868 ig.Emit (OpCodes.Ldelem_R8);
6869 else if (type == TypeManager.intptr_type)
6870 ig.Emit (OpCodes.Ldelem_I);
6871 else if (type.IsValueType){
6872 ig.Emit (OpCodes.Ldelema, type);
6873 ig.Emit (OpCodes.Ldobj, type);
6875 ig.Emit (OpCodes.Ldelem_Ref);
6879 /// Emits the right opcode to store an object of Type 't'
6880 /// from an array of T.
6882 static public void EmitStoreOpcode (ILGenerator ig, Type t)
6884 t = TypeManager.TypeToCoreType (t);
6885 if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
6886 t = TypeManager.EnumToUnderlying (t);
6887 if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
6888 t == TypeManager.bool_type)
6889 ig.Emit (OpCodes.Stelem_I1);
6890 else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
6891 ig.Emit (OpCodes.Stelem_I2);
6892 else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
6893 ig.Emit (OpCodes.Stelem_I4);
6894 else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
6895 ig.Emit (OpCodes.Stelem_I8);
6896 else if (t == TypeManager.float_type)
6897 ig.Emit (OpCodes.Stelem_R4);
6898 else if (t == TypeManager.double_type)
6899 ig.Emit (OpCodes.Stelem_R8);
6900 else if (t == TypeManager.intptr_type)
6901 ig.Emit (OpCodes.Stelem_I);
6902 else if (t.IsValueType){
6903 ig.Emit (OpCodes.Stobj, t);
6905 ig.Emit (OpCodes.Stelem_Ref);
6908 MethodInfo FetchGetMethod ()
6910 ModuleBuilder mb = CodeGen.ModuleBuilder;
6911 int arg_count = ea.Arguments.Count;
6912 Type [] args = new Type [arg_count];
6915 for (int i = 0; i < arg_count; i++){
6916 //args [i++] = a.Type;
6917 args [i] = TypeManager.int32_type;
6920 get = mb.GetArrayMethod (
6921 ea.Expr.Type, "Get",
6922 CallingConventions.HasThis |
6923 CallingConventions.Standard,
6929 MethodInfo FetchAddressMethod ()
6931 ModuleBuilder mb = CodeGen.ModuleBuilder;
6932 int arg_count = ea.Arguments.Count;
6933 Type [] args = new Type [arg_count];
6935 string ptr_type_name;
6938 ptr_type_name = type.FullName + "&";
6939 ret_type = Type.GetType (ptr_type_name);
6942 // It is a type defined by the source code we are compiling
6944 if (ret_type == null){
6945 ret_type = mb.GetType (ptr_type_name);
6948 for (int i = 0; i < arg_count; i++){
6949 //args [i++] = a.Type;
6950 args [i] = TypeManager.int32_type;
6953 address = mb.GetArrayMethod (
6954 ea.Expr.Type, "Address",
6955 CallingConventions.HasThis |
6956 CallingConventions.Standard,
6963 // Load the array arguments into the stack.
6965 // If we have been requested to cache the values (cached_locations array
6966 // initialized), then load the arguments the first time and store them
6967 // in locals. otherwise load from local variables.
6969 void LoadArrayAndArguments (EmitContext ec)
6971 ILGenerator ig = ec.ig;
6973 if (cached_locations == null){
6975 foreach (Argument a in ea.Arguments){
6976 Type argtype = a.Expr.Type;
6980 if (argtype == TypeManager.int64_type)
6981 ig.Emit (OpCodes.Conv_Ovf_I);
6982 else if (argtype == TypeManager.uint64_type)
6983 ig.Emit (OpCodes.Conv_Ovf_I_Un);
6988 if (cached_locations [0] == null){
6989 cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
6991 ig.Emit (OpCodes.Dup);
6992 cached_locations [0].Store (ec);
6996 foreach (Argument a in ea.Arguments){
6997 Type argtype = a.Expr.Type;
6999 cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
7001 if (argtype == TypeManager.int64_type)
7002 ig.Emit (OpCodes.Conv_Ovf_I);
7003 else if (argtype == TypeManager.uint64_type)
7004 ig.Emit (OpCodes.Conv_Ovf_I_Un);
7006 ig.Emit (OpCodes.Dup);
7007 cached_locations [j].Store (ec);
7013 foreach (LocalTemporary lt in cached_locations)
7017 public new void CacheTemporaries (EmitContext ec)
7019 cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
7022 public override void Emit (EmitContext ec)
7024 int rank = ea.Expr.Type.GetArrayRank ();
7025 ILGenerator ig = ec.ig;
7027 LoadArrayAndArguments (ec);
7030 EmitLoadOpcode (ig, type);
7034 method = FetchGetMethod ();
7035 ig.Emit (OpCodes.Call, method);
7039 public void EmitAssign (EmitContext ec, Expression source)
7041 int rank = ea.Expr.Type.GetArrayRank ();
7042 ILGenerator ig = ec.ig;
7043 Type t = source.Type;
7045 LoadArrayAndArguments (ec);
7048 // The stobj opcode used by value types will need
7049 // an address on the stack, not really an array/array
7053 if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
7054 (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
7055 ig.Emit (OpCodes.Ldelema, t);
7061 EmitStoreOpcode (ig, t);
7063 ModuleBuilder mb = CodeGen.ModuleBuilder;
7064 int arg_count = ea.Arguments.Count;
7065 Type [] args = new Type [arg_count + 1];
7068 for (int i = 0; i < arg_count; i++){
7069 //args [i++] = a.Type;
7070 args [i] = TypeManager.int32_type;
7073 args [arg_count] = type;
7075 set = mb.GetArrayMethod (
7076 ea.Expr.Type, "Set",
7077 CallingConventions.HasThis |
7078 CallingConventions.Standard,
7079 TypeManager.void_type, args);
7081 ig.Emit (OpCodes.Call, set);
7085 public void AddressOf (EmitContext ec, AddressOp mode)
7087 int rank = ea.Expr.Type.GetArrayRank ();
7088 ILGenerator ig = ec.ig;
7090 LoadArrayAndArguments (ec);
7093 ig.Emit (OpCodes.Ldelema, type);
7095 MethodInfo address = FetchAddressMethod ();
7096 ig.Emit (OpCodes.Call, address);
7103 public ArrayList getters, setters;
7104 static Hashtable map;
7108 map = new Hashtable ();
7111 Indexers (MemberInfo [] mi)
7113 foreach (PropertyInfo property in mi){
7114 MethodInfo get, set;
7116 get = property.GetGetMethod (true);
7118 if (getters == null)
7119 getters = new ArrayList ();
7124 set = property.GetSetMethod (true);
7126 if (setters == null)
7127 setters = new ArrayList ();
7133 static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
7135 Indexers ix = (Indexers) map [lookup_type];
7140 string p_name = TypeManager.IndexerPropertyName (lookup_type);
7142 MemberInfo [] mi = TypeManager.MemberLookup (
7143 caller_type, lookup_type, MemberTypes.Property,
7144 BindingFlags.Public | BindingFlags.Instance, p_name);
7146 if (mi == null || mi.Length == 0)
7149 ix = new Indexers (mi);
7150 map [lookup_type] = ix;
7155 static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
7157 Indexers ix = (Indexers) map [lookup_type];
7162 ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
7166 Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
7167 if (ifaces != null) {
7168 foreach (Type itype in ifaces) {
7169 ix = GetIndexersForTypeOrInterface (caller_type, itype);
7175 if (lookup_type != TypeManager.object_type)
7176 Report.Error (21, loc,
7177 "Type '" + TypeManager.MonoBASIC_Name (lookup_type) +
7178 "' does not have any indexers defined");
7184 /// Expressions that represent an indexer call.
7186 public class IndexerAccess : Expression, IAssignMethod {
7188 // Points to our "data" repository
7190 MethodInfo get, set;
7192 ArrayList set_arguments;
7193 bool is_base_indexer;
7195 protected Type indexer_type;
7196 protected Type current_type;
7197 protected Expression instance_expr;
7198 protected ArrayList arguments;
7200 public IndexerAccess (ElementAccess ea, Location loc)
7201 : this (ea.Expr, false, loc)
7203 this.arguments = ea.Arguments;
7206 protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
7209 this.instance_expr = instance_expr;
7210 this.is_base_indexer = is_base_indexer;
7211 this.eclass = ExprClass.Value;
7215 public Expression Instance {
7217 return instance_expr;
7221 public ArrayList Arguments {
7227 protected virtual bool CommonResolve (EmitContext ec)
7229 indexer_type = instance_expr.Type;
7230 current_type = ec.ContainerType;
7235 public override Expression DoResolve (EmitContext ec)
7237 if (!CommonResolve (ec))
7241 // Step 1: Query for all 'Item' *properties*. Notice
7242 // that the actual methods are pointed from here.
7244 // This is a group of properties, piles of them.
7247 ilist = Indexers.GetIndexersForType (
7248 current_type, indexer_type, loc);
7251 // Step 2: find the proper match
7253 if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
7254 get = (MethodInfo) Invocation.OverloadResolve (
7255 ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
7258 if (instance_expr.Type != TypeManager.object_type)
7259 Error (30524, "indexer can not be used in this context, because " +
7260 "it lacks a 'get' accessor");
7264 type = get.ReturnType;
7265 if (type.IsPointer && !ec.InUnsafe){
7270 eclass = ExprClass.IndexerAccess;
7274 public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
7276 if (!CommonResolve (ec))
7279 Type right_type = right_side.Type;
7282 ilist = Indexers.GetIndexersForType (
7283 current_type, indexer_type, loc);
7285 if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
7286 set_arguments = (ArrayList) arguments.Clone ();
7287 set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
7289 set = (MethodInfo) Invocation.OverloadResolve (
7290 ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
7294 Error (30526, "indexer X.this [" + TypeManager.MonoBASIC_Name (right_type) +
7295 "] lacks a 'set' accessor");
7299 type = TypeManager.void_type;
7300 eclass = ExprClass.IndexerAccess;
7304 public override void Emit (EmitContext ec)
7306 Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
7310 // source is ignored, because we already have a copy of it from the
7311 // LValue resolution and we have already constructed a pre-cached
7312 // version of the arguments (ea.set_arguments);
7314 public void EmitAssign (EmitContext ec, Expression source)
7316 Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
7321 /// The base operator for method names
7323 public class BaseAccess : Expression {
7324 public string member;
7326 public BaseAccess (string member, Location l)
7328 this.member = member;
7332 public override Expression DoResolve (EmitContext ec)
7334 Expression member_lookup;
7335 Type current_type = ec.ContainerType;
7336 Type base_type = current_type.BaseType;
7340 Error (1511, "Keyword MyBase is not allowed in static method");
7344 if (member == "New")
7347 member_lookup = MemberLookup (ec, current_type, base_type, member,
7348 AllMemberTypes, AllBindingFlags, loc);
7350 if (member_lookup == null) {
7352 TypeManager.MonoBASIC_Name (base_type) + " does not " +
7353 "contain a definition for '" + member + "'");
7360 left = new TypeExpr (base_type, loc);
7364 e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
7366 if (e is PropertyExpr) {
7367 PropertyExpr pe = (PropertyExpr) e;
7375 public override void Emit (EmitContext ec)
7377 throw new Exception ("Should never be called");
7382 /// The base indexer operator
7384 public class BaseIndexerAccess : IndexerAccess {
7385 public BaseIndexerAccess (ArrayList args, Location loc)
7386 : base (null, true, loc)
7388 arguments = new ArrayList ();
7389 foreach (Expression tmp in args)
7390 arguments.Add (new Argument (tmp, Argument.AType.Expression));
7393 protected override bool CommonResolve (EmitContext ec)
7395 instance_expr = ec.This;
7397 current_type = ec.ContainerType.BaseType;
7398 indexer_type = current_type;
7400 foreach (Argument a in arguments){
7401 if (!a.Resolve (ec, loc))
7410 /// This class exists solely to pass the Type around and to be a dummy
7411 /// that can be passed to the conversion functions (this is used by
7412 /// foreach implementation to typecast the object return value from
7413 /// get_Current into the proper type. All code has been generated and
7414 /// we only care about the side effect conversions to be performed
7416 /// This is also now used as a placeholder where a no-action expression
7417 /// is needed (the 'New' class).
7419 public class EmptyExpression : Expression {
7420 public EmptyExpression ()
7422 type = TypeManager.object_type;
7423 eclass = ExprClass.Value;
7424 loc = Location.Null;
7427 public EmptyExpression (Type t)
7430 eclass = ExprClass.Value;
7431 loc = Location.Null;
7434 public override Expression DoResolve (EmitContext ec)
7439 public override void Emit (EmitContext ec)
7441 // nothing, as we only exist to not do anything.
7445 // This is just because we might want to reuse this bad boy
7446 // instead of creating gazillions of EmptyExpressions.
7447 // (CanConvertImplicit uses it)
7449 public void SetType (Type t)
7455 public class UserCast : Expression {
7459 public UserCast (MethodInfo method, Expression source, Location l)
7461 this.method = method;
7462 this.source = source;
7463 type = method.ReturnType;
7464 eclass = ExprClass.Value;
7468 public override Expression DoResolve (EmitContext ec)
7471 // We are born fully resolved
7476 public override void Emit (EmitContext ec)
7478 ILGenerator ig = ec.ig;
7482 if (method is MethodInfo)
7483 ig.Emit (OpCodes.Call, (MethodInfo) method);
7485 ig.Emit (OpCodes.Call, (ConstructorInfo) method);
7491 // This class is used to "construct" the type during a typecast
7492 // operation. Since the Type.GetType class in .NET can parse
7493 // the type specification, we just use this to construct the type
7494 // one bit at a time.
7496 public class ComposedCast : Expression, ITypeExpression {
7500 public ComposedCast (Expression left, string dim, Location l)
7507 public Expression DoResolveType (EmitContext ec)
7509 Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
7514 // ltype.Fullname is already fully qualified, so we can skip
7515 // a lot of probes, and go directly to TypeManager.LookupType
7517 string cname = ltype.FullName + dim;
7518 type = TypeManager.LookupTypeDirect (cname);
7521 // For arrays of enumerations we are having a problem
7522 // with the direct lookup. Need to investigate.
7524 // For now, fall back to the full lookup in that case.
7526 type = RootContext.LookupType (
7527 ec.DeclSpace, cname, false, loc);
7533 if (!ec.ResolvingTypeTree){
7535 // If the above flag is set, this is being invoked from the ResolveType function.
7536 // Upper layers take care of the type validity in this context.
7538 if (!ec.InUnsafe && type.IsPointer){
7544 eclass = ExprClass.Type;
7548 public override Expression DoResolve (EmitContext ec)
7550 return DoResolveType (ec);
7553 public override void Emit (EmitContext ec)
7555 throw new Exception ("This should never be called");
7558 public override string ToString ()
7565 // This class is used to represent the address of an array, used
7566 // only by the Fixed statement, this is like the C "&a [0]" construct.
7568 public class ArrayPtr : Expression {
7571 public ArrayPtr (Expression array, Location l)
7573 Type array_type = array.Type.GetElementType ();
7577 string array_ptr_type_name = array_type.FullName + "*";
7579 type = Type.GetType (array_ptr_type_name);
7581 ModuleBuilder mb = CodeGen.ModuleBuilder;
7583 type = mb.GetType (array_ptr_type_name);
7586 eclass = ExprClass.Value;
7590 public override void Emit (EmitContext ec)
7592 ILGenerator ig = ec.ig;
7595 IntLiteral.EmitInt (ig, 0);
7596 ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
7599 public override Expression DoResolve (EmitContext ec)
7602 // We are born fully resolved
7609 // Used by the fixed statement
7611 public class StringPtr : Expression {
7614 public StringPtr (LocalBuilder b, Location l)
7617 eclass = ExprClass.Value;
7618 type = TypeManager.char_ptr_type;
7622 public override Expression DoResolve (EmitContext ec)
7624 // This should never be invoked, we are born in fully
7625 // initialized state.
7630 public override void Emit (EmitContext ec)
7632 ILGenerator ig = ec.ig;
7634 ig.Emit (OpCodes.Ldloc, b);
7635 ig.Emit (OpCodes.Conv_I);
7636 ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
7637 ig.Emit (OpCodes.Add);
7642 // Implements the 'stackalloc' keyword
7644 public class StackAlloc : Expression {
7649 public StackAlloc (Expression type, Expression count, Location l)
7656 public override Expression DoResolve (EmitContext ec)
7658 count = count.Resolve (ec);
7662 if (count.Type != TypeManager.int32_type){
7663 count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
7668 if (ec.InCatch || ec.InFinally){
7670 "stackalloc can not be used in a catch or finally block");
7674 otype = ec.DeclSpace.ResolveType (t, false, loc);
7679 if (!TypeManager.VerifyUnManaged (otype, loc))
7682 string ptr_name = otype.FullName + "*";
7683 type = Type.GetType (ptr_name);
7685 ModuleBuilder mb = CodeGen.ModuleBuilder;
7687 type = mb.GetType (ptr_name);
7689 eclass = ExprClass.Value;
7694 public override void Emit (EmitContext ec)
7696 int size = GetTypeSize (otype);
7697 ILGenerator ig = ec.ig;
7700 ig.Emit (OpCodes.Sizeof, otype);
7702 IntConstant.EmitInt (ig, size);
7704 ig.Emit (OpCodes.Mul);
7705 ig.Emit (OpCodes.Localloc);
7708 public class Preserve : ExpressionStatement {
7709 ArrayList args = null;
7710 MethodInfo mi = null;
7711 Expression target = null;
7712 ExpressionStatement source = null;
7715 public Preserve (Expression RedimTarget, ExpressionStatement acExpr, Location l)
7717 Type type = typeof(Microsoft.VisualBasic.CompilerServices.Utils);
7718 mi = type.GetMethod("CopyArray");
7720 target = RedimTarget;
7723 eclass = ExprClass.Value;
7727 public override Expression DoResolve (EmitContext ec)
7730 // We are born fully resolved
7732 type = mi.ReturnType;
7734 source.Resolve (ec);
7739 public override void Emit (EmitContext ec)
7741 args = new ArrayList (2);
7743 args.Add (new Argument (target, Argument.AType.Expression));
7744 args.Add (new Argument (source, Argument.AType.Expression));
7746 Invocation.EmitArguments (ec, mi, args);
7748 ec.ig.Emit (OpCodes.Call, mi);
7752 public override void EmitStatement (EmitContext ec)