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
;
20 class DynamicTypeExpr
: TypeExpr
22 public DynamicTypeExpr (Location loc
)
26 type
= InternalType
.Dynamic
;
27 eclass
= ExprClass
.Type
;
30 public override bool CheckAccessLevel (IMemberContext ds
)
35 protected override TypeExpr
DoResolveAsTypeStep (IMemberContext ec
)
42 // Expression created from runtime dynamic object value
44 public class RuntimeValueExpression
: Expression
, IAssignMethod
47 public class DynamicMetaObject { public Type RuntimeType; }
50 readonly DynamicMetaObject obj
;
52 // When strongly typed expression is required
55 public RuntimeValueExpression (DynamicMetaObject obj
, bool typed
)
59 this.type
= obj
.RuntimeType
;
60 this.eclass
= ExprClass
.Value
;
63 public override Expression
CreateExpressionTree (ResolveContext ec
)
65 throw new NotImplementedException ();
68 public override Expression
DoResolve (ResolveContext ec
)
73 public override Expression
DoResolveLValue (ResolveContext ec
, Expression right_side
)
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 ();
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
;
108 interface IDynamicBinder
110 Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
);
113 class DynamicExpressionStatement
: ExpressionStatement
115 class StaticDataClass
: CompilerGeneratedClass
117 public StaticDataClass ()
118 : base (new RootDeclSpace (new NamespaceEntry (null, null, null)),
119 new MemberName (CompilerGeneratedClass
.MakeName (null, "c", "DynamicSites", 0)),
120 Modifiers
.INTERNAL
| Modifiers
.STATIC
)
122 ModFlags
&= ~Modifiers
.SEALED
;
126 static StaticDataClass global_site_container
;
127 static int field_counter
;
128 static int container_counter
;
130 readonly Arguments arguments
;
131 protected IDynamicBinder binder
;
132 Expression binder_expr
;
134 public DynamicExpressionStatement (IDynamicBinder binder
, Arguments args
, Location loc
)
136 this.binder
= binder
;
137 this.arguments
= args
;
141 public Arguments Arguments
{
147 static TypeContainer
CreateSiteContainer ()
149 if (global_site_container
== null) {
150 global_site_container
= new StaticDataClass ();
151 RootContext
.ToplevelTypes
.AddCompilerGeneratedClass (global_site_container
);
152 global_site_container
.DefineType ();
153 global_site_container
.Define ();
154 // global_site_container.EmitType ();
156 RootContext
.RegisterCompilerGeneratedType (global_site_container
.TypeBuilder
);
159 return global_site_container
;
162 static Field
CreateSiteField (FullNamedExpression type
)
164 TypeContainer site_container
= CreateSiteContainer ();
165 Field f
= new Field (site_container
, type
, Modifiers
.PUBLIC
| Modifiers
.STATIC
,
166 new MemberName ("Site" + field_counter
++), null);
169 site_container
.AddField (f
);
173 public override Expression
CreateExpressionTree (ResolveContext ec
)
175 throw new NotImplementedException ();
178 public override Expression
DoResolve (ResolveContext ec
)
180 if (eclass
!= ExprClass
.Invalid
)
183 if (TypeManager
.call_site_type
== null)
184 TypeManager
.call_site_type
= TypeManager
.CoreLookupType (ec
.Compiler
,
185 "System.Runtime.CompilerServices", "CallSite", Kind
.Class
, true);
187 if (TypeManager
.generic_call_site_type
== null)
188 TypeManager
.generic_call_site_type
= TypeManager
.CoreLookupType (ec
.Compiler
,
189 "System.Runtime.CompilerServices", "CallSite`1", Kind
.Class
, true);
191 eclass
= ExprClass
.Value
;
194 type
= InternalType
.Dynamic
;
196 binder_expr
= binder
.CreateCallSiteBinder (ec
, arguments
);
200 public override void Emit (EmitContext ec
)
202 EmitCall (ec
, false);
205 public override void EmitStatement (EmitContext ec
)
210 void EmitCall (EmitContext ec
, bool isStatement
)
212 int dyn_args_count
= arguments
== null ? 0 : arguments
.Count
;
213 TypeExpr site_type
= CreateSiteType (RootContext
.ToplevelTypes
.Compiler
, isStatement
, dyn_args_count
);
214 FieldExpr site_field_expr
= new FieldExpr (CreateSiteField (site_type
).FieldBuilder
, loc
);
216 SymbolWriter
.OpenCompilerGeneratedBlock (ec
.ig
);
218 Arguments args
= new Arguments (1);
219 args
.Add (new Argument (binder_expr
));
220 StatementExpression s
= new StatementExpression (new SimpleAssign (site_field_expr
, new Invocation (new MemberAccess (site_type
, "Create"), args
)));
222 BlockContext bc
= new BlockContext (ec
.MemberContext
, null, TypeManager
.void_type
);
223 if (s
.Resolve (bc
)) {
224 Statement init
= new If (new Binary (Binary
.Operator
.Equality
, site_field_expr
, new NullLiteral (loc
)), s
, loc
);
228 args
= new Arguments (1 + dyn_args_count
);
229 args
.Add (new Argument (site_field_expr
));
230 if (arguments
!= null) {
231 foreach (Argument a
in arguments
) {
232 if (a
is NamedArgument
) {
233 // Name is not valid in this context
234 args
.Add (new Argument (a
.Expr
, a
.ArgType
));
242 ResolveContext rc
= new ResolveContext (ec
.MemberContext
);
243 Expression target
= new DelegateInvocation (new MemberAccess (site_field_expr
, "Target", loc
).Resolve (rc
), args
, loc
).Resolve (rc
);
247 SymbolWriter
.CloseCompilerGeneratedBlock (ec
.ig
);
250 public static MemberAccess
GetBinderNamespace (Location loc
)
252 return new MemberAccess (new MemberAccess (
253 new QualifiedAliasMember (QualifiedAliasMember
.GlobalAlias
, "Microsoft", loc
), "CSharp", loc
), "RuntimeBinder", loc
);
256 TypeExpr
CreateSiteType (CompilerContext ctx
, bool isStatement
, int dyn_args_count
)
258 int default_args
= isStatement
? 1 : 2;
260 bool has_ref_out_argument
= false;
261 FullNamedExpression
[] targs
= new FullNamedExpression
[dyn_args_count
+ default_args
];
262 targs
[0] = new TypeExpression (TypeManager
.call_site_type
, loc
);
263 for (int i
= 0; i
< dyn_args_count
; ++i
) {
265 Argument a
= arguments
[i
];
266 if (a
.Type
== TypeManager
.null_type
)
267 arg_type
= TypeManager
.object_type
;
269 arg_type
= TypeManager
.TypeToReflectionType (a
.Type
);
271 if (a
.ArgType
== Argument
.AType
.Out
|| a
.ArgType
== Argument
.AType
.Ref
)
272 has_ref_out_argument
= true;
274 targs
[i
+ 1] = new TypeExpression (arg_type
, loc
);
277 TypeExpr del_type
= null;
278 if (!has_ref_out_argument
) {
279 string d_name
= isStatement
? "Action`" : "Func`";
281 Type t
= TypeManager
.CoreLookupType (ctx
, "System", d_name
+ (dyn_args_count
+ default_args
), Kind
.Delegate
, false);
284 targs
[targs
.Length
- 1] = new TypeExpression (TypeManager
.TypeToReflectionType (type
), loc
);
286 del_type
= new GenericTypeExpr (t
, new TypeArguments (targs
), loc
);
290 // No appropriate predefined delegate found
291 if (del_type
== null) {
292 Type rt
= isStatement
? TypeManager
.void_type
: type
;
293 Parameter
[] p
= new Parameter
[dyn_args_count
+ 1];
294 p
[0] = new Parameter (targs
[0], "p0", Parameter
.Modifier
.NONE
, null, loc
);
296 for (int i
= 1; i
< dyn_args_count
+ 1; ++i
)
297 p
[i
] = new Parameter (targs
[i
], "p" + i
.ToString ("X"), arguments
[i
- 1].Modifier
, null, loc
);
299 TypeContainer parent
= CreateSiteContainer ();
300 Delegate d
= new Delegate (parent
.NamespaceEntry
, parent
, new TypeExpression (rt
, loc
),
301 Modifiers
.INTERNAL
| Modifiers
.COMPILER_GENERATED
,
302 new MemberName ("Container" + container_counter
++.ToString ("X")),
303 new ParametersCompiled (p
), null);
308 parent
.AddDelegate (d
);
309 del_type
= new TypeExpression (d
.TypeBuilder
, loc
);
312 TypeExpr site_type
= new GenericTypeExpr (TypeManager
.generic_call_site_type
, new TypeArguments (del_type
), loc
);
316 public static void Reset ()
318 global_site_container
= null;
319 field_counter
= container_counter
= 0;
324 // Dynamic member access compound assignment for events
326 class DynamicEventCompoundAssign
: DynamicExpressionStatement
, IDynamicBinder
329 ExpressionStatement assignment
;
330 ExpressionStatement invoke
;
332 public DynamicEventCompoundAssign (string name
, Arguments args
, ExpressionStatement assignment
, ExpressionStatement invoke
, Location loc
)
333 : base (null, args
, loc
)
336 this.assignment
= assignment
;
337 this.invoke
= invoke
;
340 // Used by += or -= only
341 type
= TypeManager
.bool_type
;
344 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
346 Arguments binder_args
= new Arguments (2);
347 MemberAccess binder
= GetBinderNamespace (loc
);
349 binder_args
.Add (new Argument (new StringLiteral (name
, loc
)));
350 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.CurrentType
, loc
), loc
)));
352 return new New (new MemberAccess (binder
, "CSharpIsEventBinder", loc
), binder_args
, loc
);
355 public override void EmitStatement (EmitContext ec
)
357 Statement cond
= new If (
358 new Binary (Binary
.Operator
.Equality
, this, new BoolLiteral (true, loc
)),
359 new StatementExpression (invoke
),
360 new StatementExpression (assignment
),
366 class DynamicConversion
: DynamicExpressionStatement
, IDynamicBinder
370 public DynamicConversion (Type targetType
, bool isExplicit
, Arguments args
, Location loc
)
371 : base (null, args
, loc
)
374 is_explicit
= isExplicit
;
378 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
380 Arguments binder_args
= new Arguments (2);
381 MemberAccess binder
= GetBinderNamespace (loc
);
383 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (type
, loc
), loc
)));
384 binder_args
.Add (new Argument (new MemberAccess (new MemberAccess (binder
, "CSharpConversionKind", loc
),
385 is_explicit
? "ExplicitConversion" : "ImplicitConversion", loc
)));
386 binder_args
.Add (new Argument (new BoolLiteral (ec
.HasSet (ResolveContext
.Options
.CheckedScope
), loc
)));
388 return new New (new MemberAccess (binder
, "CSharpConvertBinder", loc
), binder_args
, loc
);
392 class DynamicIndexBinder
: DynamicExpressionStatement
, IDynamicBinder
, IAssignMethod
396 public DynamicIndexBinder (bool isSet
, Arguments args
, Location loc
)
397 : base (null, args
, loc
)
403 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
405 Arguments binder_args
= new Arguments (2);
406 MemberAccess binder
= GetBinderNamespace (loc
);
408 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.CurrentType
, loc
), loc
)));
409 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
411 return new New (new MemberAccess (binder
, isSet
? "CSharpSetIndexBinder" : "CSharpGetIndexBinder", loc
), binder_args
, loc
);
414 #region IAssignMethod Members
416 public void Emit (EmitContext ec
, bool leave_copy
)
418 throw new NotImplementedException ();
421 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
429 class DynamicInvocation
: DynamicExpressionStatement
, IDynamicBinder
431 ATypeNameExpression member
;
433 public DynamicInvocation (ATypeNameExpression member
, Arguments args
, Location loc
)
434 : base (null, args
, loc
)
437 this.member
= member
;
440 public DynamicInvocation (ATypeNameExpression member
, Arguments args
, Type type
, Location loc
)
441 : this (member
, args
, loc
)
443 // When a return type is known not to be dynamic
447 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
449 Arguments binder_args
= new Arguments (member
!= null ? 5 : 3);
450 MemberAccess binder
= GetBinderNamespace (loc
);
451 bool is_member_access
= member
is MemberAccess
;
454 if (!is_member_access
&& member
is SimpleName
) {
455 call_flags
= "SimpleNameCall";
456 is_member_access
= true;
461 binder_args
.Add (new Argument (new MemberAccess (new MemberAccess (binder
, "CSharpCallFlags", loc
), call_flags
, loc
)));
463 if (is_member_access
)
464 binder_args
.Add (new Argument (new StringLiteral (member
.Name
, member
.Location
)));
466 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.CurrentType
, loc
), loc
)));
468 if (member
!= null && member
.HasTypeArguments
) {
469 TypeArguments ta
= member
.TypeArguments
;
470 if (ta
.Resolve (ec
)) {
471 ArrayList targs
= new ArrayList (ta
.Count
);
472 foreach (Type t
in ta
.Arguments
)
473 targs
.Add (new TypeOf (new TypeExpression (t
, loc
), loc
));
475 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", targs
, loc
)));
477 } else if (is_member_access
) {
478 binder_args
.Add (new Argument (new NullLiteral (loc
)));
481 Expression real_args
;
483 // Cannot be null because .NET trips over
484 real_args
= new ArrayCreation (new MemberAccess (binder
, "CSharpArgumentInfo", loc
), "[]", new ArrayList (0), loc
);
486 real_args
= new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
);
489 binder_args
.Add (new Argument (real_args
));
491 return new New (new MemberAccess (binder
,
492 is_member_access
? "CSharpInvokeMemberBinder" : "CSharpInvokeBinder", loc
), binder_args
, loc
);
496 class DynamicMemberBinder
: DynamicExpressionStatement
, IDynamicBinder
, IAssignMethod
499 readonly string name
;
501 public DynamicMemberBinder (bool isSet
, string name
, Arguments args
, Location loc
)
502 : base (null, args
, loc
)
509 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
511 Arguments binder_args
= new Arguments (3);
512 MemberAccess binder
= GetBinderNamespace (loc
);
514 binder_args
.Add (new Argument (new StringLiteral (name
, loc
)));
515 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.CurrentType
, loc
), loc
)));
516 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
518 return new New (new MemberAccess (binder
, isSet
? "CSharpSetMemberBinder" : "CSharpGetMemberBinder", loc
), binder_args
, loc
);
521 #region IAssignMethod Members
523 public void Emit (EmitContext ec
, bool leave_copy
)
525 throw new NotImplementedException ();
528 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
536 class DynamicUnaryConversion
: DynamicExpressionStatement
, IDynamicBinder
540 public DynamicUnaryConversion (string name
, Arguments args
, Location loc
)
541 : base (null, args
, loc
)
545 if (name
== "IsTrue" || name
== "IsFalse")
546 type
= TypeManager
.bool_type
;
549 public Expression
CreateCallSiteBinder (ResolveContext ec
, Arguments args
)
551 Arguments binder_args
= new Arguments (3);
553 MemberAccess sle
= new MemberAccess (new MemberAccess (
554 new QualifiedAliasMember (QualifiedAliasMember
.GlobalAlias
, "System", loc
), "Linq", loc
), "Expressions", loc
);
556 MemberAccess binder
= GetBinderNamespace (loc
);
558 binder_args
.Add (new Argument (new MemberAccess (new MemberAccess (sle
, "ExpressionType", loc
), name
, loc
)));
559 binder_args
.Add (new Argument (new BoolLiteral (ec
.HasSet (ResolveContext
.Options
.CheckedScope
), loc
)));
560 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
562 return new New (new MemberAccess (binder
, "CSharpUnaryOperationBinder", loc
), binder_args
, loc
);