* ConsoleLogger.cs (no_colors): Rename to ..
[mcs.git] / mcs / dynamic.cs
blob5355f7128b5a61f2a929ba39cbf389333e491348
1 //
2 // dynamic.cs: support for dynamic expressions
3 //
4 // Authors: Marek Safar (marek.safar@gmail.com)
5 //
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
7 //
8 // Copyright 2009 Novell, Inc
9 //
11 using System;
12 using System.Collections;
14 #if NET_4_0
15 using System.Dynamic;
16 #endif
18 namespace Mono.CSharp
20 class DynamicTypeExpr : TypeExpr
22 public DynamicTypeExpr (Location loc)
24 this.loc = loc;
26 type = InternalType.Dynamic;
27 eclass = ExprClass.Type;
30 public override bool CheckAccessLevel (IMemberContext ds)
32 return true;
35 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
37 return this;
42 // Expression created from runtime dynamic object value
44 public class RuntimeValueExpression : Expression, IAssignMethod
46 #if !NET_4_0
47 public class DynamicMetaObject { public Type RuntimeType; }
48 #endif
50 readonly DynamicMetaObject obj;
52 // When strongly typed expression is required
53 readonly bool typed;
55 public RuntimeValueExpression (DynamicMetaObject obj, bool typed)
57 this.obj = obj;
58 this.typed = typed;
59 this.type = obj.RuntimeType;
60 this.eclass = ExprClass.Variable;
63 public override Expression CreateExpressionTree (ResolveContext ec)
65 throw new NotImplementedException ();
68 public override Expression DoResolve (ResolveContext ec)
70 return this;
73 public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
75 return this;
78 public override void Emit (EmitContext ec)
80 throw new NotImplementedException ();
83 #region IAssignMethod Members
85 public void Emit (EmitContext ec, bool leave_copy)
87 throw new NotImplementedException ();
90 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
92 throw new NotImplementedException ();
95 #endregion
97 #if NET_4_0
98 public override System.Linq.Expressions.Expression MakeExpression (BuilderContext ctx)
100 if (typed && obj.Expression.Type != type)
101 return System.Linq.Expressions.Expression.Convert (obj.Expression, type);
103 return obj.Expression;
105 #endif
107 public DynamicMetaObject MetaObject {
108 get { return obj; }
112 interface IDynamicBinder
114 Expression CreateCallSiteBinder (ResolveContext ec, Arguments args);
117 class DynamicExpressionStatement : ExpressionStatement
119 class StaticDataClass : CompilerGeneratedClass
121 public StaticDataClass ()
122 : base (new RootDeclSpace (new NamespaceEntry (null, null, null)),
123 new MemberName (CompilerGeneratedClass.MakeName (null, "c", "DynamicSites", 0)),
124 Modifiers.INTERNAL | Modifiers.STATIC)
126 ModFlags &= ~Modifiers.SEALED;
130 static StaticDataClass global_site_container;
131 static int field_counter;
132 static int container_counter;
134 readonly Arguments arguments;
135 protected IDynamicBinder binder;
136 Expression binder_expr;
138 public DynamicExpressionStatement (IDynamicBinder binder, Arguments args, Location loc)
140 this.binder = binder;
141 this.arguments = args;
142 this.loc = loc;
145 public Arguments Arguments {
146 get {
147 return arguments;
151 static TypeContainer CreateSiteContainer ()
153 if (global_site_container == null) {
154 global_site_container = new StaticDataClass ();
155 RootContext.ToplevelTypes.AddCompilerGeneratedClass (global_site_container);
156 global_site_container.DefineType ();
157 global_site_container.Define ();
158 // global_site_container.EmitType ();
160 RootContext.RegisterCompilerGeneratedType (global_site_container.TypeBuilder);
163 return global_site_container;
166 static Field CreateSiteField (FullNamedExpression type)
168 TypeContainer site_container = CreateSiteContainer ();
169 Field f = new Field (site_container, type, Modifiers.PUBLIC | Modifiers.STATIC,
170 new MemberName ("Site" + field_counter++), null);
171 f.Define ();
173 site_container.AddField (f);
174 return f;
177 public override Expression CreateExpressionTree (ResolveContext ec)
179 throw new NotImplementedException ();
182 public override Expression DoResolve (ResolveContext ec)
184 if (eclass != ExprClass.Invalid)
185 return this;
187 if (TypeManager.call_site_type == null)
188 TypeManager.call_site_type = TypeManager.CoreLookupType (ec.Compiler,
189 "System.Runtime.CompilerServices", "CallSite", Kind.Class, true);
191 if (TypeManager.generic_call_site_type == null)
192 TypeManager.generic_call_site_type = TypeManager.CoreLookupType (ec.Compiler,
193 "System.Runtime.CompilerServices", "CallSite`1", Kind.Class, true);
195 eclass = ExprClass.Value;
197 if (type == null)
198 type = InternalType.Dynamic;
200 binder_expr = binder.CreateCallSiteBinder (ec, arguments);
201 return this;
204 public override void Emit (EmitContext ec)
206 EmitCall (ec, false);
209 public override void EmitStatement (EmitContext ec)
211 EmitCall (ec, true);
214 void EmitCall (EmitContext ec, bool isStatement)
216 int dyn_args_count = arguments == null ? 0 : arguments.Count;
217 TypeExpr site_type = CreateSiteType (RootContext.ToplevelTypes.Compiler, isStatement, dyn_args_count);
218 FieldExpr site_field_expr = new FieldExpr (CreateSiteField (site_type).FieldBuilder, loc);
220 SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
222 Arguments args = new Arguments (1);
223 args.Add (new Argument (binder_expr));
224 StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (site_type, "Create"), args)));
226 BlockContext bc = new BlockContext (ec.MemberContext, null, TypeManager.void_type);
227 if (s.Resolve (bc)) {
228 Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc);
229 init.Emit (ec);
232 args = new Arguments (1 + dyn_args_count);
233 args.Add (new Argument (site_field_expr));
234 if (arguments != null) {
235 foreach (Argument a in arguments) {
236 if (a is NamedArgument) {
237 // Name is not valid in this context
238 args.Add (new Argument (a.Expr, a.ArgType));
239 continue;
242 args.Add (a);
246 ResolveContext rc = new ResolveContext (ec.MemberContext);
247 Expression target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (rc), args, loc).Resolve (rc);
248 if (target != null)
249 target.Emit (ec);
251 SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
254 public static MemberAccess GetBinderNamespace (Location loc)
256 return new MemberAccess (new MemberAccess (
257 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "Microsoft", loc), "CSharp", loc), "RuntimeBinder", loc);
260 TypeExpr CreateSiteType (CompilerContext ctx, bool isStatement, int dyn_args_count)
262 int default_args = isStatement ? 1 : 2;
264 bool has_ref_out_argument = false;
265 FullNamedExpression[] targs = new FullNamedExpression[dyn_args_count + default_args];
266 targs [0] = new TypeExpression (TypeManager.call_site_type, loc);
267 for (int i = 0; i < dyn_args_count; ++i) {
268 Type arg_type;
269 Argument a = arguments [i];
270 if (a.Type == TypeManager.null_type)
271 arg_type = TypeManager.object_type;
272 else
273 arg_type = TypeManager.TypeToReflectionType (a.Type);
275 if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
276 has_ref_out_argument = true;
278 targs [i + 1] = new TypeExpression (arg_type, loc);
281 TypeExpr del_type = null;
282 if (!has_ref_out_argument) {
283 string d_name = isStatement ? "Action`" : "Func`";
285 Type t = TypeManager.CoreLookupType (ctx, "System", d_name + (dyn_args_count + default_args), Kind.Delegate, false);
286 if (t != null) {
287 if (!isStatement)
288 targs[targs.Length - 1] = new TypeExpression (TypeManager.TypeToReflectionType (type), loc);
290 del_type = new GenericTypeExpr (t, new TypeArguments (targs), loc);
294 // No appropriate predefined delegate found
295 if (del_type == null) {
296 Type rt = isStatement ? TypeManager.void_type : type;
297 Parameter[] p = new Parameter [dyn_args_count + 1];
298 p[0] = new Parameter (targs [0], "p0", Parameter.Modifier.NONE, null, loc);
300 for (int i = 1; i < dyn_args_count + 1; ++i)
301 p[i] = new Parameter (targs[i], "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc);
303 TypeContainer parent = CreateSiteContainer ();
304 Delegate d = new Delegate (parent.NamespaceEntry, parent, new TypeExpression (rt, loc),
305 Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
306 new MemberName ("Container" + container_counter++.ToString ("X")),
307 new ParametersCompiled (p), null);
309 d.DefineType ();
310 d.Define ();
312 parent.AddDelegate (d);
313 del_type = new TypeExpression (d.TypeBuilder, loc);
316 TypeExpr site_type = new GenericTypeExpr (TypeManager.generic_call_site_type, new TypeArguments (del_type), loc);
317 return site_type;
320 public static void Reset ()
322 global_site_container = null;
323 field_counter = container_counter = 0;
328 // Dynamic member access compound assignment for events
330 class DynamicEventCompoundAssign : DynamicExpressionStatement, IDynamicBinder
332 string name;
333 ExpressionStatement assignment;
334 ExpressionStatement invoke;
336 public DynamicEventCompoundAssign (string name, Arguments args, ExpressionStatement assignment, ExpressionStatement invoke, Location loc)
337 : base (null, args, loc)
339 this.name = name;
340 this.assignment = assignment;
341 this.invoke = invoke;
342 base.binder = this;
344 // Used by += or -= only
345 type = TypeManager.bool_type;
348 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
350 Arguments binder_args = new Arguments (2);
351 MemberAccess binder = GetBinderNamespace (loc);
353 binder_args.Add (new Argument (new StringLiteral (name, loc)));
354 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
356 return new New (new MemberAccess (binder, "CSharpIsEventBinder", loc), binder_args, loc);
359 public override void EmitStatement (EmitContext ec)
361 Statement cond = new If (
362 new Binary (Binary.Operator.Equality, this, new BoolLiteral (true, loc)),
363 new StatementExpression (invoke),
364 new StatementExpression (assignment),
365 loc);
366 cond.Emit (ec);
370 class DynamicConversion : DynamicExpressionStatement, IDynamicBinder
372 bool is_explicit;
374 public DynamicConversion (Type targetType, bool isExplicit, Arguments args, Location loc)
375 : base (null, args, loc)
377 type = targetType;
378 is_explicit = isExplicit;
379 base.binder = this;
382 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
384 Arguments binder_args = new Arguments (2);
385 MemberAccess binder = GetBinderNamespace (loc);
387 binder_args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
388 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (binder, "CSharpConversionKind", loc),
389 is_explicit ? "ExplicitConversion" : "ImplicitConversion", loc)));
390 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
392 return new New (new MemberAccess (binder, "CSharpConvertBinder", loc), binder_args, loc);
396 class DynamicIndexBinder : DynamicExpressionStatement, IDynamicBinder, IAssignMethod
398 readonly bool isSet;
400 public DynamicIndexBinder (bool isSet, Arguments args, Location loc)
401 : base (null, args, loc)
403 base.binder = this;
404 this.isSet = isSet;
407 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
409 Arguments binder_args = new Arguments (2);
410 MemberAccess binder = GetBinderNamespace (loc);
412 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
413 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
415 return new New (new MemberAccess (binder, isSet ? "CSharpSetIndexBinder" : "CSharpGetIndexBinder", loc), binder_args, loc);
418 #region IAssignMethod Members
420 public void Emit (EmitContext ec, bool leave_copy)
422 throw new NotImplementedException ();
425 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
427 EmitStatement (ec);
430 #endregion
433 class DynamicInvocation : DynamicExpressionStatement, IDynamicBinder
435 ATypeNameExpression member;
437 public DynamicInvocation (ATypeNameExpression member, Arguments args, Location loc)
438 : base (null, args, loc)
440 base.binder = this;
441 this.member = member;
444 public DynamicInvocation (ATypeNameExpression member, Arguments args, Type type, Location loc)
445 : this (member, args, loc)
447 // When a return type is known not to be dynamic
448 this.type = type;
451 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
453 Arguments binder_args = new Arguments (member != null ? 5 : 3);
454 MemberAccess binder = GetBinderNamespace (loc);
455 bool is_member_access = member is MemberAccess;
457 string call_flags;
458 if (!is_member_access && member is SimpleName) {
459 call_flags = "SimpleNameCall";
460 is_member_access = true;
461 } else {
462 call_flags = "None";
465 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (binder, "CSharpCallFlags", loc), call_flags, loc)));
467 if (is_member_access)
468 binder_args.Add (new Argument (new StringLiteral (member.Name, member.Location)));
470 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
472 if (member != null && member.HasTypeArguments) {
473 TypeArguments ta = member.TypeArguments;
474 if (ta.Resolve (ec)) {
475 ArrayList targs = new ArrayList (ta.Count);
476 foreach (Type t in ta.Arguments)
477 targs.Add (new TypeOf (new TypeExpression (t, loc), loc));
479 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", targs, loc)));
481 } else if (is_member_access) {
482 binder_args.Add (new Argument (new NullLiteral (loc)));
485 Expression real_args;
486 if (args == null) {
487 // Cannot be null because .NET trips over
488 real_args = new ArrayCreation (new MemberAccess (binder, "CSharpArgumentInfo", loc), "[]", new ArrayList (0), loc);
489 } else {
490 real_args = new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc);
493 binder_args.Add (new Argument (real_args));
495 return new New (new MemberAccess (binder,
496 is_member_access ? "CSharpInvokeMemberBinder" : "CSharpInvokeBinder", loc), binder_args, loc);
500 class DynamicMemberBinder : DynamicExpressionStatement, IDynamicBinder, IAssignMethod
502 readonly bool isSet;
503 readonly string name;
505 public DynamicMemberBinder (bool isSet, string name, Arguments args, Location loc)
506 : base (null, args, loc)
508 base.binder = this;
509 this.isSet = isSet;
510 this.name = name;
513 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
515 Arguments binder_args = new Arguments (3);
516 MemberAccess binder = GetBinderNamespace (loc);
518 binder_args.Add (new Argument (new StringLiteral (name, loc)));
519 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
520 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
522 return new New (new MemberAccess (binder, isSet ? "CSharpSetMemberBinder" : "CSharpGetMemberBinder", loc), binder_args, loc);
525 #region IAssignMethod Members
527 public void Emit (EmitContext ec, bool leave_copy)
529 throw new NotImplementedException ();
532 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
534 EmitStatement (ec);
537 #endregion
540 class DynamicUnaryConversion : DynamicExpressionStatement, IDynamicBinder
542 string name;
544 public DynamicUnaryConversion (string name, Arguments args, Location loc)
545 : base (null, args, loc)
547 this.name = name;
548 base.binder = this;
549 if (name == "IsTrue" || name == "IsFalse")
550 type = TypeManager.bool_type;
553 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
555 Arguments binder_args = new Arguments (3);
557 MemberAccess sle = new MemberAccess (new MemberAccess (
558 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
560 MemberAccess binder = GetBinderNamespace (loc);
562 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), name, loc)));
563 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
564 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
566 return new New (new MemberAccess (binder, "CSharpUnaryOperationBinder", loc), binder_args, loc);