monotouch uses the real HttpWebRequest
[mcs.git] / mcs / argument.cs
blobe7b0ed4d643080d053bfcf3cd03b7a30841e5db9
1 //
2 // argument.cs: Argument expressions
3 //
4 // Author:
5 // Miguel de Icaza (miguel@ximain.com)
6 // Marek Safar (marek.safar@gmail.com)
7 //
8 // Dual licensed under the terms of the MIT X11 or GNU GPL
9 // Copyright 2003-2008 Novell, Inc.
12 using System;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
17 namespace Mono.CSharp
20 // Argument expression used for invocation
22 public class Argument
24 public enum AType : byte
26 Ref = 1, // ref modifier used
27 Out = 2, // out modifier used
28 Default = 3 // argument created from default parameter value
31 public readonly AType ArgType;
32 public Expression Expr;
34 public Argument (Expression expr, AType type)
36 this.Expr = expr;
37 this.ArgType = type;
40 public Argument (Expression expr)
42 if (expr == null)
43 throw new ArgumentNullException ();
45 this.Expr = expr;
48 public Type Type {
49 get { return Expr.Type; }
52 public Parameter.Modifier Modifier {
53 get {
54 switch (ArgType) {
55 case AType.Out:
56 return Parameter.Modifier.OUT;
58 case AType.Ref:
59 return Parameter.Modifier.REF;
61 default:
62 return Parameter.Modifier.NONE;
67 public virtual Expression CreateExpressionTree (EmitContext ec)
69 if (ArgType == AType.Default)
70 Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
72 return Expr.CreateExpressionTree (ec);
75 public string GetSignatureForError ()
77 if (Expr.eclass == ExprClass.MethodGroup)
78 return Expr.ExprClassName;
80 return TypeManager.CSharpName (Expr.Type);
83 public bool IsByRef {
84 get { return ArgType == AType.Ref || ArgType == AType.Out; }
87 public bool IsDefaultArgument {
88 get { return ArgType == AType.Default; }
91 public bool ResolveMethodGroup (EmitContext ec)
93 SimpleName sn = Expr as SimpleName;
94 if (sn != null)
95 Expr = sn.GetMethodGroup ();
97 // FIXME: csc doesn't report any error if you try to use `ref' or
98 // `out' in a delegate creation expression.
99 Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
100 if (Expr == null)
101 return false;
103 return true;
106 public void Resolve (EmitContext ec)
108 if (Expr == EmptyExpression.Null)
109 return;
111 using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
112 // Verify that the argument is readable
113 if (ArgType != AType.Out)
114 Expr = Expr.Resolve (ec);
116 // Verify that the argument is writeable
117 if (Expr != null && IsByRef)
118 Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess);
120 if (Expr == null)
121 Expr = EmptyExpression.Null;
125 public virtual void Emit (EmitContext ec)
127 if (!IsByRef) {
128 Expr.Emit (ec);
129 return;
132 AddressOp mode = AddressOp.Store;
133 if (ArgType == AType.Ref)
134 mode |= AddressOp.Load;
136 IMemoryLocation ml = (IMemoryLocation) Expr;
137 ParameterReference pr = ml as ParameterReference;
140 // ParameterReferences might already be references, so we want
141 // to pass just the value
143 if (pr != null && pr.IsRef)
144 pr.EmitLoad (ec);
145 else
146 ml.AddressOf (ec, mode);
149 public Argument Clone (CloneContext clonectx)
151 Argument a = (Argument) MemberwiseClone ();
152 a.Expr = Expr.Clone (clonectx);
153 return a;
157 public class NamedArgument : Argument
159 public readonly LocatedToken Name;
160 LocalTemporary variable;
162 public NamedArgument (LocatedToken name, Expression expr)
163 : base (expr)
165 Name = name;
168 public override Expression CreateExpressionTree (EmitContext ec)
170 Report.Error (853, Name.Location, "An expression tree cannot contain named argument");
171 return base.CreateExpressionTree (ec);
174 public override void Emit (EmitContext ec)
176 // TODO: Should guard against multiple emits
177 base.Emit (ec);
179 // Release temporary variable when used
180 if (variable != null)
181 variable.Release (ec);
184 public void EmitAssign (EmitContext ec)
186 Expr.Emit (ec);
187 variable = new LocalTemporary (Expr.Type);
188 variable.Store (ec);
190 Expr = variable;
194 public class Arguments
196 ArrayList args; // TODO: This should really be linked list
197 ArrayList reordered; // TODO: LinkedList
199 public Arguments (int capacity)
201 args = new ArrayList (capacity);
204 public int Add (Argument arg)
206 return args.Add (arg);
209 public void AddRange (Arguments args)
211 this.args.AddRange (args.args);
214 public ArrayList CreateDynamicBinderArguments ()
216 ArrayList all = new ArrayList (args.Count);
217 Location loc = Location.Null;
219 MemberAccess binder = DynamicExpressionStatement.GetBinderNamespace (loc);
221 foreach (Argument a in args) {
222 Arguments dargs = new Arguments (2);
224 // TODO: Inspect a.Type or a.Expression
226 // CSharpArgumentInfoFlags.None = 0
227 dargs.Add (new Argument (new IntLiteral (0, loc)));
229 // TODO: named
230 dargs.Add (new Argument (new NullLiteral (loc)));
231 all.Add (new New (new MemberAccess (binder, "CSharpArgumentInfo", loc), dargs, loc));
234 return all;
237 public static Arguments CreateForExpressionTree (EmitContext ec, Arguments args, params Expression[] e)
239 Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
240 for (int i = 0; i < e.Length; ++i) {
241 if (e [i] != null)
242 all.Add (new Argument (e[i]));
245 if (args != null) {
246 foreach (Argument a in args.args) {
247 Expression tree_arg = a.CreateExpressionTree (ec);
248 if (tree_arg != null)
249 all.Add (new Argument (tree_arg));
253 return all;
256 public void CheckArrayAsAttribute ()
258 foreach (Argument arg in args) {
259 // Type is undefined (was error 246)
260 if (arg.Type == null)
261 continue;
263 if (arg.Type.IsArray)
264 Report.Warning (3016, 1, arg.Expr.Location, "Arrays as attribute arguments are not CLS-compliant");
268 public Arguments Clone (CloneContext ctx)
270 Arguments cloned = new Arguments (args.Count);
271 foreach (Argument a in args)
272 cloned.Add (a.Clone (ctx));
274 return cloned;
277 public int Count {
278 get { return args.Count; }
282 // Emits a list of resolved Arguments
284 public void Emit (EmitContext ec)
286 Emit (ec, false, null);
290 // if `dup_args' is true, a copy of the arguments will be left
291 // on the stack. If `dup_args' is true, you can specify `this_arg'
292 // which will be duplicated before any other args. Only EmitCall
293 // should be using this interface.
295 public void Emit (EmitContext ec, bool dup_args, LocalTemporary this_arg)
297 LocalTemporary[] temps = null;
299 if (dup_args && Count != 0)
300 temps = new LocalTemporary [Count];
302 if (reordered != null && Count > 1) {
303 foreach (NamedArgument na in reordered)
304 na.EmitAssign (ec);
307 int i = 0;
308 foreach (Argument a in args) {
309 a.Emit (ec);
310 if (dup_args) {
311 ec.ig.Emit (OpCodes.Dup);
312 (temps [i++] = new LocalTemporary (a.Type)).Store (ec);
316 if (dup_args) {
317 if (this_arg != null)
318 this_arg.Emit (ec);
320 for (i = 0; i < temps.Length; i++) {
321 temps[i].Emit (ec);
322 temps[i].Release (ec);
327 public bool GetAttributableValue (EmitContext ec, out object[] values)
329 values = new object [args.Count];
330 for (int j = 0; j < values.Length; ++j) {
331 Argument a = this [j];
332 if (!a.Expr.GetAttributableValue (ec, a.Type, out values[j]))
333 return false;
336 return true;
339 public IEnumerator GetEnumerator ()
341 return args.GetEnumerator ();
344 public void Insert (int index, Argument arg)
346 args.Insert (index, arg);
349 public void MarkReorderedArgument (NamedArgument a)
352 // Constant expression can have no effect on left-to-right execution
354 if (a.Expr is Constant)
355 return;
357 if (reordered == null)
358 reordered = new ArrayList ();
360 reordered.Add (a);
364 // Returns dynamic when at least one argument is of dynamic type
366 public void Resolve (EmitContext ec, out bool dynamic)
368 dynamic = false;
369 foreach (Argument a in args) {
370 a.Resolve (ec);
371 dynamic |= TypeManager.IsDynamicType (a.Type);
375 public void MutateHoistedGenericType (AnonymousMethodStorey storey)
377 foreach (Argument a in args)
378 a.Expr.MutateHoistedGenericType (storey);
381 public void RemoveAt (int index)
383 args.RemoveAt (index);
386 public Argument this [int index] {
387 get { return (Argument) args [index]; }
388 set { args [index] = value; }