2 // dynamic.cs: support for dynamic expressions
4 // Authors: Marek Safar (marek.safar@gmail.com)
6 // Dual licensed under the terms of the MIT X11 or GNU GPL
8 // Copyright 2009 Novell, Inc
12 using System.Collections;
16 class DynamicTypeExpr : TypeExpr
18 public DynamicTypeExpr (Location loc)
22 type = InternalType.Dynamic;
23 eclass = ExprClass.Type;
26 public override bool CheckAccessLevel (IMemberContext ds)
31 protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
37 public class RuntimeExpression : Expression
39 public RuntimeExpression (Type type)
42 this.eclass = ExprClass.Value;
45 public override Expression CreateExpressionTree (ResolveContext ec)
47 throw new NotImplementedException ();
50 public override Expression DoResolve (ResolveContext ec)
55 public override void Emit (EmitContext ec)
57 throw new NotImplementedException ();
61 interface IDynamicBinder
63 Expression CreateCallSiteBinder (ResolveContext ec, Arguments args);
66 class DynamicExpressionStatement : ExpressionStatement
68 class StaticDataClass : CompilerGeneratedClass
70 public StaticDataClass ()
71 : base (new RootDeclSpace (new NamespaceEntry (null, null, null)),
72 new MemberName (CompilerGeneratedClass.MakeName (null, "c", "DynamicSites", 0)),
73 Modifiers.INTERNAL | Modifiers.STATIC)
75 ModFlags &= ~Modifiers.SEALED;
79 static StaticDataClass global_site_container;
80 static int field_counter;
81 static int container_counter;
83 readonly Arguments arguments;
84 protected IDynamicBinder binder;
86 public DynamicExpressionStatement (IDynamicBinder binder, Arguments args, Location loc)
89 this.arguments = args;
93 public Arguments Arguments {
99 static TypeContainer CreateSiteContainer ()
101 if (global_site_container == null) {
102 global_site_container = new StaticDataClass ();
103 RootContext.ToplevelTypes.AddCompilerGeneratedClass (global_site_container);
104 global_site_container.DefineType ();
105 global_site_container.Define ();
106 // global_site_container.EmitType ();
108 RootContext.RegisterCompilerGeneratedType (global_site_container.TypeBuilder);
111 return global_site_container;
114 static Field CreateSiteField (FullNamedExpression type)
116 TypeContainer site_container = CreateSiteContainer ();
117 Field f = new Field (site_container, type, Modifiers.PUBLIC | Modifiers.STATIC,
118 new MemberName ("Site" + field_counter++), null);
121 site_container.AddField (f);
125 public override Expression CreateExpressionTree (ResolveContext ec)
127 throw new NotImplementedException ();
130 public override Expression DoResolve (ResolveContext ec)
132 if (TypeManager.call_site_type == null)
133 TypeManager.call_site_type = TypeManager.CoreLookupType (ec.Compiler,
134 "System.Runtime.CompilerServices", "CallSite", Kind.Class, true);
136 if (TypeManager.generic_call_site_type == null)
137 TypeManager.generic_call_site_type = TypeManager.CoreLookupType (ec.Compiler,
138 "System.Runtime.CompilerServices", "CallSite`1", Kind.Class, true);
140 eclass = ExprClass.Value;
143 type = InternalType.Dynamic;
148 public override void Emit (EmitContext ec)
150 EmitCall (ec, false);
153 public override void EmitStatement (EmitContext ec)
158 void EmitCall (EmitContext ec, bool isStatement)
160 int dyn_args_count = arguments == null ? 0 : arguments.Count;
161 TypeExpr site_type = CreateSiteType (RootContext.ToplevelTypes.Compiler, isStatement, dyn_args_count);
162 FieldExpr site_field_expr = new FieldExpr (CreateSiteField (site_type).FieldBuilder, loc);
164 SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
166 BlockContext bc = new BlockContext (ec.MemberContext, null, TypeManager.void_type);
168 Arguments args = new Arguments (1);
169 args.Add (new Argument (binder.CreateCallSiteBinder (bc, arguments)));
170 StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (site_type, "Create"), args)));
171 if (s.Resolve (bc)) {
172 Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc);
176 args = new Arguments (1 + dyn_args_count);
177 args.Add (new Argument (site_field_expr));
178 if (arguments != null) {
179 foreach (Argument a in arguments) {
180 if (a is NamedArgument) {
181 // Name is not valid in this context
182 args.Add (new Argument (a.Expr, a.ArgType));
190 ResolveContext rc = new ResolveContext (ec.MemberContext);
191 Expression target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (rc), args, loc).Resolve (rc);
195 SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
198 public static MemberAccess GetBinderNamespace (Location loc)
200 return new MemberAccess (new MemberAccess (
201 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "Microsoft", loc), "CSharp", loc), "RuntimeBinder", loc);
204 TypeExpr CreateSiteType (CompilerContext ctx, bool isStatement, int dyn_args_count)
206 int default_args = isStatement ? 1 : 2;
208 bool has_ref_out_argument = false;
209 FullNamedExpression[] targs = new FullNamedExpression[dyn_args_count + default_args];
210 targs [0] = new TypeExpression (TypeManager.call_site_type, loc);
211 for (int i = 0; i < dyn_args_count; ++i) {
213 Argument a = arguments [i];
214 if (a.Type == TypeManager.null_type)
215 arg_type = TypeManager.object_type;
217 arg_type = TypeManager.TypeToReflectionType (a.Type);
219 if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
220 has_ref_out_argument = true;
222 targs [i + 1] = new TypeExpression (arg_type, loc);
225 TypeExpr del_type = null;
226 if (!has_ref_out_argument) {
227 string d_name = isStatement ? "Action`" : "Func`";
229 Type t = TypeManager.CoreLookupType (ctx, "System", d_name + (dyn_args_count + default_args), Kind.Delegate, false);
232 targs[targs.Length - 1] = new TypeExpression (TypeManager.TypeToReflectionType (type), loc);
234 del_type = new GenericTypeExpr (t, new TypeArguments (targs), loc);
238 // No appropriate predefined delegate found
239 if (del_type == null) {
240 Type rt = isStatement ? TypeManager.void_type : type;
241 Parameter[] p = new Parameter [dyn_args_count + 1];
242 p[0] = new Parameter (targs [0], "p0", Parameter.Modifier.NONE, null, loc);
244 for (int i = 1; i < dyn_args_count + 1; ++i)
245 p[i] = new Parameter (targs[i], "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc);
247 TypeContainer parent = CreateSiteContainer ();
248 Delegate d = new Delegate (null, parent, new TypeExpression (rt, loc),
249 Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
250 new MemberName ("Container" + container_counter++.ToString ("X")),
251 new ParametersCompiled (p), null);
256 parent.AddDelegate (d);
257 del_type = new TypeExpression (d.TypeBuilder, loc);
260 TypeExpr site_type = new GenericTypeExpr (TypeManager.generic_call_site_type, new TypeArguments (del_type), loc);
266 // Dynamic member access compound assignment for events
268 class DynamicEventCompoundAssign : DynamicExpressionStatement, IDynamicBinder
271 ExpressionStatement assignment;
272 ExpressionStatement invoke;
274 public DynamicEventCompoundAssign (string name, Arguments args, ExpressionStatement assignment, ExpressionStatement invoke, Location loc)
275 : base (null, args, loc)
278 this.assignment = assignment;
279 this.invoke = invoke;
282 // Used by += or -= only
283 type = TypeManager.bool_type;
286 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
288 Arguments binder_args = new Arguments (2);
289 MemberAccess binder = GetBinderNamespace (loc);
291 binder_args.Add (new Argument (new StringLiteral (name, loc)));
292 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
294 return new New (new MemberAccess (binder, "CSharpIsEventBinder", loc), binder_args, loc);
297 public override void EmitStatement (EmitContext ec)
299 Statement cond = new If (
300 new Binary (Binary.Operator.Equality, this, new BoolLiteral (true, loc)),
301 new StatementExpression (invoke),
302 new StatementExpression (assignment),
308 class DynamicConversion : DynamicExpressionStatement, IDynamicBinder
312 public DynamicConversion (Type targetType, bool isExplicit, Arguments args, Location loc)
313 : base (null, args, loc)
316 is_explicit = isExplicit;
320 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
322 Arguments binder_args = new Arguments (2);
323 MemberAccess binder = GetBinderNamespace (loc);
325 binder_args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
326 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (binder, "CSharpConversionKind", loc),
327 is_explicit ? "ExplicitConversion" : "ImplicitConversion", loc)));
328 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
330 return new New (new MemberAccess (binder, "CSharpConvertBinder", loc), binder_args, loc);
334 class DynamicIndexBinder : DynamicExpressionStatement, IDynamicBinder, IAssignMethod
338 public DynamicIndexBinder (bool isSet, Arguments args, Location loc)
339 : base (null, args, loc)
345 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
347 Arguments binder_args = new Arguments (2);
348 MemberAccess binder = GetBinderNamespace (loc);
350 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
351 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
353 return new New (new MemberAccess (binder, isSet ? "CSharpSetIndexBinder" : "CSharpGetIndexBinder", loc), binder_args, loc);
356 #region IAssignMethod Members
358 public void Emit (EmitContext ec, bool leave_copy)
360 throw new NotImplementedException ();
363 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
371 class DynamicInvocation : DynamicExpressionStatement, IDynamicBinder
373 ATypeNameExpression member;
375 public DynamicInvocation (ATypeNameExpression member, Arguments args, Location loc)
376 : base (null, args, loc)
379 this.member = member;
382 public DynamicInvocation (ATypeNameExpression member, Arguments args, Type type, Location loc)
383 : this (member, args, loc)
385 // When a return type is known not to be dynamic
389 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
391 Arguments binder_args = new Arguments (member != null ? 5 : 3);
392 MemberAccess binder = GetBinderNamespace (loc);
393 bool is_member_access = member is MemberAccess;
396 if (!is_member_access && member is SimpleName) {
397 call_flags = "SimpleNameCall";
398 is_member_access = true;
403 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (binder, "CSharpCallFlags", loc), call_flags, loc)));
405 if (is_member_access)
406 binder_args.Add (new Argument (new StringLiteral (member.Name, member.Location)));
408 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
410 if (member != null && member.HasTypeArguments) {
411 TypeArguments ta = member.TypeArguments;
412 if (ta.Resolve (ec)) {
413 ArrayList targs = new ArrayList (ta.Count);
414 foreach (Type t in ta.Arguments)
415 targs.Add (new TypeOf (new TypeExpression (t, loc), loc));
417 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", targs, loc)));
419 } else if (is_member_access) {
420 binder_args.Add (new Argument (new NullLiteral (loc)));
423 Expression real_args;
425 // Cannot be null because .NET trips over
426 real_args = new ArrayCreation (new MemberAccess (binder, "CSharpArgumentInfo", loc), "[]", new ArrayList (0), loc);
428 real_args = new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc);
431 binder_args.Add (new Argument (real_args));
433 return new New (new MemberAccess (binder,
434 is_member_access ? "CSharpInvokeMemberBinder" : "CSharpInvokeBinder", loc), binder_args, loc);
438 class DynamicMemberBinder : DynamicExpressionStatement, IDynamicBinder, IAssignMethod
441 readonly string name;
443 public DynamicMemberBinder (bool isSet, string name, Arguments args, Location loc)
444 : base (null, args, loc)
451 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
453 Arguments binder_args = new Arguments (3);
454 MemberAccess binder = GetBinderNamespace (loc);
456 binder_args.Add (new Argument (new StringLiteral (name, loc)));
457 binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
458 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
460 return new New (new MemberAccess (binder, isSet ? "CSharpSetMemberBinder" : "CSharpGetMemberBinder", loc), binder_args, loc);
463 #region IAssignMethod Members
465 public void Emit (EmitContext ec, bool leave_copy)
467 throw new NotImplementedException ();
470 public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
478 class DynamicUnaryConversion : DynamicExpressionStatement, IDynamicBinder
482 public DynamicUnaryConversion (string name, Arguments args, Location loc)
483 : base (null, args, loc)
487 if (name == "IsTrue" || name == "IsFalse")
488 type = TypeManager.bool_type;
491 public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
493 Arguments binder_args = new Arguments (3);
495 MemberAccess sle = new MemberAccess (new MemberAccess (
496 new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
498 MemberAccess binder = GetBinderNamespace (loc);
500 binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), name, loc)));
501 binder_args.Add (new Argument (new BoolLiteral (ec.HasSet (ResolveContext.Options.CheckedScope), loc)));
502 binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (), loc)));
504 return new New (new MemberAccess (binder, "CSharpUnaryOperationBinder", loc), binder_args, loc);