2009-07-20 Jb Evain <jbevain@novell.com>
[mcs.git] / mcs / dynamic.cs
blobed62c25ab71b42c5e0ba1505df7203b7be0d2ffd
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;
13 namespace Mono.CSharp
15 class DynamicTypeExpr : TypeExpr
17 public DynamicTypeExpr (Location loc)
19 this.loc = loc;
21 type = InternalType.Dynamic;
22 eclass = ExprClass.Type;
25 public override bool CheckAccessLevel (DeclSpace ds)
27 return true;
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)
62 this.binder = binder;
63 this.arguments = args;
64 this.loc = loc;
67 public Arguments Arguments {
68 get {
69 return 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);
87 f.Define ();
89 site_container.AddField (f);
90 return f;
94 // Returns DynamicMetaObjectBinder.ReturnType value for each binder. It
95 // has to be kept in sync manually !
97 protected virtual Type CallSiteReturnType {
98 get {
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;
120 return this;
123 public override void Emit (EmitContext ec)
125 EmitCall (ec, false);
128 public override void EmitStatement (EmitContext ec)
130 EmitCall (ec, true);
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);
140 if (t == null)
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);
148 if (!isStatement)
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);
161 init.Emit (ec);
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);
170 if (target != null)
171 target.Emit (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
188 string name;
189 ExpressionStatement assignment;
190 ExpressionStatement invoke;
192 public DynamicEventCompoundAssign (string name, Arguments args, ExpressionStatement assignment, ExpressionStatement invoke, Location loc)
193 : base (null, args, loc)
195 this.name = name;
196 this.assignment = assignment;
197 this.invoke = invoke;
198 base.binder = this;
201 protected override Type CallSiteReturnType {
202 get {
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),
230 loc);
231 cond.Emit (ec);
235 class DynamicConversion : DynamicExpressionStatement, IDynamicBinder
237 Type target_type;
238 bool is_explicit;
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;
245 base.binder = this;
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
264 readonly bool isSet;
266 public DynamicIndexBinder (bool isSet, Arguments args, Location loc)
267 : base (null, args, loc)
269 base.binder = this;
270 this.isSet = isSet;
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)
293 EmitStatement (ec);
296 #endregion
299 class DynamicInvocation : DynamicExpressionStatement, IDynamicBinder
301 MemberAccess member_access;
303 public DynamicInvocation (MemberAccess memberAccess, Arguments args, Location loc)
304 : base (null, args, loc)
306 base.binder = this;
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
334 readonly bool isSet;
335 readonly string name;
337 public DynamicMemberBinder (bool isSet, string name, Arguments args, Location loc)
338 : base (null, args, loc)
340 base.binder = this;
341 this.isSet = isSet;
342 this.name = name;
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)
366 EmitStatement (ec);
369 #endregion
372 class DynamicUnaryConversion : DynamicExpressionStatement, IDynamicBinder
374 string name;
376 public DynamicUnaryConversion (string name, Arguments args, Location loc)
377 : base (null, args, loc)
379 this.name = name;
380 base.binder = this;
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);