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
15 class DynamicTypeExpr
: TypeExpr
17 public DynamicTypeExpr (Location loc
)
21 type
= InternalType
.Dynamic
;
22 eclass
= ExprClass
.Type
;
25 public override bool CheckAccessLevel (DeclSpace ds
)
30 protected override TypeExpr
DoResolveAsTypeStep (IResolveContext ec
)
32 throw new NotImplementedException ();
36 interface IDynamicBinder
38 Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
);
41 class DynamicExpressionStatement
: ExpressionStatement
43 class StaticDataClass
: CompilerGeneratedClass
45 public StaticDataClass ()
46 : base (new RootDeclSpace (new NamespaceEntry (null, null, null)),
47 new MemberName (CompilerGeneratedClass
.MakeName (null, "c", "DynamicSites", 0)),
48 Modifiers
.INTERNAL
| Modifiers
.STATIC
)
50 ModFlags
&= ~Modifiers
.SEALED
;
54 static StaticDataClass site_container
;
55 static int field_counter
;
57 readonly Arguments arguments
;
58 protected IDynamicBinder binder
;
60 public DynamicExpressionStatement (IDynamicBinder binder
, Arguments args
, Location loc
)
63 this.arguments
= args
;
67 public Arguments Arguments
{
73 protected static Field
CreateSiteField (FullNamedExpression type
)
75 if (site_container
== null) {
76 site_container
= new StaticDataClass ();
77 RootContext
.ToplevelTypes
.AddCompilerGeneratedClass (site_container
);
78 site_container
.DefineType ();
79 site_container
.Define ();
80 // site_container.EmitType ();
82 RootContext
.RegisterCompilerGeneratedType (site_container
.TypeBuilder
);
85 Field f
= new Field (site_container
, type
, Modifiers
.PUBLIC
| Modifiers
.STATIC
,
86 new MemberName ("Site" + field_counter
++), null);
89 site_container
.AddField (f
);
94 // Returns DynamicMetaObjectBinder.ReturnType value for each binder. It
95 // has to be kept in sync manually !
97 protected virtual Type CallSiteReturnType
{
99 return TypeManager
.object_type
;
103 public override Expression
CreateExpressionTree (EmitContext ec
)
105 throw new NotImplementedException ();
108 public override Expression
DoResolve (EmitContext ec
)
110 if (TypeManager
.call_site_type
== null)
111 TypeManager
.call_site_type
= TypeManager
.CoreLookupType (
112 "System.Runtime.CompilerServices", "CallSite", Kind
.Class
, true);
114 if (TypeManager
.generic_call_site_type
== null)
115 TypeManager
.generic_call_site_type
= TypeManager
.CoreLookupType (
116 "System.Runtime.CompilerServices", "CallSite`1", Kind
.Class
, true);
118 eclass
= ExprClass
.Value
;
119 type
= InternalType
.Dynamic
;
123 public override void Emit (EmitContext ec
)
125 EmitCall (ec
, false);
128 public override void EmitStatement (EmitContext ec
)
133 void EmitCall (EmitContext ec
, bool isStatement
)
135 int dyn_args_count
= arguments
== null ? 0 : arguments
.Count
;
136 int default_args
= isStatement
? 1 : 2;
138 string d_name
= isStatement
? "Action`" : "Func`";
139 Type t
= TypeManager
.CoreLookupType ("System", d_name
+ (dyn_args_count
+ default_args
), Kind
.Delegate
, false);
141 throw new NotImplementedException ("Create compiler generated delegate");
143 FullNamedExpression
[] targs
= new FullNamedExpression
[dyn_args_count
+ default_args
];
144 targs
[0] = new TypeExpression (TypeManager
.call_site_type
, loc
);
145 for (int i
= 0; i
< dyn_args_count
; ++i
)
146 targs
[i
+ 1] = new TypeExpression (TypeManager
.TypeToReflectionType (arguments
[i
].Type
), loc
);
149 targs
[targs
.Length
- 1] = new TypeExpression (CallSiteReturnType
, loc
);
151 TypeExpr site_type
= new GenericTypeExpr (TypeManager
.generic_call_site_type
, new TypeArguments (new GenericTypeExpr (t
, new TypeArguments (targs
), loc
)), loc
);
152 FieldExpr site_field_expr
= new FieldExpr (CreateSiteField (site_type
).FieldBuilder
, loc
);
154 SymbolWriter
.OpenCompilerGeneratedBlock (ec
.ig
);
156 Arguments args
= new Arguments (1);
157 args
.Add (new Argument (binder
.CreateCallSiteBinder (ec
, arguments
)));
158 StatementExpression s
= new StatementExpression (new SimpleAssign (site_field_expr
, new Invocation (new MemberAccess (site_type
, "Create"), args
)));
159 if (s
.Resolve (ec
)) {
160 Statement init
= new If (new Binary (Binary
.Operator
.Equality
, site_field_expr
, new NullLiteral (loc
)), s
, loc
);
164 args
= new Arguments (1 + dyn_args_count
);
165 args
.Add (new Argument (site_field_expr
));
166 if (arguments
!= null)
167 args
.AddRange (arguments
);
169 Expression target
= new DelegateInvocation (new MemberAccess (site_field_expr
, "Target", loc
).Resolve (ec
), args
, loc
).Resolve (ec
);
173 SymbolWriter
.CloseCompilerGeneratedBlock (ec
.ig
);
176 public static MemberAccess
GetBinderNamespace (Location loc
)
178 return new MemberAccess (new MemberAccess (
179 new QualifiedAliasMember (QualifiedAliasMember
.GlobalAlias
, "Microsoft", loc
), "CSharp", loc
), "RuntimeBinder", loc
);
184 // Dynamic member access compound assignment for events
186 class DynamicEventCompoundAssign
: DynamicExpressionStatement
, IDynamicBinder
189 ExpressionStatement assignment
;
190 ExpressionStatement invoke
;
192 public DynamicEventCompoundAssign (string name
, Arguments args
, ExpressionStatement assignment
, ExpressionStatement invoke
, Location loc
)
193 : base (null, args
, loc
)
196 this.assignment
= assignment
;
197 this.invoke
= invoke
;
201 protected override Type CallSiteReturnType
{
203 // Used by += or -= only
204 return TypeManager
.bool_type
;
208 public Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
)
210 Arguments binder_args
= new Arguments (2);
211 MemberAccess binder
= GetBinderNamespace (loc
);
213 binder_args
.Add (new Argument (new StringLiteral (name
, loc
)));
214 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.ContainerType
, loc
), loc
)));
216 return new New (new MemberAccess (binder
, "CSharpIsEventBinder", loc
), binder_args
, loc
);
219 public override Expression
DoResolve (EmitContext ec
)
221 return base.DoResolve (ec
);
224 public override void EmitStatement (EmitContext ec
)
226 Statement cond
= new If (
227 new Binary (Binary
.Operator
.Equality
, this, new BoolLiteral (true, loc
)),
228 new StatementExpression (invoke
),
229 new StatementExpression (assignment
),
235 class DynamicConversion
: DynamicExpressionStatement
, IDynamicBinder
240 public DynamicConversion (Type targetType
, bool isExplicit
, Arguments args
, Location loc
)
241 : base (null, args
, loc
)
243 this.target_type
= targetType
;
244 is_explicit
= isExplicit
;
248 public Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
)
250 Arguments binder_args
= new Arguments (2);
251 MemberAccess binder
= GetBinderNamespace (loc
);
253 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (target_type
, loc
), loc
)));
254 binder_args
.Add (new Argument (new MemberAccess (new MemberAccess (binder
, "CSharpConversionKind", loc
),
255 is_explicit
? "ExplicitConversion" : "ImplicitConversion", loc
)));
256 binder_args
.Add (new Argument (new BoolLiteral (ec
.CheckState
, loc
)));
258 return new New (new MemberAccess (binder
, "CSharpConvertBinder", loc
), binder_args
, loc
);
262 class DynamicIndexBinder
: DynamicExpressionStatement
, IDynamicBinder
, IAssignMethod
266 public DynamicIndexBinder (bool isSet
, Arguments args
, Location loc
)
267 : base (null, args
, loc
)
273 public Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
)
275 Arguments binder_args
= new Arguments (2);
276 MemberAccess binder
= GetBinderNamespace (loc
);
278 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.ContainerType
, loc
), loc
)));
279 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
281 return new New (new MemberAccess (binder
, isSet
? "CSharpSetIndexBinder" : "CSharpGetIndexBinder", loc
), binder_args
, loc
);
284 #region IAssignMethod Members
286 public void Emit (EmitContext ec
, bool leave_copy
)
288 throw new NotImplementedException ();
291 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
299 class DynamicInvocation
: DynamicExpressionStatement
, IDynamicBinder
301 MemberAccess member_access
;
303 public DynamicInvocation (MemberAccess memberAccess
, Arguments args
, Location loc
)
304 : base (null, args
, loc
)
307 this.member_access
= memberAccess
;
310 public Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
)
312 Arguments binder_args
= new Arguments (member_access
!= null ? 5 : 3);
313 MemberAccess binder
= GetBinderNamespace (loc
);
315 binder_args
.Add (new Argument (new MemberAccess (new MemberAccess (binder
, "CSharpCallFlags", loc
), "None", loc
)));
316 if (member_access
!= null)
317 binder_args
.Add (new Argument (new StringLiteral (member_access
.Name
, member_access
.Location
)));
319 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.ContainerType
, loc
), loc
)));
321 // TODO: member_access.TypeArguments
322 if (member_access
!= null)
323 binder_args
.Add (new Argument (new NullLiteral (loc
)));
325 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
327 return new New (new MemberAccess (binder
,
328 member_access
!= null ? "CSharpInvokeMemberBinder" : "CSharpInvokeBinder", loc
), binder_args
, loc
);
332 class DynamicMemberBinder
: DynamicExpressionStatement
, IDynamicBinder
, IAssignMethod
335 readonly string name
;
337 public DynamicMemberBinder (bool isSet
, string name
, Arguments args
, Location loc
)
338 : base (null, args
, loc
)
345 public Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
)
347 Arguments binder_args
= new Arguments (3);
348 MemberAccess binder
= GetBinderNamespace (loc
);
350 binder_args
.Add (new Argument (new StringLiteral (name
, loc
)));
351 binder_args
.Add (new Argument (new TypeOf (new TypeExpression (ec
.ContainerType
, loc
), loc
)));
352 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
354 return new New (new MemberAccess (binder
, isSet
? "CSharpSetMemberBinder" : "CSharpGetMemberBinder", loc
), binder_args
, loc
);
357 #region IAssignMethod Members
359 public void Emit (EmitContext ec
, bool leave_copy
)
361 throw new NotImplementedException ();
364 public void EmitAssign (EmitContext ec
, Expression source
, bool leave_copy
, bool prepare_for_load
)
372 class DynamicUnaryConversion
: DynamicExpressionStatement
, IDynamicBinder
376 public DynamicUnaryConversion (string name
, Arguments args
, Location loc
)
377 : base (null, args
, loc
)
383 protected override Type CallSiteReturnType
387 return name
== "IsTrue" || name
== "IsFalse" ? TypeManager
.bool_type
: base.CallSiteReturnType
;
391 public Expression
CreateCallSiteBinder (EmitContext ec
, Arguments args
)
393 Arguments binder_args
= new Arguments (3);
395 MemberAccess sle
= new MemberAccess (new MemberAccess (
396 new QualifiedAliasMember (QualifiedAliasMember
.GlobalAlias
, "System", loc
), "Linq", loc
), "Expressions", loc
);
398 MemberAccess binder
= GetBinderNamespace (loc
);
400 binder_args
.Add (new Argument (new MemberAccess (new MemberAccess (sle
, "ExpressionType", loc
), name
, loc
)));
401 binder_args
.Add (new Argument (new BoolLiteral (ec
.CheckState
, loc
)));
402 binder_args
.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args
.CreateDynamicBinderArguments (), loc
)));
404 return new New (new MemberAccess (binder
, "CSharpUnaryOperationBinder", loc
), binder_args
, loc
);