-//\r
-// expression.cs: Expression representation for the IL tree.\r
-//\r
-// Author:\r
-// Miguel de Icaza (miguel@ximian.com)\r
-//\r
-// (C) 2001 Ximian, Inc.\r
-//\r
-//\r
-#define USE_OLD\r
-\r
-namespace Mono.CSharp {\r
- using System;\r
- using System.Collections;\r
- using System.Diagnostics;\r
- using System.Reflection;\r
- using System.Reflection.Emit;\r
- using System.Text;\r
-\r
- /// <summary>\r
- /// This is just a helper class, it is generated by Unary, UnaryMutator\r
- /// when an overloaded method has been found. It just emits the code for a\r
- /// static call.\r
- /// </summary>\r
- public class StaticCallExpr : ExpressionStatement {\r
- ArrayList args;\r
- MethodInfo mi;\r
-\r
- StaticCallExpr (MethodInfo m, ArrayList a)\r
- {\r
- mi = m;\r
- args = a;\r
-\r
- type = m.ReturnType;\r
- eclass = ExprClass.Value;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // We are born fully resolved\r
- //\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- if (args != null) \r
- Invocation.EmitArguments (ec, mi, args);\r
-\r
- ec.ig.Emit (OpCodes.Call, mi);\r
- return;\r
- }\r
- \r
- static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,\r
- Expression e, Location loc)\r
- {\r
- ArrayList args;\r
- MethodBase method;\r
- \r
- args = new ArrayList (1);\r
- args.Add (new Argument (e, Argument.AType.Expression));\r
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);\r
-\r
- if (method == null)\r
- return null;\r
-\r
- return new StaticCallExpr ((MethodInfo) method, args);\r
- }\r
-\r
- public override void EmitStatement (EmitContext ec)\r
- {\r
- Emit (ec);\r
- if (type != TypeManager.void_type)\r
- ec.ig.Emit (OpCodes.Pop);\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// Unary expressions. \r
- /// </summary>\r
- ///\r
- /// <remarks>\r
- /// Unary implements unary expressions. It derives from\r
- /// ExpressionStatement becuase the pre/post increment/decrement\r
- /// operators can be used in a statement context.\r
- /// </remarks>\r
- public class Unary : Expression {\r
- public enum Operator : byte {\r
- UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,\r
- Indirection, AddressOf, TOP\r
- }\r
-\r
- Operator oper;\r
- Expression expr;\r
- Location loc;\r
- \r
- public Unary (Operator op, Expression expr, Location loc)\r
- {\r
- this.oper = op;\r
- this.expr = expr;\r
- this.loc = loc;\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
-\r
- set {\r
- expr = value;\r
- }\r
- }\r
-\r
- public Operator Oper {\r
- get {\r
- return oper;\r
- }\r
-\r
- set {\r
- oper = value;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Returns a stringified representation of the Operator\r
- /// </summary>\r
- static public string OperName (Operator oper)\r
- {\r
- switch (oper){\r
- case Operator.UnaryPlus:\r
- return "+";\r
- case Operator.UnaryNegation:\r
- return "-";\r
- case Operator.LogicalNot:\r
- return "!";\r
- case Operator.OnesComplement:\r
- return "~";\r
- case Operator.AddressOf:\r
- return "&";\r
- case Operator.Indirection:\r
- return "*";\r
- }\r
-\r
- return oper.ToString ();\r
- }\r
-\r
- static string [] oper_names;\r
-\r
- static Unary ()\r
- {\r
- oper_names = new string [(int)Operator.TOP];\r
-\r
- oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";\r
- oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";\r
- oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";\r
- oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";\r
- oper_names [(int) Operator.Indirection] = "op_Indirection";\r
- oper_names [(int) Operator.AddressOf] = "op_AddressOf";\r
- }\r
-\r
- void Error23 (Type t)\r
- {\r
- Report.Error (\r
- 23, loc, "Operator " + OperName (oper) +\r
- " cannot be applied to operand of type `" +\r
- TypeManager.CSharpName (t) + "'");\r
- }\r
-\r
- /// <remarks>\r
- /// The result has been already resolved:\r
- ///\r
- /// FIXME: a minus constant -128 sbyte cant be turned into a\r
- /// constant byte.\r
- /// </remarks>\r
- static Expression TryReduceNegative (Expression expr)\r
- {\r
- Expression e = null;\r
- \r
- if (expr is IntConstant)\r
- e = new IntConstant (-((IntConstant) expr).Value);\r
- else if (expr is UIntConstant)\r
- e = new LongConstant (-((UIntConstant) expr).Value);\r
- else if (expr is LongConstant)\r
- e = new LongConstant (-((LongConstant) expr).Value);\r
- else if (expr is FloatConstant)\r
- e = new FloatConstant (-((FloatConstant) expr).Value);\r
- else if (expr is DoubleConstant)\r
- e = new DoubleConstant (-((DoubleConstant) expr).Value);\r
- else if (expr is DecimalConstant)\r
- e = new DecimalConstant (-((DecimalConstant) expr).Value);\r
- else if (expr is ShortConstant)\r
- e = new IntConstant (-((ShortConstant) expr).Value);\r
- else if (expr is UShortConstant)\r
- e = new IntConstant (-((UShortConstant) expr).Value);\r
-\r
- return e;\r
- }\r
- \r
- Expression Reduce (EmitContext ec, Expression e)\r
- {\r
- Type expr_type = e.Type;\r
- \r
- switch (oper){\r
- case Operator.UnaryPlus:\r
- return e;\r
- \r
- case Operator.UnaryNegation:\r
- return TryReduceNegative (e);\r
- \r
- case Operator.LogicalNot:\r
- if (expr_type != TypeManager.bool_type) {\r
- Error23 (expr_type);\r
- return null;\r
- }\r
- \r
- BoolConstant b = (BoolConstant) e;\r
- return new BoolConstant (!(b.Value));\r
- \r
- case Operator.OnesComplement:\r
- if (!((expr_type == TypeManager.int32_type) ||\r
- (expr_type == TypeManager.uint32_type) ||\r
- (expr_type == TypeManager.int64_type) ||\r
- (expr_type == TypeManager.uint64_type) ||\r
- (expr_type.IsSubclassOf (TypeManager.enum_type)))){\r
- Error23 (expr_type);\r
- return null;\r
- }\r
-\r
- if (e is EnumConstant){\r
- EnumConstant enum_constant = (EnumConstant) e;\r
- \r
- Expression reduced = Reduce (ec, enum_constant.Child);\r
-\r
- return new EnumConstant ((Constant) reduced, enum_constant.Type);\r
- }\r
-\r
- if (expr_type == TypeManager.int32_type)\r
- return new IntConstant (~ ((IntConstant) e).Value);\r
- if (expr_type == TypeManager.uint32_type)\r
- return new UIntConstant (~ ((UIntConstant) e).Value);\r
- if (expr_type == TypeManager.int64_type)\r
- return new LongConstant (~ ((LongConstant) e).Value);\r
- if (expr_type == TypeManager.uint64_type)\r
- return new ULongConstant (~ ((ULongConstant) e).Value);\r
-\r
- Error23 (expr_type);\r
- return null;\r
- }\r
- throw new Exception ("Can not constant fold");\r
- }\r
-\r
- Expression ResolveOperator (EmitContext ec)\r
- {\r
- Type expr_type = expr.Type;\r
-\r
- //\r
- // Step 1: Perform Operator Overload location\r
- //\r
- Expression mg;\r
- string op_name;\r
- \r
- op_name = oper_names [(int) oper];\r
-\r
- mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);\r
- \r
- if (mg != null) {\r
- Expression e = StaticCallExpr.MakeSimpleCall (\r
- ec, (MethodGroupExpr) mg, expr, loc);\r
-\r
- if (e == null){\r
- Error23 (expr_type);\r
- return null;\r
- }\r
- \r
- return e;\r
- }\r
-\r
- // Only perform numeric promotions on:\r
- // +, - \r
-\r
- if (expr_type == null)\r
- return null;\r
- \r
- //\r
- // Step 2: Default operations on CLI native types.\r
- //\r
- if (expr is Constant)\r
- return Reduce (ec, expr);\r
-\r
- if (oper == Operator.LogicalNot){\r
- if (expr_type != TypeManager.bool_type) {\r
- Error23 (expr.Type);\r
- return null;\r
- }\r
- \r
- type = TypeManager.bool_type;\r
- return this;\r
- }\r
-\r
- if (oper == Operator.OnesComplement) {\r
- if (!((expr_type == TypeManager.int32_type) ||\r
- (expr_type == TypeManager.uint32_type) ||\r
- (expr_type == TypeManager.int64_type) ||\r
- (expr_type == TypeManager.uint64_type) ||\r
- (expr_type.IsSubclassOf (TypeManager.enum_type)))){\r
- Error23 (expr.Type);\r
- return null;\r
- }\r
- type = expr_type;\r
- return this;\r
- }\r
-\r
- if (oper == Operator.UnaryPlus) {\r
- //\r
- // A plus in front of something is just a no-op, so return the child.\r
- //\r
- return expr;\r
- }\r
-\r
- //\r
- // Deals with -literals\r
- // int operator- (int x)\r
- // long operator- (long x)\r
- // float operator- (float f)\r
- // double operator- (double d)\r
- // decimal operator- (decimal d)\r
- //\r
- if (oper == Operator.UnaryNegation){\r
- Expression e = null;\r
-\r
- //\r
- // perform numeric promotions to int,\r
- // long, double.\r
- //\r
- //\r
- // The following is inneficient, because we call\r
- // ConvertImplicit too many times.\r
- //\r
- // It is also not clear if we should convert to Float\r
- // or Double initially.\r
- //\r
- if (expr_type == TypeManager.uint32_type){\r
- //\r
- // FIXME: handle exception to this rule that\r
- // permits the int value -2147483648 (-2^31) to\r
- // bt wrote as a decimal interger literal\r
- //\r
- type = TypeManager.int64_type;\r
- expr = ConvertImplicit (ec, expr, type, loc);\r
- return this;\r
- }\r
-\r
- if (expr_type == TypeManager.uint64_type){\r
- //\r
- // FIXME: Handle exception of `long value'\r
- // -92233720368547758087 (-2^63) to be wrote as\r
- // decimal integer literal.\r
- //\r
- Error23 (expr_type);\r
- return null;\r
- }\r
-\r
- if (expr_type == TypeManager.float_type){\r
- type = expr_type;\r
- return this;\r
- }\r
- \r
- e = ConvertImplicit (ec, expr, TypeManager.int32_type, loc);\r
- if (e != null){\r
- expr = e;\r
- type = e.Type;\r
- return this;\r
- } \r
-\r
- e = ConvertImplicit (ec, expr, TypeManager.int64_type, loc);\r
- if (e != null){\r
- expr = e;\r
- type = e.Type;\r
- return this;\r
- }\r
-\r
- e = ConvertImplicit (ec, expr, TypeManager.double_type, loc);\r
- if (e != null){\r
- expr = e;\r
- type = e.Type;\r
- return this;\r
- }\r
-\r
- Error23 (expr_type);\r
- return null;\r
- }\r
-\r
- if (oper == Operator.AddressOf){\r
- if (expr.eclass != ExprClass.Variable){\r
- Error (211, loc, "Cannot take the address of non-variables");\r
- return null;\r
- }\r
-\r
- if (!ec.InUnsafe) {\r
- UnsafeError (loc); \r
- return null;\r
- }\r
-\r
- if (!TypeManager.VerifyUnManaged (expr.Type, loc)){\r
- return null;\r
- }\r
- \r
- //\r
- // This construct is needed because dynamic types\r
- // are not known by Type.GetType, so we have to try then to use\r
- // ModuleBuilder.GetType.\r
- //\r
- string ptr_type_name = expr.Type.FullName + "*";\r
- type = Type.GetType (ptr_type_name);\r
- if (type == null)\r
- type = RootContext.ModuleBuilder.GetType (ptr_type_name);\r
- \r
- return this;\r
- }\r
-\r
- if (oper == Operator.Indirection){\r
- if (!ec.InUnsafe){\r
- UnsafeError (loc);\r
- return null;\r
- }\r
-\r
- if (!expr_type.IsPointer){\r
- Report.Error (\r
- 193, loc,\r
- "The * or -> operator can only be applied to pointers");\r
- return null;\r
- }\r
-\r
- //\r
- // We create an Indirection expression, because\r
- // it can implement the IMemoryLocation.\r
- // \r
- return new Indirection (expr);\r
- }\r
- \r
- Error (187, loc, "No such operator '" + OperName (oper) + "' defined for type '" +\r
- TypeManager.CSharpName (expr_type) + "'");\r
- return null;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- expr = expr.Resolve (ec);\r
- \r
- if (expr == null)\r
- return null;\r
-\r
- eclass = ExprClass.Value;\r
- return ResolveOperator (ec);\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- Type expr_type = expr.Type;\r
- \r
- switch (oper) {\r
- case Operator.UnaryPlus:\r
- throw new Exception ("This should be caught by Resolve");\r
- \r
- case Operator.UnaryNegation:\r
- expr.Emit (ec);\r
- ig.Emit (OpCodes.Neg);\r
- break;\r
- \r
- case Operator.LogicalNot:\r
- expr.Emit (ec);\r
- ig.Emit (OpCodes.Ldc_I4_0);\r
- ig.Emit (OpCodes.Ceq);\r
- break;\r
- \r
- case Operator.OnesComplement:\r
- expr.Emit (ec);\r
- ig.Emit (OpCodes.Not);\r
- break;\r
- \r
- case Operator.AddressOf:\r
- ((IMemoryLocation)expr).AddressOf (ec, AddressOp.LoadStore);\r
- break;\r
- \r
- default:\r
- throw new Exception ("This should not happen: Operator = "\r
- + oper.ToString ());\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// This will emit the child expression for `ec' avoiding the logical\r
- /// not. The parent will take care of changing brfalse/brtrue\r
- /// </summary>\r
- public void EmitLogicalNot (EmitContext ec)\r
- {\r
- if (oper != Operator.LogicalNot)\r
- throw new Exception ("EmitLogicalNot can only be called with !expr");\r
-\r
- expr.Emit (ec);\r
- }\r
-\r
- public override string ToString ()\r
- {\r
- return "Unary (" + oper + ", " + expr + ")";\r
- }\r
- \r
- }\r
-\r
- //\r
- // Unary operators are turned into Indirection expressions\r
- // after semantic analysis (this is so we can take the address\r
- // of an indirection).\r
- //\r
- public class Indirection : Expression, IMemoryLocation, IAssignMethod {\r
- Expression expr;\r
- \r
- public Indirection (Expression expr)\r
- {\r
- this.expr = expr;\r
- this.type = expr.Type.GetElementType ();\r
- eclass = ExprClass.Variable;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- expr.Emit (ec);\r
- LoadFromPtr (ec.ig, Type, false);\r
- }\r
-\r
- public void EmitAssign (EmitContext ec, Expression source)\r
- {\r
- expr.Emit (ec);\r
- source.Emit (ec);\r
- StoreFromPtr (ec.ig, type);\r
- }\r
- \r
- public void AddressOf (EmitContext ec, AddressOp Mode)\r
- {\r
- expr.Emit (ec);\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // Born fully resolved\r
- //\r
- return this;\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// Unary Mutator expressions (pre and post ++ and --)\r
- /// </summary>\r
- ///\r
- /// <remarks>\r
- /// UnaryMutator implements ++ and -- expressions. It derives from\r
- /// ExpressionStatement becuase the pre/post increment/decrement\r
- /// operators can be used in a statement context.\r
- ///\r
- /// FIXME: Idea, we could split this up in two classes, one simpler\r
- /// for the common case, and one with the extra fields for more complex\r
- /// classes (indexers require temporary access; overloaded require method)\r
- ///\r
- /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,\r
- /// PostDecrement, that way we could save the `Mode' byte as well. \r
- /// </remarks>\r
- public class UnaryMutator : ExpressionStatement {\r
- public enum Mode : byte {\r
- PreIncrement, PreDecrement, PostIncrement, PostDecrement\r
- }\r
- \r
- Mode mode;\r
- Location loc;\r
- Expression expr;\r
- LocalTemporary temp_storage;\r
-\r
- //\r
- // This is expensive for the simplest case.\r
- //\r
- Expression method;\r
- \r
- public UnaryMutator (Mode m, Expression e, Location l)\r
- {\r
- mode = m;\r
- loc = l;\r
- expr = e;\r
- }\r
-\r
- static string OperName (Mode mode)\r
- {\r
- return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?\r
- "++" : "--";\r
- }\r
- \r
- void Error23 (Type t)\r
- {\r
- Report.Error (\r
- 23, loc, "Operator " + OperName (mode) + \r
- " cannot be applied to operand of type `" +\r
- TypeManager.CSharpName (t) + "'");\r
- }\r
-\r
- /// <summary>\r
- /// Returns whether an object of type `t' can be incremented\r
- /// or decremented with add/sub (ie, basically whether we can\r
- /// use pre-post incr-decr operations on it, but it is not a\r
- /// System.Decimal, which we require operator overloading to catch)\r
- /// </summary>\r
- static bool IsIncrementableNumber (Type t)\r
- {\r
- return (t == TypeManager.sbyte_type) ||\r
- (t == TypeManager.byte_type) ||\r
- (t == TypeManager.short_type) ||\r
- (t == TypeManager.ushort_type) ||\r
- (t == TypeManager.int32_type) ||\r
- (t == TypeManager.uint32_type) ||\r
- (t == TypeManager.int64_type) ||\r
- (t == TypeManager.uint64_type) ||\r
- (t == TypeManager.char_type) ||\r
- (t.IsSubclassOf (TypeManager.enum_type)) ||\r
- (t == TypeManager.float_type) ||\r
- (t == TypeManager.double_type) ||\r
- (t.IsPointer && t != TypeManager.void_ptr_type);\r
- }\r
-\r
- Expression ResolveOperator (EmitContext ec)\r
- {\r
- Type expr_type = expr.Type;\r
-\r
- //\r
- // Step 1: Perform Operator Overload location\r
- //\r
- Expression mg;\r
- string op_name;\r
- \r
- if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)\r
- op_name = "op_Increment";\r
- else \r
- op_name = "op_Decrement";\r
-\r
- mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);\r
-\r
- if (mg == null && expr_type.BaseType != null)\r
- mg = MemberLookup (ec, expr_type.BaseType, op_name,\r
- MemberTypes.Method, AllBindingFlags, loc);\r
- \r
- if (mg != null) {\r
- method = StaticCallExpr.MakeSimpleCall (\r
- ec, (MethodGroupExpr) mg, expr, loc);\r
-\r
- type = method.Type;\r
- return this;\r
- }\r
-\r
- //\r
- // The operand of the prefix/postfix increment decrement operators\r
- // should be an expression that is classified as a variable,\r
- // a property access or an indexer access\r
- //\r
- type = expr_type;\r
- if (expr.eclass == ExprClass.Variable){\r
- if (IsIncrementableNumber (expr_type) ||\r
- expr_type == TypeManager.decimal_type){\r
- return this;\r
- }\r
- } else if (expr.eclass == ExprClass.IndexerAccess){\r
- IndexerAccess ia = (IndexerAccess) expr;\r
- \r
- temp_storage = new LocalTemporary (ec, expr.Type);\r
- \r
- expr = ia.ResolveLValue (ec, temp_storage);\r
- if (expr == null)\r
- return null;\r
-\r
- return this;\r
- } else if (expr.eclass == ExprClass.PropertyAccess){\r
- PropertyExpr pe = (PropertyExpr) expr;\r
-\r
- if (pe.VerifyAssignable ())\r
- return this;\r
-\r
- return null;\r
- } else {\r
- report118 (loc, expr, "variable, indexer or property access");\r
- return null;\r
- }\r
-\r
- Error (187, loc, "No such operator '" + OperName (mode) + "' defined for type '" +\r
- TypeManager.CSharpName (expr_type) + "'");\r
- return null;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- expr = expr.Resolve (ec);\r
- \r
- if (expr == null)\r
- return null;\r
-\r
- eclass = ExprClass.Value;\r
- return ResolveOperator (ec);\r
- }\r
-\r
- static int PtrTypeSize (Type t)\r
- {\r
- return GetTypeSize (t.GetElementType ());\r
- }\r
- \r
- //\r
- // FIXME: We need some way of avoiding the use of temp_storage\r
- // for some types of storage (parameters, local variables,\r
- // static fields) and single-dimension array access.\r
- //\r
- void EmitCode (EmitContext ec, bool is_expr)\r
- {\r
- ILGenerator ig = ec.ig;\r
- IAssignMethod ia = (IAssignMethod) expr;\r
- Type expr_type = expr.Type;\r
- \r
- if (temp_storage == null)\r
- temp_storage = new LocalTemporary (ec, expr_type);\r
-\r
- switch (mode){\r
- case Mode.PreIncrement:\r
- case Mode.PreDecrement:\r
- if (method == null){\r
- expr.Emit (ec);\r
-\r
- if (expr_type == TypeManager.uint64_type ||\r
- expr_type == TypeManager.int64_type)\r
- ig.Emit (OpCodes.Ldc_I8, 1L);\r
- else if (expr_type == TypeManager.double_type)\r
- ig.Emit (OpCodes.Ldc_R8, 1.0);\r
- else if (expr_type == TypeManager.float_type)\r
- ig.Emit (OpCodes.Ldc_R4, 1.0F);\r
- else if (expr_type.IsPointer){\r
- int n = PtrTypeSize (expr_type);\r
-\r
- if (n == 0)\r
- ig.Emit (OpCodes.Sizeof, expr_type);\r
- else\r
- IntConstant.EmitInt (ig, n);\r
- } else \r
- ig.Emit (OpCodes.Ldc_I4_1);\r
-\r
- //\r
- // Select the opcode based on the check state (then the type)\r
- // and the actual operation\r
- //\r
- if (ec.CheckState){\r
- if (expr_type == TypeManager.int32_type ||\r
- expr_type == TypeManager.int64_type){\r
- if (mode == Mode.PreDecrement)\r
- ig.Emit (OpCodes.Sub_Ovf);\r
- else\r
- ig.Emit (OpCodes.Add_Ovf);\r
- } else if (expr_type == TypeManager.uint32_type ||\r
- expr_type == TypeManager.uint64_type){\r
- if (mode == Mode.PreDecrement)\r
- ig.Emit (OpCodes.Sub_Ovf_Un);\r
- else\r
- ig.Emit (OpCodes.Add_Ovf_Un);\r
- } else {\r
- if (mode == Mode.PreDecrement)\r
- ig.Emit (OpCodes.Sub_Ovf);\r
- else\r
- ig.Emit (OpCodes.Add_Ovf);\r
- }\r
- } else {\r
- if (mode == Mode.PreDecrement)\r
- ig.Emit (OpCodes.Sub);\r
- else\r
- ig.Emit (OpCodes.Add);\r
- }\r
- } else\r
- method.Emit (ec);\r
- \r
- temp_storage.Store (ec);\r
- ia.EmitAssign (ec, temp_storage);\r
- if (is_expr)\r
- temp_storage.Emit (ec);\r
- break;\r
- \r
- case Mode.PostIncrement:\r
- case Mode.PostDecrement:\r
- if (is_expr)\r
- expr.Emit (ec);\r
- \r
- if (method == null){\r
- if (!is_expr)\r
- expr.Emit (ec);\r
- else\r
- ig.Emit (OpCodes.Dup);\r
-\r
- if (expr_type == TypeManager.uint64_type ||\r
- expr_type == TypeManager.int64_type)\r
- ig.Emit (OpCodes.Ldc_I8, 1L);\r
- else if (expr_type == TypeManager.double_type)\r
- ig.Emit (OpCodes.Ldc_R8, 1.0);\r
- else if (expr_type == TypeManager.float_type)\r
- ig.Emit (OpCodes.Ldc_R4, 1.0F);\r
- else if (expr_type.IsPointer){\r
- int n = PtrTypeSize (expr_type);\r
-\r
- if (n == 0)\r
- ig.Emit (OpCodes.Sizeof, expr_type);\r
- else\r
- IntConstant.EmitInt (ig, n);\r
- } else\r
- ig.Emit (OpCodes.Ldc_I4_1);\r
-\r
- if (ec.CheckState){\r
- if (expr_type == TypeManager.int32_type ||\r
- expr_type == TypeManager.int64_type){\r
- if (mode == Mode.PostDecrement)\r
- ig.Emit (OpCodes.Sub_Ovf);\r
- else\r
- ig.Emit (OpCodes.Add_Ovf);\r
- } else if (expr_type == TypeManager.uint32_type ||\r
- expr_type == TypeManager.uint64_type){\r
- if (mode == Mode.PostDecrement)\r
- ig.Emit (OpCodes.Sub_Ovf_Un);\r
- else\r
- ig.Emit (OpCodes.Add_Ovf_Un);\r
- } else {\r
- if (mode == Mode.PostDecrement)\r
- ig.Emit (OpCodes.Sub_Ovf);\r
- else\r
- ig.Emit (OpCodes.Add_Ovf);\r
- }\r
- } else {\r
- if (mode == Mode.PostDecrement)\r
- ig.Emit (OpCodes.Sub);\r
- else\r
- ig.Emit (OpCodes.Add);\r
- }\r
- } else {\r
- method.Emit (ec);\r
- }\r
- \r
- temp_storage.Store (ec);\r
- ia.EmitAssign (ec, temp_storage);\r
- break;\r
- }\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- EmitCode (ec, true);\r
- \r
- }\r
- \r
- public override void EmitStatement (EmitContext ec)\r
- {\r
- EmitCode (ec, false);\r
- }\r
-\r
- }\r
-\r
- /// <summary>\r
- /// Base class for the `Is' and `As' classes. \r
- /// </summary>\r
- ///\r
- /// <remarks>\r
- /// FIXME: Split this in two, and we get to save the `Operator' Oper\r
- /// size. \r
- /// </remarks>\r
- public abstract class Probe : Expression {\r
- public readonly string ProbeType;\r
- protected Expression expr;\r
- protected Type probe_type;\r
- protected Location loc;\r
- \r
- public Probe (Expression expr, string probe_type, Location l)\r
- {\r
- ProbeType = probe_type;\r
- loc = l;\r
- this.expr = expr;\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- probe_type = RootContext.LookupType (ec.DeclSpace, ProbeType, false, loc);\r
-\r
- if (probe_type == null)\r
- return null;\r
-\r
- expr = expr.Resolve (ec);\r
- \r
- return this;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implementation of the `is' operator.\r
- /// </summary>\r
- public class Is : Probe {\r
- public Is (Expression expr, string probe_type, Location l)\r
- : base (expr, probe_type, l)\r
- {\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- \r
- expr.Emit (ec);\r
- \r
- ig.Emit (OpCodes.Isinst, probe_type);\r
- ig.Emit (OpCodes.Ldnull);\r
- ig.Emit (OpCodes.Cgt_Un);\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- Expression e = base.DoResolve (ec);\r
-\r
- if (e == null)\r
- return null;\r
-\r
- if (RootContext.WarningLevel >= 1){\r
- if (expr.Type == probe_type || expr.Type.IsSubclassOf (probe_type)){\r
- Report.Warning (\r
- 183, loc,\r
- "The expression is always of type `" +\r
- TypeManager.CSharpName (probe_type) + "'");\r
- }\r
-\r
- if (expr.Type != probe_type && !probe_type.IsSubclassOf (expr.Type)){\r
- if (!(probe_type.IsInterface || expr.Type.IsInterface))\r
- Report.Warning (\r
- 184, loc,\r
- "The expression is never of type `" +\r
- TypeManager.CSharpName (probe_type) + "'");\r
- }\r
- }\r
- \r
- type = TypeManager.bool_type;\r
- eclass = ExprClass.Value;\r
-\r
- return this;\r
- } \r
- }\r
-\r
- /// <summary>\r
- /// Implementation of the `as' operator.\r
- /// </summary>\r
- public class As : Probe {\r
- public As (Expression expr, string probe_type, Location l)\r
- : base (expr, probe_type, l)\r
- {\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
-\r
- expr.Emit (ec);\r
- ig.Emit (OpCodes.Isinst, probe_type);\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- Expression e = base.DoResolve (ec);\r
-\r
- if (e == null)\r
- return null;\r
-\r
- type = probe_type;\r
- eclass = ExprClass.Value;\r
-\r
- return this;\r
- } \r
- }\r
- \r
- /// <summary>\r
- /// This represents a typecast in the source language.\r
- ///\r
- /// FIXME: Cast expressions have an unusual set of parsing\r
- /// rules, we need to figure those out.\r
- /// </summary>\r
- public class Cast : Expression {\r
- Expression target_type;\r
- Expression expr;\r
- Location loc;\r
- \r
- public Cast (Expression cast_type, Expression expr, Location loc)\r
- {\r
- this.target_type = cast_type;\r
- this.expr = expr;\r
- this.loc = loc;\r
- }\r
-\r
- public Expression TargetType {\r
- get {\r
- return target_type;\r
- }\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
- set {\r
- expr = value;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Attempts to do a compile-time folding of a constant cast.\r
- /// </summary>\r
- Expression TryReduce (EmitContext ec, Type target_type)\r
- {\r
- if (expr is ByteConstant){\r
- byte v = ((ByteConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is SByteConstant){\r
- sbyte v = ((SByteConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is ShortConstant){\r
- short v = ((ShortConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is UShortConstant){\r
- ushort v = ((UShortConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is IntConstant){\r
- int v = ((IntConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is UIntConstant){\r
- uint v = ((UIntConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is LongConstant){\r
- long v = ((LongConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is ULongConstant){\r
- ulong v = ((ULongConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is FloatConstant){\r
- float v = ((FloatConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.double_type)\r
- return new DoubleConstant ((double) v);\r
- }\r
- if (expr is DoubleConstant){\r
- double v = ((DoubleConstant) expr).Value;\r
- \r
- if (target_type == TypeManager.byte_type)\r
- return new ByteConstant ((byte) v);\r
- if (target_type == TypeManager.sbyte_type)\r
- return new SByteConstant ((sbyte) v);\r
- if (target_type == TypeManager.short_type)\r
- return new ShortConstant ((short) v);\r
- if (target_type == TypeManager.ushort_type)\r
- return new UShortConstant ((ushort) v);\r
- if (target_type == TypeManager.int32_type)\r
- return new IntConstant ((int) v);\r
- if (target_type == TypeManager.uint32_type)\r
- return new UIntConstant ((uint) v);\r
- if (target_type == TypeManager.int64_type)\r
- return new LongConstant ((long) v);\r
- if (target_type == TypeManager.uint64_type)\r
- return new ULongConstant ((ulong) v);\r
- if (target_type == TypeManager.float_type)\r
- return new FloatConstant ((float) v);\r
- }\r
-\r
- return null;\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- expr = expr.Resolve (ec);\r
- if (expr == null)\r
- return null;\r
-\r
- bool old_state = ec.OnlyLookupTypes;\r
- ec.OnlyLookupTypes = true;\r
- target_type = target_type.Resolve (ec);\r
- ec.OnlyLookupTypes = old_state;\r
- \r
- if (target_type == null){\r
- Report.Error (-10, loc, "Can not resolve type");\r
- return null;\r
- }\r
-\r
- if (target_type.eclass != ExprClass.Type){\r
- report118 (loc, target_type, "class");\r
- return null;\r
- }\r
- \r
- type = target_type.Type;\r
- eclass = ExprClass.Value;\r
- \r
- if (type == null)\r
- return null;\r
-\r
- if (expr is Constant){\r
- Expression e = TryReduce (ec, type);\r
-\r
- if (e != null)\r
- return e;\r
- }\r
- \r
- expr = ConvertExplicit (ec, expr, type, loc);\r
- return expr;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- //\r
- // This one will never happen\r
- //\r
- throw new Exception ("Should not happen");\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Binary operators\r
- /// </summary>\r
- public class Binary : Expression {\r
- public enum Operator : byte {\r
- Multiply, Division, Modulus,\r
- Addition, Subtraction,\r
- LeftShift, RightShift,\r
- LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual, \r
- Equality, Inequality,\r
- BitwiseAnd,\r
- ExclusiveOr,\r
- BitwiseOr,\r
- LogicalAnd,\r
- LogicalOr\r
- }\r
-\r
- Operator oper;\r
- Expression left, right;\r
- MethodBase method;\r
- ArrayList Arguments;\r
- Location loc;\r
-\r
- bool DelegateOperation;\r
-\r
- public Binary (Operator oper, Expression left, Expression right, Location loc)\r
- {\r
- this.oper = oper;\r
- this.left = left;\r
- this.right = right;\r
- this.loc = loc;\r
- }\r
-\r
- public Operator Oper {\r
- get {\r
- return oper;\r
- }\r
- set {\r
- oper = value;\r
- }\r
- }\r
- \r
- public Expression Left {\r
- get {\r
- return left;\r
- }\r
- set {\r
- left = value;\r
- }\r
- }\r
-\r
- public Expression Right {\r
- get {\r
- return right;\r
- }\r
- set {\r
- right = value;\r
- }\r
- }\r
-\r
-\r
- /// <summary>\r
- /// Returns a stringified representation of the Operator\r
- /// </summary>\r
- static string OperName (Operator oper)\r
- {\r
- switch (oper){\r
- case Operator.Multiply:\r
- return "*";\r
- case Operator.Division:\r
- return "/";\r
- case Operator.Modulus:\r
- return "%";\r
- case Operator.Addition:\r
- return "+";\r
- case Operator.Subtraction:\r
- return "-";\r
- case Operator.LeftShift:\r
- return "<<";\r
- case Operator.RightShift:\r
- return ">>";\r
- case Operator.LessThan:\r
- return "<";\r
- case Operator.GreaterThan:\r
- return ">";\r
- case Operator.LessThanOrEqual:\r
- return "<=";\r
- case Operator.GreaterThanOrEqual:\r
- return ">=";\r
- case Operator.Equality:\r
- return "==";\r
- case Operator.Inequality:\r
- return "!=";\r
- case Operator.BitwiseAnd:\r
- return "&";\r
- case Operator.BitwiseOr:\r
- return "|";\r
- case Operator.ExclusiveOr:\r
- return "^";\r
- case Operator.LogicalOr:\r
- return "||";\r
- case Operator.LogicalAnd:\r
- return "&&";\r
- }\r
-\r
- return oper.ToString ();\r
- }\r
-\r
- Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)\r
- {\r
- if (expr.Type == target_type)\r
- return expr;\r
-\r
- return ConvertImplicit (ec, expr, target_type, new Location (-1));\r
- }\r
-\r
- public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)\r
- {\r
- Report.Error (\r
- 34, loc, "Operator `" + OperName (oper) \r
- + "' is ambiguous on operands of type `"\r
- + TypeManager.CSharpName (l) + "' "\r
- + "and `" + TypeManager.CSharpName (r)\r
- + "'");\r
- }\r
-\r
- //\r
- // Note that handling the case l == Decimal || r == Decimal\r
- // is taken care of by the Step 1 Operator Overload resolution.\r
- //\r
- bool DoNumericPromotions (EmitContext ec, Type l, Type r)\r
- {\r
- if (l == TypeManager.double_type || r == TypeManager.double_type){\r
- //\r
- // If either operand is of type double, the other operand is\r
- // conveted to type double.\r
- //\r
- if (r != TypeManager.double_type)\r
- right = ConvertImplicit (ec, right, TypeManager.double_type, loc);\r
- if (l != TypeManager.double_type)\r
- left = ConvertImplicit (ec, left, TypeManager.double_type, loc);\r
- \r
- type = TypeManager.double_type;\r
- } else if (l == TypeManager.float_type || r == TypeManager.float_type){\r
- //\r
- // if either operand is of type float, the other operand is\r
- // converted to type float.\r
- //\r
- if (r != TypeManager.double_type)\r
- right = ConvertImplicit (ec, right, TypeManager.float_type, loc);\r
- if (l != TypeManager.double_type)\r
- left = ConvertImplicit (ec, left, TypeManager.float_type, loc);\r
- type = TypeManager.float_type;\r
- } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){\r
- Expression e;\r
- Type other;\r
- //\r
- // If either operand is of type ulong, the other operand is\r
- // converted to type ulong. or an error ocurrs if the other\r
- // operand is of type sbyte, short, int or long\r
- //\r
- if (l == TypeManager.uint64_type){\r
- if (r != TypeManager.uint64_type){\r
- if (right is IntConstant){\r
- IntConstant ic = (IntConstant) right;\r
- \r
- e = TryImplicitIntConversion (l, ic);\r
- if (e != null)\r
- right = e;\r
- } else if (right is LongConstant){\r
- long ll = ((LongConstant) right).Value;\r
-\r
- if (ll > 0)\r
- right = new ULongConstant ((ulong) ll);\r
- } else {\r
- e = ImplicitNumericConversion (ec, right, l, loc);\r
- if (e != null)\r
- right = e;\r
- }\r
- }\r
- other = right.Type;\r
- } else {\r
- if (left is IntConstant){\r
- e = TryImplicitIntConversion (r, (IntConstant) left);\r
- if (e != null)\r
- left = e;\r
- } else if (left is LongConstant){\r
- long ll = ((LongConstant) left).Value;\r
- \r
- if (ll > 0)\r
- left = new ULongConstant ((ulong) ll);\r
- } else {\r
- e = ImplicitNumericConversion (ec, left, r, loc);\r
- if (e != null)\r
- left = e;\r
- }\r
- other = left.Type;\r
- }\r
-\r
- if ((other == TypeManager.sbyte_type) ||\r
- (other == TypeManager.short_type) ||\r
- (other == TypeManager.int32_type) ||\r
- (other == TypeManager.int64_type))\r
- Error_OperatorAmbiguous (loc, oper, l, r);\r
- type = TypeManager.uint64_type;\r
- } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){\r
- //\r
- // If either operand is of type long, the other operand is converted\r
- // to type long.\r
- //\r
- if (l != TypeManager.int64_type)\r
- left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);\r
- if (r != TypeManager.int64_type)\r
- right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);\r
-\r
- type = TypeManager.int64_type;\r
- } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){\r
- //\r
- // If either operand is of type uint, and the other\r
- // operand is of type sbyte, short or int, othe operands are\r
- // converted to type long.\r
- //\r
- Type other = null;\r
- \r
- if (l == TypeManager.uint32_type){\r
- if (right is IntConstant){\r
- IntConstant ic = (IntConstant) right;\r
- int val = ic.Value;\r
- \r
- if (val >= 0)\r
- right = new UIntConstant ((uint) val);\r
-\r
- type = l;\r
- return true;\r
- }\r
- other = r;\r
- } \r
- else if (r == TypeManager.uint32_type){\r
- if (left is IntConstant){\r
- IntConstant ic = (IntConstant) left;\r
- int val = ic.Value;\r
- \r
- if (val >= 0)\r
- left = new UIntConstant ((uint) val);\r
-\r
- type = r;\r
- return true;\r
- }\r
- \r
- other = l;\r
- }\r
-\r
- if ((other == TypeManager.sbyte_type) ||\r
- (other == TypeManager.short_type) ||\r
- (other == TypeManager.int32_type)){\r
- left = ForceConversion (ec, left, TypeManager.int64_type);\r
- right = ForceConversion (ec, right, TypeManager.int64_type);\r
- type = TypeManager.int64_type;\r
- } else {\r
- //\r
- // if either operand is of type uint, the other\r
- // operand is converd to type uint\r
- //\r
- left = ForceConversion (ec, left, TypeManager.uint32_type);\r
- right = ForceConversion (ec, right, TypeManager.uint32_type);\r
- type = TypeManager.uint32_type;\r
- } \r
- } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){\r
- if (l != TypeManager.decimal_type)\r
- left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);\r
- if (r != TypeManager.decimal_type)\r
- right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);\r
-\r
- type = TypeManager.decimal_type;\r
- } else {\r
- Expression l_tmp, r_tmp;\r
-\r
- l_tmp = ForceConversion (ec, left, TypeManager.int32_type);\r
- if (l_tmp == null)\r
- return false;\r
- \r
- r_tmp = ForceConversion (ec, right, TypeManager.int32_type);\r
- if (r_tmp == null)\r
- return false;\r
-\r
- left = l_tmp;\r
- right = r_tmp;\r
- \r
- type = TypeManager.int32_type;\r
- }\r
-\r
- return true;\r
- }\r
-\r
- static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)\r
- {\r
- Error (19, loc,\r
- "Operator " + name + " cannot be applied to operands of type `" +\r
- TypeManager.CSharpName (l) + "' and `" +\r
- TypeManager.CSharpName (r) + "'");\r
- }\r
- \r
- void error19 ()\r
- {\r
- Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);\r
- }\r
-\r
- static bool is_32_or_64 (Type t)\r
- {\r
- return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||\r
- t == TypeManager.int64_type || t == TypeManager.uint64_type);\r
- }\r
- \r
- Expression CheckShiftArguments (EmitContext ec)\r
- {\r
- Expression e;\r
- Type l = left.Type;\r
- Type r = right.Type;\r
-\r
- e = ForceConversion (ec, right, TypeManager.int32_type);\r
- if (e == null){\r
- error19 ();\r
- return null;\r
- }\r
- right = e;\r
-\r
- if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||\r
- ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||\r
- ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||\r
- ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){\r
- left = e;\r
- type = e.Type;\r
-\r
- return this;\r
- }\r
- error19 ();\r
- return null;\r
- }\r
- \r
- Expression ResolveOperator (EmitContext ec)\r
- {\r
- Type l = left.Type;\r
- Type r = right.Type;\r
-\r
- //\r
- // Step 1: Perform Operator Overload location\r
- //\r
- Expression left_expr, right_expr;\r
- \r
- string op = "op_" + oper;\r
-\r
- MethodGroupExpr union;\r
- left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);\r
- if (r != l){\r
- right_expr = MemberLookup (\r
- ec, r, op, MemberTypes.Method, AllBindingFlags, loc);\r
- union = Invocation.MakeUnionSet (left_expr, right_expr);\r
- } else\r
- union = (MethodGroupExpr) left_expr;\r
- \r
- if (union != null) {\r
- Arguments = new ArrayList ();\r
- Arguments.Add (new Argument (left, Argument.AType.Expression));\r
- Arguments.Add (new Argument (right, Argument.AType.Expression));\r
-\r
- method = Invocation.OverloadResolve (ec, union, Arguments, loc);\r
- if (method != null) {\r
- MethodInfo mi = (MethodInfo) method;\r
-\r
- type = mi.ReturnType;\r
- return this;\r
- } else {\r
- error19 ();\r
- return null;\r
- }\r
- } \r
-\r
- //\r
- // Step 2: Default operations on CLI native types.\r
- //\r
-\r
- // Only perform numeric promotions on:\r
- // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=\r
- //\r
- if (oper == Operator.Addition){\r
- //\r
- // If any of the arguments is a string, cast to string\r
- //\r
- if (l == TypeManager.string_type){\r
- \r
- if (r == TypeManager.void_type) {\r
- error19 ();\r
- return null;\r
- }\r
- \r
- if (r == TypeManager.string_type){\r
- if (left is Constant && right is Constant){\r
- StringConstant ls = (StringConstant) left;\r
- StringConstant rs = (StringConstant) right;\r
- \r
- return new StringConstant (\r
- ls.Value + rs.Value);\r
- }\r
- \r
- // string + string\r
- method = TypeManager.string_concat_string_string;\r
- } else {\r
- // string + object\r
- method = TypeManager.string_concat_object_object;\r
- right = ConvertImplicit (ec, right,\r
- TypeManager.object_type, loc);\r
- }\r
- type = TypeManager.string_type;\r
-\r
- Arguments = new ArrayList ();\r
- Arguments.Add (new Argument (left, Argument.AType.Expression));\r
- Arguments.Add (new Argument (right, Argument.AType.Expression));\r
-\r
- return this;\r
- \r
- } else if (r == TypeManager.string_type){\r
- // object + string\r
-\r
- if (l == TypeManager.void_type) {\r
- error19 ();\r
- return null;\r
- }\r
- \r
- method = TypeManager.string_concat_object_object;\r
- left = ConvertImplicit (ec, left, TypeManager.object_type, loc);\r
- Arguments = new ArrayList ();\r
- Arguments.Add (new Argument (left, Argument.AType.Expression));\r
- Arguments.Add (new Argument (right, Argument.AType.Expression));\r
-\r
- type = TypeManager.string_type;\r
-\r
- return this;\r
- }\r
- }\r
-\r
- if (oper == Operator.Addition || oper == Operator.Subtraction) {\r
- if (l.IsSubclassOf (TypeManager.delegate_type) &&\r
- r.IsSubclassOf (TypeManager.delegate_type)) {\r
- \r
- Arguments = new ArrayList ();\r
- Arguments.Add (new Argument (left, Argument.AType.Expression));\r
- Arguments.Add (new Argument (right, Argument.AType.Expression));\r
- \r
- if (oper == Operator.Addition)\r
- method = TypeManager.delegate_combine_delegate_delegate;\r
- else\r
- method = TypeManager.delegate_remove_delegate_delegate;\r
- \r
- DelegateOperation = true;\r
- type = l;\r
- return this;\r
- }\r
-\r
- //\r
- // Pointer arithmetic:\r
- //\r
- // T* operator + (T* x, int y);\r
- // T* operator + (T* x, uint y);\r
- // T* operator + (T* x, long y);\r
- // T* operator + (T* x, ulong y);\r
- //\r
- // T* operator + (int y, T* x);\r
- // T* operator + (uint y, T *x);\r
- // T* operator + (long y, T *x);\r
- // T* operator + (ulong y, T *x);\r
- //\r
- // T* operator - (T* x, int y);\r
- // T* operator - (T* x, uint y);\r
- // T* operator - (T* x, long y);\r
- // T* operator - (T* x, ulong y);\r
- //\r
- // long operator - (T* x, T *y)\r
- //\r
- if (l.IsPointer){\r
- if (r.IsPointer && oper == Operator.Subtraction){\r
- if (r == l)\r
- return new PointerArithmetic (\r
- false, left, right, TypeManager.int64_type);\r
- } else if (is_32_or_64 (r))\r
- return new PointerArithmetic (\r
- oper == Operator.Addition, left, right, l);\r
- } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)\r
- return new PointerArithmetic (\r
- true, right, left, r);\r
- }\r
- \r
- //\r
- // Enumeration operators\r
- //\r
- bool lie = TypeManager.IsEnumType (l);\r
- bool rie = TypeManager.IsEnumType (r);\r
- if (lie || rie){\r
- Expression temp;\r
-\r
- if (!rie){\r
- temp = ConvertImplicit (ec, right, l, loc);\r
- if (temp != null)\r
- right = temp;\r
- } if (!lie){\r
- temp = ConvertImplicit (ec, left, r, loc);\r
- if (temp != null){\r
- left = temp;\r
- l = r;\r
- }\r
- }\r
- \r
- if (oper == Operator.Equality || oper == Operator.Inequality ||\r
- oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||\r
- oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){\r
- type = TypeManager.bool_type;\r
- return this;\r
- }\r
-\r
- if (oper == Operator.BitwiseAnd ||\r
- oper == Operator.BitwiseOr ||\r
- oper == Operator.ExclusiveOr){\r
- type = l;\r
- return this;\r
- }\r
- }\r
- \r
- if (oper == Operator.LeftShift || oper == Operator.RightShift)\r
- return CheckShiftArguments (ec);\r
-\r
- if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){\r
- if (l != TypeManager.bool_type || r != TypeManager.bool_type){\r
- error19 ();\r
- return null;\r
- }\r
-\r
- type = TypeManager.bool_type;\r
- return this;\r
- } \r
-\r
- if (oper == Operator.Equality || oper == Operator.Inequality){\r
- if (l == TypeManager.bool_type || r == TypeManager.bool_type){\r
- if (r != TypeManager.bool_type || l != TypeManager.bool_type){\r
- error19 ();\r
- return null;\r
- }\r
- \r
- type = TypeManager.bool_type;\r
- return this;\r
- }\r
-\r
- //\r
- // operator != (object a, object b)\r
- // operator == (object a, object b)\r
- //\r
- // For this to be used, both arguments have to be reference-types.\r
- // Read the rationale on the spec (14.9.6)\r
- //\r
- // Also, if at compile time we know that the classes do not inherit\r
- // one from the other, then we catch the error there.\r
- //\r
- if (!(l.IsValueType || r.IsValueType)){\r
- type = TypeManager.bool_type;\r
-\r
- if (l == r)\r
- return this;\r
- \r
- if (l.IsSubclassOf (r) || r.IsSubclassOf (l))\r
- return this;\r
-\r
- //\r
- // We are going to have to convert to an object to compare\r
- //\r
- if (l != TypeManager.object_type)\r
- left = new EmptyCast (left, TypeManager.object_type);\r
- if (r != TypeManager.object_type)\r
- right = new EmptyCast (right, TypeManager.object_type);\r
-\r
- return this;\r
- }\r
- }\r
-\r
- //\r
- // Pointer comparison\r
- //\r
- if (l.IsPointer && r.IsPointer){\r
- if (oper == Operator.Equality || oper == Operator.Inequality ||\r
- oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||\r
- oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){\r
- type = TypeManager.bool_type;\r
- return this;\r
- }\r
- }\r
- \r
- //\r
- // We are dealing with numbers\r
- //\r
-\r
- if (!DoNumericPromotions (ec, l, r)){\r
- error19 ();\r
- return null;\r
- }\r
-\r
- if (left == null || right == null)\r
- return null;\r
-\r
- //\r
- // reload our cached types if required\r
- //\r
- l = left.Type;\r
- r = right.Type;\r
- \r
- if (oper == Operator.BitwiseAnd ||\r
- oper == Operator.BitwiseOr ||\r
- oper == Operator.ExclusiveOr){\r
- if (l == r){\r
- if (!((l == TypeManager.int32_type) ||\r
- (l == TypeManager.uint32_type) ||\r
- (l == TypeManager.int64_type) ||\r
- (l == TypeManager.uint64_type)))\r
- type = l;\r
- } else {\r
- error19 ();\r
- return null;\r
- }\r
- }\r
-\r
- if (oper == Operator.Equality ||\r
- oper == Operator.Inequality ||\r
- oper == Operator.LessThanOrEqual ||\r
- oper == Operator.LessThan ||\r
- oper == Operator.GreaterThanOrEqual ||\r
- oper == Operator.GreaterThan){\r
- type = TypeManager.bool_type;\r
- }\r
-\r
- return this;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- left = left.Resolve (ec);\r
- right = right.Resolve (ec);\r
-\r
- if (left == null || right == null)\r
- return null;\r
-\r
- if (left.Type == null)\r
- throw new Exception (\r
- "Resolve returned non null, but did not set the type! (" +\r
- left + ") at Line: " + loc.Row);\r
- if (right.Type == null)\r
- throw new Exception (\r
- "Resolve returned non null, but did not set the type! (" +\r
- right + ") at Line: "+ loc.Row);\r
-\r
- eclass = ExprClass.Value;\r
-\r
- if (left is Constant && right is Constant){\r
- Expression e = ConstantFold.BinaryFold (\r
- ec, oper, (Constant) left, (Constant) right, loc);\r
- if (e != null)\r
- return e;\r
- }\r
-\r
- return ResolveOperator (ec);\r
- }\r
-\r
- public bool IsBranchable ()\r
- {\r
- if (oper == Operator.Equality ||\r
- oper == Operator.Inequality ||\r
- oper == Operator.LessThan ||\r
- oper == Operator.GreaterThan ||\r
- oper == Operator.LessThanOrEqual ||\r
- oper == Operator.GreaterThanOrEqual){\r
- return true;\r
- } else\r
- return false;\r
- }\r
-\r
- /// <summary>\r
- /// This entry point is used by routines that might want\r
- /// to emit a brfalse/brtrue after an expression, and instead\r
- /// they could use a more compact notation.\r
- ///\r
- /// Typically the code would generate l.emit/r.emit, followed\r
- /// by the comparission and then a brtrue/brfalse. The comparissions\r
- /// are sometimes inneficient (there are not as complete as the branches\r
- /// look for the hacks in Emit using double ceqs).\r
- ///\r
- /// So for those cases we provide EmitBranchable that can emit the\r
- /// branch with the test\r
- /// </summary>\r
- public void EmitBranchable (EmitContext ec, int target)\r
- {\r
- OpCode opcode;\r
- bool close_target = false;\r
- ILGenerator ig = ec.ig;\r
- \r
- //\r
- // short-circuit operators\r
- //\r
- if (oper == Operator.LogicalAnd){\r
- left.Emit (ec);\r
- ig.Emit (OpCodes.Brfalse, target);\r
- right.Emit (ec);\r
- ig.Emit (OpCodes.Brfalse, target);\r
- } else if (oper == Operator.LogicalOr){\r
- left.Emit (ec);\r
- ig.Emit (OpCodes.Brtrue, target);\r
- right.Emit (ec);\r
- ig.Emit (OpCodes.Brfalse, target);\r
- }\r
- \r
- left.Emit (ec);\r
- right.Emit (ec);\r
- \r
- switch (oper){\r
- case Operator.Equality:\r
- if (close_target)\r
- opcode = OpCodes.Beq_S;\r
- else\r
- opcode = OpCodes.Beq;\r
- break;\r
-\r
- case Operator.Inequality:\r
- if (close_target)\r
- opcode = OpCodes.Bne_Un_S;\r
- else\r
- opcode = OpCodes.Bne_Un;\r
- break;\r
-\r
- case Operator.LessThan:\r
- if (close_target)\r
- opcode = OpCodes.Blt_S;\r
- else\r
- opcode = OpCodes.Blt;\r
- break;\r
-\r
- case Operator.GreaterThan:\r
- if (close_target)\r
- opcode = OpCodes.Bgt_S;\r
- else\r
- opcode = OpCodes.Bgt;\r
- break;\r
-\r
- case Operator.LessThanOrEqual:\r
- if (close_target)\r
- opcode = OpCodes.Ble_S;\r
- else\r
- opcode = OpCodes.Ble;\r
- break;\r
-\r
- case Operator.GreaterThanOrEqual:\r
- if (close_target)\r
- opcode = OpCodes.Bge_S;\r
- else\r
- opcode = OpCodes.Ble;\r
- break;\r
-\r
- default:\r
- throw new Exception ("EmitBranchable called on non-EmitBranchable operator: "\r
- + oper.ToString ());\r
- }\r
-\r
- ig.Emit (opcode, target);\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- Type l = left.Type;\r
- Type r = right.Type;\r
- OpCode opcode;\r
-\r
- if (method != null) {\r
-\r
- // Note that operators are static anyway\r
- \r
- if (Arguments != null) \r
- Invocation.EmitArguments (ec, method, Arguments);\r
- \r
- if (method is MethodInfo)\r
- ig.Emit (OpCodes.Call, (MethodInfo) method);\r
- else\r
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
-\r
- if (DelegateOperation)\r
- ig.Emit (OpCodes.Castclass, type);\r
- \r
- return;\r
- }\r
-\r
- //\r
- // Handle short-circuit operators differently\r
- // than the rest\r
- //\r
- if (oper == Operator.LogicalAnd){\r
- Label load_zero = ig.DefineLabel ();\r
- Label end = ig.DefineLabel ();\r
- \r
- left.Emit (ec);\r
- ig.Emit (OpCodes.Brfalse, load_zero);\r
- right.Emit (ec);\r
- ig.Emit (OpCodes.Br, end);\r
- ig.MarkLabel (load_zero);\r
- ig.Emit (OpCodes.Ldc_I4_0);\r
- ig.MarkLabel (end);\r
- return;\r
- } else if (oper == Operator.LogicalOr){\r
- Label load_one = ig.DefineLabel ();\r
- Label end = ig.DefineLabel ();\r
- \r
- left.Emit (ec);\r
- ig.Emit (OpCodes.Brtrue, load_one);\r
- right.Emit (ec);\r
- ig.Emit (OpCodes.Br, end);\r
- ig.MarkLabel (load_one);\r
- ig.Emit (OpCodes.Ldc_I4_1);\r
- ig.MarkLabel (end);\r
- return;\r
- }\r
- \r
- left.Emit (ec);\r
- right.Emit (ec);\r
-\r
- switch (oper){\r
- case Operator.Multiply:\r
- if (ec.CheckState){\r
- if (l == TypeManager.int32_type || l == TypeManager.int64_type)\r
- opcode = OpCodes.Mul_Ovf;\r
- else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)\r
- opcode = OpCodes.Mul_Ovf_Un;\r
- else\r
- opcode = OpCodes.Mul;\r
- } else\r
- opcode = OpCodes.Mul;\r
-\r
- break;\r
-\r
- case Operator.Division:\r
- if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)\r
- opcode = OpCodes.Div_Un;\r
- else\r
- opcode = OpCodes.Div;\r
- break;\r
-\r
- case Operator.Modulus:\r
- if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)\r
- opcode = OpCodes.Rem_Un;\r
- else\r
- opcode = OpCodes.Rem;\r
- break;\r
-\r
- case Operator.Addition:\r
- if (ec.CheckState){\r
- if (l == TypeManager.int32_type || l == TypeManager.int64_type)\r
- opcode = OpCodes.Add_Ovf;\r
- else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)\r
- opcode = OpCodes.Add_Ovf_Un;\r
- else\r
- opcode = OpCodes.Add;\r
- } else\r
- opcode = OpCodes.Add;\r
- break;\r
-\r
- case Operator.Subtraction:\r
- if (ec.CheckState){\r
- if (l == TypeManager.int32_type || l == TypeManager.int64_type)\r
- opcode = OpCodes.Sub_Ovf;\r
- else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)\r
- opcode = OpCodes.Sub_Ovf_Un;\r
- else\r
- opcode = OpCodes.Sub;\r
- } else\r
- opcode = OpCodes.Sub;\r
- break;\r
-\r
- case Operator.RightShift:\r
- opcode = OpCodes.Shr;\r
- break;\r
- \r
- case Operator.LeftShift:\r
- opcode = OpCodes.Shl;\r
- break;\r
-\r
- case Operator.Equality:\r
- opcode = OpCodes.Ceq;\r
- break;\r
-\r
- case Operator.Inequality:\r
- ec.ig.Emit (OpCodes.Ceq);\r
- ec.ig.Emit (OpCodes.Ldc_I4_0);\r
- \r
- opcode = OpCodes.Ceq;\r
- break;\r
-\r
- case Operator.LessThan:\r
- opcode = OpCodes.Clt;\r
- break;\r
-\r
- case Operator.GreaterThan:\r
- opcode = OpCodes.Cgt;\r
- break;\r
-\r
- case Operator.LessThanOrEqual:\r
- ec.ig.Emit (OpCodes.Cgt);\r
- ec.ig.Emit (OpCodes.Ldc_I4_0);\r
- \r
- opcode = OpCodes.Ceq;\r
- break;\r
-\r
- case Operator.GreaterThanOrEqual:\r
- ec.ig.Emit (OpCodes.Clt);\r
- ec.ig.Emit (OpCodes.Ldc_I4_1);\r
- \r
- opcode = OpCodes.Sub;\r
- break;\r
-\r
- case Operator.BitwiseOr:\r
- opcode = OpCodes.Or;\r
- break;\r
-\r
- case Operator.BitwiseAnd:\r
- opcode = OpCodes.And;\r
- break;\r
-\r
- case Operator.ExclusiveOr:\r
- opcode = OpCodes.Xor;\r
- break;\r
-\r
- default:\r
- throw new Exception ("This should not happen: Operator = "\r
- + oper.ToString ());\r
- }\r
-\r
- ig.Emit (opcode);\r
- }\r
- }\r
-\r
- public class PointerArithmetic : Expression {\r
- Expression left, right;\r
- bool is_add;\r
-\r
- //\r
- // We assume that `l' is always a pointer\r
- //\r
- public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t)\r
- {\r
- type = t;\r
- eclass = ExprClass.Variable;\r
- left = l;\r
- right = r;\r
- is_add = is_addition;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // We are born fully resolved\r
- //\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- Type op_type = left.Type;\r
- ILGenerator ig = ec.ig;\r
- int size = GetTypeSize (op_type.GetElementType ());\r
- \r
- if (right.Type.IsPointer){\r
- //\r
- // handle (pointer - pointer)\r
- //\r
- left.Emit (ec);\r
- right.Emit (ec);\r
- ig.Emit (OpCodes.Sub);\r
-\r
- if (size != 1){\r
- if (size == 0)\r
- ig.Emit (OpCodes.Sizeof, op_type);\r
- else \r
- IntLiteral.EmitInt (ig, size);\r
- ig.Emit (OpCodes.Div);\r
- }\r
- ig.Emit (OpCodes.Conv_I8);\r
- } else {\r
- //\r
- // handle + and - on (pointer op int)\r
- //\r
- left.Emit (ec);\r
- ig.Emit (OpCodes.Conv_I);\r
- right.Emit (ec);\r
- if (size != 1){\r
- if (size == 0)\r
- ig.Emit (OpCodes.Sizeof, op_type);\r
- else \r
- IntLiteral.EmitInt (ig, size);\r
- ig.Emit (OpCodes.Mul);\r
- }\r
- if (is_add)\r
- ig.Emit (OpCodes.Add);\r
- else\r
- ig.Emit (OpCodes.Sub);\r
- }\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// Implements the ternary conditiona operator (?:)\r
- /// </summary>\r
- public class Conditional : Expression {\r
- Expression expr, trueExpr, falseExpr;\r
- Location loc;\r
- \r
- public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)\r
- {\r
- this.expr = expr;\r
- this.trueExpr = trueExpr;\r
- this.falseExpr = falseExpr;\r
- this.loc = l;\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
- }\r
-\r
- public Expression TrueExpr {\r
- get {\r
- return trueExpr;\r
- }\r
- }\r
-\r
- public Expression FalseExpr {\r
- get {\r
- return falseExpr;\r
- }\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- expr = expr.Resolve (ec);\r
-\r
- if (expr.Type != TypeManager.bool_type)\r
- expr = Expression.ConvertImplicitRequired (\r
- ec, expr, TypeManager.bool_type, loc);\r
- \r
- trueExpr = trueExpr.Resolve (ec);\r
- falseExpr = falseExpr.Resolve (ec);\r
-\r
- if (expr == null || trueExpr == null || falseExpr == null)\r
- return null;\r
-\r
- eclass = ExprClass.Value;\r
- if (trueExpr.Type == falseExpr.Type)\r
- type = trueExpr.Type;\r
- else {\r
- Expression conv;\r
- Type true_type = trueExpr.Type;\r
- Type false_type = falseExpr.Type;\r
-\r
- if (trueExpr is NullLiteral){\r
- type = false_type;\r
- return this;\r
- } else if (falseExpr is NullLiteral){\r
- type = true_type;\r
- return this;\r
- }\r
- \r
- //\r
- // First, if an implicit conversion exists from trueExpr\r
- // to falseExpr, then the result type is of type falseExpr.Type\r
- //\r
- conv = ConvertImplicit (ec, trueExpr, false_type, loc);\r
- if (conv != null){\r
- //\r
- // Check if both can convert implicitl to each other's type\r
- //\r
- if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){\r
- Report.Error (\r
- 172, loc,\r
- "Can not compute type of conditional expression " +\r
- "as `" + TypeManager.CSharpName (trueExpr.Type) +\r
- "' and `" + TypeManager.CSharpName (falseExpr.Type) +\r
- "' convert implicitly to each other");\r
- return null;\r
- }\r
- type = false_type;\r
- trueExpr = conv;\r
- } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){\r
- type = true_type;\r
- falseExpr = conv;\r
- } else {\r
- Error (173, loc, "The type of the conditional expression can " +\r
- "not be computed because there is no implicit conversion" +\r
- " from `" + TypeManager.CSharpName (trueExpr.Type) + "'" +\r
- " and `" + TypeManager.CSharpName (falseExpr.Type) + "'");\r
- return null;\r
- }\r
- }\r
-\r
- if (expr is BoolConstant){\r
- BoolConstant bc = (BoolConstant) expr;\r
-\r
- if (bc.Value)\r
- return trueExpr;\r
- else\r
- return falseExpr;\r
- }\r
-\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- Label false_target = ig.DefineLabel ();\r
- Label end_target = ig.DefineLabel ();\r
-\r
- expr.Emit (ec);\r
- ig.Emit (OpCodes.Brfalse, false_target);\r
- trueExpr.Emit (ec);\r
- ig.Emit (OpCodes.Br, end_target);\r
- ig.MarkLabel (false_target);\r
- falseExpr.Emit (ec);\r
- ig.MarkLabel (end_target);\r
- }\r
-\r
- }\r
-\r
- /// <summary>\r
- /// Local variables\r
- /// </summary>\r
- public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation {\r
- public readonly string Name;\r
- public readonly Block Block;\r
- Location loc;\r
- VariableInfo variable_info;\r
- \r
- public LocalVariableReference (Block block, string name, Location l)\r
- {\r
- Block = block;\r
- Name = name;\r
- loc = l;\r
- eclass = ExprClass.Variable;\r
- }\r
-\r
- public VariableInfo VariableInfo {\r
- get {\r
- if (variable_info == null)\r
- variable_info = Block.GetVariableInfo (Name);\r
- return variable_info;\r
- }\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- VariableInfo vi = VariableInfo;\r
-\r
- if (Block.IsConstant (Name)) {\r
- Expression e = Block.GetConstantExpression (Name);\r
-\r
- vi.Used = true;\r
- return e;\r
- }\r
-\r
- type = vi.VariableType;\r
- return this;\r
- }\r
-\r
- override public Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
- {\r
- Expression e = DoResolve (ec);\r
-\r
- if (e == null)\r
- return null;\r
-\r
- VariableInfo vi = VariableInfo;\r
- \r
- if (vi.ReadOnly){\r
- if (vi.Assigned){\r
- Report.Error (\r
- 1604, loc,\r
- "cannot assign to `" + Name + "' because it is readonly");\r
- return null;\r
- }\r
- }\r
- \r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- VariableInfo vi = VariableInfo;\r
- ILGenerator ig = ec.ig;\r
-\r
- ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);\r
- vi.Used = true;\r
- }\r
- \r
- public void EmitAssign (EmitContext ec, Expression source)\r
- {\r
- ILGenerator ig = ec.ig;\r
- VariableInfo vi = VariableInfo;\r
-\r
- vi.Assigned = true;\r
-\r
- source.Emit (ec);\r
- \r
- ig.Emit (OpCodes.Stloc, vi.LocalBuilder);\r
- }\r
- \r
- public void AddressOf (EmitContext ec, AddressOp mode)\r
- {\r
- VariableInfo vi = VariableInfo;\r
-\r
- if ((mode & AddressOp.Load) != 0)\r
- vi.Used = true;\r
- if ((mode & AddressOp.Store) != 0)\r
- vi.Assigned = true;\r
-\r
- ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// This represents a reference to a parameter in the intermediate\r
- /// representation.\r
- /// </summary>\r
- public class ParameterReference : Expression, IAssignMethod, IMemoryLocation {\r
- Parameters pars;\r
- String name;\r
- int idx;\r
- public bool is_ref;\r
- \r
- public ParameterReference (Parameters pars, int idx, string name)\r
- {\r
- this.pars = pars;\r
- this.idx = idx;\r
- this.name = name;\r
- eclass = ExprClass.Variable;\r
- }\r
-\r
- //\r
- // Notice that for ref/out parameters, the type exposed is not the\r
- // same type exposed externally.\r
- //\r
- // for "ref int a":\r
- // externally we expose "int&"\r
- // here we expose "int".\r
- //\r
- // We record this in "is_ref". This means that the type system can treat\r
- // the type as it is expected, but when we generate the code, we generate\r
- // the alternate kind of code.\r
- //\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- type = pars.GetParameterInfo (ec.DeclSpace, idx, out is_ref);\r
- eclass = ExprClass.Variable;\r
-\r
- return this;\r
- }\r
-\r
- //\r
- // This method is used by parameters that are references, that are\r
- // being passed as references: we only want to pass the pointer (that\r
- // is already stored in the parameter, not the address of the pointer,\r
- // and not the value of the variable).\r
- //\r
- public void EmitLoad (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- int arg_idx = idx;\r
-\r
- if (!ec.IsStatic)\r
- arg_idx++;\r
- \r
- if (arg_idx <= 255)\r
- ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);\r
- else\r
- ig.Emit (OpCodes.Ldarg, arg_idx);\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- int arg_idx = idx;\r
-\r
- if (!ec.IsStatic)\r
- arg_idx++;\r
- \r
- if (arg_idx <= 255)\r
- ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);\r
- else\r
- ig.Emit (OpCodes.Ldarg, arg_idx);\r
-\r
- if (!is_ref)\r
- return;\r
-\r
- //\r
- // If we are a reference, we loaded on the stack a pointer\r
- // Now lets load the real value\r
- //\r
- LoadFromPtr (ig, type, true);\r
- }\r
-\r
- public void EmitAssign (EmitContext ec, Expression source)\r
- {\r
- ILGenerator ig = ec.ig;\r
- int arg_idx = idx;\r
-\r
- if (!ec.IsStatic)\r
- arg_idx++;\r
-\r
- if (is_ref){\r
- // Load the pointer\r
- if (arg_idx <= 255)\r
- ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);\r
- else\r
- ig.Emit (OpCodes.Ldarg, arg_idx);\r
- }\r
- \r
- source.Emit (ec);\r
-\r
- if (is_ref)\r
- StoreFromPtr (ig, type);\r
- else {\r
- if (arg_idx <= 255)\r
- ig.Emit (OpCodes.Starg_S, (byte) arg_idx);\r
- else\r
- ig.Emit (OpCodes.Starg, arg_idx);\r
- }\r
- \r
- }\r
-\r
- public void AddressOf (EmitContext ec, AddressOp mode)\r
- {\r
- int arg_idx = idx;\r
-\r
- if (!ec.IsStatic)\r
- arg_idx++;\r
-\r
- if (arg_idx <= 255)\r
- ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);\r
- else\r
- ec.ig.Emit (OpCodes.Ldarga, arg_idx);\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// Used for arguments to New(), Invocation()\r
- /// </summary>\r
- public class Argument {\r
- public enum AType : byte {\r
- Expression,\r
- Ref,\r
- Out\r
- };\r
-\r
- public readonly AType ArgType;\r
- public Expression expr;\r
- \r
- public Argument (Expression expr, AType type)\r
- {\r
- this.expr = expr;\r
- this.ArgType = type;\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
-\r
- set {\r
- expr = value;\r
- }\r
- }\r
-\r
- public Type Type {\r
- get {\r
- return expr.Type;\r
- }\r
- }\r
-\r
- public Parameter.Modifier GetParameterModifier ()\r
- {\r
- if (ArgType == AType.Ref || ArgType == AType.Out)\r
- return Parameter.Modifier.OUT;\r
-\r
- return Parameter.Modifier.NONE;\r
- }\r
-\r
- public static string FullDesc (Argument a)\r
- {\r
- return (a.ArgType == AType.Ref ? "ref " :\r
- (a.ArgType == AType.Out ? "out " : "")) +\r
- TypeManager.CSharpName (a.Expr.Type);\r
- }\r
- \r
- public bool Resolve (EmitContext ec, Location loc)\r
- {\r
- expr = expr.Resolve (ec);\r
-\r
- if (ArgType == AType.Expression)\r
- return expr != null;\r
-\r
- if (expr.eclass != ExprClass.Variable){\r
- //\r
- // We just probe to match the CSC output\r
- //\r
- if (expr.eclass == ExprClass.PropertyAccess ||\r
- expr.eclass == ExprClass.IndexerAccess){\r
- Report.Error (\r
- 206, loc,\r
- "A property or indexer can not be passed as an out or ref " +\r
- "parameter");\r
- } else {\r
- Report.Error (\r
- 1510, loc,\r
- "An lvalue is required as an argument to out or ref");\r
- }\r
- return false;\r
- }\r
- \r
- return expr != null;\r
- }\r
-\r
- public void Emit (EmitContext ec)\r
- {\r
- //\r
- // Ref and Out parameters need to have their addresses taken.\r
- //\r
- // ParameterReferences might already be references, so we want\r
- // to pass just the value\r
- //\r
- if (ArgType == AType.Ref || ArgType == AType.Out){\r
- AddressOp mode = AddressOp.Store;\r
-\r
- if (ArgType == AType.Ref)\r
- mode |= AddressOp.Load;\r
- \r
- if (expr is ParameterReference){\r
- ParameterReference pr = (ParameterReference) expr;\r
-\r
- if (pr.is_ref)\r
- pr.EmitLoad (ec);\r
- else {\r
- \r
- pr.AddressOf (ec, mode);\r
- }\r
- } else\r
- ((IMemoryLocation)expr).AddressOf (ec, mode);\r
- } else\r
- expr.Emit (ec);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Invocation of methods or delegates.\r
- /// </summary>\r
- public class Invocation : ExpressionStatement {\r
- public readonly ArrayList Arguments;\r
- Location loc;\r
-\r
- Expression expr;\r
- MethodBase method = null;\r
- bool is_base;\r
- \r
- static Hashtable method_parameter_cache;\r
-\r
- static Invocation ()\r
- {\r
- method_parameter_cache = new PtrHashtable ();\r
- }\r
- \r
- //\r
- // arguments is an ArrayList, but we do not want to typecast,\r
- // as it might be null.\r
- //\r
- // FIXME: only allow expr to be a method invocation or a\r
- // delegate invocation (7.5.5)\r
- //\r
- public Invocation (Expression expr, ArrayList arguments, Location l)\r
- {\r
- this.expr = expr;\r
- Arguments = arguments;\r
- loc = l;\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Returns the Parameters (a ParameterData interface) for the\r
- /// Method `mb'\r
- /// </summary>\r
- public static ParameterData GetParameterData (MethodBase mb)\r
- {\r
- object pd = method_parameter_cache [mb];\r
- object ip;\r
- \r
- if (pd != null)\r
- return (ParameterData) pd;\r
-\r
- \r
- ip = TypeManager.LookupParametersByBuilder (mb);\r
- if (ip != null){\r
- method_parameter_cache [mb] = ip;\r
-\r
- return (ParameterData) ip;\r
- } else {\r
- ParameterInfo [] pi = mb.GetParameters ();\r
- ReflectionParameters rp = new ReflectionParameters (pi);\r
- method_parameter_cache [mb] = rp;\r
-\r
- return (ParameterData) rp;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Determines "better conversion" as specified in 7.4.2.3\r
- /// Returns : 1 if a->p is better\r
- /// 0 if a->q or neither is better \r
- /// </summary>\r
- static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)\r
- {\r
- Type argument_type = a.Type;\r
- Expression argument_expr = a.Expr;\r
-\r
- if (argument_type == null)\r
- throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");\r
-\r
- if (p == q)\r
- return 0;\r
- \r
- if (argument_type == p)\r
- return 1;\r
-\r
- if (argument_type == q)\r
- return 0;\r
-\r
- //\r
- // Now probe whether an implicit constant expression conversion\r
- // can be used.\r
- //\r
- // An implicit constant expression conversion permits the following\r
- // conversions:\r
- //\r
- // * A constant-expression of type `int' can be converted to type\r
- // sbyte, byute, short, ushort, uint, ulong provided the value of\r
- // of the expression is withing the range of the destination type.\r
- //\r
- // * A constant-expression of type long can be converted to type\r
- // ulong, provided the value of the constant expression is not negative\r
- //\r
- // FIXME: Note that this assumes that constant folding has\r
- // taken place. We dont do constant folding yet.\r
- //\r
-\r
- if (argument_expr is IntConstant){\r
- IntConstant ei = (IntConstant) argument_expr;\r
- int value = ei.Value;\r
- \r
- if (p == TypeManager.sbyte_type){\r
- if (value >= SByte.MinValue && value <= SByte.MaxValue)\r
- return 1;\r
- } else if (p == TypeManager.byte_type){\r
- if (Byte.MinValue >= 0 && value <= Byte.MaxValue)\r
- return 1;\r
- } else if (p == TypeManager.short_type){\r
- if (value >= Int16.MinValue && value <= Int16.MaxValue)\r
- return 1;\r
- } else if (p == TypeManager.ushort_type){\r
- if (value >= UInt16.MinValue && value <= UInt16.MaxValue)\r
- return 1;\r
- } else if (p == TypeManager.uint32_type){\r
- //\r
- // we can optimize this case: a positive int32\r
- // always fits on a uint32\r
- //\r
- if (value >= 0)\r
- return 1;\r
- } else if (p == TypeManager.uint64_type){\r
- //\r
- // we can optimize this case: a positive int32\r
- // always fits on a uint64\r
- //\r
- if (value >= 0)\r
- return 1;\r
- }\r
- } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){\r
- LongConstant lc = (LongConstant) argument_expr;\r
- \r
- if (p == TypeManager.uint64_type){\r
- if (lc.Value > 0)\r
- return 1;\r
- }\r
- }\r
-\r
- if (q == null) {\r
- Expression tmp = ConvertImplicitStandard (ec, argument_expr, p, loc);\r
- \r
- if (tmp != null)\r
- return 1;\r
- else\r
- return 0;\r
- }\r
-\r
- Expression p_tmp = new EmptyExpression (p);\r
- Expression q_tmp = new EmptyExpression (q);\r
- \r
- if (StandardConversionExists (p_tmp, q) == true &&\r
- StandardConversionExists (q_tmp, p) == false)\r
- return 1;\r
-\r
- if (p == TypeManager.sbyte_type)\r
- if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||\r
- q == TypeManager.uint32_type || q == TypeManager.uint64_type)\r
- return 1;\r
-\r
- if (p == TypeManager.short_type)\r
- if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||\r
- q == TypeManager.uint64_type)\r
- return 1;\r
-\r
- if (p == TypeManager.int32_type)\r
- if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)\r
- return 1;\r
-\r
- if (p == TypeManager.int64_type)\r
- if (q == TypeManager.uint64_type)\r
- return 1;\r
-\r
- return 0;\r
- }\r
- \r
- /// <summary>\r
- /// Determines "Better function"\r
- /// </summary>\r
- /// <remarks>\r
- /// and returns an integer indicating :\r
- /// 0 if candidate ain't better\r
- /// 1 if candidate is better than the current best match\r
- /// </remarks>\r
- static int BetterFunction (EmitContext ec, ArrayList args,\r
- MethodBase candidate, MethodBase best,\r
- bool expanded_form, Location loc)\r
- {\r
- ParameterData candidate_pd = GetParameterData (candidate);\r
- ParameterData best_pd;\r
- int argument_count;\r
- \r
-\r
- if (args == null)\r
- argument_count = 0;\r
- else\r
- argument_count = args.Count;\r
-\r
- int cand_count = candidate_pd.Count;\r
-\r
- if (cand_count == 0 && argument_count == 0)\r
- return 1;\r
-\r
- if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)\r
- if (cand_count != argument_count)\r
- return 0;\r
- \r
- if (best == null) {\r
- int x = 0;\r
-\r
- if (argument_count == 0 && cand_count == 1 &&\r
- candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)\r
- return 1;\r
- \r
- for (int j = argument_count; j > 0;) {\r
- j--;\r
-\r
- Argument a = (Argument) args [j];\r
- Type t = candidate_pd.ParameterType (j);\r
-\r
- if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)\r
- if (expanded_form)\r
- t = t.GetElementType ();\r
-\r
- x = BetterConversion (ec, a, t, null, loc);\r
- \r
- if (x <= 0)\r
- break;\r
- }\r
- \r
- if (x > 0)\r
- return 1;\r
- else\r
- return 0;\r
- }\r
-\r
- best_pd = GetParameterData (best);\r
-\r
- int rating1 = 0, rating2 = 0;\r
- \r
- for (int j = 0; j < argument_count; ++j) {\r
- int x, y;\r
- \r
- Argument a = (Argument) args [j];\r
-\r
- Type ct = candidate_pd.ParameterType (j);\r
- Type bt = best_pd.ParameterType (j);\r
-\r
- if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)\r
- if (expanded_form)\r
- ct = ct.GetElementType ();\r
-\r
- if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)\r
- if (expanded_form)\r
- bt = bt.GetElementType ();\r
- \r
- x = BetterConversion (ec, a, ct, bt, loc);\r
- y = BetterConversion (ec, a, bt, ct, loc);\r
-\r
- if (x < y)\r
- return 0;\r
- \r
- rating1 += x;\r
- rating2 += y;\r
- }\r
-\r
- if (rating1 > rating2)\r
- return 1;\r
- else\r
- return 0;\r
- }\r
-\r
- public static string FullMethodDesc (MethodBase mb)\r
- {\r
- string ret_type = "";\r
-\r
- if (mb is MethodInfo)\r
- ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);\r
- \r
- StringBuilder sb = new StringBuilder (ret_type + " " + mb.Name);\r
- ParameterData pd = GetParameterData (mb);\r
-\r
- int count = pd.Count;\r
- sb.Append (" (");\r
- \r
- for (int i = count; i > 0; ) {\r
- i--;\r
-\r
- sb.Append (pd.ParameterDesc (count - i - 1));\r
- if (i != 0)\r
- sb.Append (", ");\r
- }\r
- \r
- sb.Append (")");\r
- return sb.ToString ();\r
- }\r
-\r
- public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2)\r
- {\r
- MemberInfo [] miset;\r
- MethodGroupExpr union;\r
- \r
- if (mg1 != null && mg2 != null) {\r
- \r
- MethodGroupExpr left_set = null, right_set = null;\r
- int length1 = 0, length2 = 0;\r
- \r
- left_set = (MethodGroupExpr) mg1;\r
- length1 = left_set.Methods.Length;\r
- \r
- right_set = (MethodGroupExpr) mg2;\r
- length2 = right_set.Methods.Length;\r
-\r
- ArrayList common = new ArrayList ();\r
- \r
- for (int i = 0; i < left_set.Methods.Length; i++) {\r
- for (int j = 0; j < right_set.Methods.Length; j++) {\r
- if (left_set.Methods [i] == right_set.Methods [j]) \r
- common.Add (left_set.Methods [i]);\r
- }\r
- }\r
- \r
- miset = new MemberInfo [length1 + length2 - common.Count];\r
-\r
- left_set.Methods.CopyTo (miset, 0);\r
-\r
- int k = 0;\r
- \r
- for (int j = 0; j < right_set.Methods.Length; j++)\r
- if (!common.Contains (right_set.Methods [j]))\r
- miset [length1 + k++] = right_set.Methods [j];\r
- \r
- union = new MethodGroupExpr (miset);\r
-\r
- return union;\r
-\r
- } else if (mg1 == null && mg2 != null) {\r
- \r
- MethodGroupExpr me = (MethodGroupExpr) mg2; \r
- \r
- miset = new MemberInfo [me.Methods.Length];\r
- me.Methods.CopyTo (miset, 0);\r
-\r
- union = new MethodGroupExpr (miset);\r
- \r
- return union;\r
-\r
- } else if (mg2 == null && mg1 != null) {\r
- \r
- MethodGroupExpr me = (MethodGroupExpr) mg1; \r
- \r
- miset = new MemberInfo [me.Methods.Length];\r
- me.Methods.CopyTo (miset, 0);\r
-\r
- union = new MethodGroupExpr (miset);\r
- \r
- return union;\r
- }\r
- \r
- return null;\r
- }\r
-\r
- /// <summary>\r
- /// Determines is the candidate method, if a params method, is applicable\r
- /// in its expanded form to the given set of arguments\r
- /// </summary>\r
- static bool IsParamsMethodApplicable (ArrayList arguments, MethodBase candidate)\r
- {\r
- int arg_count;\r
- \r
- if (arguments == null)\r
- arg_count = 0;\r
- else\r
- arg_count = arguments.Count;\r
- \r
- ParameterData pd = GetParameterData (candidate);\r
- \r
- int pd_count = pd.Count;\r
-\r
- if (pd_count == 0)\r
- return false;\r
- \r
- if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)\r
- return false;\r
- \r
- if (pd_count - 1 > arg_count)\r
- return false;\r
- \r
- if (pd_count == 1 && arg_count == 0)\r
- return true;\r
- \r
- //\r
- // If we have come this far, the case which remains is when the number of parameters\r
- // is less than or equal to the argument count.\r
-\r
- for (int i = 0; i < pd_count - 1; ++i) {\r
-\r
- Argument a = (Argument) arguments [i];\r
-\r
- Parameter.Modifier a_mod = a.GetParameterModifier ();\r
- Parameter.Modifier p_mod = pd.ParameterModifier (i);\r
-\r
- if (a_mod == p_mod) {\r
- \r
- if (a_mod == Parameter.Modifier.NONE)\r
- if (!StandardConversionExists (a.Expr, pd.ParameterType (i)))\r
- return false;\r
- \r
- if (a_mod == Parameter.Modifier.REF ||\r
- a_mod == Parameter.Modifier.OUT)\r
- if (pd.ParameterType (i) != a.Type)\r
- return false;\r
- } else\r
- return false;\r
- \r
- }\r
-\r
- Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();\r
-\r
- for (int i = pd_count - 1; i < arg_count; i++) {\r
- Argument a = (Argument) arguments [i];\r
- \r
- if (!StandardConversionExists (a.Expr, element_type))\r
- return false;\r
- }\r
- \r
- return true;\r
- }\r
-\r
- /// <summary>\r
- /// Determines if the candidate method is applicable (section 14.4.2.1)\r
- /// to the given set of arguments\r
- /// </summary>\r
- static bool IsApplicable (ArrayList arguments, MethodBase candidate)\r
- {\r
- int arg_count;\r
-\r
- if (arguments == null)\r
- arg_count = 0;\r
- else\r
- arg_count = arguments.Count;\r
-\r
- ParameterData pd = GetParameterData (candidate);\r
-\r
- int pd_count = pd.Count;\r
-\r
- if (arg_count != pd.Count)\r
- return false;\r
-\r
- for (int i = arg_count; i > 0; ) {\r
- i--;\r
-\r
- Argument a = (Argument) arguments [i];\r
-\r
- Parameter.Modifier a_mod = a.GetParameterModifier ();\r
- Parameter.Modifier p_mod = pd.ParameterModifier (i);\r
-\r
- if (a_mod == p_mod) {\r
- \r
- if (a_mod == Parameter.Modifier.NONE)\r
- if (!StandardConversionExists (a.Expr, pd.ParameterType (i)))\r
- return false;\r
- \r
- if (a_mod == Parameter.Modifier.REF ||\r
- a_mod == Parameter.Modifier.OUT)\r
- if (pd.ParameterType (i) != a.Type)\r
- return false;\r
- } else\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
- \r
- \r
-\r
- /// <summary>\r
- /// Find the Applicable Function Members (7.4.2.1)\r
- ///\r
- /// me: Method Group expression with the members to select.\r
- /// it might contain constructors or methods (or anything\r
- /// that maps to a method).\r
- ///\r
- /// Arguments: ArrayList containing resolved Argument objects.\r
- ///\r
- /// loc: The location if we want an error to be reported, or a Null\r
- /// location for "probing" purposes.\r
- ///\r
- /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)\r
- /// that is the best match of me on Arguments.\r
- ///\r
- /// </summary>\r
- public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,\r
- ArrayList Arguments, Location loc)\r
- {\r
- ArrayList afm = new ArrayList ();\r
- int best_match_idx = -1;\r
- MethodBase method = null;\r
- int argument_count;\r
- ArrayList candidates = new ArrayList ();\r
-\r
- for (int i = me.Methods.Length; i > 0; ){\r
- i--;\r
- MethodBase candidate = me.Methods [i];\r
- int x;\r
-\r
- // Check if candidate is applicable (section 14.4.2.1)\r
- if (!IsApplicable (Arguments, candidate))\r
- continue;\r
-\r
- candidates.Add (candidate);\r
-\r
- x = BetterFunction (ec, Arguments, candidate, method, false, loc);\r
- \r
- if (x == 0)\r
- continue;\r
- else {\r
- best_match_idx = i;\r
- method = me.Methods [best_match_idx];\r
- }\r
- }\r
-\r
- if (Arguments == null)\r
- argument_count = 0;\r
- else\r
- argument_count = Arguments.Count;\r
- \r
- //\r
- // Now we see if we can find params functions, applicable in their expanded form\r
- // since if they were applicable in their normal form, they would have been selected\r
- // above anyways\r
- //\r
- bool chose_params_expanded = false;\r
- \r
- if (best_match_idx == -1) {\r
-\r
- candidates = new ArrayList ();\r
- for (int i = me.Methods.Length; i > 0; ) {\r
- i--;\r
- MethodBase candidate = me.Methods [i];\r
-\r
- if (!IsParamsMethodApplicable (Arguments, candidate))\r
- continue;\r
-\r
- candidates.Add (candidate);\r
-\r
- int x = BetterFunction (ec, Arguments, candidate, method, true, loc);\r
-\r
- if (x == 0)\r
- continue;\r
- else {\r
- best_match_idx = i;\r
- method = me.Methods [best_match_idx];\r
- chose_params_expanded = true;\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Now we see if we can at least find a method with the same number of arguments\r
- //\r
- ParameterData pd;\r
- int method_count = 0;\r
-\r
- if (best_match_idx == -1) {\r
-\r
- for (int i = me.Methods.Length; i > 0;) {\r
- i--;\r
- MethodBase mb = me.Methods [i];\r
- pd = GetParameterData (mb);\r
- \r
- if (pd.Count == argument_count) {\r
- best_match_idx = i;\r
- method = me.Methods [best_match_idx];\r
- method_count++;\r
- } else\r
- continue;\r
- }\r
- }\r
-\r
- if (method == null)\r
- return null;\r
-\r
- //\r
- // Now check that there are no ambiguities i.e the selected method\r
- // should be better than all the others\r
- //\r
-\r
- for (int i = 0; i < candidates.Count; ++i) {\r
- MethodBase candidate = (MethodBase) candidates [i];\r
-\r
- if (candidate == method)\r
- continue;\r
-\r
- //\r
- // If a normal method is applicable in the sense that it has the same\r
- // number of arguments, then the expanded params method is never applicable\r
- // so we debar the params method.\r
- //\r
- if (IsParamsMethodApplicable (Arguments, candidate) &&\r
- IsApplicable (Arguments, method))\r
- continue;\r
- \r
- int x = BetterFunction (ec, Arguments, method, candidate,\r
- chose_params_expanded, loc);\r
-\r
- if (x != 1) {\r
- //Console.WriteLine ("Candidate : " + FullMethodDesc (candidate));\r
- //Console.WriteLine ("Best : " + FullMethodDesc (method));\r
- Report.Error (\r
- 121, loc,\r
- "Ambiguous call when selecting function due to implicit casts");\r
- return null;\r
- }\r
- }\r
- \r
- // And now convert implicitly, each argument to the required type\r
- \r
- pd = GetParameterData (method);\r
- int pd_count = pd.Count;\r
-\r
- for (int j = 0; j < argument_count; j++) {\r
- Argument a = (Argument) Arguments [j];\r
- Expression a_expr = a.Expr;\r
- Type parameter_type = pd.ParameterType (j);\r
-\r
- if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS && chose_params_expanded)\r
- parameter_type = parameter_type.GetElementType ();\r
-\r
- if (a.Type != parameter_type){\r
- Expression conv;\r
- \r
- conv = ConvertImplicitStandard (ec, a_expr, parameter_type, loc);\r
-\r
- if (conv == null) {\r
- if (!Location.IsNull (loc)) {\r
- Error (1502, loc,\r
- "The best overloaded match for method '" +\r
- FullMethodDesc (method) +\r
- "' has some invalid arguments");\r
- Error (1503, loc,\r
- "Argument " + (j+1) +\r
- ": Cannot convert from '" + Argument.FullDesc (a) \r
- + "' to '" + pd.ParameterDesc (j) + "'");\r
- }\r
- return null;\r
- }\r
- \r
- //\r
- // Update the argument with the implicit conversion\r
- //\r
- if (a_expr != conv)\r
- a.Expr = conv;\r
-\r
- // FIXME : For the case of params methods, we need to actually instantiate\r
- // an array and initialize it with the argument values etc etc.\r
-\r
- }\r
- \r
- if (a.GetParameterModifier () != pd.ParameterModifier (j) &&\r
- pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {\r
- if (!Location.IsNull (loc)) {\r
- Console.WriteLine ("A:P: " + a.GetParameterModifier ());\r
- Console.WriteLine ("PP:: " + pd.ParameterModifier (j));\r
- Console.WriteLine ("PT: " + parameter_type.IsByRef);\r
- Error (1502, loc,\r
- "The best overloaded match for method '" + FullMethodDesc (method)+\r
- "' has some invalid arguments");\r
- Error (1503, loc,\r
- "Argument " + (j+1) +\r
- ": Cannot convert from '" + Argument.FullDesc (a) \r
- + "' to '" + pd.ParameterDesc (j) + "'");\r
- }\r
- return null;\r
- }\r
- }\r
- \r
- return method;\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // First, resolve the expression that is used to\r
- // trigger the invocation\r
- //\r
- if (expr is BaseAccess)\r
- is_base = true;\r
-\r
- expr = expr.Resolve (ec);\r
- if (expr == null)\r
- return null;\r
-\r
- if (!(expr is MethodGroupExpr)) {\r
- Type expr_type = expr.Type;\r
-\r
- if (expr_type != null){\r
- bool IsDelegate = TypeManager.IsDelegateType (expr_type);\r
- if (IsDelegate)\r
- return (new DelegateInvocation (\r
- this.expr, Arguments, loc)).Resolve (ec);\r
- }\r
- }\r
-\r
- if (!(expr is MethodGroupExpr)){\r
- report118 (loc, this.expr, "method group");\r
- return null;\r
- }\r
-\r
- //\r
- // Next, evaluate all the expressions in the argument list\r
- //\r
- if (Arguments != null){\r
- for (int i = Arguments.Count; i > 0;){\r
- --i;\r
- Argument a = (Argument) Arguments [i];\r
-\r
- if (!a.Resolve (ec, loc))\r
- return null;\r
- }\r
- }\r
-\r
- method = OverloadResolve (ec, (MethodGroupExpr) this.expr, Arguments, loc);\r
-\r
- if (method == null){\r
- Error (-6, loc,\r
- "Could not find any applicable function for this argument list");\r
- return null;\r
- }\r
-\r
- if (method is MethodInfo)\r
- type = ((MethodInfo)method).ReturnType;\r
-\r
- if (type.IsPointer){\r
- if (!ec.InUnsafe){\r
- UnsafeError (loc);\r
- return null;\r
- }\r
- }\r
- \r
- eclass = ExprClass.Value;\r
- return this;\r
- }\r
-\r
- // <summary>\r
- // Emits the list of arguments as an array\r
- // </summary>\r
- static void EmitParams (EmitContext ec, int idx, ArrayList arguments)\r
- {\r
- ILGenerator ig = ec.ig;\r
- int count = arguments.Count - idx;\r
- Argument a = (Argument) arguments [idx];\r
- Type t = a.expr.Type;\r
- string array_type = t.FullName + "[]";\r
- LocalBuilder array;\r
- \r
- array = ig.DeclareLocal (Type.GetType (array_type));\r
- IntConstant.EmitInt (ig, count);\r
- ig.Emit (OpCodes.Newarr, t);\r
- ig.Emit (OpCodes.Stloc, array);\r
-\r
- int top = arguments.Count;\r
- for (int j = idx; j < top; j++){\r
- a = (Argument) arguments [j];\r
- \r
- ig.Emit (OpCodes.Ldloc, array);\r
- IntConstant.EmitInt (ig, j - idx);\r
- a.Emit (ec);\r
- \r
- ArrayAccess.EmitStoreOpcode (ig, t);\r
- }\r
- ig.Emit (OpCodes.Ldloc, array);\r
- }\r
- \r
- /// <summary>\r
- /// Emits a list of resolved Arguments that are in the arguments\r
- /// ArrayList.\r
- /// \r
- /// The MethodBase argument might be null if the\r
- /// emission of the arguments is known not to contain\r
- /// a `params' field (for example in constructors or other routines\r
- /// that keep their arguments in this structure\r
- /// </summary>\r
- public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)\r
- {\r
- ParameterData pd = null;\r
- int top;\r
-\r
- if (arguments != null)\r
- top = arguments.Count;\r
- else\r
- top = 0;\r
-\r
- if (mb != null)\r
- pd = GetParameterData (mb);\r
-\r
- for (int i = 0; i < top; i++){\r
- Argument a = (Argument) arguments [i];\r
-\r
- if (pd != null){\r
- if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){\r
- EmitParams (ec, i, arguments);\r
- return;\r
- }\r
- }\r
- \r
- a.Emit (ec);\r
- }\r
- }\r
-\r
- /// <remarks>\r
- /// is_base tells whether we want to force the use of the `call'\r
- /// opcode instead of using callvirt. Call is required to call\r
- /// a specific method, while callvirt will always use the most\r
- /// recent method in the vtable.\r
- ///\r
- /// is_static tells whether this is an invocation on a static method\r
- ///\r
- /// instance_expr is an expression that represents the instance\r
- /// it must be non-null if is_static is false.\r
- ///\r
- /// method is the method to invoke.\r
- ///\r
- /// Arguments is the list of arguments to pass to the method or constructor.\r
- /// </remarks>\r
- public static void EmitCall (EmitContext ec, bool is_base,\r
- bool is_static, Expression instance_expr,\r
- MethodBase method, ArrayList Arguments)\r
- {\r
- ILGenerator ig = ec.ig;\r
- bool struct_call = false;\r
- \r
- if (!is_static){\r
- \r
- if (method.DeclaringType.IsValueType)\r
- struct_call = true;\r
- //\r
- // If this is ourselves, push "this"\r
- //\r
- if (instance_expr == null){\r
- ig.Emit (OpCodes.Ldarg_0);\r
- } else {\r
- //\r
- // Push the instance expression\r
- //\r
- if (instance_expr.Type.IsSubclassOf (TypeManager.value_type)){\r
- //\r
- // Special case: calls to a function declared in a \r
- // reference-type with a value-type argument need\r
- // to have their value boxed. \r
-\r
- struct_call = true;\r
- if (method.DeclaringType.IsValueType){\r
- //\r
- // If the expression implements IMemoryLocation, then\r
- // we can optimize and use AddressOf on the\r
- // return.\r
- //\r
- // If not we have to use some temporary storage for\r
- // it.\r
- if (instance_expr is IMemoryLocation){\r
- ((IMemoryLocation)instance_expr).\r
- AddressOf (ec, AddressOp.LoadStore);\r
- }\r
- else {\r
- Type t = instance_expr.Type;\r
- \r
- instance_expr.Emit (ec);\r
- LocalBuilder temp = ig.DeclareLocal (t);\r
- ig.Emit (OpCodes.Stloc, temp);\r
- ig.Emit (OpCodes.Ldloca, temp);\r
- }\r
- } else {\r
- instance_expr.Emit (ec);\r
- ig.Emit (OpCodes.Box, instance_expr.Type);\r
- } \r
- } else\r
- instance_expr.Emit (ec);\r
- }\r
- }\r
-\r
- if (Arguments != null)\r
- EmitArguments (ec, method, Arguments);\r
-\r
- if (is_static || struct_call || is_base){\r
- if (method is MethodInfo)\r
- ig.Emit (OpCodes.Call, (MethodInfo) method);\r
- else\r
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
- } else {\r
- if (method is MethodInfo)\r
- ig.Emit (OpCodes.Callvirt, (MethodInfo) method);\r
- else\r
- ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);\r
- }\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- MethodGroupExpr mg = (MethodGroupExpr) this.expr;\r
-\r
- EmitCall (ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments);\r
- }\r
- \r
- public override void EmitStatement (EmitContext ec)\r
- {\r
- Emit (ec);\r
-\r
- // \r
- // Pop the return value if there is one\r
- //\r
- if (method is MethodInfo){\r
- if (((MethodInfo)method).ReturnType != TypeManager.void_type)\r
- ec.ig.Emit (OpCodes.Pop);\r
- }\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implements the new expression \r
- /// </summary>\r
- public class New : ExpressionStatement {\r
- public readonly ArrayList Arguments;\r
- public readonly string RequestedType;\r
-\r
- Location loc;\r
- MethodBase method = null;\r
-\r
- //\r
- // If set, the new expression is for a value_target, and\r
- // we will not leave anything on the stack.\r
- //\r
- Expression value_target;\r
- \r
- public New (string requested_type, ArrayList arguments, Location l)\r
- {\r
- RequestedType = requested_type;\r
- Arguments = arguments;\r
- loc = l;\r
- }\r
-\r
- public Expression ValueTypeVariable {\r
- get {\r
- return value_target;\r
- }\r
-\r
- set {\r
- value_target = value;\r
- }\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- type = RootContext.LookupType (ec.DeclSpace, RequestedType, false, loc);\r
- \r
- if (type == null)\r
- return null;\r
- \r
- bool IsDelegate = TypeManager.IsDelegateType (type);\r
- \r
- if (IsDelegate)\r
- return (new NewDelegate (type, Arguments, loc)).Resolve (ec);\r
- \r
- bool is_struct = false;\r
- is_struct = type.IsSubclassOf (TypeManager.value_type);\r
- eclass = ExprClass.Value;\r
-\r
- //\r
- // SRE returns a match for .ctor () on structs (the object constructor), \r
- // so we have to manually ignore it.\r
- //\r
- if (is_struct && Arguments == null)\r
- return this;\r
- \r
- Expression ml;\r
- ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor, AllBindingFlags, loc);\r
- \r
- if (! (ml is MethodGroupExpr)){\r
- if (!is_struct){\r
- report118 (loc, ml, "method group");\r
- return null;\r
- }\r
- }\r
- \r
- if (ml != null) {\r
- if (Arguments != null){\r
- for (int i = Arguments.Count; i > 0;){\r
- --i;\r
- Argument a = (Argument) Arguments [i];\r
- \r
- if (!a.Resolve (ec, loc))\r
- return null;\r
- }\r
- }\r
-\r
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,\r
- Arguments, loc);\r
- \r
- }\r
- \r
- if (method == null && !is_struct) {\r
- Error (-6, loc,\r
- "New invocation: Can not find a constructor for " +\r
- "this argument list");\r
- return null;\r
- }\r
- return this;\r
- }\r
-\r
- //\r
- // This DoEmit can be invoked in two contexts:\r
- // * As a mechanism that will leave a value on the stack (new object)\r
- // * As one that wont (init struct)\r
- //\r
- // You can control whether a value is required on the stack by passing\r
- // need_value_on_stack. The code *might* leave a value on the stack\r
- // so it must be popped manually\r
- //\r
- // If we are dealing with a ValueType, we have a few\r
- // situations to deal with:\r
- //\r
- // * The target is a ValueType, and we have been provided\r
- // the instance (this is easy, we are being assigned).\r
- //\r
- // * The target of New is being passed as an argument,\r
- // to a boxing operation or a function that takes a\r
- // ValueType.\r
- //\r
- // In this case, we need to create a temporary variable\r
- // that is the argument of New.\r
- //\r
- // Returns whether a value is left on the stack\r
- //\r
- bool DoEmit (EmitContext ec, bool need_value_on_stack)\r
- {\r
- bool is_value_type = type.IsSubclassOf (TypeManager.value_type);\r
- ILGenerator ig = ec.ig;\r
- \r
- if (is_value_type){\r
- IMemoryLocation ml;\r
-\r
- if (value_target == null)\r
- value_target = new LocalTemporary (ec, type);\r
-\r
- ml = (IMemoryLocation) value_target;\r
- ml.AddressOf (ec, AddressOp.Store);\r
- }\r
-\r
- if (method != null)\r
- Invocation.EmitArguments (ec, method, Arguments);\r
-\r
- if (is_value_type){\r
- if (method == null)\r
- ig.Emit (OpCodes.Initobj, type);\r
- else\r
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
-\r
- if (need_value_on_stack){\r
- value_target.Emit (ec);\r
- return true;\r
- }\r
- return false;\r
- } else {\r
- ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);\r
- return true;\r
- }\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- DoEmit (ec, true);\r
- }\r
- \r
- public override void EmitStatement (EmitContext ec)\r
- {\r
- if (DoEmit (ec, false))\r
- ec.ig.Emit (OpCodes.Pop);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Represents an array creation expression.\r
- /// </summary>\r
- ///\r
- /// <remarks>\r
- /// There are two possible scenarios here: one is an array creation\r
- /// expression that specifies the dimensions and optionally the\r
- /// initialization data and the other which does not need dimensions\r
- /// specified but where initialization data is mandatory.\r
- /// </remarks>\r
- public class ArrayCreation : ExpressionStatement {\r
- string RequestedType;\r
- string Rank;\r
- ArrayList Initializers;\r
- Location loc;\r
-\r
- //\r
- // The list of Argument types.\r
- // This is used to constrcut the `newarray' or constructor signature\r
- //\r
- ArrayList Arguments;\r
-\r
- MethodBase method = null;\r
- Type array_element_type;\r
- bool IsOneDimensional = false;\r
- bool IsBuiltinType = false;\r
- bool ExpectInitializers = false;\r
-\r
- int dimensions = 0;\r
- Type underlying_type;\r
-\r
- ArrayList ArrayData;\r
-\r
- Hashtable Bounds;\r
-\r
- //\r
- // The number of array initializers that we can handle\r
- // via the InitializeArray method - through EmitStaticInitializers\r
- //\r
- int num_automatic_initializers;\r
- \r
- public ArrayCreation (string requested_type, ArrayList exprs,\r
- string rank, ArrayList initializers, Location l)\r
- {\r
- RequestedType = requested_type;\r
- Rank = rank;\r
- Initializers = initializers;\r
- loc = l;\r
-\r
- Arguments = new ArrayList ();\r
-\r
- foreach (Expression e in exprs)\r
- Arguments.Add (new Argument (e, Argument.AType.Expression));\r
- }\r
-\r
- public ArrayCreation (string requested_type, string rank, ArrayList initializers, Location l)\r
- {\r
- RequestedType = requested_type;\r
- Initializers = initializers;\r
- loc = l;\r
-\r
- Rank = rank.Substring (0, rank.LastIndexOf ("["));\r
-\r
- string tmp = rank.Substring (rank.LastIndexOf ("["));\r
-\r
- dimensions = tmp.Length - 1;\r
- ExpectInitializers = true;\r
- }\r
-\r
- public static string FormArrayType (string base_type, int idx_count, string rank)\r
- {\r
- StringBuilder sb = new StringBuilder (base_type);\r
-\r
- sb.Append (rank);\r
- \r
- sb.Append ("[");\r
- for (int i = 1; i < idx_count; i++)\r
- sb.Append (",");\r
- \r
- sb.Append ("]");\r
-\r
- return sb.ToString ();\r
- }\r
-\r
- public static string FormElementType (string base_type, int idx_count, string rank)\r
- {\r
- StringBuilder sb = new StringBuilder (base_type);\r
- \r
- sb.Append ("[");\r
- for (int i = 1; i < idx_count; i++)\r
- sb.Append (",");\r
- \r
- sb.Append ("]");\r
- \r
- sb.Append (rank);\r
-\r
- string val = sb.ToString ();\r
-\r
- return val.Substring (0, val.LastIndexOf ("["));\r
- }\r
-\r
- void error178 ()\r
- {\r
- Report.Error (178, loc, "Incorrectly structured array initializer");\r
- }\r
- \r
- public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)\r
- {\r
- if (specified_dims) { \r
- Argument a = (Argument) Arguments [idx];\r
- \r
- if (!a.Resolve (ec, loc))\r
- return false;\r
- \r
- if (!(a.Expr is Constant)) {\r
- Report.Error (150, loc, "A constant value is expected");\r
- return false;\r
- }\r
- \r
- int value = (int) ((Constant) a.Expr).GetValue ();\r
- \r
- if (value != probe.Count) {\r
- error178 ();\r
- return false;\r
- }\r
- \r
- Bounds [idx] = value;\r
- }\r
- \r
- foreach (object o in probe) {\r
- if (o is ArrayList) {\r
- bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);\r
- if (!ret)\r
- return false;\r
- } else {\r
- Expression tmp = (Expression) o;\r
- tmp = tmp.Resolve (ec);\r
- if (tmp == null)\r
- continue;\r
- \r
- // Handle initialization from vars, fields etc.\r
-\r
- Expression conv = ConvertImplicitRequired (\r
- ec, tmp, underlying_type, loc);\r
- \r
- if (conv == null) \r
- return false;\r
-\r
- if (conv is StringConstant)\r
- ArrayData.Add (conv);\r
- else if (conv is Constant) {\r
- ArrayData.Add (conv);\r
- num_automatic_initializers++;\r
- } else\r
- ArrayData.Add (conv);\r
- }\r
- }\r
-\r
- return true;\r
- }\r
- \r
- public void UpdateIndices (EmitContext ec)\r
- {\r
- int i = 0;\r
- for (ArrayList probe = Initializers; probe != null;) {\r
- if (probe.Count > 0 && probe [0] is ArrayList) {\r
- Expression e = new IntConstant (probe.Count);\r
- Arguments.Add (new Argument (e, Argument.AType.Expression));\r
-\r
- Bounds [i++] = probe.Count;\r
- \r
- probe = (ArrayList) probe [0];\r
- \r
- } else {\r
- Expression e = new IntConstant (probe.Count);\r
- Arguments.Add (new Argument (e, Argument.AType.Expression));\r
-\r
- Bounds [i++] = probe.Count;\r
- probe = null;\r
- }\r
- }\r
-\r
- }\r
- \r
- public bool ValidateInitializers (EmitContext ec)\r
- {\r
- if (Initializers == null) {\r
- if (ExpectInitializers)\r
- return false;\r
- else\r
- return true;\r
- }\r
- \r
- underlying_type = RootContext.LookupType (\r
- ec.DeclSpace, RequestedType, false, loc);\r
- \r
- //\r
- // We use this to store all the date values in the order in which we\r
- // will need to store them in the byte blob later\r
- //\r
- ArrayData = new ArrayList ();\r
- Bounds = new Hashtable ();\r
- \r
- bool ret;\r
-\r
- if (Arguments != null) {\r
- ret = CheckIndices (ec, Initializers, 0, true);\r
- return ret;\r
- \r
- } else {\r
- Arguments = new ArrayList ();\r
-\r
- ret = CheckIndices (ec, Initializers, 0, false);\r
- \r
- if (!ret)\r
- return false;\r
- \r
- UpdateIndices (ec);\r
- \r
- if (Arguments.Count != dimensions) {\r
- error178 ();\r
- return false;\r
- }\r
-\r
- return ret;\r
- }\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- int arg_count;\r
-\r
- //\r
- // First step is to validate the initializers and fill\r
- // in any missing bits\r
- //\r
- if (!ValidateInitializers (ec))\r
- return null;\r
-\r
- if (Arguments == null)\r
- arg_count = 0;\r
- else {\r
- arg_count = Arguments.Count;\r
- for (int i = 0; i < arg_count; i++){\r
- Argument a = (Argument) Arguments [i];\r
- \r
- if (!a.Resolve (ec, loc))\r
- return null;\r
-\r
- //\r
- // Now, convert that to an integer\r
- //\r
- Expression real_arg;\r
- bool old_checked = ec.CheckState;\r
- ec.CheckState = true;\r
- \r
- real_arg = ConvertExplicit (\r
- ec, a.expr, TypeManager.uint32_type, loc);\r
- ec.CheckState = old_checked;\r
- if (real_arg == null)\r
- return null;\r
-\r
- a.expr = real_arg;\r
- }\r
- }\r
- \r
- string array_type = FormArrayType (RequestedType, arg_count, Rank);\r
- string element_type = FormElementType (RequestedType, arg_count, Rank);\r
-\r
- type = RootContext.LookupType (ec.DeclSpace, array_type, false, loc);\r
- \r
- array_element_type = RootContext.LookupType (\r
- ec.DeclSpace, element_type, false, loc);\r
- \r
- if (type == null)\r
- return null;\r
- \r
- if (arg_count == 1) {\r
- IsOneDimensional = true;\r
- eclass = ExprClass.Value;\r
- return this;\r
- }\r
-\r
- IsBuiltinType = TypeManager.IsBuiltinType (type);\r
- \r
- if (IsBuiltinType) {\r
-\r
- Expression ml;\r
- \r
- ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,\r
- AllBindingFlags, loc);\r
- \r
- if (!(ml is MethodGroupExpr)){\r
- report118 (loc, ml, "method group");\r
- return null;\r
- }\r
- \r
- if (ml == null) {\r
- Report.Error (-6, loc, "New invocation: Can not find a constructor for " +\r
- "this argument list");\r
- return null;\r
- }\r
- \r
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);\r
-\r
- if (method == null) {\r
- Report.Error (-6, loc, "New invocation: Can not find a constructor for " +\r
- "this argument list");\r
- return null;\r
- }\r
- \r
- eclass = ExprClass.Value;\r
- return this;\r
- \r
- } else {\r
-\r
- ModuleBuilder mb = RootContext.ModuleBuilder;\r
-\r
- ArrayList args = new ArrayList ();\r
- if (Arguments != null){\r
- for (int i = arg_count; i > 0;){\r
- --i;\r
- Argument a = (Argument) Arguments [i];\r
- \r
- args.Add (TypeManager.int32_type);\r
- }\r
- }\r
- \r
- Type [] arg_types = null;\r
-\r
- if (args.Count > 0)\r
- arg_types = new Type [args.Count];\r
- \r
- args.CopyTo (arg_types, 0);\r
- \r
- method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,\r
- arg_types);\r
-\r
- if (method == null) {\r
- Report.Error (-6, loc, "New invocation: Can not find a constructor for " +\r
- "this argument list");\r
- return null;\r
- }\r
- \r
- eclass = ExprClass.Value;\r
- return this;\r
- \r
- }\r
- }\r
-\r
- public static byte [] MakeByteBlob (ArrayList ArrayData, Type underlying_type, Location loc)\r
- {\r
- int factor;\r
- byte [] data;\r
- byte [] element;\r
- int count = ArrayData.Count;\r
-\r
- factor = GetTypeSize (underlying_type);\r
- if (factor == 0)\r
- return null;\r
-\r
- data = new byte [(count * factor + 4) & ~3];\r
- int idx = 0;\r
- \r
- for (int i = 0; i < count; ++i) {\r
- object v = ArrayData [i];\r
-\r
- if (v is EnumConstant)\r
- v = ((EnumConstant) v).Child;\r
- \r
- if (v is Constant && !(v is StringConstant))\r
- v = ((Constant) v).GetValue ();\r
- else {\r
- idx += factor;\r
- continue;\r
- }\r
- \r
- if (underlying_type == TypeManager.int64_type){\r
- if (!(v is Expression)){\r
- long val = (long) v;\r
- \r
- for (int j = 0; j < factor; ++j) {\r
- data [idx + j] = (byte) (val & 0xFF);\r
- val = (val >> 8);\r
- }\r
- }\r
- } else if (underlying_type == TypeManager.uint64_type){\r
- if (!(v is Expression)){\r
- ulong val = (ulong) v;\r
-\r
- for (int j = 0; j < factor; ++j) {\r
- data [idx + j] = (byte) (val & 0xFF);\r
- val = (val >> 8);\r
- }\r
- }\r
- } else if (underlying_type == TypeManager.float_type) {\r
- if (!(v is Expression)){\r
- element = BitConverter.GetBytes ((float) v);\r
- \r
- for (int j = 0; j < factor; ++j)\r
- data [idx + j] = element [j];\r
- }\r
- } else if (underlying_type == TypeManager.double_type) {\r
- if (!(v is Expression)){\r
- element = BitConverter.GetBytes ((double) v);\r
-\r
- for (int j = 0; j < factor; ++j)\r
- data [idx + j] = element [j];\r
- }\r
- } else if (underlying_type == TypeManager.char_type){\r
- if (!(v is Expression)){\r
- int val = (int) ((char) v);\r
- \r
- data [idx] = (byte) (val & 0xff);\r
- data [idx+1] = (byte) (val >> 8);\r
- }\r
- } else if (underlying_type == TypeManager.short_type){\r
- if (!(v is Expression)){\r
- int val = (int) ((short) v);\r
- \r
- data [idx] = (byte) (val & 0xff);\r
- data [idx+1] = (byte) (val >> 8);\r
- }\r
- } else if (underlying_type == TypeManager.ushort_type){\r
- if (!(v is Expression)){\r
- int val = (int) ((ushort) v);\r
- \r
- data [idx] = (byte) (val & 0xff);\r
- data [idx+1] = (byte) (val >> 8);\r
- }\r
- } else if (underlying_type == TypeManager.int32_type) {\r
- if (!(v is Expression)){\r
- int val = (int) v;\r
- \r
- data [idx] = (byte) (val & 0xff);\r
- data [idx+1] = (byte) ((val >> 8) & 0xff);\r
- data [idx+2] = (byte) ((val >> 16) & 0xff);\r
- data [idx+3] = (byte) (val >> 24);\r
- }\r
- } else if (underlying_type == TypeManager.uint32_type) {\r
- if (!(v is Expression)){\r
- uint val = (uint) v;\r
- \r
- data [idx] = (byte) (val & 0xff);\r
- data [idx+1] = (byte) ((val >> 8) & 0xff);\r
- data [idx+2] = (byte) ((val >> 16) & 0xff);\r
- data [idx+3] = (byte) (val >> 24);\r
- }\r
- } else if (underlying_type == TypeManager.sbyte_type) {\r
- if (!(v is Expression)){\r
- sbyte val = (sbyte) v;\r
- data [idx] = (byte) val;\r
- }\r
- } else if (underlying_type == TypeManager.byte_type) {\r
- if (!(v is Expression)){\r
- byte val = (byte) v;\r
- data [idx] = (byte) val;\r
- }\r
- } else\r
- throw new Exception ("Unrecognized type in MakeByteBlob");\r
-\r
- idx += factor;\r
- }\r
-\r
- return data;\r
- }\r
-\r
- //\r
- // Emits the initializers for the array\r
- //\r
- void EmitStaticInitializers (EmitContext ec, bool is_expression)\r
- {\r
- //\r
- // First, the static data\r
- //\r
- FieldBuilder fb;\r
- ILGenerator ig = ec.ig;\r
- \r
- byte [] data = MakeByteBlob (ArrayData, underlying_type, loc);\r
- \r
- if (data != null) {\r
- fb = RootContext.MakeStaticData (data);\r
-\r
- if (is_expression)\r
- ig.Emit (OpCodes.Dup);\r
- ig.Emit (OpCodes.Ldtoken, fb);\r
- ig.Emit (OpCodes.Call,\r
- TypeManager.void_initializearray_array_fieldhandle);\r
- }\r
- }\r
- \r
- //\r
- // Emits pieces of the array that can not be computed at compile\r
- // time (variables and string locations).\r
- //\r
- // This always expect the top value on the stack to be the array\r
- //\r
- void EmitDynamicInitializers (EmitContext ec, bool is_expression)\r
- {\r
- ILGenerator ig = ec.ig;\r
- int dims = Bounds.Count;\r
- int [] current_pos = new int [dims];\r
- int top = ArrayData.Count;\r
- LocalBuilder temp = ig.DeclareLocal (type);\r
-\r
- ig.Emit (OpCodes.Stloc, temp);\r
-\r
- MethodInfo set = null;\r
-\r
- if (dims != 1){\r
- Type [] args;\r
- ModuleBuilder mb = null;\r
- mb = RootContext.ModuleBuilder;\r
- args = new Type [dims + 1];\r
-\r
- int j;\r
- for (j = 0; j < dims; j++)\r
- args [j] = TypeManager.int32_type;\r
-\r
- args [j] = array_element_type;\r
- \r
- set = mb.GetArrayMethod (\r
- type, "Set",\r
- CallingConventions.HasThis | CallingConventions.Standard,\r
- TypeManager.void_type, args);\r
- }\r
- \r
- for (int i = 0; i < top; i++){\r
-\r
- Expression e = null;\r
-\r
- if (ArrayData [i] is Expression)\r
- e = (Expression) ArrayData [i];\r
-\r
- if (e != null) {\r
- //\r
- // Basically we do this for string literals and\r
- // other non-literal expressions\r
- //\r
- if (e is StringConstant || !(e is Constant) || num_automatic_initializers <= 2) {\r
-\r
- ig.Emit (OpCodes.Ldloc, temp);\r
-\r
- for (int idx = dims; idx > 0; ) {\r
- idx--;\r
- IntConstant.EmitInt (ig, current_pos [idx]);\r
- }\r
-\r
- e.Emit (ec);\r
- \r
- if (dims == 1)\r
- ArrayAccess.EmitStoreOpcode (ig, array_element_type);\r
- else \r
- ig.Emit (OpCodes.Call, set);\r
- \r
- }\r
- }\r
- \r
- //\r
- // Advance counter\r
- //\r
- for (int j = 0; j < dims; j++){\r
- current_pos [j]++;\r
- if (current_pos [j] < (int) Bounds [j])\r
- break;\r
- current_pos [j] = 0;\r
- }\r
- }\r
-\r
- if (is_expression)\r
- ig.Emit (OpCodes.Ldloc, temp);\r
- }\r
-\r
- void EmitArrayArguments (EmitContext ec)\r
- {\r
- foreach (Argument a in Arguments)\r
- a.Emit (ec);\r
- }\r
- \r
- void DoEmit (EmitContext ec, bool is_statement)\r
- {\r
- ILGenerator ig = ec.ig;\r
- \r
- EmitArrayArguments (ec);\r
- if (IsOneDimensional)\r
- ig.Emit (OpCodes.Newarr, array_element_type);\r
- else {\r
- if (IsBuiltinType) \r
- ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);\r
- else \r
- ig.Emit (OpCodes.Newobj, (MethodInfo) method);\r
- }\r
- \r
- if (Initializers != null){\r
- //\r
- // FIXME: Set this variable correctly.\r
- // \r
- bool dynamic_initializers = true;\r
-\r
- if (underlying_type != TypeManager.string_type &&\r
- underlying_type != TypeManager.object_type) {\r
- if (num_automatic_initializers > 2)\r
- EmitStaticInitializers (ec, dynamic_initializers || !is_statement);\r
- }\r
- \r
- if (dynamic_initializers)\r
- EmitDynamicInitializers (ec, !is_statement);\r
- }\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- DoEmit (ec, false);\r
- }\r
-\r
- public override void EmitStatement (EmitContext ec)\r
- {\r
- DoEmit (ec, true);\r
- }\r
- \r
- }\r
- \r
- /// <summary>\r
- /// Represents the `this' construct\r
- /// </summary>\r
- public class This : Expression, IAssignMethod, IMemoryLocation {\r
- Location loc;\r
- \r
- public This (Location loc)\r
- {\r
- this.loc = loc;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- eclass = ExprClass.Variable;\r
- type = ec.TypeContainer.TypeBuilder;\r
-\r
- if (ec.IsStatic){\r
- Report.Error (26, loc,\r
- "Keyword this not valid in static code");\r
- return null;\r
- }\r
- \r
- return this;\r
- }\r
-\r
- override public Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
- {\r
- DoResolve (ec);\r
- \r
- if (ec.TypeContainer is Class){\r
- Report.Error (1604, loc, "Cannot assign to `this'");\r
- return null;\r
- }\r
-\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ec.ig.Emit (OpCodes.Ldarg_0);\r
- }\r
-\r
- public void EmitAssign (EmitContext ec, Expression source)\r
- {\r
- source.Emit (ec);\r
- ec.ig.Emit (OpCodes.Starg, 0);\r
- }\r
-\r
- public void AddressOf (EmitContext ec, AddressOp mode)\r
- {\r
- ec.ig.Emit (OpCodes.Ldarg_0);\r
-\r
- // FIMXE\r
- // FIGURE OUT WHY LDARG_S does not work\r
- //\r
- // consider: struct X { int val; int P { set { val = value; }}}\r
- //\r
- // Yes, this looks very bad. Look at `NOTAS' for\r
- // an explanation.\r
- // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implements the typeof operator\r
- /// </summary>\r
- public class TypeOf : Expression {\r
- public readonly string QueriedType;\r
- Type typearg;\r
- Location loc;\r
- \r
- public TypeOf (string queried_type, Location l)\r
- {\r
- QueriedType = queried_type;\r
- loc = l;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- typearg = RootContext.LookupType (\r
- ec.DeclSpace, QueriedType, false, loc);\r
-\r
- if (typearg == null)\r
- return null;\r
-\r
- type = TypeManager.type_type;\r
- eclass = ExprClass.Type;\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ec.ig.Emit (OpCodes.Ldtoken, typearg);\r
- ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implements the sizeof expression\r
- /// </summary>\r
- public class SizeOf : Expression {\r
- public readonly string QueriedType;\r
- Type type_queried;\r
- Location loc;\r
- \r
- public SizeOf (string queried_type, Location l)\r
- {\r
- this.QueriedType = queried_type;\r
- loc = l;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- type_queried = RootContext.LookupType (\r
- ec.DeclSpace, QueriedType, false, loc);\r
- if (type_queried == null)\r
- return null;\r
-\r
- type = TypeManager.int32_type;\r
- eclass = ExprClass.Value;\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- int size = GetTypeSize (type_queried);\r
-\r
- if (size == 0)\r
- ec.ig.Emit (OpCodes.Sizeof, type_queried);\r
- else\r
- IntConstant.EmitInt (ec.ig, size);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implements the member access expression\r
- /// </summary>\r
- public class MemberAccess : Expression {\r
- public readonly string Identifier;\r
- Expression expr;\r
- Expression member_lookup;\r
- Location loc;\r
- \r
- public MemberAccess (Expression expr, string id, Location l)\r
- {\r
- this.expr = expr;\r
- Identifier = id;\r
- loc = l;\r
- }\r
-\r
- public Expression Expr {\r
- get {\r
- return expr;\r
- }\r
- }\r
-\r
- static void error176 (Location loc, string name)\r
- {\r
- Report.Error (176, loc, "Static member `" +\r
- name + "' cannot be accessed " +\r
- "with an instance reference, qualify with a " +\r
- "type name instead");\r
- }\r
-\r
- static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)\r
- {\r
- if (left_original == null)\r
- return false;\r
-\r
- if (!(left_original is SimpleName))\r
- return false;\r
-\r
- SimpleName sn = (SimpleName) left_original;\r
-\r
- Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);\r
- if (t != null)\r
- return true;\r
-\r
- return false;\r
- }\r
- \r
- public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,\r
- Expression left, Location loc,\r
- Expression left_original)\r
- {\r
- //\r
- // Method Groups\r
- //\r
- if (member_lookup is MethodGroupExpr){\r
- MethodGroupExpr mg = (MethodGroupExpr) member_lookup;\r
-\r
- //\r
- // Type.MethodGroup\r
- //\r
- if (left is TypeExpr){\r
- if (!mg.RemoveInstanceMethods ()){\r
- SimpleName.Error120 (loc, mg.Methods [0].Name); \r
- return null;\r
- }\r
-\r
- return member_lookup;\r
- }\r
-\r
- //\r
- // Instance.MethodGroup\r
- //\r
- if (IdenticalNameAndTypeName (ec, left_original, loc)){\r
- if (mg.RemoveInstanceMethods ())\r
- return member_lookup;\r
- }\r
- \r
- if (!mg.RemoveStaticMethods ()){\r
- error176 (loc, mg.Methods [0].Name);\r
- return null;\r
- } \r
- \r
- mg.InstanceExpression = left;\r
- return member_lookup;\r
-#if ORIGINAL\r
- if (!mg.RemoveStaticMethods ()){\r
- if (IdenticalNameAndTypeName (ec, left_original, loc)){\r
- if (!mg.RemoveInstanceMethods ()){\r
- SimpleName.Error120 (loc, mg.Methods [0].Name);\r
- return null;\r
- }\r
- return member_lookup;\r
- }\r
- \r
- error176 (loc, mg.Methods [0].Name);\r
- return null;\r
- }\r
- \r
- mg.InstanceExpression = left;\r
- \r
- return member_lookup;\r
-#endif\r
- }\r
-\r
- if (member_lookup is FieldExpr){\r
- FieldExpr fe = (FieldExpr) member_lookup;\r
- FieldInfo fi = fe.FieldInfo;\r
-\r
- if (fi is FieldBuilder) {\r
- Const c = TypeManager.LookupConstant ((FieldBuilder) fi);\r
- \r
- if (c != null) {\r
- object o = c.LookupConstantValue (ec);\r
- object real_value = ((Constant) c.Expr).GetValue ();\r
-\r
- return Constantify (real_value, fi.FieldType);\r
- }\r
- }\r
-\r
- if (fi.IsLiteral) {\r
- Type t = fi.FieldType;\r
- Type decl_type = fi.DeclaringType;\r
- object o;\r
-\r
- if (fi is FieldBuilder)\r
- o = TypeManager.GetValue ((FieldBuilder) fi);\r
- else\r
- o = fi.GetValue (fi);\r
- \r
- if (decl_type.IsSubclassOf (TypeManager.enum_type)) {\r
- Expression enum_member = MemberLookup (\r
- ec, decl_type, "value__", MemberTypes.Field,\r
- AllBindingFlags, loc); \r
-\r
- Enum en = TypeManager.LookupEnum (decl_type);\r
-\r
- Constant c;\r
- if (en != null)\r
- c = Constantify (o, en.UnderlyingType);\r
- else \r
- c = Constantify (o, enum_member.Type);\r
- \r
- return new EnumConstant (c, decl_type);\r
- }\r
- \r
- Expression exp = Constantify (o, t);\r
-\r
- if (!(left is TypeExpr)) {\r
- error176 (loc, fe.FieldInfo.Name);\r
- return null;\r
- }\r
- \r
- return exp;\r
- }\r
-\r
- if (fi.FieldType.IsPointer && !ec.InUnsafe){\r
- UnsafeError (loc);\r
- return null;\r
- }\r
- \r
- if (left is TypeExpr){\r
- // and refers to a type name or an \r
- if (!fe.FieldInfo.IsStatic){\r
- error176 (loc, fe.FieldInfo.Name);\r
- return null;\r
- }\r
- return member_lookup;\r
- } else {\r
- if (fe.FieldInfo.IsStatic){\r
- if (IdenticalNameAndTypeName (ec, left_original, loc))\r
- return member_lookup;\r
-\r
- error176 (loc, fe.FieldInfo.Name);\r
- return null;\r
- }\r
- fe.InstanceExpression = left;\r
-\r
- return fe;\r
- }\r
- }\r
-\r
- if (member_lookup is PropertyExpr){\r
- PropertyExpr pe = (PropertyExpr) member_lookup;\r
-\r
- if (left is TypeExpr){\r
- if (!pe.IsStatic){\r
- SimpleName.Error120 (loc, pe.PropertyInfo.Name);\r
- return null;\r
- }\r
- return pe;\r
- } else {\r
- if (pe.IsStatic){\r
- if (IdenticalNameAndTypeName (ec, left_original, loc))\r
- return member_lookup;\r
- error176 (loc, pe.PropertyInfo.Name);\r
- return null;\r
- }\r
- pe.InstanceExpression = left;\r
- \r
- return pe;\r
- }\r
- }\r
-\r
- if (member_lookup is EventExpr) {\r
-\r
- EventExpr ee = (EventExpr) member_lookup;\r
- \r
- //\r
- // If the event is local to this class, we transform ourselves into\r
- // a FieldExpr\r
- //\r
-\r
- Expression ml = MemberLookup (\r
- ec, ec.TypeContainer.TypeBuilder,\r
- ee.EventInfo.Name, MemberTypes.Event, AllBindingFlags, loc);\r
-\r
- if (ml != null) {\r
- MemberInfo mi = ec.TypeContainer.GetFieldFromEvent ((EventExpr) ml);\r
-\r
- if (mi == null) {\r
- //\r
- // If this happens, then we have an event with its own\r
- // accessors and private field etc so there's no need\r
- // to transform ourselves : we should instead flag an error\r
- //\r
- Assign.error70 (ee.EventInfo, loc);\r
- return null;\r
- }\r
-\r
- ml = ExprClassFromMemberInfo (ec, mi, loc);\r
- \r
- if (ml == null) {\r
- Report.Error (-200, loc, "Internal error!!");\r
- return null;\r
- }\r
- return ResolveMemberAccess (ec, ml, left, loc, left_original);\r
- }\r
-\r
- if (left is TypeExpr) {\r
- if (!ee.IsStatic) {\r
- SimpleName.Error120 (loc, ee.EventInfo.Name);\r
- return null;\r
- }\r
-\r
- return ee;\r
-\r
- } else {\r
- if (ee.IsStatic) {\r
- if (IdenticalNameAndTypeName (ec, left_original, loc))\r
- return ee;\r
- \r
- error176 (loc, ee.EventInfo.Name);\r
- return null;\r
- }\r
-\r
- ee.InstanceExpression = left;\r
-\r
- return ee;\r
- }\r
- }\r
-\r
- if (member_lookup is TypeExpr){\r
- member_lookup.Resolve (ec);\r
- return member_lookup;\r
- }\r
- \r
- Console.WriteLine ("Left is: " + left);\r
- Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");\r
- Environment.Exit (0);\r
- return null;\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // We are the sole users of ResolveWithSimpleName (ie, the only\r
- // ones that can cope with it\r
- //\r
- Expression original = expr;\r
- expr = expr.ResolveWithSimpleName (ec);\r
-\r
- if (expr == null)\r
- return null;\r
-\r
- if (expr is SimpleName){\r
- SimpleName child_expr = (SimpleName) expr;\r
- \r
- expr = new SimpleName (child_expr.Name + "." + Identifier, loc);\r
-\r
- return expr.ResolveWithSimpleName (ec);\r
- }\r
- \r
- //\r
- // TODO: I mailed Ravi about this, and apparently we can get rid\r
- // of this and put it in the right place.\r
- // \r
- // Handle enums here when they are in transit.\r
- // Note that we cannot afford to hit MemberLookup in this case because\r
- // it will fail to find any members at all\r
- //\r
-\r
- Type expr_type = expr.Type;\r
- if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))){\r
- \r
- Enum en = TypeManager.LookupEnum (expr_type);\r
- \r
- if (en != null) {\r
- object value = en.LookupEnumValue (ec, Identifier, loc);\r
-\r
- if (value != null){\r
- Constant c = Constantify (value, en.UnderlyingType);\r
- return new EnumConstant (c, expr_type);\r
- }\r
- }\r
- }\r
-\r
- if (expr_type.IsPointer){\r
- Report.Error (23, loc,\r
- "The `.' operator can not be applied to pointer operands (" +\r
- TypeManager.CSharpName (expr_type) + ")");\r
- return null;\r
- }\r
- \r
- member_lookup = MemberLookup (ec, expr_type, Identifier, loc);\r
-\r
- if (member_lookup == null){\r
- Report.Error (117, loc, "`" + expr_type + "' does not contain a " +\r
- "definition for `" + Identifier + "'");\r
- \r
- return null;\r
- }\r
-\r
- return ResolveMemberAccess (ec, member_lookup, expr, loc, original);\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- throw new Exception ("Should not happen");\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implements checked expressions\r
- /// </summary>\r
- public class CheckedExpr : Expression {\r
-\r
- public Expression Expr;\r
-\r
- public CheckedExpr (Expression e)\r
- {\r
- Expr = e;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- bool last_const_check = ec.ConstantCheckState;\r
-\r
- ec.ConstantCheckState = true;\r
- Expr = Expr.Resolve (ec);\r
- ec.ConstantCheckState = last_const_check;\r
- \r
- if (Expr == null)\r
- return null;\r
-\r
- eclass = Expr.eclass;\r
- type = Expr.Type;\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- bool last_check = ec.CheckState;\r
- bool last_const_check = ec.ConstantCheckState;\r
- \r
- ec.CheckState = true;\r
- ec.ConstantCheckState = true;\r
- Expr.Emit (ec);\r
- ec.CheckState = last_check;\r
- ec.ConstantCheckState = last_const_check;\r
- }\r
- \r
- }\r
-\r
- /// <summary>\r
- /// Implements the unchecked expression\r
- /// </summary>\r
- public class UnCheckedExpr : Expression {\r
-\r
- public Expression Expr;\r
-\r
- public UnCheckedExpr (Expression e)\r
- {\r
- Expr = e;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- bool last_const_check = ec.ConstantCheckState;\r
-\r
- ec.ConstantCheckState = false;\r
- Expr = Expr.Resolve (ec);\r
- ec.ConstantCheckState = last_const_check;\r
-\r
- if (Expr == null)\r
- return null;\r
-\r
- eclass = Expr.eclass;\r
- type = Expr.Type;\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- bool last_check = ec.CheckState;\r
- bool last_const_check = ec.ConstantCheckState;\r
- \r
- ec.CheckState = false;\r
- ec.ConstantCheckState = false;\r
- Expr.Emit (ec);\r
- ec.CheckState = last_check;\r
- ec.ConstantCheckState = last_const_check;\r
- }\r
- \r
- }\r
-\r
- /// <summary>\r
- /// An Element Access expression.\r
- ///\r
- /// During semantic analysis these are transformed into \r
- /// IndexerAccess or ArrayAccess \r
- /// </summary>\r
- public class ElementAccess : Expression {\r
- public ArrayList Arguments;\r
- public Expression Expr;\r
- public Location loc;\r
- \r
- public ElementAccess (Expression e, ArrayList e_list, Location l)\r
- {\r
- Expr = e;\r
-\r
- loc = l;\r
- \r
- if (e_list == null)\r
- return;\r
- \r
- Arguments = new ArrayList ();\r
- foreach (Expression tmp in e_list)\r
- Arguments.Add (new Argument (tmp, Argument.AType.Expression));\r
- \r
- }\r
-\r
- bool CommonResolve (EmitContext ec)\r
- {\r
- Expr = Expr.Resolve (ec);\r
-\r
- if (Expr == null) \r
- return false;\r
-\r
- if (Arguments == null)\r
- return false;\r
-\r
- for (int i = Arguments.Count; i > 0;){\r
- --i;\r
- Argument a = (Argument) Arguments [i];\r
- \r
- if (!a.Resolve (ec, loc))\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
-\r
- Expression MakePointerAccess ()\r
- {\r
- Type t = Expr.Type;\r
-\r
- if (t == TypeManager.void_ptr_type){\r
- Report.Error (\r
- 242, loc,\r
- "The array index operation is not valid for void pointers");\r
- return null;\r
- }\r
- if (Arguments.Count != 1){\r
- Report.Error (\r
- 196, loc,\r
- "A pointer must be indexed by a single value");\r
- return null;\r
- }\r
- Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t);\r
- return new Indirection (p);\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- if (!CommonResolve (ec))\r
- return null;\r
-\r
- //\r
- // We perform some simple tests, and then to "split" the emit and store\r
- // code we create an instance of a different class, and return that.\r
- //\r
- // I am experimenting with this pattern.\r
- //\r
- Type t = Expr.Type;\r
-\r
- if (t.IsSubclassOf (TypeManager.array_type))\r
- return (new ArrayAccess (this)).Resolve (ec);\r
- else if (t.IsPointer)\r
- return MakePointerAccess ();\r
- else\r
- return (new IndexerAccess (this)).Resolve (ec);\r
- }\r
-\r
- public override Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
- {\r
- if (!CommonResolve (ec))\r
- return null;\r
-\r
- Type t = Expr.Type;\r
- if (t.IsSubclassOf (TypeManager.array_type))\r
- return (new ArrayAccess (this)).ResolveLValue (ec, right_side);\r
- else if (t.IsPointer)\r
- return MakePointerAccess ();\r
- else\r
- return (new IndexerAccess (this)).ResolveLValue (ec, right_side);\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- throw new Exception ("Should never be reached");\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Implements array access \r
- /// </summary>\r
- public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {\r
- //\r
- // Points to our "data" repository\r
- //\r
- ElementAccess ea;\r
- \r
- public ArrayAccess (ElementAccess ea_data)\r
- {\r
- ea = ea_data;\r
- eclass = ExprClass.Variable;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- if (ea.Expr.eclass != ExprClass.Variable) {\r
- report118 (ea.loc, ea.Expr, "variable");\r
- return null;\r
- }\r
-\r
- Type t = ea.Expr.Type;\r
- if (t.GetArrayRank () != ea.Arguments.Count){\r
- Report.Error (22, ea.loc,\r
- "Incorrect number of indexes for array " +\r
- " expected: " + t.GetArrayRank () + " got: " +\r
- ea.Arguments.Count);\r
- return null;\r
- }\r
- type = t.GetElementType ();\r
- if (type.IsPointer && !ec.InUnsafe){\r
- UnsafeError (ea.loc);\r
- return null;\r
- }\r
- \r
- eclass = ExprClass.Variable;\r
-\r
- return this;\r
- }\r
-\r
- /// <summary>\r
- /// Emits the right opcode to load an object of Type `t'\r
- /// from an array of T\r
- /// </summary>\r
- static public void EmitLoadOpcode (ILGenerator ig, Type type)\r
- {\r
- if (type == TypeManager.byte_type || type == TypeManager.bool_type)\r
- ig.Emit (OpCodes.Ldelem_I1);\r
- else if (type == TypeManager.sbyte_type)\r
- ig.Emit (OpCodes.Ldelem_U1);\r
- else if (type == TypeManager.short_type)\r
- ig.Emit (OpCodes.Ldelem_I2);\r
- else if (type == TypeManager.ushort_type)\r
- ig.Emit (OpCodes.Ldelem_U2);\r
- else if (type == TypeManager.int32_type)\r
- ig.Emit (OpCodes.Ldelem_I4);\r
- else if (type == TypeManager.uint32_type)\r
- ig.Emit (OpCodes.Ldelem_U4);\r
- else if (type == TypeManager.uint64_type)\r
- ig.Emit (OpCodes.Ldelem_I8);\r
- else if (type == TypeManager.int64_type)\r
- ig.Emit (OpCodes.Ldelem_I8);\r
- else if (type == TypeManager.float_type)\r
- ig.Emit (OpCodes.Ldelem_R4);\r
- else if (type == TypeManager.double_type)\r
- ig.Emit (OpCodes.Ldelem_R8);\r
- else if (type == TypeManager.intptr_type)\r
- ig.Emit (OpCodes.Ldelem_I);\r
- else if (type.IsValueType){\r
- ig.Emit (OpCodes.Ldelema, type);\r
- ig.Emit (OpCodes.Ldobj, type);\r
- } else \r
- ig.Emit (OpCodes.Ldelem_Ref);\r
- }\r
-\r
- /// <summary>\r
- /// Emits the right opcode to store an object of Type `t'\r
- /// from an array of T. \r
- /// </summary>\r
- static public void EmitStoreOpcode (ILGenerator ig, Type t)\r
- {\r
- if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||\r
- t == TypeManager.bool_type)\r
- ig.Emit (OpCodes.Stelem_I1);\r
- else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)\r
- ig.Emit (OpCodes.Stelem_I2);\r
- else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)\r
- ig.Emit (OpCodes.Stelem_I4);\r
- else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)\r
- ig.Emit (OpCodes.Stelem_I8);\r
- else if (t == TypeManager.float_type)\r
- ig.Emit (OpCodes.Stelem_R4);\r
- else if (t == TypeManager.double_type)\r
- ig.Emit (OpCodes.Stelem_R8);\r
- else if (t == TypeManager.intptr_type)\r
- ig.Emit (OpCodes.Stelem_I);\r
- else if (t.IsValueType)\r
- ig.Emit (OpCodes.Stobj, t);\r
- else\r
- ig.Emit (OpCodes.Stelem_Ref);\r
- }\r
-\r
- MethodInfo FetchGetMethod ()\r
- {\r
- ModuleBuilder mb = RootContext.ModuleBuilder;\r
- int arg_count = ea.Arguments.Count;\r
- Type [] args = new Type [arg_count];\r
- MethodInfo get;\r
- \r
- for (int i = 0; i < arg_count; i++){\r
- //args [i++] = a.Type;\r
- args [i] = TypeManager.int32_type;\r
- }\r
- \r
- get = mb.GetArrayMethod (\r
- ea.Expr.Type, "Get",\r
- CallingConventions.HasThis |\r
- CallingConventions.Standard,\r
- type, args);\r
- return get;\r
- }\r
- \r
-\r
- MethodInfo FetchAddressMethod ()\r
- {\r
- ModuleBuilder mb = RootContext.ModuleBuilder;\r
- int arg_count = ea.Arguments.Count;\r
- Type [] args = new Type [arg_count];\r
- MethodInfo address;\r
- string ptr_type_name;\r
- Type ret_type;\r
- \r
- ptr_type_name = type.FullName + "&";\r
- ret_type = Type.GetType (ptr_type_name);\r
- \r
- //\r
- // It is a type defined by the source code we are compiling\r
- //\r
- if (ret_type == null){\r
- ret_type = mb.GetType (ptr_type_name);\r
- }\r
-\r
- for (int i = 0; i < arg_count; i++){\r
- //args [i++] = a.Type;\r
- args [i] = TypeManager.int32_type;\r
- }\r
- \r
- address = mb.GetArrayMethod (\r
- ea.Expr.Type, "Address",\r
- CallingConventions.HasThis |\r
- CallingConventions.Standard,\r
- ret_type, args);\r
-\r
- return address;\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- int rank = ea.Expr.Type.GetArrayRank ();\r
- ILGenerator ig = ec.ig;\r
-\r
- ea.Expr.Emit (ec);\r
-\r
- foreach (Argument a in ea.Arguments)\r
- a.Expr.Emit (ec);\r
-\r
- if (rank == 1)\r
- EmitLoadOpcode (ig, type);\r
- else {\r
- MethodInfo method;\r
- \r
- method = FetchGetMethod ();\r
- ig.Emit (OpCodes.Call, method);\r
- }\r
- }\r
-\r
- public void EmitAssign (EmitContext ec, Expression source)\r
- {\r
- int rank = ea.Expr.Type.GetArrayRank ();\r
- ILGenerator ig = ec.ig;\r
-\r
- ea.Expr.Emit (ec);\r
-\r
- foreach (Argument a in ea.Arguments)\r
- a.Expr.Emit (ec);\r
-\r
- Type t = source.Type;\r
-\r
- //\r
- // The stobj opcode used by value types will need\r
- // an address on the stack, not really an array/array\r
- // pair\r
- //\r
- if (rank == 1){\r
- if (t.IsValueType && !TypeManager.IsBuiltinType (t))\r
- ig.Emit (OpCodes.Ldelema, t);\r
- }\r
- \r
- source.Emit (ec);\r
-\r
- if (rank == 1)\r
- EmitStoreOpcode (ig, t);\r
- else {\r
- ModuleBuilder mb = RootContext.ModuleBuilder;\r
- int arg_count = ea.Arguments.Count;\r
- Type [] args = new Type [arg_count + 1];\r
- MethodInfo set;\r
- \r
- for (int i = 0; i < arg_count; i++){\r
- //args [i++] = a.Type;\r
- args [i] = TypeManager.int32_type;\r
- }\r
-\r
- args [arg_count] = type;\r
- \r
- set = mb.GetArrayMethod (\r
- ea.Expr.Type, "Set",\r
- CallingConventions.HasThis |\r
- CallingConventions.Standard,\r
- TypeManager.void_type, args);\r
- \r
- ig.Emit (OpCodes.Call, set);\r
- }\r
- }\r
-\r
- public void AddressOf (EmitContext ec, AddressOp mode)\r
- {\r
- int rank = ea.Expr.Type.GetArrayRank ();\r
- ILGenerator ig = ec.ig;\r
- \r
- ea.Expr.Emit (ec);\r
-\r
- foreach (Argument a in ea.Arguments)\r
- a.Expr.Emit (ec);\r
-\r
- if (rank == 1){\r
- ig.Emit (OpCodes.Ldelema, type);\r
- } else {\r
- MethodInfo address = FetchAddressMethod ();\r
- ig.Emit (OpCodes.Call, address);\r
- }\r
- }\r
- }\r
-\r
- \r
- class Indexers {\r
- public ArrayList getters, setters;\r
- static Hashtable map;\r
-\r
- static Indexers ()\r
- {\r
- map = new Hashtable ();\r
- }\r
-\r
- Indexers (MemberInfo [] mi)\r
- {\r
- foreach (PropertyInfo property in mi){\r
- MethodInfo get, set;\r
- \r
- get = property.GetGetMethod (true);\r
- if (get != null){\r
- if (getters == null)\r
- getters = new ArrayList ();\r
-\r
- getters.Add (get);\r
- }\r
- \r
- set = property.GetSetMethod (true);\r
- if (set != null){\r
- if (setters == null)\r
- setters = new ArrayList ();\r
- setters.Add (set);\r
- }\r
- }\r
- }\r
- \r
- static public Indexers GetIndexersForType (Type t, TypeManager tm, Location loc) \r
- {\r
- Indexers ix = (Indexers) map [t];\r
- string p_name = TypeManager.IndexerPropertyName (t);\r
- \r
- if (ix != null)\r
- return ix;\r
-\r
- MemberInfo [] mi = tm.FindMembers (\r
- t, MemberTypes.Property,\r
- BindingFlags.Public | BindingFlags.Instance,\r
- Type.FilterName, p_name);\r
-\r
- if (mi == null || mi.Length == 0){\r
- Report.Error (21, loc,\r
- "Type `" + TypeManager.CSharpName (t) + "' does not have " +\r
- "any indexers defined");\r
- return null;\r
- }\r
- \r
- ix = new Indexers (mi);\r
- map [t] = ix;\r
-\r
- return ix;\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// Expressions that represent an indexer call.\r
- /// </summary>\r
- public class IndexerAccess : Expression, IAssignMethod {\r
- //\r
- // Points to our "data" repository\r
- //\r
- ElementAccess ea;\r
- MethodInfo get, set;\r
- Indexers ilist;\r
- ArrayList set_arguments;\r
- \r
- public IndexerAccess (ElementAccess ea_data)\r
- {\r
- ea = ea_data;\r
- eclass = ExprClass.Value;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- Type indexer_type = ea.Expr.Type;\r
- \r
- //\r
- // Step 1: Query for all `Item' *properties*. Notice\r
- // that the actual methods are pointed from here.\r
- //\r
- // This is a group of properties, piles of them. \r
-\r
- if (ilist == null)\r
- ilist = Indexers.GetIndexersForType (\r
- indexer_type, RootContext.TypeManager, ea.loc);\r
-\r
-\r
- //\r
- // Step 2: find the proper match\r
- //\r
- if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)\r
- get = (MethodInfo) Invocation.OverloadResolve (\r
- ec, new MethodGroupExpr (ilist.getters), ea.Arguments, ea.loc);\r
-\r
- if (get == null){\r
- Report.Error (154, ea.loc,\r
- "indexer can not be used in this context, because " +\r
- "it lacks a `get' accessor");\r
- return null;\r
- }\r
-\r
- type = get.ReturnType;\r
- if (type.IsPointer && !ec.InUnsafe){\r
- UnsafeError (ea.loc);\r
- return null;\r
- }\r
- \r
- eclass = ExprClass.IndexerAccess;\r
- return this;\r
- }\r
-\r
- public override Expression DoResolveLValue (EmitContext ec, Expression right_side)\r
- {\r
- Type indexer_type = ea.Expr.Type;\r
- Type right_type = right_side.Type;\r
-\r
- if (ilist == null)\r
- ilist = Indexers.GetIndexersForType (\r
- indexer_type, RootContext.TypeManager, ea.loc);\r
-\r
- if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){\r
- set_arguments = (ArrayList) ea.Arguments.Clone ();\r
- set_arguments.Add (new Argument (right_side, Argument.AType.Expression));\r
-\r
- set = (MethodInfo) Invocation.OverloadResolve (\r
- ec, new MethodGroupExpr (ilist.setters), set_arguments, ea.loc);\r
- }\r
- \r
- if (set == null){\r
- Report.Error (200, ea.loc,\r
- "indexer X.this [" + TypeManager.CSharpName (right_type) +\r
- "] lacks a `set' accessor");\r
- return null;\r
- }\r
-\r
- type = TypeManager.void_type;\r
- eclass = ExprClass.IndexerAccess;\r
- return this;\r
- }\r
- \r
- public override void Emit (EmitContext ec)\r
- {\r
- Invocation.EmitCall (ec, false, false, ea.Expr, get, ea.Arguments);\r
- }\r
-\r
- //\r
- // source is ignored, because we already have a copy of it from the\r
- // LValue resolution and we have already constructed a pre-cached\r
- // version of the arguments (ea.set_arguments);\r
- //\r
- public void EmitAssign (EmitContext ec, Expression source)\r
- {\r
- Invocation.EmitCall (ec, false, false, ea.Expr, set, set_arguments);\r
- }\r
- }\r
-\r
- /// <summary>\r
- /// The base operator for method names\r
- /// </summary>\r
- public class BaseAccess : Expression {\r
- string member;\r
- Location loc;\r
- \r
- public BaseAccess (string member, Location l)\r
- {\r
- this.member = member;\r
- loc = l;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- Expression member_lookup;\r
- Type current_type = ec.TypeContainer.TypeBuilder;\r
- Type base_type = current_type.BaseType;\r
- Expression e;\r
-\r
- if (ec.IsStatic){\r
- Report.Error (1511, loc,\r
- "Keyword base is not allowed in static method");\r
- return null;\r
- }\r
- \r
- member_lookup = MemberLookup (ec, base_type, member, loc);\r
- if (member_lookup == null)\r
- return null;\r
-\r
- Expression left;\r
- \r
- if (ec.IsStatic)\r
- left = new TypeExpr (base_type);\r
- else\r
- left = ec.This;\r
- \r
- e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);\r
- if (e is PropertyExpr){\r
- PropertyExpr pe = (PropertyExpr) e;\r
-\r
- pe.IsBase = true;\r
- }\r
-\r
- return e;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- throw new Exception ("Should never be called"); \r
- }\r
- }\r
-\r
- /// <summary>\r
- /// The base indexer operator\r
- /// </summary>\r
- public class BaseIndexerAccess : Expression {\r
- ArrayList Arguments;\r
- Location loc;\r
- \r
- public BaseIndexerAccess (ArrayList args, Location l)\r
- {\r
- Arguments = args;\r
- loc = l;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- Type current_type = ec.TypeContainer.TypeBuilder;\r
- Type base_type = current_type.BaseType;\r
- Expression member_lookup;\r
-\r
- if (ec.IsStatic){\r
- Report.Error (1511, loc,\r
- "Keyword base is not allowed in static method");\r
- return null;\r
- }\r
- \r
- member_lookup = MemberLookup (ec, base_type, "get_Item", MemberTypes.Method, AllBindingFlags, loc);\r
- if (member_lookup == null)\r
- return null;\r
-\r
- return MemberAccess.ResolveMemberAccess (ec, member_lookup, ec.This, loc, null);\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- throw new Exception ("Should never be called");\r
- }\r
- }\r
- \r
- /// <summary>\r
- /// This class exists solely to pass the Type around and to be a dummy\r
- /// that can be passed to the conversion functions (this is used by\r
- /// foreach implementation to typecast the object return value from\r
- /// get_Current into the proper type. All code has been generated and\r
- /// we only care about the side effect conversions to be performed\r
- /// </summary>\r
- public class EmptyExpression : Expression {\r
- public EmptyExpression ()\r
- {\r
- type = TypeManager.object_type;\r
- eclass = ExprClass.Value;\r
- }\r
-\r
- public EmptyExpression (Type t)\r
- {\r
- type = t;\r
- eclass = ExprClass.Value;\r
- }\r
- \r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- // nothing, as we only exist to not do anything.\r
- }\r
-\r
- //\r
- // This is just because we might want to reuse this bad boy\r
- // instead of creating gazillions of EmptyExpressions.\r
- // (CanConvertImplicit uses it)\r
- //\r
- public void SetType (Type t)\r
- {\r
- type = t;\r
- }\r
- }\r
-\r
- public class UserCast : Expression {\r
- MethodBase method;\r
- Expression source;\r
- \r
- public UserCast (MethodInfo method, Expression source)\r
- {\r
- this.method = method;\r
- this.source = source;\r
- type = method.ReturnType;\r
- eclass = ExprClass.Value;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // We are born fully resolved\r
- //\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
-\r
- source.Emit (ec);\r
- \r
- if (method is MethodInfo)\r
- ig.Emit (OpCodes.Call, (MethodInfo) method);\r
- else\r
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);\r
-\r
- }\r
- }\r
-\r
- // <summary>\r
- // This class is used to "construct" the type during a typecast\r
- // operation. Since the Type.GetType class in .NET can parse\r
- // the type specification, we just use this to construct the type\r
- // one bit at a time.\r
- // </summary>\r
- public class ComposedCast : Expression {\r
- Expression left;\r
- string dim;\r
- Location loc;\r
- \r
- public ComposedCast (Expression left, string dim, Location l)\r
- {\r
- this.left = left;\r
- this.dim = dim;\r
- loc = l;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- left = left.Resolve (ec);\r
- if (left == null)\r
- return null;\r
-\r
- if (left.eclass != ExprClass.Type){\r
- report118 (loc, left, "type");\r
- return null;\r
- }\r
- \r
- type = RootContext.LookupType (\r
- ec.DeclSpace, left.Type.FullName + dim, false, loc);\r
- if (type == null)\r
- return null;\r
-\r
- if (!ec.InUnsafe && type.IsPointer){\r
- UnsafeError (loc);\r
- return null;\r
- }\r
- \r
- eclass = ExprClass.Type;\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- throw new Exception ("This should never be called");\r
- }\r
- }\r
-\r
- //\r
- // This class is used to represent the address of an array, used\r
- // only by the Fixed statement, this is like the C "&a [0]" construct.\r
- //\r
- public class ArrayPtr : Expression {\r
- Expression array;\r
- \r
- public ArrayPtr (Expression array)\r
- {\r
- Type array_type = array.Type.GetElementType ();\r
-\r
- this.array = array;\r
- \r
- string array_ptr_type_name = array_type.FullName + "*";\r
- \r
- type = Type.GetType (array_ptr_type_name);\r
- if (type == null){\r
- ModuleBuilder mb = RootContext.ModuleBuilder;\r
- \r
- type = mb.GetType (array_ptr_type_name);\r
- }\r
-\r
- eclass = ExprClass.Value;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
- \r
- array.Emit (ec);\r
- IntLiteral.EmitInt (ig, 0);\r
- ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- //\r
- // We are born fully resolved\r
- //\r
- return this;\r
- }\r
- }\r
-\r
- //\r
- // Used by the fixed statement\r
- //\r
- public class StringPtr : Expression {\r
- LocalBuilder b;\r
- \r
- public StringPtr (LocalBuilder b)\r
- {\r
- this.b = b;\r
- eclass = ExprClass.Value;\r
- type = TypeManager.char_ptr_type;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- // This should never be invoked, we are born in fully\r
- // initialized state.\r
-\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- ILGenerator ig = ec.ig;\r
-\r
- ig.Emit (OpCodes.Ldloc, b);\r
- ig.Emit (OpCodes.Conv_I);\r
- ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);\r
- ig.Emit (OpCodes.Add);\r
- }\r
- }\r
- \r
- //\r
- // Implements the `stackalloc' keyword\r
- //\r
- public class StackAlloc : Expression {\r
- Type otype;\r
- string t;\r
- Expression count;\r
- Location loc;\r
- \r
- public StackAlloc (string type, Expression count, Location l)\r
- {\r
- t = type;\r
- this.count = count;\r
- loc = l;\r
- }\r
-\r
- public override Expression DoResolve (EmitContext ec)\r
- {\r
- count = count.Resolve (ec);\r
- if (count == null)\r
- return null;\r
- \r
- if (count.Type != TypeManager.int32_type){\r
- count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);\r
- if (count == null)\r
- return null;\r
- }\r
-\r
- if (ec.InCatch || ec.InFinally){\r
- Report.Error (255, loc,\r
- "stackalloc can not be used in a catch or finally block");\r
- return null;\r
- }\r
- \r
- otype = RootContext.LookupType (ec.DeclSpace, t, false, loc);\r
-\r
- if (otype == null)\r
- return null;\r
-\r
- if (!TypeManager.VerifyUnManaged (otype, loc))\r
- return null;\r
-\r
- string ptr_name = otype.FullName + "*";\r
- type = Type.GetType (ptr_name);\r
- if (type == null){\r
- ModuleBuilder mb = RootContext.ModuleBuilder;\r
- \r
- type = mb.GetType (ptr_name);\r
- }\r
- eclass = ExprClass.Value;\r
-\r
- return this;\r
- }\r
-\r
- public override void Emit (EmitContext ec)\r
- {\r
- int size = GetTypeSize (otype);\r
- ILGenerator ig = ec.ig;\r
- \r
- if (size == 0)\r
- ig.Emit (OpCodes.Sizeof, otype);\r
- else\r
- IntConstant.EmitInt (ig, size);\r
- count.Emit (ec);\r
- ig.Emit (OpCodes.Mul);\r
- ig.Emit (OpCodes.Localloc);\r
- }\r
- }\r
-}\r
+//
+// expression.cs: Expression representation for the IL tree.
+//
+// Author:
+// Miguel de Icaza (miguel@ximian.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+//
+#define USE_OLD
+
+namespace Mono.MonoBASIC {
+ using System;
+ using System.Collections;
+ using System.Reflection;
+ using System.Reflection.Emit;
+ using System.Text;
+
+ /// <summary>
+ /// This is just a helper class, it is generated by Unary, UnaryMutator
+ /// when an overloaded method has been found. It just emits the code for a
+ /// static call.
+ /// </summary>
+ public class StaticCallExpr : ExpressionStatement {
+ ArrayList args;
+ MethodInfo mi;
+
+ StaticCallExpr (MethodInfo m, ArrayList a, Location l)
+ {
+ mi = m;
+ args = a;
+
+ type = m.ReturnType;
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (args != null)
+ Invocation.EmitArguments (ec, mi, args);
+
+ ec.ig.Emit (OpCodes.Call, mi);
+ return;
+ }
+
+ static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
+ Expression e, Location loc)
+ {
+ ArrayList args;
+ MethodBase method;
+
+ args = new ArrayList (1);
+ args.Add (new Argument (e, Argument.AType.Expression));
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
+
+ if (method == null)
+ return null;
+
+ return new StaticCallExpr ((MethodInfo) method, args, loc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ if (TypeManager.TypeToCoreType (type) != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ /// <summary>
+ /// Unary expressions.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// Unary implements unary expressions. It derives from
+ /// ExpressionStatement becuase the pre/post increment/decrement
+ /// operators can be used in a statement context.
+ /// </remarks>
+ public class Unary : Expression {
+ public enum Operator : byte {
+ UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
+ Indirection, AddressOf, TOP
+ }
+
+ public Operator Oper;
+ public Expression Expr;
+
+ public Unary (Operator op, Expression expr, Location loc)
+ {
+ this.Oper = op;
+ this.Expr = expr;
+ this.loc = loc;
+ }
+
+ /// <summary>
+ /// Returns a stringified representation of the Operator
+ /// </summary>
+ static public string OperName (Operator oper)
+ {
+ switch (oper){
+ case Operator.UnaryPlus:
+ return "+";
+ case Operator.UnaryNegation:
+ return "-";
+ case Operator.LogicalNot:
+ return "!";
+ case Operator.OnesComplement:
+ return "~";
+ case Operator.AddressOf:
+ return "&";
+ case Operator.Indirection:
+ return "*";
+ }
+
+ return oper.ToString ();
+ }
+
+ static string [] oper_names;
+
+ static Unary ()
+ {
+ oper_names = new string [(int)Operator.TOP];
+
+ oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
+ oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
+ oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
+ oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
+ oper_names [(int) Operator.Indirection] = "op_Indirection";
+ oper_names [(int) Operator.AddressOf] = "op_AddressOf";
+ }
+
+ void Error23 (Type t)
+ {
+ Error (
+ 23, "Operator " + OperName (Oper) +
+ " cannot be applied to operand of type '" +
+ TypeManager.MonoBASIC_Name (t) + "'");
+ }
+
+ /// <remarks>
+ /// The result has been already resolved:
+ ///
+ /// FIXME: a minus constant -128 sbyte cant be turned into a
+ /// constant byte.
+ /// </remarks>
+ static Expression TryReduceNegative (Constant expr)
+ {
+ Expression e = null;
+
+ if (expr is IntConstant)
+ e = new IntConstant (-((IntConstant) expr).Value);
+ else if (expr is UIntConstant){
+ uint value = ((UIntConstant) expr).Value;
+
+ if (value < 2147483649)
+ return new IntConstant (-(int)value);
+ else
+ e = new LongConstant (value);
+ }
+ else if (expr is LongConstant)
+ e = new LongConstant (-((LongConstant) expr).Value);
+ else if (expr is ULongConstant){
+ ulong value = ((ULongConstant) expr).Value;
+
+ if (value < 9223372036854775809)
+ return new LongConstant(-(long)value);
+ }
+ else if (expr is FloatConstant)
+ e = new FloatConstant (-((FloatConstant) expr).Value);
+ else if (expr is DoubleConstant)
+ e = new DoubleConstant (-((DoubleConstant) expr).Value);
+ else if (expr is DecimalConstant)
+ e = new DecimalConstant (-((DecimalConstant) expr).Value);
+ else if (expr is ShortConstant)
+ e = new IntConstant (-((ShortConstant) expr).Value);
+ else if (expr is UShortConstant)
+ e = new IntConstant (-((UShortConstant) expr).Value);
+ return e;
+ }
+
+ // <summary>
+ // This routine will attempt to simplify the unary expression when the
+ // argument is a constant. The result is returned in 'result' and the
+ // function returns true or false depending on whether a reduction
+ // was performed or not
+ // </summary>
+ bool Reduce (EmitContext ec, Constant e, out Expression result)
+ {
+ Type expr_type = e.Type;
+
+ switch (Oper){
+ case Operator.UnaryPlus:
+ result = e;
+ return true;
+
+ case Operator.UnaryNegation:
+ result = TryReduceNegative (e);
+ return true;
+
+ case Operator.LogicalNot:
+ if (expr_type != TypeManager.bool_type) {
+ result = null;
+ Error23 (expr_type);
+ return false;
+ }
+
+ BoolConstant b = (BoolConstant) e;
+ result = new BoolConstant (!(b.Value));
+ return true;
+
+ case Operator.OnesComplement:
+ if (!((expr_type == TypeManager.int32_type) ||
+ (expr_type == TypeManager.uint32_type) ||
+ (expr_type == TypeManager.int64_type) ||
+ (expr_type == TypeManager.uint64_type) ||
+ (expr_type.IsSubclassOf (TypeManager.enum_type)))){
+ result = null;
+ Error23 (expr_type);
+ return false;
+ }
+
+ if (e is EnumConstant){
+ EnumConstant enum_constant = (EnumConstant) e;
+ Expression reduced;
+
+ if (Reduce (ec, enum_constant.Child, out reduced)){
+ result = new EnumConstant ((Constant) reduced, enum_constant.Type);
+ return true;
+ } else {
+ result = null;
+ return false;
+ }
+ }
+
+ if (expr_type == TypeManager.int32_type){
+ result = new IntConstant (~ ((IntConstant) e).Value);
+ } else if (expr_type == TypeManager.uint32_type){
+ result = new UIntConstant (~ ((UIntConstant) e).Value);
+ } else if (expr_type == TypeManager.int64_type){
+ result = new LongConstant (~ ((LongConstant) e).Value);
+ } else if (expr_type == TypeManager.uint64_type){
+ result = new ULongConstant (~ ((ULongConstant) e).Value);
+ } else {
+ result = null;
+ Error23 (expr_type);
+ return false;
+ }
+ return true;
+
+ case Operator.AddressOf:
+ result = this;
+ return false;
+
+ case Operator.Indirection:
+ result = this;
+ return false;
+ }
+ throw new Exception ("Can not constant fold: " + Oper.ToString());
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type expr_type = Expr.Type;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression mg;
+ string op_name;
+
+ op_name = oper_names [(int) Oper];
+
+ mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+
+ if (mg != null) {
+ Expression e = StaticCallExpr.MakeSimpleCall (
+ ec, (MethodGroupExpr) mg, Expr, loc);
+
+ if (e == null){
+ Error23 (expr_type);
+ return null;
+ }
+
+ return e;
+ }
+
+ // Only perform numeric promotions on:
+ // +, -
+
+ if (expr_type == null)
+ return null;
+
+ //
+ // Step 2: Default operations on CLI native types.
+ //
+
+ // Attempt to use a constant folding operation.
+ if (Expr is Constant){
+ Expression result;
+
+ if (Reduce (ec, (Constant) Expr, out result))
+ return result;
+ }
+
+ switch (Oper){
+ case Operator.LogicalNot:
+ if (expr_type != TypeManager.bool_type) {
+ Error23 (Expr.Type);
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+
+ case Operator.OnesComplement:
+ if (!((expr_type == TypeManager.int32_type) ||
+ (expr_type == TypeManager.uint32_type) ||
+ (expr_type == TypeManager.int64_type) ||
+ (expr_type == TypeManager.uint64_type) ||
+ (expr_type.IsSubclassOf (TypeManager.enum_type)))){
+ Expression e;
+
+ e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
+ if (e != null){
+ type = TypeManager.int32_type;
+ return this;
+ }
+ e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
+ if (e != null){
+ type = TypeManager.uint32_type;
+ return this;
+ }
+ e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
+ if (e != null){
+ type = TypeManager.int64_type;
+ return this;
+ }
+ e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);
+ if (e != null){
+ type = TypeManager.uint64_type;
+ return this;
+ }
+ Error23 (expr_type);
+ return null;
+ }
+ type = expr_type;
+ return this;
+
+ case Operator.AddressOf:
+ if (Expr.eclass != ExprClass.Variable){
+ Error (211, "Cannot take the address of non-variables");
+ return null;
+ }
+
+ if (!ec.InUnsafe) {
+ UnsafeError (loc);
+ return null;
+ }
+
+ if (!TypeManager.VerifyUnManaged (Expr.Type, loc)){
+ return null;
+ }
+
+ string ptr_type_name = Expr.Type.FullName + "*";
+ type = TypeManager.LookupType (ptr_type_name);
+
+ return this;
+
+ case Operator.Indirection:
+ if (!ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+
+ if (!expr_type.IsPointer){
+ Error (
+ 193,
+ "The * or -> operator can only be applied to pointers");
+ return null;
+ }
+
+ //
+ // We create an Indirection expression, because
+ // it can implement the IMemoryLocation.
+ //
+ return new Indirection (Expr, loc);
+
+ case Operator.UnaryPlus:
+ //
+ // A plus in front of something is just a no-op, so return the child.
+ //
+ return Expr;
+
+ case Operator.UnaryNegation:
+ //
+ // Deals with -literals
+ // int operator- (int x)
+ // long operator- (long x)
+ // float operator- (float f)
+ // double operator- (double d)
+ // decimal operator- (decimal d)
+ //
+ Expression expr = null;
+
+ //
+ // transform - - expr into expr
+ //
+ if (Expr is Unary){
+ Unary unary = (Unary) Expr;
+
+ if (unary.Oper == Operator.UnaryNegation)
+ return unary.Expr;
+ }
+
+ //
+ // perform numeric promotions to int,
+ // long, double.
+ //
+ //
+ // The following is inneficient, because we call
+ // ConvertImplicit too many times.
+ //
+ // It is also not clear if we should convert to Float
+ // or Double initially.
+ //
+ if (expr_type == TypeManager.uint32_type){
+ //
+ // FIXME: handle exception to this rule that
+ // permits the int value -2147483648 (-2^31) to
+ // bt wrote as a decimal interger literal
+ //
+ type = TypeManager.int64_type;
+ Expr = ConvertImplicit (ec, Expr, type, loc);
+ return this;
+ }
+
+ if (expr_type == TypeManager.uint64_type){
+ //
+ // FIXME: Handle exception of 'long value'
+ // -92233720368547758087 (-2^63) to be wrote as
+ // decimal integer literal.
+ //
+ Error23 (expr_type);
+ return null;
+ }
+
+ if (expr_type == TypeManager.float_type){
+ type = expr_type;
+ return this;
+ }
+
+ expr = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
+ if (expr != null){
+ Expr = expr;
+ type = expr.Type;
+ return this;
+ }
+
+ Error23 (expr_type);
+ return null;
+ }
+
+ Error (187, "No such operator '" + OperName (Oper) + "' defined for type '" +
+ TypeManager.MonoBASIC_Name (expr_type) + "'");
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (Oper == Operator.AddressOf)
+ Expr = Expr.ResolveLValue (ec, new EmptyExpression ());
+ else
+ Expr = Expr.Resolve (ec);
+
+ if (Expr == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ return ResolveOperator (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Type expr_type = Expr.Type;
+
+ switch (Oper) {
+ case Operator.UnaryPlus:
+ throw new Exception ("This should be caught by Resolve");
+
+ case Operator.UnaryNegation:
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Neg);
+ break;
+
+ case Operator.LogicalNot:
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ceq);
+ break;
+
+ case Operator.OnesComplement:
+ Expr.Emit (ec);
+ ig.Emit (OpCodes.Not);
+ break;
+
+ case Operator.AddressOf:
+ ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
+ break;
+
+ default:
+ throw new Exception ("This should not happen: Operator = "
+ + Oper.ToString ());
+ }
+ }
+
+ /// <summary>
+ /// This will emit the child expression for 'ec' avoiding the logical
+ /// not. The parent will take care of changing brfalse/brtrue
+ /// </summary>
+ public void EmitLogicalNot (EmitContext ec)
+ {
+ if (Oper != Operator.LogicalNot)
+ throw new Exception ("EmitLogicalNot can only be called with !expr");
+
+ Expr.Emit (ec);
+ }
+
+ public override string ToString ()
+ {
+ return "Unary (" + Oper + ", " + Expr + ")";
+ }
+
+ }
+
+ //
+ // Unary operators are turned into Indirection expressions
+ // after semantic analysis (this is so we can take the address
+ // of an indirection).
+ //
+ public class Indirection : Expression, IMemoryLocation, IAssignMethod {
+ Expression expr;
+ LocalTemporary temporary;
+ bool have_temporary;
+
+ public Indirection (Expression expr, Location l)
+ {
+ this.expr = expr;
+ this.type = TypeManager.TypeToCoreType (expr.Type.GetElementType ());
+ eclass = ExprClass.Variable;
+ loc = l;
+ }
+
+ void LoadExprValue (EmitContext ec)
+ {
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (temporary != null){
+ if (have_temporary){
+ temporary.Emit (ec);
+ return;
+ }
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Dup);
+ temporary.Store (ec);
+ have_temporary = true;
+ } else
+ expr.Emit (ec);
+
+ LoadFromPtr (ig, Type);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ if (temporary != null){
+ if (have_temporary){
+ temporary.Emit (ec);
+ return;
+ }
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Dup);
+ temporary.Store (ec);
+ have_temporary = true;
+ } else
+ expr.Emit (ec);
+
+ source.Emit (ec);
+ StoreFromPtr (ec.ig, type);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp Mode)
+ {
+ if (temporary != null){
+ if (have_temporary){
+ temporary.Emit (ec);
+ return;
+ }
+ expr.Emit (ec);
+ ec.ig.Emit (OpCodes.Dup);
+ temporary.Store (ec);
+ have_temporary = true;
+ } else
+ expr.Emit (ec);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // Born fully resolved
+ //
+ return this;
+ }
+
+ public new void CacheTemporaries (EmitContext ec)
+ {
+ temporary = new LocalTemporary (ec, type);
+ }
+ }
+
+ /// <summary>
+ /// Unary Mutator expressions (pre and post ++ and --)
+ /// </summary>
+ ///
+ /// <remarks>
+ /// UnaryMutator implements ++ and -- expressions. It derives from
+ /// ExpressionStatement becuase the pre/post increment/decrement
+ /// operators can be used in a statement context.
+ ///
+ /// FIXME: Idea, we could split this up in two classes, one simpler
+ /// for the common case, and one with the extra fields for more complex
+ /// classes (indexers require temporary access; overloaded require method)
+ ///
+ /// Maybe we should have classes PreIncrement, PostIncrement, PreDecrement,
+ /// PostDecrement, that way we could save the 'Mode' byte as well.
+ /// </remarks>
+ public class UnaryMutator : ExpressionStatement {
+ public enum Mode : byte {
+ PreIncrement, PreDecrement, PostIncrement, PostDecrement
+ }
+
+ Mode mode;
+ Expression expr;
+ LocalTemporary temp_storage;
+
+ //
+ // This is expensive for the simplest case.
+ //
+ Expression method;
+
+ public UnaryMutator (Mode m, Expression e, Location l)
+ {
+ mode = m;
+ loc = l;
+ expr = e;
+ }
+
+ static string OperName (Mode mode)
+ {
+ return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
+ "++" : "--";
+ }
+
+ void Error23 (Type t)
+ {
+ Error (
+ 23, "Operator " + OperName (mode) +
+ " cannot be applied to operand of type '" +
+ TypeManager.MonoBASIC_Name (t) + "'");
+ }
+
+ /// <summary>
+ /// Returns whether an object of type 't' can be incremented
+ /// or decremented with add/sub (ie, basically whether we can
+ /// use pre-post incr-decr operations on it, but it is not a
+ /// System.Decimal, which we require operator overloading to catch)
+ /// </summary>
+ static bool IsIncrementableNumber (Type t)
+ {
+ return (t == TypeManager.sbyte_type) ||
+ (t == TypeManager.byte_type) ||
+ (t == TypeManager.short_type) ||
+ (t == TypeManager.ushort_type) ||
+ (t == TypeManager.int32_type) ||
+ (t == TypeManager.uint32_type) ||
+ (t == TypeManager.int64_type) ||
+ (t == TypeManager.uint64_type) ||
+ (t == TypeManager.char_type) ||
+ (t.IsSubclassOf (TypeManager.enum_type)) ||
+ (t == TypeManager.float_type) ||
+ (t == TypeManager.double_type) ||
+ (t.IsPointer && t != TypeManager.void_ptr_type);
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type expr_type = expr.Type;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression mg;
+ string op_name;
+
+ if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
+ op_name = "op_Increment";
+ else
+ op_name = "op_Decrement";
+
+ mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+
+ if (mg == null && expr_type.BaseType != null)
+ mg = MemberLookup (ec, expr_type.BaseType, op_name,
+ MemberTypes.Method, AllBindingFlags, loc);
+
+ if (mg != null) {
+ method = StaticCallExpr.MakeSimpleCall (
+ ec, (MethodGroupExpr) mg, expr, loc);
+
+ type = method.Type;
+ return this;
+ }
+
+ //
+ // The operand of the prefix/postfix increment decrement operators
+ // should be an expression that is classified as a variable,
+ // a property access or an indexer access
+ //
+ type = expr_type;
+ if (expr.eclass == ExprClass.Variable){
+ if (IsIncrementableNumber (expr_type) ||
+ expr_type == TypeManager.decimal_type){
+ return this;
+ }
+ } else if (expr.eclass == ExprClass.IndexerAccess){
+ IndexerAccess ia = (IndexerAccess) expr;
+
+ temp_storage = new LocalTemporary (ec, expr.Type);
+
+ expr = ia.ResolveLValue (ec, temp_storage);
+ if (expr == null)
+ return null;
+
+ return this;
+ } else if (expr.eclass == ExprClass.PropertyAccess){
+ PropertyExpr pe = (PropertyExpr) expr;
+
+ if (pe.VerifyAssignable ())
+ return this;
+
+ return null;
+ } else {
+ expr.Error118 ("variable, indexer or property access");
+ return null;
+ }
+
+ Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
+ TypeManager.MonoBASIC_Name (expr_type) + "'");
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+
+ if (expr == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ return ResolveOperator (ec);
+ }
+
+ static int PtrTypeSize (Type t)
+ {
+ return GetTypeSize (t.GetElementType ());
+ }
+
+ //
+ // Loads the proper "1" into the stack based on the type
+ //
+ static void LoadOne (ILGenerator ig, Type t)
+ {
+ if (t == TypeManager.uint64_type || t == TypeManager.int64_type)
+ ig.Emit (OpCodes.Ldc_I8, 1L);
+ else if (t == TypeManager.double_type)
+ ig.Emit (OpCodes.Ldc_R8, 1.0);
+ else if (t == TypeManager.float_type)
+ ig.Emit (OpCodes.Ldc_R4, 1.0F);
+ else if (t.IsPointer){
+ int n = PtrTypeSize (t);
+
+ if (n == 0)
+ ig.Emit (OpCodes.Sizeof, t);
+ else
+ IntConstant.EmitInt (ig, n);
+ } else
+ ig.Emit (OpCodes.Ldc_I4_1);
+ }
+
+
+ //
+ // FIXME: We need some way of avoiding the use of temp_storage
+ // for some types of storage (parameters, local variables,
+ // static fields) and single-dimension array access.
+ //
+ void EmitCode (EmitContext ec, bool is_expr)
+ {
+ ILGenerator ig = ec.ig;
+ IAssignMethod ia = (IAssignMethod) expr;
+ Type expr_type = expr.Type;
+
+ if (temp_storage == null)
+ temp_storage = new LocalTemporary (ec, expr_type);
+
+ ia.CacheTemporaries (ec);
+ ig.Emit (OpCodes.Nop);
+ switch (mode){
+ case Mode.PreIncrement:
+ case Mode.PreDecrement:
+ if (method == null){
+ expr.Emit (ec);
+
+ LoadOne (ig, expr_type);
+
+ //
+ // Select the opcode based on the check state (then the type)
+ // and the actual operation
+ //
+ if (ec.CheckState){
+ if (expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.int64_type){
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ } else if (expr_type == TypeManager.uint32_type ||
+ expr_type == TypeManager.uint64_type){
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub_Ovf_Un);
+ else
+ ig.Emit (OpCodes.Add_Ovf_Un);
+ } else {
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ }
+ } else {
+ if (mode == Mode.PreDecrement)
+ ig.Emit (OpCodes.Sub);
+ else
+ ig.Emit (OpCodes.Add);
+ }
+ } else
+ method.Emit (ec);
+
+ temp_storage.Store (ec);
+ ia.EmitAssign (ec, temp_storage);
+ if (is_expr)
+ temp_storage.Emit (ec);
+ break;
+
+ case Mode.PostIncrement:
+ case Mode.PostDecrement:
+ if (is_expr)
+ expr.Emit (ec);
+
+ if (method == null){
+ if (!is_expr)
+ expr.Emit (ec);
+ else
+ ig.Emit (OpCodes.Dup);
+
+ LoadOne (ig, expr_type);
+
+ if (ec.CheckState){
+ if (expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.int64_type){
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ } else if (expr_type == TypeManager.uint32_type ||
+ expr_type == TypeManager.uint64_type){
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub_Ovf_Un);
+ else
+ ig.Emit (OpCodes.Add_Ovf_Un);
+ } else {
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub_Ovf);
+ else
+ ig.Emit (OpCodes.Add_Ovf);
+ }
+ } else {
+ if (mode == Mode.PostDecrement)
+ ig.Emit (OpCodes.Sub);
+ else
+ ig.Emit (OpCodes.Add);
+ }
+ } else {
+ method.Emit (ec);
+ }
+
+ temp_storage.Store (ec);
+ ia.EmitAssign (ec, temp_storage);
+ break;
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ EmitCode (ec, true);
+
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ EmitCode (ec, false);
+ }
+
+ }
+
+ /// <summary>
+ /// Base class for the 'Is' and 'As' classes.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// FIXME: Split this in two, and we get to save the 'Operator' Oper
+ /// size.
+ /// </remarks>
+ public abstract class Probe : Expression {
+ public readonly Expression ProbeType;
+ protected Expression expr;
+ protected Type probe_type;
+
+ public Probe (Expression expr, Expression probe_type, Location l)
+ {
+ ProbeType = probe_type;
+ loc = l;
+ this.expr = expr;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
+
+ if (probe_type == null)
+ return null;
+
+ expr = expr.Resolve (ec);
+
+ return this;
+ }
+ }
+
+ /// <summary>
+ /// Implementation of the 'is' operator.
+ /// </summary>
+ public class Is : Probe {
+ public Is (Expression expr, Expression probe_type, Location l)
+ : base (expr, probe_type, l)
+ {
+ }
+
+ enum Action {
+ AlwaysTrue, AlwaysNull, AlwaysFalse, LeaveOnStack, Probe
+ }
+
+ Action action;
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ expr.Emit (ec);
+
+ switch (action){
+ case Action.AlwaysFalse:
+ ig.Emit (OpCodes.Pop);
+ IntConstant.EmitInt (ig, 0);
+ return;
+ case Action.AlwaysTrue:
+ ig.Emit (OpCodes.Pop);
+ ig.Emit (OpCodes.Nop);
+ IntConstant.EmitInt (ig, 1);
+ return;
+ case Action.LeaveOnStack:
+ // the 'e != null' rule.
+ return;
+ case Action.Probe:
+ ig.Emit (OpCodes.Isinst, probe_type);
+ ig.Emit (OpCodes.Ldnull);
+ ig.Emit (OpCodes.Cgt_Un);
+ return;
+ }
+ throw new Exception ("never reached");
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expression e = base.DoResolve (ec);
+
+ if ((e == null) || (expr == null))
+ return null;
+
+ Type etype = expr.Type;
+ bool warning_always_matches = false;
+ bool warning_never_matches = false;
+
+ type = TypeManager.bool_type;
+ eclass = ExprClass.Value;
+
+ //
+ // First case, if at compile time, there is an implicit conversion
+ // then e != null (objects) or true (value types)
+ //
+ e = ConvertImplicitStandard (ec, expr, probe_type, loc);
+ if (e != null){
+ expr = e;
+ if (etype.IsValueType)
+ action = Action.AlwaysTrue;
+ else
+ action = Action.LeaveOnStack;
+
+ warning_always_matches = true;
+ } else if (ExplicitReferenceConversionExists (etype, probe_type)){
+ //
+ // Second case: explicit reference convresion
+ //
+ if (expr is NullLiteral)
+ action = Action.AlwaysFalse;
+ else
+ action = Action.Probe;
+ } else {
+ action = Action.AlwaysFalse;
+ warning_never_matches = true;
+ }
+
+ if (RootContext.WarningLevel >= 1){
+ if (warning_always_matches)
+ Warning (
+ 183,
+ "The expression is always of type '" +
+ TypeManager.MonoBASIC_Name (probe_type) + "'");
+ else if (warning_never_matches){
+ if (!(probe_type.IsInterface || expr.Type.IsInterface))
+ Warning (
+ 184,
+ "The expression is never of type '" +
+ TypeManager.MonoBASIC_Name (probe_type) + "'");
+ }
+ }
+
+ return this;
+ }
+ }
+
+ /// <summary>
+ /// Implementation of the 'as' operator.
+ /// </summary>
+ public class As : Probe {
+ public As (Expression expr, Expression probe_type, Location l)
+ : base (expr, probe_type, l)
+ {
+ }
+
+ bool do_isinst = false;
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ expr.Emit (ec);
+
+ if (do_isinst)
+ ig.Emit (OpCodes.Isinst, probe_type);
+ }
+
+ static void Error_CannotConvertType (Type source, Type target, Location loc)
+ {
+ Report.Error (
+ 39, loc, "as operator can not convert from '" +
+ TypeManager.MonoBASIC_Name (source) + "' to '" +
+ TypeManager.MonoBASIC_Name (target) + "'");
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expression e = base.DoResolve (ec);
+
+ if (e == null)
+ return null;
+
+ type = probe_type;
+ eclass = ExprClass.Value;
+ Type etype = expr.Type;
+
+ if (TypeManager.IsValueType (probe_type)){
+ Report.Error (77, loc, "The as operator should be used with a reference type only (" +
+ TypeManager.MonoBASIC_Name (probe_type) + " is a value type)");
+ return null;
+
+ }
+
+ e = ConvertImplicit (ec, expr, probe_type, loc);
+ if (e != null){
+ expr = e;
+ do_isinst = false;
+ return this;
+ }
+
+ if (ExplicitReferenceConversionExists (etype, probe_type)){
+ do_isinst = true;
+ return this;
+ }
+
+ Error_CannotConvertType (etype, probe_type, loc);
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// This represents a typecast in the source language.
+ ///
+ /// FIXME: Cast expressions have an unusual set of parsing
+ /// rules, we need to figure those out.
+ /// </summary>
+ public class Cast : Expression {
+ Expression target_type;
+ Expression expr;
+ bool runtime_cast;
+
+ public Cast (Expression cast_type, Expression expr, Location loc)
+ {
+ this.target_type = cast_type;
+ this.expr = expr;
+ this.loc = loc;
+ runtime_cast = false;
+ }
+
+ public Expression TargetType {
+ get {
+ return target_type;
+ }
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ set {
+ expr = value;
+ }
+ }
+
+ public bool IsRuntimeCast\r
+ {
+ get {
+ return runtime_cast;
+ }
+ set{
+ runtime_cast = value;
+ }
+ }
+
+ /// <summary>
+ /// Attempts to do a compile-time folding of a constant cast.
+ /// </summary>
+ Expression TryReduce (EmitContext ec, Type target_type)
+ {
+ if (expr is ByteConstant){
+ byte v = ((ByteConstant) expr).Value;
+
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is SByteConstant){
+ sbyte v = ((SByteConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is ShortConstant){
+ short v = ((ShortConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is UShortConstant){
+ ushort v = ((UShortConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is IntConstant){
+ int v = ((IntConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is UIntConstant){
+ uint v = ((UIntConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is LongConstant){
+ long v = ((LongConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is ULongConstant){
+ ulong v = ((ULongConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is FloatConstant){
+ float v = ((FloatConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.double_type)
+ return new DoubleConstant ((double) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+ if (expr is DoubleConstant){
+ double v = ((DoubleConstant) expr).Value;
+
+ if (target_type == TypeManager.byte_type)
+ return new ByteConstant ((byte) v);
+ if (target_type == TypeManager.sbyte_type)
+ return new SByteConstant ((sbyte) v);
+ if (target_type == TypeManager.short_type)
+ return new ShortConstant ((short) v);
+ if (target_type == TypeManager.ushort_type)
+ return new UShortConstant ((ushort) v);
+ if (target_type == TypeManager.int32_type)
+ return new IntConstant ((int) v);
+ if (target_type == TypeManager.uint32_type)
+ return new UIntConstant ((uint) v);
+ if (target_type == TypeManager.int64_type)
+ return new LongConstant ((long) v);
+ if (target_type == TypeManager.uint64_type)
+ return new ULongConstant ((ulong) v);
+ if (target_type == TypeManager.float_type)
+ return new FloatConstant ((float) v);
+ if (target_type == TypeManager.char_type)
+ return new CharConstant ((char) v);
+ if (target_type == TypeManager.decimal_type)
+ return new DecimalConstant ((decimal) v);
+ }
+
+ return null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+ if (expr == null)
+ return null;
+
+ int errors = Report.Errors;
+
+ type = ec.DeclSpace.ResolveType (target_type, false, Location);
+
+ if (type == null)
+ return null;
+
+ eclass = ExprClass.Value;
+
+ if (expr is Constant){
+ Expression e = TryReduce (ec, type);
+
+ if (e != null)
+ return e;
+ }
+
+ expr = ConvertExplicit (ec, expr, type, runtime_cast, loc);
+ return expr;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ //
+ // This one will never happen
+ //
+ throw new Exception ("Should not happen");
+ }
+ }
+
+ /// <summary>
+ /// Binary operators
+ /// </summary>
+ public class Binary : Expression {
+ public enum Operator : byte {
+ Multiply, Division, Modulus,
+ Addition, Subtraction,
+ LeftShift, RightShift,
+ LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
+ Equality, Inequality,
+ BitwiseAnd,
+ ExclusiveOr,
+ BitwiseOr,
+ LogicalAnd,
+ LogicalOr,
+ TOP
+ }
+
+ Operator oper;
+ Expression left, right;
+
+ //
+ // After resolution, method might contain the operator overload
+ // method.
+ //
+ protected MethodBase method;
+ ArrayList Arguments;
+
+ bool DelegateOperation;
+
+ // This must be kept in sync with Operator!!!
+ static string [] oper_names;
+
+ static Binary ()
+ {
+ oper_names = new string [(int) Operator.TOP];
+
+ oper_names [(int) Operator.Multiply] = "op_Multiply";
+ oper_names [(int) Operator.Division] = "op_Division";
+ oper_names [(int) Operator.Modulus] = "op_Modulus";
+ oper_names [(int) Operator.Addition] = "op_Addition";
+ oper_names [(int) Operator.Subtraction] = "op_Subtraction";
+ oper_names [(int) Operator.LeftShift] = "op_LeftShift";
+ oper_names [(int) Operator.RightShift] = "op_RightShift";
+ oper_names [(int) Operator.LessThan] = "op_LessThan";
+ oper_names [(int) Operator.GreaterThan] = "op_GreaterThan";
+ oper_names [(int) Operator.LessThanOrEqual] = "op_LessThanOrEqual";
+ oper_names [(int) Operator.GreaterThanOrEqual] = "op_GreaterThanOrEqual";
+ oper_names [(int) Operator.Equality] = "op_Equality";
+ oper_names [(int) Operator.Inequality] = "op_Inequality";
+ oper_names [(int) Operator.BitwiseAnd] = "op_BitwiseAnd";
+ oper_names [(int) Operator.BitwiseOr] = "op_BitwiseOr";
+ oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
+ oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
+ oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
+ }
+
+ public Binary (Operator oper, Expression left, Expression right, Location loc)
+ {
+ this.oper = oper;
+ this.left = left;
+ this.right = right;
+ this.loc = loc;
+ }
+
+ public Operator Oper {
+ get {
+ return oper;
+ }
+ set {
+ oper = value;
+ }
+ }
+
+ public Expression Left {
+ get {
+ return left;
+ }
+ set {
+ left = value;
+ }
+ }
+
+ public Expression Right {
+ get {
+ return right;
+ }
+ set {
+ right = value;
+ }
+ }
+
+
+ /// <summary>
+ /// Returns a stringified representation of the Operator
+ /// </summary>
+ static string OperName (Operator oper)
+ {
+ switch (oper){
+ case Operator.Multiply:
+ return "*";
+ case Operator.Division:
+ return "/";
+ case Operator.Modulus:
+ return "%";
+ case Operator.Addition:
+ return "+";
+ case Operator.Subtraction:
+ return "-";
+ case Operator.LeftShift:
+ return "<<";
+ case Operator.RightShift:
+ return ">>";
+ case Operator.LessThan:
+ return "<";
+ case Operator.GreaterThan:
+ return ">";
+ case Operator.LessThanOrEqual:
+ return "<=";
+ case Operator.GreaterThanOrEqual:
+ return ">=";
+ case Operator.Equality:
+ return "==";
+ case Operator.Inequality:
+ return "!=";
+ case Operator.BitwiseAnd:
+ return "&";
+ case Operator.BitwiseOr:
+ return "|";
+ case Operator.ExclusiveOr:
+ return "^";
+ case Operator.LogicalOr:
+ return "||";
+ case Operator.LogicalAnd:
+ return "&&";
+ }
+
+ return oper.ToString ();
+ }
+
+ public override string ToString ()
+ {
+ return "operator " + OperName (oper) + "(" + left.ToString () + ", " +
+ right.ToString () + ")";
+ }
+
+ Expression ForceConversion (EmitContext ec, Expression expr, Type target_type)
+ {
+ if (expr.Type == target_type)
+ return expr;
+
+ return ConvertImplicit (ec, expr, target_type, Location.Null);
+ }
+
+ public static void Error_OperatorAmbiguous (Location loc, Operator oper, Type l, Type r)
+ {
+ Report.Error (
+ 34, loc, "Operator '" + OperName (oper)
+ + "' is ambiguous on operands of type '"
+ + TypeManager.MonoBASIC_Name (l) + "' "
+ + "and '" + TypeManager.MonoBASIC_Name (r)
+ + "'");
+ }
+
+ //
+ // Note that handling the case l == Decimal || r == Decimal
+ // is taken care of by the Step 1 Operator Overload resolution.
+ //
+ bool DoNumericPromotions (EmitContext ec, Type l, Type r)
+ {
+ if (l == TypeManager.double_type || r == TypeManager.double_type){
+ //
+ // If either operand is of type double, the other operand is
+ // conveted to type double.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
+
+ type = TypeManager.double_type;
+ } else if (l == TypeManager.float_type || r == TypeManager.float_type){
+ //
+ // if either operand is of type float, the other operand is
+ // converted to type float.
+ //
+ if (r != TypeManager.double_type)
+ right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
+ if (l != TypeManager.double_type)
+ left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
+ type = TypeManager.float_type;
+ } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
+ Expression e;
+ Type other;
+ //
+ // If either operand is of type ulong, the other operand is
+ // converted to type ulong. or an error ocurrs if the other
+ // operand is of type sbyte, short, int or long
+ //
+ if (l == TypeManager.uint64_type){
+ if (r != TypeManager.uint64_type){
+ if (right is IntConstant){
+ IntConstant ic = (IntConstant) right;
+
+ e = TryImplicitIntConversion (l, ic);
+ if (e != null)
+ right = e;
+ } else if (right is LongConstant){
+ long ll = ((LongConstant) right).Value;
+
+ if (ll > 0)
+ right = new ULongConstant ((ulong) ll);
+ } else {
+ e = ImplicitNumericConversion (ec, right, l, loc);
+ if (e != null)
+ right = e;
+ }
+ }
+ other = right.Type;
+ } else {
+ if (left is IntConstant){
+ e = TryImplicitIntConversion (r, (IntConstant) left);
+ if (e != null)
+ left = e;
+ } else if (left is LongConstant){
+ long ll = ((LongConstant) left).Value;
+
+ if (ll > 0)
+ left = new ULongConstant ((ulong) ll);
+ } else {
+ e = ImplicitNumericConversion (ec, left, r, loc);
+ if (e != null)
+ left = e;
+ }
+ other = left.Type;
+ }
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type) ||
+ (other == TypeManager.int64_type))
+ Error_OperatorAmbiguous (loc, oper, l, r);
+ type = TypeManager.uint64_type;
+ } else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
+ //
+ // If either operand is of type long, the other operand is converted
+ // to type long.
+ //
+ if (l != TypeManager.int64_type)
+ left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
+ if (r != TypeManager.int64_type)
+ right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
+
+ type = TypeManager.int64_type;
+ } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
+ //
+ // If either operand is of type uint, and the other
+ // operand is of type sbyte, short or int, othe operands are
+ // converted to type long.
+ //
+ Type other = null;
+
+ if (l == TypeManager.uint32_type){
+ if (right is IntConstant){
+ IntConstant ic = (IntConstant) right;
+ int val = ic.Value;
+
+ if (val >= 0)
+ right = new UIntConstant ((uint) val);
+
+ type = l;
+ return true;
+ }
+ other = r;
+ }
+ else if (r == TypeManager.uint32_type){
+ if (left is IntConstant){
+ IntConstant ic = (IntConstant) left;
+ int val = ic.Value;
+
+ if (val >= 0)
+ left = new UIntConstant ((uint) val);
+
+ type = r;
+ return true;
+ }
+
+ other = l;
+ }
+
+ if ((other == TypeManager.sbyte_type) ||
+ (other == TypeManager.short_type) ||
+ (other == TypeManager.int32_type)){
+ left = ForceConversion (ec, left, TypeManager.int64_type);
+ right = ForceConversion (ec, right, TypeManager.int64_type);
+ type = TypeManager.int64_type;
+ } else {
+ //
+ // if either operand is of type uint, the other
+ // operand is converd to type uint
+ //
+ left = ForceConversion (ec, left, TypeManager.uint32_type);
+ right = ForceConversion (ec, right, TypeManager.uint32_type);
+ type = TypeManager.uint32_type;
+ }
+ } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
+ if (l != TypeManager.decimal_type)
+ left = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
+
+ if (r != TypeManager.decimal_type)
+ right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
+ type = TypeManager.decimal_type;
+ } else {
+ left = ForceConversion (ec, left, TypeManager.int32_type);
+ right = ForceConversion (ec, right, TypeManager.int32_type);
+
+ type = TypeManager.int32_type;
+ }
+
+ return (left != null) && (right != null);
+ }
+
+ static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
+ {
+ Report.Error (19, loc,
+ "Operator " + name + " cannot be applied to operands of type '" +
+ TypeManager.MonoBASIC_Name (l) + "' and '" +
+ TypeManager.MonoBASIC_Name (r) + "'");
+ }
+
+ void Error_OperatorCannotBeApplied ()
+ {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
+ }
+
+ static bool is_32_or_64 (Type t)
+ {
+ return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
+ t == TypeManager.int64_type || t == TypeManager.uint64_type);
+ }
+
+ static bool is_unsigned (Type t)
+ {
+ return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+ t == TypeManager.short_type || t == TypeManager.byte_type);
+ }
+
+ Expression CheckShiftArguments (EmitContext ec)
+ {
+ Expression e;
+ Type l = left.Type;
+ Type r = right.Type;
+
+ e = ForceConversion (ec, right, TypeManager.int32_type);
+ if (e == null){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ right = e;
+
+ if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
+ ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
+ left = e;
+ type = e.Type;
+
+ return this;
+ }
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
+ Type l = left.Type;
+ Type r = right.Type;
+
+ bool overload_failed = false;
+
+ //
+ // Step 1: Perform Operator Overload location
+ //
+ Expression left_expr, right_expr;
+
+ string op = oper_names [(int) oper];
+
+ MethodGroupExpr union;
+ left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
+ if (r != l){
+ right_expr = MemberLookup (
+ ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
+ union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
+ } else
+ union = (MethodGroupExpr) left_expr;
+
+ if (union != null) {
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
+ if (method != null) {
+ MethodInfo mi = (MethodInfo) method;
+
+ type = mi.ReturnType;
+ return this;
+ } else {
+ overload_failed = true;
+ }
+ }
+
+ //
+ // Step 2: Default operations on CLI native types.
+ //
+
+ //
+ // Step 0: String concatenation (because overloading will get this wrong)
+ //
+ if (oper == Operator.Addition){
+ //
+ // If any of the arguments is a string, cast to string
+ //
+
+ if (l == TypeManager.string_type){
+
+ if (r == TypeManager.void_type) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ if (r == TypeManager.string_type){
+ if (left is Constant && right is Constant){
+ StringConstant ls = (StringConstant) left;
+ StringConstant rs = (StringConstant) right;
+
+ return new StringConstant (
+ ls.Value + rs.Value);
+ }
+
+ // string + string
+ method = TypeManager.string_concat_string_string;
+ } else {
+ // string + object
+ method = TypeManager.string_concat_object_object;
+ right = ConvertImplicit (ec, right,
+ TypeManager.object_type, loc);
+ if (right == null){
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ }
+ type = TypeManager.string_type;
+
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ return this;
+
+ } else if (r == TypeManager.string_type){
+ // object + string
+
+ if (l == TypeManager.void_type) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ method = TypeManager.string_concat_object_object;
+ left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
+ if (left == null){
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ type = TypeManager.string_type;
+
+ return this;
+ }
+
+ //
+ // Transform a + ( - b) into a - b
+ //
+ if (right is Unary){
+ Unary right_unary = (Unary) right;
+
+ if (right_unary.Oper == Unary.Operator.UnaryNegation){
+ oper = Operator.Subtraction;
+ right = right_unary.Expr;
+ r = right.Type;
+ }
+ }
+ }
+
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ if (l == TypeManager.bool_type || r == TypeManager.bool_type){
+ if (r != TypeManager.bool_type || l != TypeManager.bool_type){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ //
+ // operator != (object a, object b)
+ // operator == (object a, object b)
+ //
+ // For this to be used, both arguments have to be reference-types.
+ // Read the rationale on the spec (14.9.6)
+ //
+ // Also, if at compile time we know that the classes do not inherit
+ // one from the other, then we catch the error there.
+ //
+ if (!(l.IsValueType || r.IsValueType)){
+ type = TypeManager.bool_type;
+
+ if (l == r)
+ return this;
+
+ if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
+ return this;
+
+ //
+ // Also, a standard conversion must exist from either one
+ //
+ if (!(StandardConversionExists (left, r) ||
+ StandardConversionExists (right, l))){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ //
+ // We are going to have to convert to an object to compare
+ //
+ if (l != TypeManager.object_type)
+ left = new EmptyCast (left, TypeManager.object_type);
+ if (r != TypeManager.object_type)
+ right = new EmptyCast (right, TypeManager.object_type);
+
+ //
+ // FIXME: CSC here catches errors cs254 and cs252
+ //
+ return this;
+ }
+
+ //
+ // One of them is a valuetype, but the other one is not.
+ //
+ if (!l.IsValueType || !r.IsValueType) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ }
+
+ // Only perform numeric promotions on:
+ // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
+ //
+ if (oper == Operator.Addition || oper == Operator.Subtraction) {
+ if (l.IsSubclassOf (TypeManager.delegate_type) &&
+ r.IsSubclassOf (TypeManager.delegate_type)) {
+
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ if (oper == Operator.Addition)
+ method = TypeManager.delegate_combine_delegate_delegate;
+ else
+ method = TypeManager.delegate_remove_delegate_delegate;
+
+ if (l != r) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ DelegateOperation = true;
+ type = l;
+ return this;
+ }
+
+ //
+ // Pointer arithmetic:
+ //
+ // T* operator + (T* x, int y);
+ // T* operator + (T* x, uint y);
+ // T* operator + (T* x, long y);
+ // T* operator + (T* x, ulong y);
+ //
+ // T* operator + (int y, T* x);
+ // T* operator + (uint y, T *x);
+ // T* operator + (long y, T *x);
+ // T* operator + (ulong y, T *x);
+ //
+ // T* operator - (T* x, int y);
+ // T* operator - (T* x, uint y);
+ // T* operator - (T* x, long y);
+ // T* operator - (T* x, ulong y);
+ //
+ // long operator - (T* x, T *y)
+ //
+ if (l.IsPointer){
+ if (r.IsPointer && oper == Operator.Subtraction){
+ if (r == l)
+ return new PointerArithmetic (
+ false, left, right, TypeManager.int64_type,
+ loc);
+ } else if (is_32_or_64 (r))
+ return new PointerArithmetic (
+ oper == Operator.Addition, left, right, l, loc);
+ } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
+ return new PointerArithmetic (
+ true, right, left, r, loc);
+ }
+
+ //
+ // Enumeration operators
+ //
+ bool lie = TypeManager.IsEnumType (l);
+ bool rie = TypeManager.IsEnumType (r);
+ if (lie || rie){
+ Expression temp;
+
+ // U operator - (E e, E f)
+ if (lie && rie && oper == Operator.Subtraction){
+ if (l == r){
+ type = TypeManager.EnumToUnderlying (l);
+ return this;
+ }
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ //
+ // operator + (E e, U x)
+ // operator - (E e, U x)
+ //
+ if (oper == Operator.Addition || oper == Operator.Subtraction){
+ Type enum_type = lie ? l : r;
+ Type other_type = lie ? r : l;
+ Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
+;
+
+ if (underlying_type != other_type){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ type = enum_type;
+ return this;
+ }
+
+ if (!rie){
+ temp = ConvertImplicit (ec, right, l, loc);
+ if (temp != null)
+ right = temp;
+ else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ } if (!lie){
+ temp = ConvertImplicit (ec, left, r, loc);
+ if (temp != null){
+ left = temp;
+ l = r;
+ } else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ }
+
+ if (oper == Operator.Equality || oper == Operator.Inequality ||
+ oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
+ oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ type = l;
+ return this;
+ }
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ if (oper == Operator.LeftShift || oper == Operator.RightShift)
+ return CheckShiftArguments (ec);
+
+ if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
+ if (l != TypeManager.bool_type || r != TypeManager.bool_type){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ //
+ // operator & (bool x, bool y)
+ // operator | (bool x, bool y)
+ // operator ^ (bool x, bool y)
+ //
+ if (l == TypeManager.bool_type && r == TypeManager.bool_type){
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ type = l;
+ return this;
+ }
+ }
+
+ //
+ // Pointer comparison
+ //
+ if (l.IsPointer && r.IsPointer){
+ if (oper == Operator.Equality || oper == Operator.Inequality ||
+ oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
+ type = TypeManager.bool_type;
+ return this;
+ }
+ }
+
+ //
+ // We are dealing with numbers
+ //
+ if (overload_failed){
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ //
+ // This will leave left or right set to null if there is an error
+ //
+ DoNumericPromotions (ec, l, r);
+ if (left == null || right == null){
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+
+ //
+ // reload our cached types if required
+ //
+ l = left.Type;
+ r = right.Type;
+
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr){
+ if (l == r){
+ if (!((l == TypeManager.int32_type) ||
+ (l == TypeManager.uint32_type) ||
+ (l == TypeManager.int64_type) ||
+ (l == TypeManager.uint64_type)))
+ type = l;
+ } else {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+ }
+
+ if (oper == Operator.Equality ||
+ oper == Operator.Inequality ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.LessThan ||
+ oper == Operator.GreaterThanOrEqual ||
+ oper == Operator.GreaterThan){
+ type = TypeManager.bool_type;
+ }
+
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ left = left.Resolve (ec);
+ right = right.Resolve (ec);
+
+ if (left == null || right == null)
+ return null;
+
+ if (left.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ left + ") at Line: " + loc.Row);
+ if (right.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ right + ") at Line: "+ loc.Row);
+
+ eclass = ExprClass.Value;
+
+ if (left is Constant && right is Constant){
+ Expression e = ConstantFold.BinaryFold (
+ ec, oper, (Constant) left, (Constant) right, loc);
+ if (e != null)
+ return e;
+ }
+
+ return ResolveOperator (ec);
+ }
+
+ /// <remarks>
+ /// EmitBranchable is called from Statement.EmitBoolExpression in the
+ /// context of a conditional bool expression. This function will return
+ /// false if it is was possible to use EmitBranchable, or true if it was.
+ ///
+ /// The expression's code is generated, and we will generate a branch to 'target'
+ /// if the resulting expression value is equal to isTrue
+ /// </remarks>
+ public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ if (method != null)
+ return false;
+
+ ILGenerator ig = ec.ig;
+
+ //
+ // This is more complicated than it looks, but its just to avoid
+ // duplicated tests: basically, we allow ==, !=, >, <, >= and <=
+ // but on top of that we want for == and != to use a special path
+ // if we are comparing against null
+ //
+ if (oper == Operator.Equality || oper == Operator.Inequality){
+ bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
+
+ if (left is NullLiteral){
+ right.Emit (ec);
+ if (my_on_true)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ } else if (right is NullLiteral){
+ left.Emit (ec);
+ if (my_on_true)
+ ig.Emit (OpCodes.Brtrue, target);
+ else
+ ig.Emit (OpCodes.Brfalse, target);
+ return true;
+ }
+ } else if (!(oper == Operator.LessThan ||
+ oper == Operator.GreaterThan ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThanOrEqual))
+ return false;
+
+
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ bool isUnsigned = is_unsigned (left.Type);
+
+ switch (oper){
+ case Operator.Equality:
+ if (onTrue)
+ ig.Emit (OpCodes.Beq, target);
+ else
+ ig.Emit (OpCodes.Bne_Un, target);
+ break;
+
+ case Operator.Inequality:
+ if (onTrue)
+ ig.Emit (OpCodes.Bne_Un, target);
+ else
+ ig.Emit (OpCodes.Beq, target);
+ break;
+
+ case Operator.LessThan:
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Blt_Un, target);
+ else
+ ig.Emit (OpCodes.Blt, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bge_Un, target);
+ else
+ ig.Emit (OpCodes.Bge, target);
+ break;
+
+ case Operator.GreaterThan:
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bgt_Un, target);
+ else
+ ig.Emit (OpCodes.Bgt, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Ble_Un, target);
+ else
+ ig.Emit (OpCodes.Ble, target);
+ break;
+
+ case Operator.LessThanOrEqual:
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Ble_Un, target);
+ else
+ ig.Emit (OpCodes.Ble, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bgt_Un, target);
+ else
+ ig.Emit (OpCodes.Bgt, target);
+ break;
+
+
+ case Operator.GreaterThanOrEqual:
+ if (onTrue)
+ if (isUnsigned)
+ ig.Emit (OpCodes.Bge_Un, target);
+ else
+ ig.Emit (OpCodes.Bge, target);
+ else
+ if (isUnsigned)
+ ig.Emit (OpCodes.Blt_Un, target);
+ else
+ ig.Emit (OpCodes.Blt, target);
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Type l = left.Type;
+ Type r = right.Type;
+ OpCode opcode;
+
+ if (method != null) {
+
+ // Note that operators are static anyway
+
+ if (Arguments != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+ if (DelegateOperation)
+ ig.Emit (OpCodes.Castclass, type);
+
+ return;
+ }
+
+ //
+ // Handle short-circuit operators differently
+ // than the rest
+ //
+ if (oper == Operator.LogicalAnd){
+ Label load_zero = ig.DefineLabel ();
+ Label end = ig.DefineLabel ();
+
+ left.Emit (ec);
+ ig.Emit (OpCodes.Brfalse, load_zero);
+ right.Emit (ec);
+ ig.Emit (OpCodes.Br, end);
+ ig.MarkLabel (load_zero);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.MarkLabel (end);
+ return;
+ } else if (oper == Operator.LogicalOr){
+ Label load_one = ig.DefineLabel ();
+ Label end = ig.DefineLabel ();
+
+ left.Emit (ec);
+ ig.Emit (OpCodes.Brtrue, load_one);
+ right.Emit (ec);
+ ig.Emit (OpCodes.Br, end);
+ ig.MarkLabel (load_one);
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.MarkLabel (end);
+ return;
+ }
+
+ left.Emit (ec);
+ right.Emit (ec);
+
+ switch (oper){
+ case Operator.Multiply:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Mul_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Mul_Ovf_Un;
+ else
+ opcode = OpCodes.Mul;
+ } else
+ opcode = OpCodes.Mul;
+
+ break;
+
+ case Operator.Division:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ opcode = OpCodes.Div_Un;
+ else
+ opcode = OpCodes.Div;
+ break;
+
+ case Operator.Modulus:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ opcode = OpCodes.Rem_Un;
+ else
+ opcode = OpCodes.Rem;
+ break;
+
+ case Operator.Addition:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Add_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Add_Ovf_Un;
+ else
+ opcode = OpCodes.Add;
+ } else
+ opcode = OpCodes.Add;
+ break;
+
+ case Operator.Subtraction:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Sub_Ovf;
+ else if (l==TypeManager.uint32_type || l==TypeManager.uint64_type)
+ opcode = OpCodes.Sub_Ovf_Un;
+ else
+ opcode = OpCodes.Sub;
+ } else
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.RightShift:
+ if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
+ opcode = OpCodes.Shr_Un;
+ else
+ opcode = OpCodes.Shr;
+ break;
+
+ case Operator.LeftShift:
+ opcode = OpCodes.Shl;
+ break;
+
+ case Operator.Equality:
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.Inequality:
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.LessThan:
+ opcode = OpCodes.Clt;
+ break;
+
+ case Operator.GreaterThan:
+ opcode = OpCodes.Cgt;
+ break;
+
+ case Operator.LessThanOrEqual:
+ ec.ig.Emit (OpCodes.Cgt);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.GreaterThanOrEqual:
+ ec.ig.Emit (OpCodes.Clt);
+ ec.ig.Emit (OpCodes.Ldc_I4_1);
+
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.BitwiseOr:
+ opcode = OpCodes.Or;
+ break;
+
+ case Operator.BitwiseAnd:
+ opcode = OpCodes.And;
+ break;
+
+ case Operator.ExclusiveOr:
+ opcode = OpCodes.Xor;
+ break;
+
+ default:
+ throw new Exception ("This should not happen: Operator = "
+ + oper.ToString ());
+ }
+
+ ig.Emit (opcode);
+ }
+
+ public bool IsBuiltinOperator {
+ get {
+ return method == null;
+ }
+ }
+ }
+
+ public class PointerArithmetic : Expression {
+ Expression left, right;
+ bool is_add;
+
+ //
+ // We assume that 'l' is always a pointer
+ //
+ public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t,
+ Location loc)
+ {
+ type = t;
+ eclass = ExprClass.Variable;
+ this.loc = loc;
+ left = l;
+ right = r;
+ is_add = is_addition;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Type op_type = left.Type;
+ ILGenerator ig = ec.ig;
+ int size = GetTypeSize (op_type.GetElementType ());
+
+ if (right.Type.IsPointer){
+ //
+ // handle (pointer - pointer)
+ //
+ left.Emit (ec);
+ right.Emit (ec);
+ ig.Emit (OpCodes.Sub);
+
+ if (size != 1){
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, op_type);
+ else
+ IntLiteral.EmitInt (ig, size);
+ ig.Emit (OpCodes.Div);
+ }
+ ig.Emit (OpCodes.Conv_I8);
+ } else {
+ //
+ // handle + and - on (pointer op int)
+ //
+ left.Emit (ec);
+ ig.Emit (OpCodes.Conv_I);
+ right.Emit (ec);
+ if (size != 1){
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, op_type);
+ else
+ IntLiteral.EmitInt (ig, size);
+ ig.Emit (OpCodes.Mul);
+ }
+ if (is_add)
+ ig.Emit (OpCodes.Add);
+ else
+ ig.Emit (OpCodes.Sub);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Implements the ternary conditional operator (?:)
+ /// </summary>
+ public class Conditional : Expression {
+ Expression expr, trueExpr, falseExpr;
+
+ public Conditional (Expression expr, Expression trueExpr, Expression falseExpr, Location l)
+ {
+ this.expr = expr;
+ this.trueExpr = trueExpr;
+ this.falseExpr = falseExpr;
+ this.loc = l;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ public Expression TrueExpr {
+ get {
+ return trueExpr;
+ }
+ }
+
+ public Expression FalseExpr {
+ get {
+ return falseExpr;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ expr = expr.Resolve (ec);
+
+ if (expr == null)
+ return null;
+
+ if (expr.Type != TypeManager.bool_type)
+ expr = Expression.ConvertImplicitRequired (
+ ec, expr, TypeManager.bool_type, loc);
+
+ trueExpr = trueExpr.Resolve (ec);
+ falseExpr = falseExpr.Resolve (ec);
+
+ if (trueExpr == null || falseExpr == null)
+ return null;
+
+ eclass = ExprClass.Value;
+ if (trueExpr.Type == falseExpr.Type)
+ type = trueExpr.Type;
+ else {
+ Expression conv;
+ Type true_type = trueExpr.Type;
+ Type false_type = falseExpr.Type;
+
+ if (trueExpr is NullLiteral){
+ type = false_type;
+ return this;
+ } else if (falseExpr is NullLiteral){
+ type = true_type;
+ return this;
+ }
+
+ //
+ // First, if an implicit conversion exists from trueExpr
+ // to falseExpr, then the result type is of type falseExpr.Type
+ //
+ conv = ConvertImplicit (ec, trueExpr, false_type, loc);
+ if (conv != null){
+ //
+ // Check if both can convert implicitl to each other's type
+ //
+ if (ConvertImplicit (ec, falseExpr, true_type, loc) != null){
+ Error (172,
+ "Can not compute type of conditional expression " +
+ "as '" + TypeManager.MonoBASIC_Name (trueExpr.Type) +
+ "' and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) +
+ "' convert implicitly to each other");
+ return null;
+ }
+ type = false_type;
+ trueExpr = conv;
+ } else if ((conv = ConvertImplicit(ec, falseExpr, true_type,loc))!= null){
+ type = true_type;
+ falseExpr = conv;
+ } else {
+ Error (173, "The type of the conditional expression can " +
+ "not be computed because there is no implicit conversion" +
+ " from '" + TypeManager.MonoBASIC_Name (trueExpr.Type) + "'" +
+ " and '" + TypeManager.MonoBASIC_Name (falseExpr.Type) + "'");
+ return null;
+ }
+ }
+
+ if (expr is BoolConstant){
+ BoolConstant bc = (BoolConstant) expr;
+
+ if (bc.Value)
+ return trueExpr;
+ else
+ return falseExpr;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label false_target = ig.DefineLabel ();
+ Label end_target = ig.DefineLabel ();
+
+ Statement.EmitBoolExpression (ec, expr, false_target, false);
+ trueExpr.Emit (ec);
+ ig.Emit (OpCodes.Br, end_target);
+ ig.MarkLabel (false_target);
+ falseExpr.Emit (ec);
+ ig.MarkLabel (end_target);
+ }
+
+ }
+
+ /// <summary>
+ /// Local variables
+ /// </summary>
+ public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public readonly string Name;
+ public readonly Block Block;
+ VariableInfo variable_info;
+ bool is_readonly;
+
+ public LocalVariableReference (Block block, string name, Location l)
+ {
+ Block = block;
+ Name = name;
+ loc = l;
+ eclass = ExprClass.Variable;
+ }
+
+ // Setting 'is_readonly' to false will allow you to create a writable
+ // reference to a read-only variable. This is used by foreach and using.
+ public LocalVariableReference (Block block, string name, Location l,
+ VariableInfo variable_info, bool is_readonly)
+ : this (block, name, l)
+ {
+ this.variable_info = variable_info;
+ this.is_readonly = is_readonly;
+ }
+
+ public VariableInfo VariableInfo {
+ get {
+ if (variable_info == null) {
+ variable_info = Block.GetVariableInfo (Name);
+ is_readonly = variable_info.ReadOnly;
+ }
+ return variable_info;
+ }
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ return VariableInfo.IsAssigned (ec, loc);
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
+ {
+ return VariableInfo.IsFieldAssigned (ec, name, loc);
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ VariableInfo.SetAssigned (ec);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string name)
+ {
+ VariableInfo.SetFieldAssigned (ec, name);
+ }
+
+ public bool IsReadOnly {
+ get {
+ if (variable_info == null) {
+ variable_info = Block.GetVariableInfo (Name);
+ is_readonly = variable_info.ReadOnly;
+ }
+ return is_readonly;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ VariableInfo vi = VariableInfo;
+
+ if (Block.IsConstant (Name)) {
+ Expression e = Block.GetConstantExpression (Name);
+
+ vi.Used = true;
+ return e;
+ }
+
+ if (ec.DoFlowAnalysis && !IsAssigned (ec, loc))
+ return null;
+
+ type = vi.VariableType;
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ VariableInfo vi = VariableInfo;
+
+ if (ec.DoFlowAnalysis)
+ ec.SetVariableAssigned (vi);
+
+ Expression e = DoResolve (ec);
+
+ if (e == null)
+ return null;
+
+ if (is_readonly){
+ Error (1604, "cannot assign to '" + Name + "' because it is readonly");
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ VariableInfo vi = VariableInfo;
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
+ vi.Used = true;
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+ VariableInfo vi = VariableInfo;
+
+ vi.Assigned = true;
+
+ source.Emit (ec);
+
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ VariableInfo vi = VariableInfo;
+
+ ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
+ }
+ }
+
+ /// <summary>
+ /// This represents a reference to a parameter in the intermediate
+ /// representation.
+ /// </summary>
+ public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ Parameters pars;
+ String name;
+ int idx;
+ public Parameter.Modifier mod;
+ public bool is_ref, is_out;
+
+ public ParameterReference (Parameters pars, int idx, string name, Location loc)
+ {
+ this.pars = pars;
+ this.idx = idx;
+ this.name = name;
+ this.loc = loc;
+ eclass = ExprClass.Variable;
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (!is_out || !ec.DoFlowAnalysis)
+ return true;
+
+ if (!ec.CurrentBranching.IsParameterAssigned (idx)) {
+ Report.Error (165, loc,
+ "Use of unassigned local variable '" + name + "'");
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+ {
+ if (!is_out || !ec.DoFlowAnalysis)
+ return true;
+
+ if (ec.CurrentBranching.IsParameterAssigned (idx))
+ return true;
+
+ if (!ec.CurrentBranching.IsParameterAssigned (idx, field_name)) {
+ Report.Error (170, loc,
+ "Use of possibly unassigned field '" + field_name + "'");
+ return false;
+ }
+
+ return true;
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (is_out && ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetParameterAssigned (idx);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string field_name)
+ {
+ if (is_out && ec.DoFlowAnalysis)
+ ec.CurrentBranching.SetParameterAssigned (idx, field_name);
+ }
+
+ //
+ // Notice that for ref/out parameters, the type exposed is not the
+ // same type exposed externally.
+ //
+ // for "ref int a":
+ // externally we expose "int&"
+ // here we expose "int".
+ //
+ // We record this in "is_ref". This means that the type system can treat
+ // the type as it is expected, but when we generate the code, we generate
+ // the alternate kind of code.
+ //
+ public override Expression DoResolve (EmitContext ec)
+ {
+ type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
+ is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
+ is_out = (mod & Parameter.Modifier.OUT) != 0;
+ eclass = ExprClass.Variable;
+
+ if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
+ return null;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
+ is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
+ is_out = (mod & Parameter.Modifier.OUT) != 0;
+ eclass = ExprClass.Variable;
+
+ if (is_out && ec.DoFlowAnalysis)
+ ec.SetParameterAssigned (idx);
+
+ return this;
+ }
+
+ static void EmitLdArg (ILGenerator ig, int x)
+ {
+ if (x <= 255){
+ switch (x){
+ case 0: ig.Emit (OpCodes.Ldarg_0); break;
+ case 1: ig.Emit (OpCodes.Ldarg_1); break;
+ case 2: ig.Emit (OpCodes.Ldarg_2); break;
+ case 3: ig.Emit (OpCodes.Ldarg_3); break;
+ default: ig.Emit (OpCodes.Ldarg_S, (byte) x); break;
+ }
+ } else
+ ig.Emit (OpCodes.Ldarg, x);
+ }
+
+ //
+ // This method is used by parameters that are references, that are
+ // being passed as references: we only want to pass the pointer (that
+ // is already stored in the parameter, not the address of the pointer,
+ // and not the value of the variable).
+ //
+ public void EmitLoad (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ EmitLdArg (ig, arg_idx);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ EmitLdArg (ig, arg_idx);
+
+ if (!is_ref)
+ return;
+
+ //
+ // If we are a reference, we loaded on the stack a pointer
+ // Now lets load the real value
+ //
+ LoadFromPtr (ig, type);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ if (is_ref)
+ EmitLdArg (ig, arg_idx);
+
+ source.Emit (ec);
+
+ if (is_ref)
+ StoreFromPtr (ig, type);
+ else {
+ if (arg_idx <= 255)
+ ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
+ else
+ ig.Emit (OpCodes.Starg, arg_idx);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ int arg_idx = idx;
+
+ if (!ec.IsStatic)
+ arg_idx++;
+
+ if (is_ref){
+ if (arg_idx <= 255)
+ ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
+ else
+ ec.ig.Emit (OpCodes.Ldarg, arg_idx);
+ } else {
+ if (arg_idx <= 255)
+ ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
+ else
+ ec.ig.Emit (OpCodes.Ldarga, arg_idx);
+ }
+ }
+ }
+
+
+ /// <summary>
+ /// Invocation of methods or delegates.
+ /// </summary>
+ public class Invocation : ExpressionStatement {
+ public ArrayList Arguments;
+
+ public Expression expr;
+ MethodBase method = null;
+ bool is_base;
+ bool is_left_hand; // Needed for late bound calls
+ static Hashtable method_parameter_cache;
+ static MemberFilter CompareName;
+
+ static Invocation ()
+ {
+ method_parameter_cache = new PtrHashtable ();
+ }
+
+ //
+ // arguments is an ArrayList, but we do not want to typecast,
+ // as it might be null.
+ //
+ // FIXME: only allow expr to be a method invocation or a
+ // delegate invocation (7.5.5)
+ //
+ public Invocation (Expression expr, ArrayList arguments, Location l)
+ {
+ this.expr = expr;
+ Arguments = arguments;
+ loc = l;
+ CompareName = new MemberFilter (compare_name_filter);
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ /// <summary>
+ /// Returns the Parameters (a ParameterData interface) for the
+ /// Method 'mb'
+ /// </summary>
+ public static ParameterData GetParameterData (MethodBase mb)
+ {
+ object pd = method_parameter_cache [mb];
+ object ip;
+
+ if (pd != null)
+ return (ParameterData) pd;
+
+
+ ip = TypeManager.LookupParametersByBuilder (mb);
+ if (ip != null){
+ method_parameter_cache [mb] = ip;
+
+ return (ParameterData) ip;
+ } else {
+ ParameterInfo [] pi = mb.GetParameters ();
+ ReflectionParameters rp = new ReflectionParameters (pi);
+ method_parameter_cache [mb] = rp;
+
+ return (ParameterData) rp;
+ }
+ }
+
+ /// <summary>
+ /// Determines "better conversion" as specified in 7.4.2.3
+ /// Returns : 1 if a->p is better
+ /// 0 if a->q or neither is better
+ /// </summary>
+ static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
+ {
+ Type argument_type = a.Type;
+ Expression argument_expr = a.Expr;
+
+ if (argument_type == null)
+ throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
+
+ //
+ // This is a special case since csc behaves this way. I can't find
+ // it anywhere in the spec but oh well ...
+ //
+ if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
+ return 1;
+ else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
+ return 0;
+
+ if (p == q)
+ return 0;
+
+ if (argument_type == p)
+ return 1;
+
+ if (argument_type == q)
+ return 0;
+
+ //
+ // Now probe whether an implicit constant expression conversion
+ // can be used.
+ //
+ // An implicit constant expression conversion permits the following
+ // conversions:
+ //
+ // * A constant-expression of type 'int' can be converted to type
+ // sbyte, byute, short, ushort, uint, ulong provided the value of
+ // of the expression is withing the range of the destination type.
+ //
+ // * A constant-expression of type long can be converted to type
+ // ulong, provided the value of the constant expression is not negative
+ //
+ // FIXME: Note that this assumes that constant folding has
+ // taken place. We dont do constant folding yet.
+ //
+
+ if (argument_expr is IntConstant){
+ IntConstant ei = (IntConstant) argument_expr;
+ int value = ei.Value;
+
+ if (p == TypeManager.sbyte_type){
+ if (value >= SByte.MinValue && value <= SByte.MaxValue)
+ return 1;
+ } else if (p == TypeManager.byte_type){
+ if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
+ return 1;
+ } else if (p == TypeManager.short_type){
+ if (value >= Int16.MinValue && value <= Int16.MaxValue)
+ return 1;
+ } else if (p == TypeManager.ushort_type){
+ if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
+ return 1;
+ } else if (p == TypeManager.uint32_type){
+ //
+ // we can optimize this case: a positive int32
+ // always fits on a uint32
+ //
+ if (value >= 0)
+ return 1;
+ } else if (p == TypeManager.uint64_type){
+ //
+ // we can optimize this case: a positive int32
+ // always fits on a uint64
+ //
+ if (value >= 0)
+ return 1;
+ }
+ } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
+ LongConstant lc = (LongConstant) argument_expr;
+
+ if (p == TypeManager.uint64_type){
+ if (lc.Value > 0)
+ return 1;
+ }
+ }
+
+ if (q == null) {
+ Expression tmp = ConvertImplicit (ec, argument_expr, p, loc);
+
+ if (tmp != null)
+ return 1;
+ else
+ return 0;
+ }
+
+ Expression p_tmp = new EmptyExpression (p);
+ Expression q_tmp = new EmptyExpression (q);
+
+ if (StandardConversionExists (p_tmp, q) == true &&
+ StandardConversionExists (q_tmp, p) == false)
+ return 1;
+
+ if (p == TypeManager.sbyte_type)
+ if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
+ q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+ return 1;
+
+ if (p == TypeManager.short_type)
+ if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
+ q == TypeManager.uint64_type)
+ return 1;
+
+ if (p == TypeManager.int32_type)
+ if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
+ return 1;
+
+ if (p == TypeManager.int64_type)
+ if (q == TypeManager.uint64_type)
+ return 1;
+
+ return 0;
+ }
+
+ /// <summary>
+ /// Determines "Better function"
+ /// </summary>
+ /// <remarks>
+ /// and returns an integer indicating :
+ /// 0 if candidate ain't better
+ /// 1 if candidate is better than the current best match
+ /// </remarks>
+ static int BetterFunction (EmitContext ec, ArrayList args,
+ MethodBase candidate, MethodBase best,
+ bool expanded_form, Location loc)
+ {
+ ParameterData candidate_pd = GetParameterData (candidate);
+ ParameterData best_pd;
+ int argument_count;
+
+ if (args == null)
+ argument_count = 0;
+ else
+ argument_count = args.Count;
+
+ int cand_count = candidate_pd.Count;
+
+ if (cand_count == 0 && argument_count == 0)
+ return 1;
+
+ if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
+ if (cand_count != argument_count)
+ return 0;
+
+ if (best == null) {
+ int x = 0;
+
+ if (argument_count == 0 && cand_count == 1 &&
+ candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
+ return 1;
+
+ for (int j = argument_count; j > 0;) {
+ j--;
+
+ Argument a = (Argument) args [j];
+ Type t = candidate_pd.ParameterType (j);
+
+ if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ t = t.GetElementType ();
+
+ x = BetterConversion (ec, a, t, null, loc);
+
+ if (x <= 0)
+ break;
+ }
+
+ if (x > 0)
+ return 1;
+ else
+ return 0;
+ }
+
+ best_pd = GetParameterData (best);
+
+ int rating1 = 0, rating2 = 0;
+
+ for (int j = 0; j < argument_count; ++j) {
+ int x, y;
+
+ Argument a = (Argument) args [j];
+
+ Type ct = candidate_pd.ParameterType (j);
+ Type bt = best_pd.ParameterType (j);
+
+ if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ ct = ct.GetElementType ();
+
+ if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
+ if (expanded_form)
+ bt = bt.GetElementType ();
+
+ x = BetterConversion (ec, a, ct, bt, loc);
+ y = BetterConversion (ec, a, bt, ct, loc);
+
+ if (x < y)
+ return 0;
+
+ rating1 += x;
+ rating2 += y;
+ }
+
+ if (rating1 > rating2)
+ return 1;
+ else
+ return 0;
+ }
+
+ public static string FullMethodDesc (MethodBase mb)
+ {
+ string ret_type = "";
+
+ if (mb is MethodInfo)
+ ret_type = TypeManager.MonoBASIC_Name (((MethodInfo) mb).ReturnType) + " ";
+
+ StringBuilder sb = new StringBuilder (ret_type + mb.Name);
+ ParameterData pd = GetParameterData (mb);
+
+ int count = pd.Count;
+ sb.Append (" (");
+
+ for (int i = count; i > 0; ) {
+ i--;
+
+ sb.Append (pd.ParameterDesc (count - i - 1));
+ if (i != 0)
+ sb.Append (", ");
+ }
+
+ sb.Append (")");
+ return sb.ToString ();
+ }
+
+ public static MethodGroupExpr MakeUnionSet (Expression mg1, Expression mg2, Location loc)
+ {
+ MemberInfo [] miset;
+ MethodGroupExpr union;
+
+ if (mg1 == null){
+ if (mg2 == null)
+ return null;
+ return (MethodGroupExpr) mg2;
+ } else {
+ if (mg2 == null)
+ return (MethodGroupExpr) mg1;
+ }
+
+ MethodGroupExpr left_set = null, right_set = null;
+ int length1 = 0, length2 = 0;
+
+ left_set = (MethodGroupExpr) mg1;
+ length1 = left_set.Methods.Length;
+
+ right_set = (MethodGroupExpr) mg2;
+ length2 = right_set.Methods.Length;
+
+ ArrayList common = new ArrayList ();
+
+ foreach (MethodBase l in left_set.Methods){
+ foreach (MethodBase r in right_set.Methods){
+ if (l != r)
+ continue;
+ common.Add (r);
+ break;
+ }
+ }
+
+ miset = new MemberInfo [length1 + length2 - common.Count];
+ left_set.Methods.CopyTo (miset, 0);
+
+ int k = length1;
+
+ foreach (MemberInfo mi in right_set.Methods){
+ if (!common.Contains (mi))
+ miset [k++] = mi;
+ }
+
+ union = new MethodGroupExpr (miset, loc);
+
+ return union;
+ }
+
+ /// <summary>
+ /// Determines is the candidate method, if a params method, is applicable
+ /// in its expanded form to the given set of arguments
+ /// </summary>
+ static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (candidate);
+
+ int pd_count = pd.Count;
+
+ if (pd_count == 0)
+ return false;
+
+ if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
+ return false;
+
+ if (pd_count - 1 > arg_count)
+ return false;
+
+ if (pd_count == 1 && arg_count == 0)
+ return true;
+
+ //
+ // If we have come this far, the case which remains is when the number of parameters
+ // is less than or equal to the argument count.
+ //
+ for (int i = 0; i < pd_count - 1; ++i) {
+
+ Argument a = (Argument) arguments [i];
+
+ Parameter.Modifier a_mod = a.GetParameterModifier () &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ Parameter.Modifier p_mod = pd.ParameterModifier (i) &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+
+ if (a_mod == p_mod) {
+
+ if (a_mod == Parameter.Modifier.NONE)
+ if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
+ return false;
+
+ if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
+ Type pt = pd.ParameterType (i);
+
+ if (!pt.IsByRef)
+ pt = TypeManager.LookupType (pt.FullName + "&");
+
+ if (pt != a.Type)
+ return false;
+ }
+ } else
+ return false;
+
+ }
+
+ Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
+
+ for (int i = pd_count - 1; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+
+ if (!StandardConversionExists (a.Expr, element_type))
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
+ {
+ Parameter.Modifier a_mod = a.GetParameterModifier () &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ Parameter.Modifier p_mod = pd.ParameterModifier (i) &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+
+ if (a_mod == p_mod || (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
+ if (a_mod == Parameter.Modifier.NONE)
+ if (! (ImplicitConversionExists (ec, a.Expr, ptype) || RuntimeConversionExists (ec, a.Expr, ptype)) )
+ return false;
+
+ if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
+ Type pt = pd.ParameterType (i);
+
+ if (!pt.IsByRef)
+ pt = TypeManager.LookupType (pt.FullName + "&");
+
+ if (pt != a.Type)
+ return false;
+ }
+ } else
+ return false;
+ return true;
+ }
+
+ /// <summary>
+ /// Determines if the candidate method is applicable (section 14.4.2.1)
+ /// to the given set of arguments
+ /// </summary>
+ static bool IsApplicable (EmitContext ec, ref ArrayList arguments, MethodBase candidate)
+ {
+ int arg_count, ps_count, po_count;
+ Type param_type;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (candidate);
+ Parameters ps = GetFullParameters (candidate);
+ if (ps == null) {
+ ps_count = 0;
+ po_count = 0;
+ }
+ else {
+ ps_count = ps.CountStandardParams();
+ po_count = ps.CountOptionalParams();
+ }
+ int pd_count = pd.Count;
+
+ // Validate argument count
+ if (po_count == 0) {
+ if (arg_count != pd.Count)
+ return false;
+ }
+ else {
+ if ((arg_count < ps_count) || (arg_count > pd_count))
+ return false;
+ }
+
+ if (arg_count > 0) {
+ for (int i = arg_count; i > 0 ; ) {
+ i--;
+
+ Argument a = (Argument) arguments [i];
+ if (a.ArgType == Argument.AType.NoArg) {
+ Parameter p = (Parameter) ps.FixedParameters[i];
+ a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
+ param_type = p.ParameterInitializer.Type;
+ }
+ else {
+ param_type = pd.ParameterType (i);
+ if (ps != null) {
+ Parameter p = (Parameter) ps.FixedParameters[i];
+ bool IsDelegate = TypeManager.IsDelegateType (param_type);
+
+ if (IsDelegate) {
+ if (a.ArgType == Argument.AType.AddressOf) {
+ a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
+ ArrayList args = new ArrayList();
+ args.Add (a);
+ string param_name = pd.ParameterDesc(i).Replace('+', '.');
+ Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
+
+
+ New temp_new = new New ((Expression)pname, args, Location.Null);
+ Expression del_temp = temp_new.DoResolve(ec);
+
+ if (del_temp == null)
+ return false;
+
+ a = new Argument (del_temp, Argument.AType.Expression);
+ if (!a.Resolve(ec, Location.Null))\r
+ return false;
+ }
+ }
+ else {
+ if (a.ArgType == Argument.AType.AddressOf)
+ return false;
+ }
+
+ if ((p.ModFlags & Parameter.Modifier.REF) != 0) {
+ a = new Argument (a.Expr, Argument.AType.Ref);
+ if (!a.Resolve(ec,Location.Null))
+ return false;
+ }
+ }
+ }
+\r
+ if (!CheckParameterAgainstArgument (ec, pd, i, a, param_type))
+ return (false);
+ }
+ }
+ else {
+ // If we have no arguments AND the first parameter is optional
+ // we must check for a candidate (the loop above wouldn't)
+ if (po_count > 0) {
+ ArrayList arglist = new ArrayList();
+
+ // Since we got so far, there's no need to check if
+ // arguments are optional; we simply retrieve
+ // parameter default values and build a brand-new
+ // argument list.
+
+ for (int i = 0; i < ps.FixedParameters.Length; i++) {
+ Parameter p = ps.FixedParameters[i];
+ Argument a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
+ a.Resolve(ec, Location.Null);
+ arglist.Add (a);
+ }
+ arguments = arglist;
+ return true;
+ }
+ }
+ // We've found a candidate, so we exchange the dummy NoArg arguments
+ // with new arguments containing the default value for that parameter
+
+ ArrayList newarglist = new ArrayList();
+ for (int i = 0; i < arg_count; i++) {
+ Argument a = (Argument) arguments [i];
+ Parameter p = null;
+
+ if (ps != null)
+ p = (Parameter) ps.FixedParameters[i];
+
+ if (a.ArgType == Argument.AType.NoArg){
+ a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
+ a.Resolve(ec, Location.Null);
+ }
+
+ // ToDo - This part is getting resolved second time within this function
+ // This is a costly operation
+ // The earlier resoved result should be used here.
+ // Has to be done during compiler optimization.
+ if (a.ArgType == Argument.AType.AddressOf) {
+ param_type = pd.ParameterType (i);
+ bool IsDelegate = TypeManager.IsDelegateType (param_type);
+
+ a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
+ ArrayList args = new ArrayList();
+ args.Add (a);
+ string param_name = pd.ParameterDesc(i).Replace('+', '.');
+ Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
+
+ New temp_new = new New ((Expression)pname, args, Location.Null);
+ Expression del_temp = temp_new.DoResolve(ec);
+
+ if (del_temp == null)
+ return false;
+
+ a = new Argument (del_temp, Argument.AType.Expression);
+ if (!a.Resolve(ec, Location.Null))\r
+ return false;
+ }
+
+ if ((p != null) && ((p.ModFlags & Parameter.Modifier.REF) != 0)) {
+ a.ArgType = Argument.AType.Ref;
+ a.Resolve(ec, Location.Null);
+ }
+ newarglist.Add(a);
+ int n = pd_count - arg_count;
+ if (n > 0) {
+ for (int x = 0; x < n; x++) {
+ Parameter op = (Parameter) ps.FixedParameters[x + arg_count];
+ Argument b = new Argument (op.ParameterInitializer, Argument.AType.Expression);
+ b.Resolve(ec, Location.Null);
+ newarglist.Add (b);
+ }
+ }
+ }
+ arguments = newarglist;
+ return true;
+ }
+
+ static bool compare_name_filter (MemberInfo m, object filterCriteria)
+ {
+ return (m.Name == ((string) filterCriteria));
+ }
+
+ static Parameters GetFullParameters (MethodBase mb)
+ {
+ TypeContainer tc = TypeManager.LookupTypeContainer (mb.DeclaringType);
+ InternalParameters ip = TypeManager.LookupParametersByBuilder(mb);
+
+ return (ip != null) ? ip.Parameters : null;
+ }
+
+ // We need an overload for OverloadResolve because Invocation.DoResolve
+ // must pass Arguments by reference, since a later call to IsApplicable
+ // can change the argument list if optional parameters are defined
+ // in the method declaration
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ArrayList Arguments, Location loc)
+ {
+ ArrayList a = Arguments;
+ return OverloadResolve (ec, me, ref a, loc);
+ }
+
+ /// <summary>
+ /// Find the Applicable Function Members (7.4.2.1)
+ ///
+ /// me: Method Group expression with the members to select.
+ /// it might contain constructors or methods (or anything
+ /// that maps to a method).
+ ///
+ /// Arguments: ArrayList containing resolved Argument objects.
+ ///
+ /// loc: The location if we want an error to be reported, or a Null
+ /// location for "probing" purposes.
+ ///
+ /// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
+ /// that is the best match of me on Arguments.
+ ///
+ /// </summary>
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ref ArrayList Arguments, Location loc)
+ {
+ ArrayList afm = new ArrayList ();
+ MethodBase method = null;
+ Type current_type = null;
+ int argument_count;
+ ArrayList candidates = new ArrayList ();
+
+ foreach (MethodBase candidate in me.Methods){
+ int x;
+
+ // If we're going one level higher in the class hierarchy, abort if
+ // we already found an applicable method.
+ if (candidate.DeclaringType != current_type) {
+ current_type = candidate.DeclaringType;
+ if (method != null)
+ break;
+ }
+
+ // Check if candidate is applicable (section 14.4.2.1)
+ if (!IsApplicable (ec, ref Arguments, candidate))
+ continue;
+
+ candidates.Add (candidate);
+ x = BetterFunction (ec, Arguments, candidate, method, false, loc);
+
+ if (x == 0)
+ continue;
+
+ method = candidate;
+ }
+
+ if (Arguments == null)
+ argument_count = 0;
+ else
+ argument_count = Arguments.Count;
+
+
+ //
+ // Now we see if we can find params functions, applicable in their expanded form
+ // since if they were applicable in their normal form, they would have been selected
+ // above anyways
+ //
+ bool chose_params_expanded = false;
+
+ if (method == null) {
+ candidates = new ArrayList ();
+ foreach (MethodBase candidate in me.Methods){
+ if (!IsParamsMethodApplicable (ec, Arguments, candidate))
+ continue;
+
+ candidates.Add (candidate);
+
+ int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
+ if (x == 0)
+ continue;
+
+ method = candidate;
+ chose_params_expanded = true;
+ }
+ }
+
+ if (method == null) {
+ //
+ // Okay so we have failed to find anything so we
+ // return by providing info about the closest match
+ //
+ for (int i = 0; i < me.Methods.Length; ++i) {
+
+ MethodBase c = (MethodBase) me.Methods [i];
+ ParameterData pd = GetParameterData (c);
+
+ if (pd.Count != argument_count)
+ continue;
+
+ VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
+ null, loc);
+ }
+
+ return null;
+ }
+
+ //
+ // Now check that there are no ambiguities i.e the selected method
+ // should be better than all the others
+ //
+
+ foreach (MethodBase candidate in candidates){
+ if (candidate == method)
+ continue;
+
+ //
+ // If a normal method is applicable in the sense that it has the same
+ // number of arguments, then the expanded params method is never applicable
+ // so we debar the params method.
+ //
+ if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
+ IsApplicable (ec, ref Arguments, method))
+ continue;
+
+ int x = BetterFunction (ec, Arguments, method, candidate,
+ chose_params_expanded, loc);
+
+ if (x != 1) {
+ Report.Error (
+ 121, loc,
+ "Ambiguous call when selecting function due to implicit casts");
+ return null;
+ }
+ }
+
+ //
+ // And now check if the arguments are all compatible, perform conversions
+ // if necessary etc. and return if everything is all right
+ //
+ if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
+ chose_params_expanded, null, loc))
+ return method;
+ else
+ return null;
+ }
+
+ public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
+ int argument_count,
+ MethodBase method,
+ bool chose_params_expanded,
+ Type delegate_type,
+ Location loc)
+ {
+ return (VerifyArgumentsCompat (ec, Arguments, argument_count,
+ method, chose_params_expanded, delegate_type, loc, null));
+ }
+
+ public static bool VerifyArgumentsCompat (EmitContext ec,
+ ArrayList Arguments,
+ int argument_count,
+ MethodBase method,
+ bool chose_params_expanded,
+ Type delegate_type,
+ Location loc,
+ string InvokingProperty)
+ {
+ ParameterData pd = GetParameterData (method);
+ int pd_count = pd.Count;
+
+ for (int j = 0; j < argument_count; j++) {
+ Argument a = (Argument) Arguments [j];
+ Expression a_expr = a.Expr;
+ Type parameter_type = pd.ParameterType(j);
+
+ if (parameter_type == null)
+ {
+ Error_WrongNumArguments(loc, (InvokingProperty == null)?((delegate_type == null)?FullMethodDesc (method):delegate_type.ToString ()):InvokingProperty, argument_count);
+ return false;
+ }
+ if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
+ chose_params_expanded)
+ parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
+
+ if (a.Type != parameter_type){
+ Expression conv;
+
+ conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
+
+ if (conv == null) {
+ if (!Location.IsNull (loc)) {
+ if (delegate_type == null)
+ if (InvokingProperty == null)
+ Report.Error (1502, loc,
+ "The best overloaded match for method '" +
+ FullMethodDesc (method) +
+ "' has some invalid arguments");
+ else
+ Report.Error (1502, loc,
+ "Property '" +
+ InvokingProperty +
+ "' has some invalid arguments");
+ else
+ Report.Error (1594, loc,
+ "Delegate '" + delegate_type.ToString () +
+ "' has some invalid arguments.");
+ Report.Error (1503, loc,
+ "Argument " + (j+1) +
+ ": Cannot convert from '" + Argument.FullDesc (a)
+ + "' to '" + pd.ParameterDesc (j) + "'");
+ }
+
+ return false;
+ }
+
+ //
+ // Update the argument with the implicit conversion
+ //
+ if (a_expr != conv)
+ a.Expr = conv;
+ }
+
+ Parameter.Modifier a_mod = a.GetParameterModifier () &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ Parameter.Modifier p_mod = pd.ParameterModifier (j) &
+ ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+
+
+ if (a_mod != p_mod &&
+ pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
+ if (!Location.IsNull (loc)) {
+ Report.Error (1502, loc,
+ "The best overloaded match for method '" + FullMethodDesc (method)+
+ "' has some invalid arguments");
+ Report.Error (1503, loc,
+ "Argument " + (j+1) +
+ ": Cannot convert from '" + Argument.FullDesc (a)
+ + "' to '" + pd.ParameterDesc (j) + "'");
+ }
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ this.is_left_hand = true;
+ return DoResolve (ec);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // First, resolve the expression that is used to
+ // trigger the invocation
+ //
+ Expression expr_to_return = null;
+
+ if (expr is BaseAccess)
+ is_base = true;
+
+ if ((ec.ReturnType != null) && (expr.ToString() == ec.BlockName)) {
+ ec.InvokingOwnOverload = true;
+ expr = expr.Resolve (ec, ResolveFlags.MethodGroup);
+ ec.InvokingOwnOverload = false;
+ }
+ else
+ {
+ ec.InvokingOwnOverload = false;
+ expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+ }
+ if (expr == null)
+ return null;
+
+ if (expr is Invocation) {
+ // FIXME Calls which return an Array are not resolved (here or in the grammar)
+ expr = expr.Resolve(ec);
+ }
+
+ if (!(expr is MethodGroupExpr))
+ {
+ Type expr_type = expr.Type;
+
+ if (expr_type != null)
+ {
+ bool IsDelegate = TypeManager.IsDelegateType (expr_type);
+ if (IsDelegate)
+ return (new DelegateInvocation (
+ this.expr, Arguments, loc)).Resolve (ec);
+ }
+ }
+
+ //
+ // Next, evaluate all the expressions in the argument list
+ //
+ if (Arguments != null)
+ {
+ foreach (Argument a in Arguments)
+ {
+ if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
+ Report.Error (999, "This item cannot have empty arguments");
+
+
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ if (expr is MethodGroupExpr)
+ {
+ MethodGroupExpr mg = (MethodGroupExpr) expr;
+ method = OverloadResolve (ec, mg, ref Arguments, loc);
+
+ if (method == null)
+ {
+ Error (30455,
+ "Could not find any applicable function to invoke for this argument list");
+ return null;
+ }
+
+ if ((method as MethodInfo) != null)
+ {
+ MethodInfo mi = method as MethodInfo;
+ type = TypeManager.TypeToCoreType (mi.ReturnType);
+ if (!mi.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
+ SimpleName.Error_ObjectRefRequired (ec, loc, mi.Name);
+ }
+
+ if ((method as ConstructorInfo) != null)
+ {
+ ConstructorInfo ci = method as ConstructorInfo;
+ type = TypeManager.void_type;
+ if (!ci.IsStatic && !mg.IsExplicitImpl && (mg.InstanceExpression == null))
+ SimpleName.Error_ObjectRefRequired (ec, loc, ci.Name);
+ }
+
+ if (type.IsPointer)
+ {
+ if (!ec.InUnsafe)
+ {
+ UnsafeError (loc);
+ return null;
+ }
+ }
+ eclass = ExprClass.Value;
+ expr_to_return = this;
+ }
+
+ if (expr is PropertyExpr)
+ {
+ PropertyExpr pe = ((PropertyExpr) expr);
+ pe.PropertyArgs = (ArrayList) Arguments.Clone();
+ Arguments.Clear();
+ Arguments = new ArrayList();
+ MethodBase mi = pe.PropertyInfo.GetGetMethod(true);
+
+ if(VerifyArgumentsCompat (ec, pe.PropertyArgs,
+ pe.PropertyArgs.Count, mi, false, null, loc, pe.Name))
+ {
+
+ expr_to_return = pe.DoResolve (ec);
+ expr_to_return.eclass = ExprClass.PropertyAccess;
+ }
+ else
+ {
+ throw new Exception("Error resolving Property Access expression\n" + pe.ToString());
+ }
+ }
+
+ if (expr is FieldExpr || expr is LocalVariableReference || expr is ParameterReference) {
+ if (expr.Type.IsArray) {
+ // If we are here, expr must be an ArrayAccess
+ ArrayList idxs = new ArrayList();
+ foreach (Argument a in Arguments)
+ {
+ idxs.Add (a.Expr);
+ }
+ ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
+ ArrayAccess aa = new ArrayAccess (ea, expr.Location);
+ expr_to_return = aa.DoResolve(ec);
+ expr_to_return.eclass = ExprClass.Variable;
+ }
+ else
+ {
+ // We can't resolve now, but we
+ // have to try to access the array with a call
+ // to LateIndexGet/Set in the runtime
+ Expression lig_call_expr;
+
+ if (!is_left_hand)
+ lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
+ else
+ lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexSet", Location.Null);
+ Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
+ ArrayList adims = new ArrayList();
+
+ ArrayList ainit = new ArrayList();
+ foreach (Argument a in Arguments)
+ ainit.Add ((Expression) a.Expr);
+
+ adims.Add ((Expression) new IntLiteral (Arguments.Count));
+
+ Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
+
+ ArrayList args = new ArrayList();
+ args.Add (new Argument(expr, Argument.AType.Expression));
+ args.Add (new Argument(oace, Argument.AType.Expression));
+ args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
+
+ Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
+ expr_to_return = lig_call.Resolve(ec);
+ expr_to_return.eclass = ExprClass.Variable;
+ }
+ }
+
+ return expr_to_return;
+ }
+
+ static void Error_WrongNumArguments (Location loc, String name, int arg_count)
+ {
+ Report.Error (1501, loc, "No overload for method `" + name + "' takes `" +
+ arg_count + "' arguments");
+ }
+
+ // <summary>
+ // Emits the list of arguments as an array
+ // </summary>
+ static void EmitParams (EmitContext ec, int idx, ArrayList arguments)
+ {
+ ILGenerator ig = ec.ig;
+ int count = arguments.Count - idx;
+ Argument a = (Argument) arguments [idx];
+ Type t = a.Expr.Type;
+ string array_type = t.FullName + "[]";
+ LocalBuilder array;
+
+ array = ig.DeclareLocal (TypeManager.LookupType (array_type));
+ IntConstant.EmitInt (ig, count);
+ ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
+ ig.Emit (OpCodes.Stloc, array);
+
+ int top = arguments.Count;
+ for (int j = idx; j < top; j++){
+ a = (Argument) arguments [j];
+
+ ig.Emit (OpCodes.Ldloc, array);
+ IntConstant.EmitInt (ig, j - idx);
+ a.Emit (ec);
+
+ ArrayAccess.EmitStoreOpcode (ig, t);
+ }
+ ig.Emit (OpCodes.Ldloc, array);
+ }
+
+ /// <summary>
+ /// Emits a list of resolved Arguments that are in the arguments
+ /// ArrayList.
+ ///
+ /// The MethodBase argument might be null if the
+ /// emission of the arguments is known not to contain
+ /// a 'params' field (for example in constructors or other routines
+ /// that keep their arguments in this structure)
+ /// </summary>
+ public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
+ {
+ ParameterData pd;
+ if (mb != null)
+ pd = GetParameterData (mb);
+ else
+ pd = null;
+
+ //
+ // If we are calling a params method with no arguments, special case it
+ //
+ if (arguments == null){
+ if (pd != null && pd.Count > 0 &&
+ pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
+ ILGenerator ig = ec.ig;
+
+ IntConstant.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Newarr, pd.ParameterType (0).GetElementType ());
+ }
+ return;
+ }
+
+ int top = arguments.Count;
+
+ for (int i = 0; i < top; i++){
+ Argument a = (Argument) arguments [i];
+
+ if (pd != null){
+ if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
+ //
+ // Special case if we are passing the same data as the
+ // params argument, do not put it in an array.
+ //
+ if (pd.ParameterType (i) == a.Type)
+ a.Emit (ec);
+ else
+ EmitParams (ec, i, arguments);
+ return;
+ }
+ }
+
+ a.Emit (ec);
+ }
+
+ if (pd != null && pd.Count > top &&
+ pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
+ ILGenerator ig = ec.ig;
+
+ IntConstant.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Newarr, pd.ParameterType (top).GetElementType ());
+ }
+ }
+
+ /// <remarks>
+ /// is_base tells whether we want to force the use of the 'call'
+ /// opcode instead of using callvirt. Call is required to call
+ /// a specific method, while callvirt will always use the most
+ /// recent method in the vtable.
+ ///
+ /// is_static tells whether this is an invocation on a static method
+ ///
+ /// instance_expr is an expression that represents the instance
+ /// it must be non-null if is_static is false.
+ ///
+ /// method is the method to invoke.
+ ///
+ /// Arguments is the list of arguments to pass to the method or constructor.
+ /// </remarks>
+ public static void EmitCall (EmitContext ec, bool is_base,
+ bool is_static, Expression instance_expr,
+ MethodBase method, ArrayList Arguments, Location loc)
+ {
+ EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, null, loc);
+ }
+
+ public static void EmitCall (EmitContext ec, bool is_base,
+ bool is_static, Expression instance_expr,
+ MethodBase method, ArrayList Arguments, ArrayList prop_args, Location loc)
+ {
+ ILGenerator ig = ec.ig;
+ bool struct_call = false;
+
+ Type decl_type = method.DeclaringType;
+
+ if (!RootContext.StdLib)
+ {
+ // Replace any calls to the system's System.Array type with calls to
+ // the newly created one.
+ if (method == TypeManager.system_int_array_get_length)
+ method = TypeManager.int_array_get_length;
+ else if (method == TypeManager.system_int_array_get_rank)
+ method = TypeManager.int_array_get_rank;
+ else if (method == TypeManager.system_object_array_clone)
+ method = TypeManager.object_array_clone;
+ else if (method == TypeManager.system_int_array_get_length_int)
+ method = TypeManager.int_array_get_length_int;
+ else if (method == TypeManager.system_int_array_get_lower_bound_int)
+ method = TypeManager.int_array_get_lower_bound_int;
+ else if (method == TypeManager.system_int_array_get_upper_bound_int)
+ method = TypeManager.int_array_get_upper_bound_int;
+ else if (method == TypeManager.system_void_array_copyto_array_int)
+ method = TypeManager.void_array_copyto_array_int;
+ }
+
+ //
+ // This checks the 'ConditionalAttribute' on the method, and the
+ // ObsoleteAttribute
+ //
+ TypeManager.MethodFlags flags = TypeManager.GetMethodFlags (method, loc);
+ if ((flags & TypeManager.MethodFlags.IsObsoleteError) != 0)
+ return;
+ if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0)
+ return;
+
+ if (!is_static)
+ {
+ if (decl_type.IsValueType)
+ struct_call = true;
+ //
+ // If this is ourselves, push "this"
+ //
+ if (instance_expr == null)
+ {
+ ig.Emit (OpCodes.Ldarg_0);
+ }
+ else
+ {
+ //
+ // Push the instance expression
+ //
+ if (instance_expr.Type.IsValueType)
+ {
+ //
+ // Special case: calls to a function declared in a
+ // reference-type with a value-type argument need
+ // to have their value boxed.
+
+ struct_call = true;
+ if (decl_type.IsValueType)
+ {
+ //
+ // If the expression implements IMemoryLocation, then
+ // we can optimize and use AddressOf on the
+ // return.
+ //
+ // If not we have to use some temporary storage for
+ // it.
+ if (instance_expr is IMemoryLocation)
+ {
+ ((IMemoryLocation)instance_expr).
+ AddressOf (ec, AddressOp.LoadStore);
+ }
+ else
+ {
+ Type t = instance_expr.Type;
+
+ instance_expr.Emit (ec);
+ LocalBuilder temp = ig.DeclareLocal (t);
+ ig.Emit (OpCodes.Stloc, temp);
+ ig.Emit (OpCodes.Ldloca, temp);
+ }
+ }
+ else
+ {
+ instance_expr.Emit (ec);
+ ig.Emit (OpCodes.Box, instance_expr.Type);
+ }
+ }
+ else
+ instance_expr.Emit (ec);
+ }
+ }
+
+ if (prop_args != null && prop_args.Count > 0)
+ {
+ if (Arguments == null)
+ Arguments = new ArrayList();
+
+ for (int i = prop_args.Count-1; i >=0 ; i--)
+ {
+ Arguments.Insert (0,prop_args[i]);
+ }
+
+ }
+
+ EmitArguments (ec, method, Arguments);
+
+ if (is_static || struct_call || is_base)
+ {
+ if (method is MethodInfo)
+ {
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ }
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ }
+ else
+ {
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+ }
+ }
+
+ static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
+ {
+ int top = prop_args.Count;
+
+ for (int i = 0; i < top; i++)
+ {
+ Argument a = (Argument) prop_args [i];
+ a.Emit (ec);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ MethodGroupExpr mg = (MethodGroupExpr) this.expr;
+
+ EmitCall (
+ ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+
+ //
+ // Pop the return value if there is one
+ //
+ if (method is MethodInfo){
+ Type ret = ((MethodInfo)method).ReturnType;
+ if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+ }
+
+ //
+ // This class is used to "disable" the code generation for the
+ // temporary variable when initializing value types.
+ //
+ class EmptyAddressOf : EmptyExpression, IMemoryLocation {
+ public void AddressOf (EmitContext ec, AddressOp Mode)
+ {
+ // nothing
+ }
+ }
+
+ /// <summary>
+ /// Implements the new expression
+ /// </summary>
+ public class New : ExpressionStatement {
+ public readonly ArrayList Arguments;
+ public readonly Expression RequestedType;
+
+ MethodBase method = null;
+
+ //
+ // If set, the new expression is for a value_target, and
+ // we will not leave anything on the stack.
+ //
+ Expression value_target;
+ bool value_target_set = false;
+ public bool isDelegate = false;
+
+ public New (Expression requested_type, ArrayList arguments, Location l)
+ {
+ RequestedType = requested_type;
+ Arguments = arguments;
+ loc = l;
+ }
+
+ public Expression ValueTypeVariable {
+ get {
+ return value_target;
+ }
+
+ set {
+ value_target = value;
+ value_target_set = true;
+ }
+ }
+
+ //
+ // This function is used to disable the following code sequence for
+ // value type initialization:
+ //
+ // AddressOf (temporary)
+ // Construct/Init
+ // LoadTemporary
+ //
+ // Instead the provide will have provided us with the address on the
+ // stack to store the results.
+ //
+ static Expression MyEmptyExpression;
+
+ public void DisableTemporaryValueType ()
+ {
+ if (MyEmptyExpression == null)
+ MyEmptyExpression = new EmptyAddressOf ();
+
+ //
+ // To enable this, look into:
+ // test-34 and test-89 and self bootstrapping.
+ //
+ // For instance, we can avoid a copy by using 'newobj'
+ // instead of Call + Push-temp on value types.
+// value_target = MyEmptyExpression;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (this.isDelegate) {
+ // if its a delegate resolve the type of RequestedType first
+ Expression dtype = RequestedType.Resolve(ec);
+ string ts = (dtype.Type.ToString()).Replace ('+','.');
+ dtype = Mono.MonoBASIC.Parser.DecomposeQI (ts, Location.Null);
+
+ type = ec.DeclSpace.ResolveType (dtype, false, loc);
+ }
+ else
+ type = ec.DeclSpace.ResolveType (RequestedType, false, loc);
+
+ if (type == null)
+ return null;
+
+ bool IsDelegate = TypeManager.IsDelegateType (type);
+
+ if (IsDelegate)
+ return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+
+ if (type.IsInterface || type.IsAbstract){
+ Error (
+ 30376, "It is not possible to create instances of Interfaces " +
+ "or classes marked as MustInherit");
+ return null;
+ }
+
+ bool is_struct = false;
+ is_struct = type.IsValueType;
+ eclass = ExprClass.Value;
+
+ //
+ // SRE returns a match for .ctor () on structs (the object constructor),
+ // so we have to manually ignore it.
+ //
+ if (is_struct && Arguments == null)
+ return this;
+
+ Expression ml;
+ ml = MemberLookupFinal (ec, type, ".ctor",
+ MemberTypes.Constructor,
+ AllBindingFlags | BindingFlags.Public, loc);
+
+ if (ml == null)
+ return null;
+
+ if (! (ml is MethodGroupExpr)){
+ if (!is_struct){
+ ml.Error118 ("method group");
+ return null;
+ }
+ }
+
+ if (ml != null) {
+ if (Arguments != null){
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+ }
+ }
+
+ method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml,
+ Arguments, loc);
+
+ }
+
+ if (method == null) {
+ if (!is_struct || Arguments.Count > 0) {
+ Error (1501,
+ "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+ }
+ return this;
+ }
+
+ //
+ // This DoEmit can be invoked in two contexts:
+ // * As a mechanism that will leave a value on the stack (new object)
+ // * As one that wont (init struct)
+ //
+ // You can control whether a value is required on the stack by passing
+ // need_value_on_stack. The code *might* leave a value on the stack
+ // so it must be popped manually
+ //
+ // If we are dealing with a ValueType, we have a few
+ // situations to deal with:
+ //
+ // * The target is a ValueType, and we have been provided
+ // the instance (this is easy, we are being assigned).
+ //
+ // * The target of New is being passed as an argument,
+ // to a boxing operation or a function that takes a
+ // ValueType.
+ //
+ // In this case, we need to create a temporary variable
+ // that is the argument of New.
+ //
+ // Returns whether a value is left on the stack
+ //
+ bool DoEmit (EmitContext ec, bool need_value_on_stack)
+ {
+ bool is_value_type = type.IsValueType;
+ ILGenerator ig = ec.ig;
+
+ if (is_value_type){
+ IMemoryLocation ml;
+
+ // Allow DoEmit() to be called multiple times.
+ // We need to create a new LocalTemporary each time since
+ // you can't share LocalBuilders among ILGeneators.
+ if (!value_target_set)
+ value_target = new LocalTemporary (ec, type);
+
+ ml = (IMemoryLocation) value_target;
+ ml.AddressOf (ec, AddressOp.Store);
+ }
+
+ if (method != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+
+ if (is_value_type){
+ if (method == null)
+ ig.Emit (OpCodes.Initobj, type);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ if (need_value_on_stack){
+ value_target.Emit (ec);
+ return true;
+ }
+ return false;
+ } else {
+ ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
+ return true;
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec, true);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ if (DoEmit (ec, false))
+ ec.ig.Emit (OpCodes.Pop);
+ }
+ }
+
+ /// <summary>
+ /// 14.5.10.2: Represents an array creation expression.
+ /// </summary>
+ ///
+ /// <remarks>
+ /// There are two possible scenarios here: one is an array creation
+ /// expression that specifies the dimensions and optionally the
+ /// initialization data and the other which does not need dimensions
+ /// specified but where initialization data is mandatory.
+ /// </remarks>
+ public class ArrayCreation : ExpressionStatement {
+ Expression requested_base_type;
+ ArrayList initializers;
+
+ //
+ // The list of Argument types.
+ // This is used to construct the 'newarray' or constructor signature
+ //
+ ArrayList arguments;
+
+ //
+ // Method used to create the array object.
+ //
+ MethodBase new_method = null;
+
+ Type array_element_type;
+ Type underlying_type;
+ bool is_one_dimensional = false;
+ bool is_builtin_type = false;
+ bool expect_initializers = false;
+ int num_arguments = 0;
+ int dimensions = 0;
+ string rank;
+
+ ArrayList array_data;
+
+ Hashtable bounds;
+
+ //
+ // The number of array initializers that we can handle
+ // via the InitializeArray method - through EmitStaticInitializers
+ //
+ int num_automatic_initializers;
+
+ public ArrayCreation (Expression requested_base_type, ArrayList exprs, string rank, ArrayList initializers, Location l)
+ {
+ this.requested_base_type = requested_base_type;
+ this.initializers = initializers;
+ this.rank = rank;
+ loc = l;
+
+ arguments = new ArrayList ();
+
+ foreach (Expression e in exprs) {
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+ num_arguments++;
+ }
+ }
+
+ public ArrayCreation (Expression requested_base_type, string rank, ArrayList initializers, Location l)
+ {
+ this.requested_base_type = requested_base_type;
+ this.initializers = initializers;
+ this.rank = rank;
+ loc = l;
+
+ //this.rank = rank.Substring (0, rank.LastIndexOf ("["));
+ //
+ //string tmp = rank.Substring (rank.LastIndexOf ("["));
+ //
+ //dimensions = tmp.Length - 1;
+ expect_initializers = true;
+ }
+
+ public Expression FormArrayType (Expression base_type, int idx_count, string rank)
+ {
+ StringBuilder sb = new StringBuilder (rank);
+
+ sb.Append ("[");
+ for (int i = 1; i < idx_count; i++)
+ sb.Append (",");
+
+ sb.Append ("]");
+
+ return new ComposedCast (base_type, sb.ToString (), loc);
+ }
+
+ void Error_IncorrectArrayInitializer ()
+ {
+ Error (30567, "Incorrectly structured array initializer");
+ }
+
+ public bool CheckIndices (EmitContext ec, ArrayList probe, int idx, bool specified_dims)
+ {
+ if (specified_dims) {
+ Argument a = (Argument) arguments [idx];
+
+ if (!a.Resolve (ec, loc))
+ return false;
+
+ if (!(a.Expr is Constant)) {
+ Error (150, "A constant value is expected");
+ return false;
+ }
+
+ int value = (int) ((Constant) a.Expr).GetValue ();
+
+ if (value != probe.Count) {
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+
+ bounds [idx] = value;
+ }
+
+ int child_bounds = -1;
+ foreach (object o in probe) {
+ if (o is ArrayList) {
+ int current_bounds = ((ArrayList) o).Count;
+
+ if (child_bounds == -1)
+ child_bounds = current_bounds;
+
+ else if (child_bounds != current_bounds){
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+ bool ret = CheckIndices (ec, (ArrayList) o, idx + 1, specified_dims);
+ if (!ret)
+ return false;
+ } else {
+ if (child_bounds != -1){
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+
+ Expression tmp = (Expression) o;
+ tmp = tmp.Resolve (ec);
+ if (tmp == null)
+ continue;
+
+ // Console.WriteLine ("I got: " + tmp);
+ // Handle initialization from vars, fields etc.
+
+ Expression conv = ConvertImplicitRequired (
+ ec, tmp, underlying_type, loc);
+
+ if (conv == null)
+ return false;
+
+ if (conv is StringConstant)
+ array_data.Add (conv);
+ else if (conv is Constant) {
+ array_data.Add (conv);
+ num_automatic_initializers++;
+ } else
+ array_data.Add (conv);
+ }
+ }
+
+ return true;
+ }
+
+ public void UpdateIndices (EmitContext ec)
+ {
+ int i = 0;
+ for (ArrayList probe = initializers; probe != null;) {
+ if (probe.Count > 0 && probe [0] is ArrayList) {
+ Expression e = new IntConstant (probe.Count);
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+
+ bounds [i++] = probe.Count;
+
+ probe = (ArrayList) probe [0];
+
+ } else {
+ Expression e = new IntConstant (probe.Count);
+ arguments.Add (new Argument (e, Argument.AType.Expression));
+
+ bounds [i++] = probe.Count;
+ probe = null;
+ }
+ }
+
+ }
+
+ public bool ValidateInitializers (EmitContext ec, Type array_type)
+ {
+ if (initializers == null) {
+ if (expect_initializers)
+ return false;
+ else
+ return true;
+ }
+
+ if (underlying_type == null)
+ return false;
+
+ //
+ // We use this to store all the date values in the order in which we
+ // will need to store them in the byte blob later
+ //
+ array_data = new ArrayList ();
+ bounds = new Hashtable ();
+
+ bool ret;
+
+ if (arguments != null) {
+ ret = CheckIndices (ec, initializers, 0, true);
+ return ret;
+ } else {
+ arguments = new ArrayList ();
+
+ ret = CheckIndices (ec, initializers, 0, false);
+
+ if (!ret)
+ return false;
+
+ UpdateIndices (ec);
+
+ if (arguments.Count != dimensions) {
+ Error_IncorrectArrayInitializer ();
+ return false;
+ }
+
+ return ret;
+ }
+ }
+
+ void Error_NegativeArrayIndex ()
+ {
+ Error (284, "Can not create array with a negative size");
+ }
+
+ //
+ // Converts 'source' to an int, uint, long or ulong.
+ //
+ Expression ExpressionToArrayArgument (EmitContext ec, Expression source)
+ {
+ Expression target;
+
+ bool old_checked = ec.CheckState;
+ ec.CheckState = true;
+
+ target = ConvertImplicit (ec, source, TypeManager.int32_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.uint32_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.int64_type, loc);
+ if (target == null){
+ target = ConvertImplicit (ec, source, TypeManager.uint64_type, loc);
+ if (target == null)
+ Expression.Error_CannotConvertImplicit (loc, source.Type, TypeManager.int32_type);
+ }
+ }
+ }
+ ec.CheckState = old_checked;
+
+ //
+ // Only positive constants are allowed at compile time
+ //
+ if (target is Constant){
+ if (target is IntConstant){
+ if (((IntConstant) target).Value < 0){
+ Error_NegativeArrayIndex ();
+ return null;
+ }
+ }
+
+ if (target is LongConstant){
+ if (((LongConstant) target).Value < 0){
+ Error_NegativeArrayIndex ();
+ return null;
+ }
+ }
+
+ }
+
+ return target;
+ }
+
+ //
+ // Creates the type of the array
+ //
+ bool LookupType (EmitContext ec)
+ {
+ StringBuilder array_qualifier = new StringBuilder (rank);
+
+ //
+ // 'In the first form allocates an array instace of the type that results
+ // from deleting each of the individual expression from the expression list'
+ //
+ if (num_arguments > 0) {
+ array_qualifier.Append ("[");
+ for (int i = num_arguments-1; i > 0; i--)
+ array_qualifier.Append (",");
+ array_qualifier.Append ("]");
+ }
+
+ //
+ // Lookup the type
+ //
+ Expression array_type_expr;
+ array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
+ string sss = array_qualifier.ToString ();
+ type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
+
+ if (type == null)
+ return false;
+
+ underlying_type = type;
+ if (underlying_type.IsArray)
+ underlying_type = TypeManager.TypeToCoreType (underlying_type.GetElementType ());
+ dimensions = type.GetArrayRank ();
+
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ int arg_count;
+
+ if (!LookupType (ec))
+ return null;
+
+ //
+ // First step is to validate the initializers and fill
+ // in any missing bits
+ //
+ if (!ValidateInitializers (ec, type))
+ return null;
+
+ if (arguments == null)
+ arg_count = 0;
+ else {
+ arg_count = arguments.Count;
+ foreach (Argument a in arguments){
+ if (!a.Resolve (ec, loc))
+ return null;
+
+ Expression real_arg = ExpressionToArrayArgument (ec, a.Expr, loc);
+ if (real_arg == null)
+ return null;
+
+ a.Expr = real_arg;
+ }
+ }
+
+ array_element_type = TypeManager.TypeToCoreType (type.GetElementType ());
+
+ if (arg_count == 1) {
+ is_one_dimensional = true;
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ is_builtin_type = TypeManager.IsBuiltinType (type);
+
+ if (is_builtin_type) {
+ Expression ml;
+
+ ml = MemberLookup (ec, type, ".ctor", MemberTypes.Constructor,
+ AllBindingFlags, loc);
+
+ if (!(ml is MethodGroupExpr)) {
+ ml.Error118 ("method group");
+ return null;
+ }
+
+ if (ml == null) {
+ Error (-6, "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
+
+ if (new_method == null) {
+ Error (-6, "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ eclass = ExprClass.Value;
+ return this;
+ } else {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ArrayList args = new ArrayList ();
+
+ if (arguments != null) {
+ for (int i = 0; i < arg_count; i++)
+ args.Add (TypeManager.int32_type);
+ }
+
+ Type [] arg_types = null;
+
+ if (args.Count > 0)
+ arg_types = new Type [args.Count];
+
+ args.CopyTo (arg_types, 0);
+
+ new_method = mb.GetArrayMethod (type, ".ctor", CallingConventions.HasThis, null,
+ arg_types);
+
+ if (new_method == null) {
+ Error (-6, "New invocation: Can not find a constructor for " +
+ "this argument list");
+ return null;
+ }
+
+ eclass = ExprClass.Value;
+ return this;
+ }
+ }
+
+ public static byte [] MakeByteBlob (ArrayList array_data, Type underlying_type, Location loc)
+ {
+ int factor;
+ byte [] data;
+ byte [] element;
+ int count = array_data.Count;
+
+ if (underlying_type.IsEnum)
+ underlying_type = TypeManager.EnumToUnderlying (underlying_type);
+
+ factor = GetTypeSize (underlying_type);
+ if (factor == 0)
+ throw new Exception ("unrecognized type in MakeByteBlob: " + underlying_type);
+
+ data = new byte [(count * factor + 4) & ~3];
+ int idx = 0;
+
+ for (int i = 0; i < count; ++i) {
+ object v = array_data [i];
+
+ if (v is EnumConstant)
+ v = ((EnumConstant) v).Child;
+
+ if (v is Constant && !(v is StringConstant))
+ v = ((Constant) v).GetValue ();
+ else {
+ idx += factor;
+ continue;
+ }
+
+ if (underlying_type == TypeManager.int64_type){
+ if (!(v is Expression)){
+ long val = (long) v;
+
+ for (int j = 0; j < factor; ++j) {
+ data [idx + j] = (byte) (val & 0xFF);
+ val = (val >> 8);
+ }
+ }
+ } else if (underlying_type == TypeManager.uint64_type){
+ if (!(v is Expression)){
+ ulong val = (ulong) v;
+
+ for (int j = 0; j < factor; ++j) {
+ data [idx + j] = (byte) (val & 0xFF);
+ val = (val >> 8);
+ }
+ }
+ } else if (underlying_type == TypeManager.float_type) {
+ if (!(v is Expression)){
+ element = BitConverter.GetBytes ((float) v);
+
+ for (int j = 0; j < factor; ++j)
+ data [idx + j] = element [j];
+ }
+ } else if (underlying_type == TypeManager.double_type) {
+ if (!(v is Expression)){
+ element = BitConverter.GetBytes ((double) v);
+
+ for (int j = 0; j < factor; ++j)
+ data [idx + j] = element [j];
+ }
+ } else if (underlying_type == TypeManager.char_type){
+ if (!(v is Expression)){
+ int val = (int) ((char) v);
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) (val >> 8);
+ }
+ } else if (underlying_type == TypeManager.short_type){
+ if (!(v is Expression)){
+ int val = (int) ((short) v);
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) (val >> 8);
+ }
+ } else if (underlying_type == TypeManager.ushort_type){
+ if (!(v is Expression)){
+ int val = (int) ((ushort) v);
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) (val >> 8);
+ }
+ } else if (underlying_type == TypeManager.int32_type) {
+ if (!(v is Expression)){
+ int val = (int) v;
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) ((val >> 8) & 0xff);
+ data [idx+2] = (byte) ((val >> 16) & 0xff);
+ data [idx+3] = (byte) (val >> 24);
+ }
+ } else if (underlying_type == TypeManager.uint32_type) {
+ if (!(v is Expression)){
+ uint val = (uint) v;
+
+ data [idx] = (byte) (val & 0xff);
+ data [idx+1] = (byte) ((val >> 8) & 0xff);
+ data [idx+2] = (byte) ((val >> 16) & 0xff);
+ data [idx+3] = (byte) (val >> 24);
+ }
+ } else if (underlying_type == TypeManager.sbyte_type) {
+ if (!(v is Expression)){
+ sbyte val = (sbyte) v;
+ data [idx] = (byte) val;
+ }
+ } else if (underlying_type == TypeManager.byte_type) {
+ if (!(v is Expression)){
+ byte val = (byte) v;
+ data [idx] = (byte) val;
+ }
+ } else if (underlying_type == TypeManager.bool_type) {
+ if (!(v is Expression)){
+ bool val = (bool) v;
+ data [idx] = (byte) (val ? 1 : 0);
+ }
+ } else if (underlying_type == TypeManager.decimal_type){
+ if (!(v is Expression)){
+ int [] bits = Decimal.GetBits ((decimal) v);
+ int p = idx;
+
+ for (int j = 0; j < 4; j++){
+ data [p++] = (byte) (bits [j] & 0xff);
+ data [p++] = (byte) ((bits [j] >> 8) & 0xff);
+ data [p++] = (byte) ((bits [j] >> 16) & 0xff);
+ data [p++] = (byte) (bits [j] >> 24);
+ }
+ }
+ } else
+ throw new Exception ("Unrecognized type in MakeByteBlob: " + underlying_type);
+
+ idx += factor;
+ }
+
+ return data;
+ }
+
+ //
+ // Emits the initializers for the array
+ //
+ void EmitStaticInitializers (EmitContext ec, bool is_expression)
+ {
+ //
+ // First, the static data
+ //
+ FieldBuilder fb;
+ ILGenerator ig = ec.ig;
+
+ byte [] data = MakeByteBlob (array_data, underlying_type, loc);
+
+ fb = RootContext.MakeStaticData (data);
+
+ if (is_expression)
+ ig.Emit (OpCodes.Dup);
+ ig.Emit (OpCodes.Ldtoken, fb);
+ ig.Emit (OpCodes.Call,
+ TypeManager.void_initializearray_array_fieldhandle);
+ }
+
+ //
+ // Emits pieces of the array that can not be computed at compile
+ // time (variables and string locations).
+ //
+ // This always expect the top value on the stack to be the array
+ //
+ void EmitDynamicInitializers (EmitContext ec, bool is_expression)
+ {
+ ILGenerator ig = ec.ig;
+ int dims = bounds.Count;
+ int [] current_pos = new int [dims];
+ int top = array_data.Count;
+ LocalBuilder temp = ig.DeclareLocal (type);
+
+ ig.Emit (OpCodes.Stloc, temp);
+
+ MethodInfo set = null;
+
+ if (dims != 1){
+ Type [] args;
+ ModuleBuilder mb = null;
+ mb = CodeGen.ModuleBuilder;
+ args = new Type [dims + 1];
+
+ int j;
+ for (j = 0; j < dims; j++)
+ args [j] = TypeManager.int32_type;
+
+ args [j] = array_element_type;
+
+ set = mb.GetArrayMethod (
+ type, "Set",
+ CallingConventions.HasThis | CallingConventions.Standard,
+ TypeManager.void_type, args);
+ }
+
+ for (int i = 0; i < top; i++){
+
+ Expression e = null;
+
+ if (array_data [i] is Expression)
+ e = (Expression) array_data [i];
+
+ if (e != null) {
+ //
+ // Basically we do this for string literals and
+ // other non-literal expressions
+ //
+ if (e is StringConstant || !(e is Constant) ||
+ num_automatic_initializers <= 2) {
+ Type etype = e.Type;
+
+ ig.Emit (OpCodes.Ldloc, temp);
+
+ for (int idx = 0; idx < dims; idx++)
+ IntConstant.EmitInt (ig, current_pos [idx]);
+
+ //
+ // If we are dealing with a struct, get the
+ // address of it, so we can store it.
+ //
+ if ((dims == 1) &&
+ etype.IsSubclassOf (TypeManager.value_type) &&
+ (!TypeManager.IsBuiltinType (etype) ||
+ etype == TypeManager.decimal_type)) {
+ if (e is New){
+ New n = (New) e;
+
+ //
+ // Let new know that we are providing
+ // the address where to store the results
+ //
+ n.DisableTemporaryValueType ();
+ }
+
+ ig.Emit (OpCodes.Ldelema, etype);
+ }
+
+ e.Emit (ec);
+
+ if (dims == 1)
+ ArrayAccess.EmitStoreOpcode (ig, array_element_type);
+ else
+ ig.Emit (OpCodes.Call, set);
+ }
+ }
+
+ //
+ // Advance counter
+ //
+ for (int j = dims - 1; j >= 0; j--){
+ current_pos [j]++;
+ if (current_pos [j] < (int) bounds [j])
+ break;
+ current_pos [j] = 0;
+ }
+ }
+
+ if (is_expression)
+ ig.Emit (OpCodes.Ldloc, temp);
+ }
+
+ void EmitArrayArguments (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ foreach (Argument a in arguments) {
+ Type atype = a.Type;
+ a.Emit (ec);
+
+ if (atype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_Ovf_U4);
+ else if (atype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I4);
+ }
+ }
+
+ void DoEmit (EmitContext ec, bool is_statement)
+ {
+ ILGenerator ig = ec.ig;
+
+ EmitArrayArguments (ec);
+ if (is_one_dimensional)
+ ig.Emit (OpCodes.Newarr, array_element_type);
+ else {
+ if (is_builtin_type)
+ ig.Emit (OpCodes.Newobj, (ConstructorInfo) new_method);
+ else
+ ig.Emit (OpCodes.Newobj, (MethodInfo) new_method);
+ }
+
+ if (initializers != null){
+ //
+ // FIXME: Set this variable correctly.
+ //
+ bool dynamic_initializers = true;
+
+ if (underlying_type != TypeManager.string_type &&
+ underlying_type != TypeManager.object_type) {
+ if (num_automatic_initializers > 2)
+ EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
+ }
+
+ if (dynamic_initializers)
+ EmitDynamicInitializers (ec, !is_statement);
+ }
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec, false);
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ DoEmit (ec, true);
+ }
+
+ }
+
+ /// <summary>
+ /// Represents the 'this' construct
+ /// </summary>
+ public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
+
+ Block block;
+ VariableInfo vi;
+
+ public This (Block block, Location loc)
+ {
+ this.loc = loc;
+ this.block = block;
+ }
+
+ public This (Location loc)
+ {
+ this.loc = loc;
+ }
+
+ public bool IsAssigned (EmitContext ec, Location loc)
+ {
+ if (vi == null)
+ return true;
+
+ return vi.IsAssigned (ec, loc);
+ }
+
+ public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+ {
+ if (vi == null)
+ return true;
+
+ return vi.IsFieldAssigned (ec, field_name, loc);
+ }
+
+ public void SetAssigned (EmitContext ec)
+ {
+ if (vi != null)
+ vi.SetAssigned (ec);
+ }
+
+ public void SetFieldAssigned (EmitContext ec, string field_name)
+ {
+ if (vi != null)
+ vi.SetFieldAssigned (ec, field_name);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ eclass = ExprClass.Variable;
+ type = ec.ContainerType;
+
+ if (ec.IsStatic){
+ Error (26, "Keyword this not valid in static code");
+ return null;
+ }
+
+ if (block != null)
+ vi = block.ThisVariable;
+
+ return this;
+ }
+
+ override public Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ DoResolve (ec);
+
+ VariableInfo vi = ec.CurrentBlock.ThisVariable;
+ if (vi != null)
+ vi.SetAssigned (ec);
+
+ if (ec.TypeContainer is Class){
+ Error (1604, "Cannot assign to 'this'");
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldarg_0);
+ if (ec.TypeContainer is Struct)
+ ig.Emit (OpCodes.Ldobj, type);
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (ec.TypeContainer is Struct){
+ ig.Emit (OpCodes.Ldarg_0);
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stobj, type);
+ } else {
+ source.Emit (ec);
+ ig.Emit (OpCodes.Starg, 0);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+
+ // FIMXE
+ // FIGURE OUT WHY LDARG_S does not work
+ //
+ // consider: struct X { int val; int P { set { val = value; }}}
+ //
+ // Yes, this looks very bad. Look at 'NOTAS' for
+ // an explanation.
+ // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
+ }
+ }
+
+ /// <summary>
+ /// Implements the typeof operator
+ /// </summary>
+ public class TypeOf : Expression {
+ public readonly Expression QueriedType;
+ Type typearg;
+
+ public TypeOf (Expression queried_type, Location l)
+ {
+ QueriedType = queried_type;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ typearg = ec.DeclSpace.ResolveType (QueriedType, false, loc);
+
+ if (typearg == null)
+ return null;
+
+ type = TypeManager.type_type;
+ eclass = ExprClass.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldtoken, typearg);
+ ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
+ }
+
+ public Type TypeArg {
+ get { return typearg; }
+ }
+ }
+
+ /// <summary>
+ /// Implements the sizeof expression
+ /// </summary>
+ public class SizeOf : Expression {
+ public readonly Expression QueriedType;
+ Type type_queried;
+
+ public SizeOf (Expression queried_type, Location l)
+ {
+ this.QueriedType = queried_type;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!ec.InUnsafe) {
+ Error (233, "Sizeof may only be used in an unsafe context " +
+ "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
+ return null;
+ }
+
+ type_queried = ec.DeclSpace.ResolveType (QueriedType, false, loc);
+ if (type_queried == null)
+ return null;
+
+ if (!TypeManager.IsUnmanagedType (type_queried)){
+ Report.Error (208, "Cannot take the size of an unmanaged type (" + TypeManager.MonoBASIC_Name (type_queried) + ")");
+ return null;
+ }
+
+ type = TypeManager.int32_type;
+ eclass = ExprClass.Value;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int size = GetTypeSize (type_queried);
+
+ if (size == 0)
+ ec.ig.Emit (OpCodes.Sizeof, type_queried);
+ else
+ IntConstant.EmitInt (ec.ig, size);
+ }
+ }
+
+ /// <summary>
+ /// Implements the member access expression
+ /// </summary>
+ public class MemberAccess : Expression, ITypeExpression {
+ public readonly string Identifier;
+ Expression expr;
+ Expression member_lookup;
+
+ public MemberAccess (Expression expr, string id, Location l)
+ {
+ this.expr = expr;
+ Identifier = id;
+ loc = l;
+ }
+
+ public Expression Expr {
+ get {
+ return expr;
+ }
+ }
+
+ static void error176 (Location loc, string name)
+ {
+ Report.Error (176, loc, "Static member '" +
+ name + "' cannot be accessed " +
+ "with an instance reference, qualify with a " +
+ "type name instead");
+ }
+
+ static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Location loc)
+ {
+ if (left_original == null)
+ return false;
+
+ if (!(left_original is SimpleName))
+ return false;
+
+ SimpleName sn = (SimpleName) left_original;
+
+ Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
+ if (t != null)
+ return true;
+
+ return false;
+ }
+
+ public static Expression ResolveMemberAccess (EmitContext ec, Expression member_lookup,
+ Expression left, Location loc,
+ Expression left_original)
+ {
+ bool left_is_type, left_is_explicit;
+
+ // If 'left' is null, then we're called from SimpleNameResolve and this is
+ // a member in the currently defining class.
+ if (left == null) {
+ left_is_type = ec.IsStatic || ec.IsFieldInitializer;
+ left_is_explicit = false;
+
+ // Implicitly default to 'this' unless we're static.
+ if (!ec.IsStatic && !ec.IsFieldInitializer && !ec.InEnumContext)
+ left = ec.This;
+ } else {
+ left_is_type = left is TypeExpr;
+ left_is_explicit = true;
+ }
+
+ if (member_lookup is FieldExpr){
+ FieldExpr fe = (FieldExpr) member_lookup;
+ FieldInfo fi = fe.FieldInfo;
+ Type decl_type = fi.DeclaringType;
+
+ if (fi is FieldBuilder) {
+ Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
+
+ if (c != null) {
+ object o = c.LookupConstantValue (ec);
+ object real_value = ((Constant) c.Expr).GetValue ();
+
+ return Constantify (real_value, fi.FieldType);
+ }
+ }
+
+ if (fi.IsLiteral) {
+ Type t = fi.FieldType;
+
+ object o;
+
+ if (fi is FieldBuilder)
+ o = TypeManager.GetValue ((FieldBuilder) fi);
+ else
+ o = fi.GetValue (fi);
+
+ if (decl_type.IsSubclassOf (TypeManager.enum_type)) {
+ if (left_is_explicit && !left_is_type &&
+ !IdenticalNameAndTypeName (ec, left_original, loc)) {
+ error176 (loc, fe.FieldInfo.Name);
+ return null;
+ }
+
+ Expression enum_member = MemberLookup (
+ ec, decl_type, "value__", MemberTypes.Field,
+ AllBindingFlags, loc);
+
+ Enum en = TypeManager.LookupEnum (decl_type);
+
+ Constant c;
+ if (en != null) {
+ c = Constantify (o, en.UnderlyingType);
+ return new EnumConstant (c, en.UnderlyingType);
+ }
+ else {
+ c = Constantify (o, enum_member.Type);
+ return new EnumConstant (c, enum_member.Type);
+ }
+
+
+ }
+
+ Expression exp = Constantify (o, t);
+
+ if (left_is_explicit && !left_is_type) {
+ error176 (loc, fe.FieldInfo.Name);
+ return null;
+ }
+
+ return exp;
+ }
+
+ if (fi.FieldType.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+ }
+
+ if (member_lookup is EventExpr) {
+
+ EventExpr ee = (EventExpr) member_lookup;
+
+ //
+ // If the event is local to this class, we transform ourselves into
+ // a FieldExpr
+ //
+
+ if (ee.EventInfo.DeclaringType == ec.ContainerType) {
+ MemberInfo mi = GetFieldFromEvent (ee);
+
+ if (mi == null) {
+ //
+ // If this happens, then we have an event with its own
+ // accessors and private field etc so there's no need
+ // to transform ourselves : we should instead flag an error
+ //
+ Assign.error70 (ee.EventInfo, loc);
+ return null;
+ }
+
+ Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
+
+ if (ml == null) {
+ Report.Error (-200, loc, "Internal error!!");
+ return null;
+ }
+
+ return ResolveMemberAccess (ec, ml, left, loc, left_original);
+ }
+ }
+
+ if (member_lookup is IMemberExpr) {
+ IMemberExpr me = (IMemberExpr) member_lookup;
+
+ if (left_is_type){
+ MethodGroupExpr mg = me as MethodGroupExpr;
+ if ((mg != null) && left_is_explicit && left.Type.IsInterface)
+ mg.IsExplicitImpl = left_is_explicit;
+
+ if (!me.IsStatic){
+ if (IdenticalNameAndTypeName (ec, left_original, loc))
+ return member_lookup;
+
+ SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
+ return null;
+ }
+
+ } else {
+ if (!me.IsInstance){
+ if (IdenticalNameAndTypeName (ec, left_original, loc))
+ return member_lookup;
+
+ /*if (left_is_explicit) {
+ error176 (loc, me.Name);
+ return null;
+ }*/
+ }
+
+ //
+ // Since we can not check for instance objects in SimpleName,
+ // becaue of the rule that allows types and variables to share
+ // the name (as long as they can be de-ambiguated later, see
+ // IdenticalNameAndTypeName), we have to check whether left
+ // is an instance variable in a static context
+ //
+ // However, if the left-hand value is explicitly given, then
+ // it is already our instance expression, so we aren't in
+ // static context.
+ //
+
+ if (ec.IsStatic && !left_is_explicit && left is IMemberExpr){
+ IMemberExpr mexp = (IMemberExpr) left;
+
+ if (!mexp.IsStatic){
+ SimpleName.Error_ObjectRefRequired (ec, loc, mexp.Name);
+ return null;
+ }
+ }
+
+ me.InstanceExpression = left;
+ }
+
+ return member_lookup;
+ }
+
+ if (member_lookup is TypeExpr){
+ member_lookup.Resolve (ec, ResolveFlags.Type);
+ return member_lookup;
+ }
+
+ Console.WriteLine ("Left is: " + left);
+ Report.Error (-100, loc, "Support for [" + member_lookup + "] is not present yet");
+ Environment.Exit (0);
+ return null;
+ }
+
+ public Expression DoResolve (EmitContext ec, Expression right_side, ResolveFlags flags)
+ {
+ if (type != null)
+ throw new Exception ();
+ //
+ // Resolve the expression with flow analysis turned off, we'll do the definite
+ // assignment checks later. This is because we don't know yet what the expression
+ // will resolve to - it may resolve to a FieldExpr and in this case we must do the
+ // definite assignment check on the actual field and not on the whole struct.
+ //
+
+ Expression original = expr;
+ expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
+
+ if (expr == null)
+ return null;
+
+ if (expr is SimpleName){
+ SimpleName child_expr = (SimpleName) expr;
+
+ Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
+
+ if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
+ return new_expr.Resolve (ec, flags);
+ else
+ return new_expr.Resolve (ec, flags | ResolveFlags.MethodGroup | ResolveFlags.VariableOrValue);
+ }
+
+ int errors = Report.Errors;
+
+ Type expr_type = expr.Type;
+
+ if (expr_type.IsPointer){
+ Error (23, "The '.' operator can not be applied to pointer operands (" +
+ TypeManager.MonoBASIC_Name (expr_type) + ")");
+ return null;
+ }
+
+ member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
+
+ if (member_lookup == null)
+ {
+ // Error has already been reported.
+ if (errors < Report.Errors)
+ return null;
+
+ //
+ // Try looking the member up from the same type, if we find
+ // it, we know that the error was due to limited visibility
+ //
+ object lookup = TypeManager.MemberLookup (
+ expr_type, expr_type, AllMemberTypes, AllBindingFlags |
+ BindingFlags.NonPublic, Identifier);
+
+ if (lookup == null)
+ Error (30456, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
+ else
+ {
+ if ((expr_type != ec.ContainerType) &&
+ ec.ContainerType.IsSubclassOf (expr_type))
+ {
+
+ // Although a derived class can access protected members of
+ // its base class it cannot do so through an instance of the
+ // base class (CS1540). If the expr_type is a parent of the
+ // ec.ContainerType and the lookup succeeds with the latter one,
+ // then we are in this situation.
+
+ lookup = TypeManager.MemberLookup(
+ ec.ContainerType, ec.ContainerType, AllMemberTypes,
+ AllBindingFlags, Identifier);
+
+ if (lookup != null)
+ Error (1540, "Cannot access protected member '" +
+ expr_type + "." + Identifier + "' " +
+ "via a qualifier of type '" + TypeManager.MonoBASIC_Name (expr_type) + "'; the " +
+ "qualifier must be of type '" + TypeManager.MonoBASIC_Name (ec.ContainerType) + "' " +
+ "(or derived from it)");
+ else
+ Error (30390, "'" + expr_type + "." + Identifier + "' " +
+ "is inaccessible because of its protection level");
+ } else
+ Error (30390, "'" + expr_type + "." + Identifier + "' " +
+ "is inaccessible because of its protection level");
+ }
+ return null;
+ }
+
+ if ((expr is TypeExpr) && (expr_type.IsSubclassOf (TypeManager.enum_type))) {
+ Enum en = TypeManager.LookupEnum (expr_type);
+
+ if (en != null) {
+ object value = en.LookupEnumValue (ec, Identifier, loc);
+ expr_type = TypeManager.int32_type;
+ if (value != null) {
+ Constant c = Constantify (value, en.UnderlyingType);
+ return new EnumConstant (c, en.UnderlyingType);
+ }
+ }
+ }
+
+ if (member_lookup is TypeExpr){
+ member_lookup.Resolve (ec, ResolveFlags.Type);
+
+ return member_lookup;
+ } else if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
+ return null;
+
+ member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
+ if (member_lookup == null)
+ return null;
+
+ // The following DoResolve/DoResolveLValue will do the definite assignment
+ // check.
+ if (right_side != null)
+ member_lookup = member_lookup.DoResolveLValue (ec, right_side);
+ else
+ member_lookup = member_lookup.DoResolve (ec);
+
+ return member_lookup;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return DoResolve (ec, null, ResolveFlags.VariableOrValue |
+ ResolveFlags.SimpleName | ResolveFlags.Type);
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ return DoResolve (ec, right_side, ResolveFlags.VariableOrValue |
+ ResolveFlags.SimpleName | ResolveFlags.Type);
+ }
+
+ public Expression DoResolveType (EmitContext ec)
+ {
+ return DoResolve (ec, null, ResolveFlags.Type);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should not happen");
+ }
+
+ public override string ToString ()
+ {
+ return expr + "." + Identifier;
+ }
+ }
+
+
+
+ /// <summary>
+ /// Implements checked expressions
+ /// </summary>
+ public class CheckedExpr : Expression {
+
+ public Expression Expr;
+
+ public CheckedExpr (Expression e, Location l)
+ {
+ Expr = e;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.ConstantCheckState = true;
+ Expr = Expr.Resolve (ec);
+ ec.ConstantCheckState = last_const_check;
+
+ if (Expr == null)
+ return null;
+
+ if (Expr is Constant)
+ return Expr;
+
+ eclass = Expr.eclass;
+ type = Expr.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ bool last_check = ec.CheckState;
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.CheckState = true;
+ ec.ConstantCheckState = true;
+ Expr.Emit (ec);
+ ec.CheckState = last_check;
+ ec.ConstantCheckState = last_const_check;
+ }
+
+ }
+
+ /// <summary>
+ /// Implements the unchecked expression
+ /// </summary>
+ public class UnCheckedExpr : Expression {
+
+ public Expression Expr;
+
+ public UnCheckedExpr (Expression e, Location l)
+ {
+ Expr = e;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.ConstantCheckState = false;
+ Expr = Expr.Resolve (ec);
+ ec.ConstantCheckState = last_const_check;
+
+ if (Expr == null)
+ return null;
+
+ if (Expr is Constant)
+ return Expr;
+
+ eclass = Expr.eclass;
+ type = Expr.Type;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ bool last_check = ec.CheckState;
+ bool last_const_check = ec.ConstantCheckState;
+
+ ec.CheckState = false;
+ ec.ConstantCheckState = false;
+ Expr.Emit (ec);
+ ec.CheckState = last_check;
+ ec.ConstantCheckState = last_const_check;
+ }
+
+ }
+
+ /// <summary>
+ /// An Element Access expression.
+ ///
+ /// During semantic analysis these are transformed into
+ /// IndexerAccess or ArrayAccess
+ /// </summary>
+ public class ElementAccess : Expression {
+ public ArrayList Arguments;
+ public Expression Expr;
+
+ public ElementAccess (Expression e, ArrayList e_list, Location l)
+ {
+ Expr = e;
+
+ loc = l;
+
+ if (e_list == null)
+ return;
+
+ Arguments = new ArrayList ();
+ foreach (Expression tmp in e_list)
+ Arguments.Add (new Argument (tmp, Argument.AType.Expression));
+
+ }
+
+ bool CommonResolve (EmitContext ec)
+ {
+ Expr = Expr.Resolve (ec);
+
+ if (Expr == null)
+ return false;
+
+ if (Arguments == null)
+ return false;
+
+ foreach (Argument a in Arguments){
+ if (!a.Resolve (ec, loc))
+ return false;
+ }
+
+ return true;
+ }
+
+ Expression MakePointerAccess ()
+ {
+ Type t = Expr.Type;
+
+ if (t == TypeManager.void_ptr_type){
+ Error (
+ 242,
+ "The array index operation is not valid for void pointers");
+ return null;
+ }
+ if (Arguments.Count != 1){
+ Error (
+ 196,
+ "A pointer must be indexed by a single value");
+ return null;
+ }
+ Expression p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr,
+ t, loc);
+ return new Indirection (p, loc);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ //
+ // We perform some simple tests, and then to "split" the emit and store
+ // code we create an instance of a different class, and return that.
+ //
+ // I am experimenting with this pattern.
+ //
+ Type t = Expr.Type;
+
+ if (t.IsArray)
+ return (new ArrayAccess (this, loc)).Resolve (ec);
+ else if (t.IsPointer)
+ return MakePointerAccess ();
+ else
+ return (new IndexerAccess (this, loc)).Resolve (ec);
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ Type t = Expr.Type;
+ if (t.IsArray)
+ return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
+ else if (t.IsPointer)
+ return MakePointerAccess ();
+ else
+ return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be reached");
+ }
+ }
+
+ /// <summary>
+ /// Implements array access
+ /// </summary>
+ public class ArrayAccess : Expression, IAssignMethod, IMemoryLocation {
+ //
+ // Points to our "data" repository
+ //
+ ElementAccess ea;
+
+ LocalTemporary [] cached_locations;
+
+ public ArrayAccess (ElementAccess ea_data, Location l)
+ {
+ ea = ea_data;
+ eclass = ExprClass.Variable;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ ExprClass eclass = ea.Expr.eclass;
+
+#if false
+ // As long as the type is valid
+ if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
+ eclass == ExprClass.Value)) {
+ ea.Expr.Error118 ("variable or value");
+ return null;
+ }
+#endif
+
+ Type t = ea.Expr.Type;
+/*
+ if (t == typeof (System.Object))
+ {
+ // We can't resolve now, but we
+ // have to try to access the array with a call
+ // to LateIndexGet in the runtime
+
+ Expression lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
+ Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
+ ArrayList adims = new ArrayList();
+
+ ArrayList ainit = new ArrayList();
+ foreach (Argument a in ea.Arguments)
+ ainit.Add ((Expression) a.Expr);
+
+ adims.Add ((Expression) new IntLiteral (ea.Arguments.Count));
+
+ Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
+
+ ArrayList args = new ArrayList();
+ args.Add (new Argument(ea.Expr, Argument.AType.Expression));
+ args.Add (new Argument(oace, Argument.AType.Expression));
+ args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
+
+ Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
+ lig_call = lig_call.Resolve(ec);
+ return lig_call;
+ }
+*/
+ if (t.GetArrayRank () != ea.Arguments.Count){
+ ea.Error (22,
+ "Incorrect number of indexes for array " +
+ " expected: " + t.GetArrayRank () + " got: " +
+ ea.Arguments.Count);
+ return null;
+ }
+ type = TypeManager.TypeToCoreType (t.GetElementType ());
+ if (type.IsPointer && !ec.InUnsafe){
+ UnsafeError (ea.Location);
+ return null;
+ }
+
+ foreach (Argument a in ea.Arguments){
+ Type argtype = a.Type;
+
+ if (argtype == TypeManager.int32_type ||
+ argtype == TypeManager.uint32_type ||
+ argtype == TypeManager.int64_type ||
+ argtype == TypeManager.uint64_type)
+ continue;
+
+ //
+ // Mhm. This is strage, because the Argument.Type is not the same as
+ // Argument.Expr.Type: the value changes depending on the ref/out setting.
+ //
+ // Wonder if I will run into trouble for this.
+ //
+ a.Expr = ExpressionToArrayArgument (ec, a.Expr, ea.Location);
+ if (a.Expr == null)
+ return null;
+ }
+
+ eclass = ExprClass.Variable;
+
+ return this;
+ }
+
+ /// <summary>
+ /// Emits the right opcode to load an object of Type 't'
+ /// from an array of T
+ /// </summary>
+ static public void EmitLoadOpcode (ILGenerator ig, Type type)
+ {
+ if (type == TypeManager.byte_type || type == TypeManager.bool_type)
+ ig.Emit (OpCodes.Ldelem_U1);
+ else if (type == TypeManager.sbyte_type)
+ ig.Emit (OpCodes.Ldelem_I1);
+ else if (type == TypeManager.short_type)
+ ig.Emit (OpCodes.Ldelem_I2);
+ else if (type == TypeManager.ushort_type || type == TypeManager.char_type)
+ ig.Emit (OpCodes.Ldelem_U2);
+ else if (type == TypeManager.int32_type)
+ ig.Emit (OpCodes.Ldelem_I4);
+ else if (type == TypeManager.uint32_type)
+ ig.Emit (OpCodes.Ldelem_U4);
+ else if (type == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Ldelem_I8);
+ else if (type == TypeManager.int64_type)
+ ig.Emit (OpCodes.Ldelem_I8);
+ else if (type == TypeManager.float_type)
+ ig.Emit (OpCodes.Ldelem_R4);
+ else if (type == TypeManager.double_type)
+ ig.Emit (OpCodes.Ldelem_R8);
+ else if (type == TypeManager.intptr_type)
+ ig.Emit (OpCodes.Ldelem_I);
+ else if (type.IsValueType){
+ ig.Emit (OpCodes.Ldelema, type);
+ ig.Emit (OpCodes.Ldobj, type);
+ } else
+ ig.Emit (OpCodes.Ldelem_Ref);
+ }
+
+ /// <summary>
+ /// Emits the right opcode to store an object of Type 't'
+ /// from an array of T.
+ /// </summary>
+ static public void EmitStoreOpcode (ILGenerator ig, Type t)
+ {
+ t = TypeManager.TypeToCoreType (t);
+ if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
+ t = TypeManager.EnumToUnderlying (t);
+ if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
+ t == TypeManager.bool_type)
+ ig.Emit (OpCodes.Stelem_I1);
+ else if (t == TypeManager.short_type || t == TypeManager.ushort_type || t == TypeManager.char_type)
+ ig.Emit (OpCodes.Stelem_I2);
+ else if (t == TypeManager.int32_type || t == TypeManager.uint32_type)
+ ig.Emit (OpCodes.Stelem_I4);
+ else if (t == TypeManager.int64_type || t == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Stelem_I8);
+ else if (t == TypeManager.float_type)
+ ig.Emit (OpCodes.Stelem_R4);
+ else if (t == TypeManager.double_type)
+ ig.Emit (OpCodes.Stelem_R8);
+ else if (t == TypeManager.intptr_type)
+ ig.Emit (OpCodes.Stelem_I);
+ else if (t.IsValueType){
+ ig.Emit (OpCodes.Stobj, t);
+ } else
+ ig.Emit (OpCodes.Stelem_Ref);
+ }
+
+ MethodInfo FetchGetMethod ()
+ {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ int arg_count = ea.Arguments.Count;
+ Type [] args = new Type [arg_count];
+ MethodInfo get;
+
+ for (int i = 0; i < arg_count; i++){
+ //args [i++] = a.Type;
+ args [i] = TypeManager.int32_type;
+ }
+
+ get = mb.GetArrayMethod (
+ ea.Expr.Type, "Get",
+ CallingConventions.HasThis |
+ CallingConventions.Standard,
+ type, args);
+ return get;
+ }
+
+
+ MethodInfo FetchAddressMethod ()
+ {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ int arg_count = ea.Arguments.Count;
+ Type [] args = new Type [arg_count];
+ MethodInfo address;
+ string ptr_type_name;
+ Type ret_type;
+
+ ptr_type_name = type.FullName + "&";
+ ret_type = Type.GetType (ptr_type_name);
+
+ //
+ // It is a type defined by the source code we are compiling
+ //
+ if (ret_type == null){
+ ret_type = mb.GetType (ptr_type_name);
+ }
+
+ for (int i = 0; i < arg_count; i++){
+ //args [i++] = a.Type;
+ args [i] = TypeManager.int32_type;
+ }
+
+ address = mb.GetArrayMethod (
+ ea.Expr.Type, "Address",
+ CallingConventions.HasThis |
+ CallingConventions.Standard,
+ ret_type, args);
+
+ return address;
+ }
+
+ //
+ // Load the array arguments into the stack.
+ //
+ // If we have been requested to cache the values (cached_locations array
+ // initialized), then load the arguments the first time and store them
+ // in locals. otherwise load from local variables.
+ //
+ void LoadArrayAndArguments (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (cached_locations == null){
+ ea.Expr.Emit (ec);
+ foreach (Argument a in ea.Arguments){
+ Type argtype = a.Expr.Type;
+
+ a.Expr.Emit (ec);
+
+ if (argtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I);
+ else if (argtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I_Un);
+ }
+ return;
+ }
+
+ if (cached_locations [0] == null){
+ cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type);
+ ea.Expr.Emit (ec);
+ ig.Emit (OpCodes.Dup);
+ cached_locations [0].Store (ec);
+
+ int j = 1;
+
+ foreach (Argument a in ea.Arguments){
+ Type argtype = a.Expr.Type;
+
+ cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */);
+ a.Expr.Emit (ec);
+ if (argtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I);
+ else if (argtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_Ovf_I_Un);
+
+ ig.Emit (OpCodes.Dup);
+ cached_locations [j].Store (ec);
+ j++;
+ }
+ return;
+ }
+
+ foreach (LocalTemporary lt in cached_locations)
+ lt.Emit (ec);
+ }
+
+ public new void CacheTemporaries (EmitContext ec)
+ {
+ cached_locations = new LocalTemporary [ea.Arguments.Count + 1];
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int rank = ea.Expr.Type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+
+ LoadArrayAndArguments (ec);
+
+ if (rank == 1)
+ EmitLoadOpcode (ig, type);
+ else {
+ MethodInfo method;
+
+ method = FetchGetMethod ();
+ ig.Emit (OpCodes.Call, method);
+ }
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ int rank = ea.Expr.Type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+ Type t = source.Type;
+
+ LoadArrayAndArguments (ec);
+
+ //
+ // The stobj opcode used by value types will need
+ // an address on the stack, not really an array/array
+ // pair
+ //
+ if (rank == 1){
+ if (t == TypeManager.enum_type || t == TypeManager.decimal_type ||
+ (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t)))
+ ig.Emit (OpCodes.Ldelema, t);
+ }
+
+ source.Emit (ec);
+
+ if (rank == 1)
+ EmitStoreOpcode (ig, t);
+ else {
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+ int arg_count = ea.Arguments.Count;
+ Type [] args = new Type [arg_count + 1];
+ MethodInfo set;
+
+ for (int i = 0; i < arg_count; i++){
+ //args [i++] = a.Type;
+ args [i] = TypeManager.int32_type;
+ }
+
+ args [arg_count] = type;
+
+ set = mb.GetArrayMethod (
+ ea.Expr.Type, "Set",
+ CallingConventions.HasThis |
+ CallingConventions.Standard,
+ TypeManager.void_type, args);
+
+ ig.Emit (OpCodes.Call, set);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ int rank = ea.Expr.Type.GetArrayRank ();
+ ILGenerator ig = ec.ig;
+
+ LoadArrayAndArguments (ec);
+
+ if (rank == 1){
+ ig.Emit (OpCodes.Ldelema, type);
+ } else {
+ MethodInfo address = FetchAddressMethod ();
+ ig.Emit (OpCodes.Call, address);
+ }
+ }
+ }
+
+
+ class Indexers {
+ public ArrayList getters, setters;
+ static Hashtable map;
+
+ static Indexers ()
+ {
+ map = new Hashtable ();
+ }
+
+ Indexers (MemberInfo [] mi)
+ {
+ foreach (PropertyInfo property in mi){
+ MethodInfo get, set;
+
+ get = property.GetGetMethod (true);
+ if (get != null){
+ if (getters == null)
+ getters = new ArrayList ();
+
+ getters.Add (get);
+ }
+
+ set = property.GetSetMethod (true);
+ if (set != null){
+ if (setters == null)
+ setters = new ArrayList ();
+ setters.Add (set);
+ }
+ }
+ }
+
+ static private Indexers GetIndexersForTypeOrInterface (Type caller_type, Type lookup_type)
+ {
+ Indexers ix = (Indexers) map [lookup_type];
+
+ if (ix != null)
+ return ix;
+
+ string p_name = TypeManager.IndexerPropertyName (lookup_type);
+
+ MemberInfo [] mi = TypeManager.MemberLookup (
+ caller_type, lookup_type, MemberTypes.Property,
+ BindingFlags.Public | BindingFlags.Instance, p_name);
+
+ if (mi == null || mi.Length == 0)
+ return null;
+
+ ix = new Indexers (mi);
+ map [lookup_type] = ix;
+
+ return ix;
+ }
+
+ static public Indexers GetIndexersForType (Type caller_type, Type lookup_type, Location loc)
+ {
+ Indexers ix = (Indexers) map [lookup_type];
+
+ if (ix != null)
+ return ix;
+
+ ix = GetIndexersForTypeOrInterface (caller_type, lookup_type);
+ if (ix != null)
+ return ix;
+
+ Type [] ifaces = TypeManager.GetInterfaces (lookup_type);
+ if (ifaces != null) {
+ foreach (Type itype in ifaces) {
+ ix = GetIndexersForTypeOrInterface (caller_type, itype);
+ if (ix != null)
+ return ix;
+ }
+ }
+
+ Report.Error (21, loc,
+ "Type '" + TypeManager.MonoBASIC_Name (lookup_type) +
+ "' does not have any indexers defined");
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Expressions that represent an indexer call.
+ /// </summary>
+ public class IndexerAccess : Expression, IAssignMethod {
+ //
+ // Points to our "data" repository
+ //
+ MethodInfo get, set;
+ Indexers ilist;
+ ArrayList set_arguments;
+ bool is_base_indexer;
+
+ protected Type indexer_type;
+ protected Type current_type;
+ protected Expression instance_expr;
+ protected ArrayList arguments;
+
+ public IndexerAccess (ElementAccess ea, Location loc)
+ : this (ea.Expr, false, loc)
+ {
+ this.arguments = ea.Arguments;
+ }
+
+ protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
+ Location loc)
+ {
+ this.instance_expr = instance_expr;
+ this.is_base_indexer = is_base_indexer;
+ this.eclass = ExprClass.Value;
+ this.loc = loc;
+ }
+
+ protected virtual bool CommonResolve (EmitContext ec)
+ {
+ indexer_type = instance_expr.Type;
+ current_type = ec.ContainerType;
+
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ //
+ // Step 1: Query for all 'Item' *properties*. Notice
+ // that the actual methods are pointed from here.
+ //
+ // This is a group of properties, piles of them.
+
+ if (ilist == null)
+ ilist = Indexers.GetIndexersForType (
+ current_type, indexer_type, loc);
+
+ //
+ // Step 2: find the proper match
+ //
+ if (ilist != null && ilist.getters != null && ilist.getters.Count > 0)
+ get = (MethodInfo) Invocation.OverloadResolve (
+ ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
+
+ if (get == null){
+ Error (154, "indexer can not be used in this context, because " +
+ "it lacks a 'get' accessor");
+ return null;
+ }
+
+ type = get.ReturnType;
+ if (type.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
+
+ eclass = ExprClass.IndexerAccess;
+ return this;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
+ {
+ if (!CommonResolve (ec))
+ return null;
+
+ Type right_type = right_side.Type;
+
+ if (ilist == null)
+ ilist = Indexers.GetIndexersForType (
+ current_type, indexer_type, loc);
+
+ if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
+ set_arguments = (ArrayList) arguments.Clone ();
+ set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
+
+ set = (MethodInfo) Invocation.OverloadResolve (
+ ec, new MethodGroupExpr (ilist.setters, loc), set_arguments, loc);
+ }
+
+ if (set == null){
+ Error (200, "indexer X.this [" + TypeManager.MonoBASIC_Name (right_type) +
+ "] lacks a 'set' accessor");
+ return null;
+ }
+
+ type = TypeManager.void_type;
+ eclass = ExprClass.IndexerAccess;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Invocation.EmitCall (ec, false, false, instance_expr, get, arguments, loc);
+ }
+
+ //
+ // source is ignored, because we already have a copy of it from the
+ // LValue resolution and we have already constructed a pre-cached
+ // version of the arguments (ea.set_arguments);
+ //
+ public void EmitAssign (EmitContext ec, Expression source)
+ {
+ Invocation.EmitCall (ec, false, false, instance_expr, set, set_arguments, loc);
+ }
+ }
+
+ /// <summary>
+ /// The base operator for method names
+ /// </summary>
+ public class BaseAccess : Expression {
+ public string member;
+
+ public BaseAccess (string member, Location l)
+ {
+ this.member = member;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expression member_lookup;
+ Type current_type = ec.ContainerType;
+ Type base_type = current_type.BaseType;
+ Expression e;
+
+ if (ec.IsStatic){
+ Error (1511, "Keyword MyBase is not allowed in static method");
+ return null;
+ }
+
+ if (member == "New")
+ member = ".ctor";
+
+ member_lookup = MemberLookup (ec, base_type, base_type, member,
+ AllMemberTypes, AllBindingFlags, loc);
+
+ if (member_lookup == null) {
+ Error (30456,
+ TypeManager.MonoBASIC_Name (base_type) + " does not " +
+ "contain a definition for '" + member + "'");
+ return null;
+ }
+
+ Expression left;
+
+ if (ec.IsStatic)
+ left = new TypeExpr (base_type, loc);
+ else
+ left = ec.This;
+
+ e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
+
+ if (e is PropertyExpr){
+ PropertyExpr pe = (PropertyExpr) e;
+
+ pe.IsBase = true;
+ }
+
+ return e;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should never be called");
+ }
+ }
+
+ /// <summary>
+ /// The base indexer operator
+ /// </summary>
+ public class BaseIndexerAccess : IndexerAccess {
+ public BaseIndexerAccess (ArrayList args, Location loc)
+ : base (null, true, loc)
+ {
+ arguments = new ArrayList ();
+ foreach (Expression tmp in args)
+ arguments.Add (new Argument (tmp, Argument.AType.Expression));
+ }
+
+ protected override bool CommonResolve (EmitContext ec)
+ {
+ instance_expr = ec.This;
+
+ current_type = ec.ContainerType.BaseType;
+ indexer_type = current_type;
+
+ foreach (Argument a in arguments){
+ if (!a.Resolve (ec, loc))
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// This class exists solely to pass the Type around and to be a dummy
+ /// that can be passed to the conversion functions (this is used by
+ /// foreach implementation to typecast the object return value from
+ /// get_Current into the proper type. All code has been generated and
+ /// we only care about the side effect conversions to be performed
+ ///
+ /// This is also now used as a placeholder where a no-action expression
+ /// is needed (the 'New' class).
+ /// </summary>
+ public class EmptyExpression : Expression {
+ public EmptyExpression ()
+ {
+ type = TypeManager.object_type;
+ eclass = ExprClass.Value;
+ loc = Location.Null;
+ }
+
+ public EmptyExpression (Type t)
+ {
+ type = t;
+ eclass = ExprClass.Value;
+ loc = Location.Null;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ // nothing, as we only exist to not do anything.
+ }
+
+ //
+ // This is just because we might want to reuse this bad boy
+ // instead of creating gazillions of EmptyExpressions.
+ // (CanConvertImplicit uses it)
+ //
+ public void SetType (Type t)
+ {
+ type = t;
+ }
+ }
+
+ public class UserCast : Expression {
+ MethodBase method;
+ Expression source;
+
+ public UserCast (MethodInfo method, Expression source, Location l)
+ {
+ this.method = method;
+ this.source = source;
+ type = method.ReturnType;
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ source.Emit (ec);
+
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+ }
+ }
+
+ // <summary>
+ // This class is used to "construct" the type during a typecast
+ // operation. Since the Type.GetType class in .NET can parse
+ // the type specification, we just use this to construct the type
+ // one bit at a time.
+ // </summary>
+ public class ComposedCast : Expression, ITypeExpression {
+ Expression left;
+ string dim;
+
+ public ComposedCast (Expression left, string dim, Location l)
+ {
+ this.left = left;
+ this.dim = dim;
+ loc = l;
+ }
+
+ public Expression DoResolveType (EmitContext ec)
+ {
+ Type ltype = ec.DeclSpace.ResolveType (left, false, loc);
+ if (ltype == null)
+ return null;
+
+ //
+ // ltype.Fullname is already fully qualified, so we can skip
+ // a lot of probes, and go directly to TypeManager.LookupType
+ //
+ string cname = ltype.FullName + dim;
+ type = TypeManager.LookupTypeDirect (cname);
+ if (type == null){
+ //
+ // For arrays of enumerations we are having a problem
+ // with the direct lookup. Need to investigate.
+ //
+ // For now, fall back to the full lookup in that case.
+ //
+ type = RootContext.LookupType (
+ ec.DeclSpace, cname, false, loc);
+
+ if (type == null)
+ return null;
+ }
+
+ if (!ec.ResolvingTypeTree){
+ //
+ // If the above flag is set, this is being invoked from the ResolveType function.
+ // Upper layers take care of the type validity in this context.
+ //
+ if (!ec.InUnsafe && type.IsPointer){
+ UnsafeError (loc);
+ return null;
+ }
+ }
+
+ eclass = ExprClass.Type;
+ return this;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return DoResolveType (ec);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("This should never be called");
+ }
+
+ public override string ToString ()
+ {
+ return left + dim;
+ }
+ }
+
+ //
+ // This class is used to represent the address of an array, used
+ // only by the Fixed statement, this is like the C "&a [0]" construct.
+ //
+ public class ArrayPtr : Expression {
+ Expression array;
+
+ public ArrayPtr (Expression array, Location l)
+ {
+ Type array_type = array.Type.GetElementType ();
+
+ this.array = array;
+
+ string array_ptr_type_name = array_type.FullName + "*";
+
+ type = Type.GetType (array_ptr_type_name);
+ if (type == null){
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+
+ type = mb.GetType (array_ptr_type_name);
+ }
+
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ array.Emit (ec);
+ IntLiteral.EmitInt (ig, 0);
+ ig.Emit (OpCodes.Ldelema, array.Type.GetElementType ());
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ return this;
+ }
+ }
+
+ //
+ // Used by the fixed statement
+ //
+ public class StringPtr : Expression {
+ LocalBuilder b;
+
+ public StringPtr (LocalBuilder b, Location l)
+ {
+ this.b = b;
+ eclass = ExprClass.Value;
+ type = TypeManager.char_ptr_type;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ // This should never be invoked, we are born in fully
+ // initialized state.
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldloc, b);
+ ig.Emit (OpCodes.Conv_I);
+ ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
+ ig.Emit (OpCodes.Add);
+ }
+ }
+
+ //
+ // Implements the 'stackalloc' keyword
+ //
+ public class StackAlloc : Expression {
+ Type otype;
+ Expression t;
+ Expression count;
+
+ public StackAlloc (Expression type, Expression count, Location l)
+ {
+ t = type;
+ this.count = count;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ count = count.Resolve (ec);
+ if (count == null)
+ return null;
+
+ if (count.Type != TypeManager.int32_type){
+ count = ConvertImplicitRequired (ec, count, TypeManager.int32_type, loc);
+ if (count == null)
+ return null;
+ }
+
+ if (ec.InCatch || ec.InFinally){
+ Error (255,
+ "stackalloc can not be used in a catch or finally block");
+ return null;
+ }
+
+ otype = ec.DeclSpace.ResolveType (t, false, loc);
+
+ if (otype == null)
+ return null;
+
+ if (!TypeManager.VerifyUnManaged (otype, loc))
+ return null;
+
+ string ptr_name = otype.FullName + "*";
+ type = Type.GetType (ptr_name);
+ if (type == null){
+ ModuleBuilder mb = CodeGen.ModuleBuilder;
+
+ type = mb.GetType (ptr_name);
+ }
+ eclass = ExprClass.Value;
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ int size = GetTypeSize (otype);
+ ILGenerator ig = ec.ig;
+
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, otype);
+ else
+ IntConstant.EmitInt (ig, size);
+ count.Emit (ec);
+ ig.Emit (OpCodes.Mul);
+ ig.Emit (OpCodes.Localloc);
+ }
+ }
+}