Free cookie consent management tool by TermsFeed Policy Generator

source: branches/WebJobManager/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/dynamic.cs

Last change on this file was 11700, checked in by jkarder, 10 years ago

#2077: created branch and added first version

File size: 28.1 KB
Line 
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// Copyright 2011 Xamarin Inc.
10//
11
12using System;
13using System.Linq;
14using SLE = System.Linq.Expressions;
15
16#if NET_4_0 || MOBILE_DYNAMIC
17using System.Dynamic;
18#endif
19
20namespace Mono.CSharp
21{
22  //
23  // A copy of Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpBinderFlags.cs
24  // has to be kept in sync
25  //
26  [Flags]
27  public enum CSharpBinderFlags
28  {
29    None = 0,
30    CheckedContext = 1,
31    InvokeSimpleName = 1 << 1,
32    InvokeSpecialName = 1 << 2,
33    BinaryOperationLogical = 1 << 3,
34    ConvertExplicit = 1 << 4,
35    ConvertArrayIndex = 1 << 5,
36    ResultIndexed = 1 << 6,
37    ValueFromCompoundAssignment = 1 << 7,
38    ResultDiscarded = 1 << 8
39  }
40
41  //
42  // Type expression with internal dynamic type symbol
43  //
44  class DynamicTypeExpr : TypeExpr
45  {
46    public DynamicTypeExpr (Location loc)
47    {
48      this.loc = loc;
49    }
50
51    public override TypeSpec ResolveAsType (IMemberContext ec, bool allowUnboundTypeArguments)
52    {
53      eclass = ExprClass.Type;
54      type = ec.Module.Compiler.BuiltinTypes.Dynamic;
55      return type;
56    }
57  }
58
59  #region Dynamic runtime binder expressions
60
61  //
62  // Expression created from runtime dynamic object value by dynamic binder
63  //
64  public class RuntimeValueExpression : Expression, IDynamicAssign, IMemoryLocation
65  {
66#if !NET_4_0 && !MOBILE_DYNAMIC
67    public class DynamicMetaObject
68    {
69      public TypeSpec RuntimeType;
70      public TypeSpec LimitType;
71      public SLE.Expression Expression;
72    }
73#endif
74
75    readonly DynamicMetaObject obj;
76
77    public RuntimeValueExpression (DynamicMetaObject obj, TypeSpec type)
78    {
79      this.obj = obj;
80      this.type = type;
81      this.eclass = ExprClass.Variable;
82    }
83
84    #region Properties
85
86    public bool IsSuggestionOnly { get; set; }
87
88    public DynamicMetaObject MetaObject {
89      get { return obj; }
90    }
91
92    #endregion
93
94    public void AddressOf (EmitContext ec, AddressOp mode)
95    {
96      throw new NotImplementedException ();
97    }
98
99    public override bool ContainsEmitWithAwait ()
100    {
101      throw new NotSupportedException ();
102    }
103
104    public override Expression CreateExpressionTree (ResolveContext ec)
105    {
106      throw new NotSupportedException ();
107    }
108
109    protected override Expression DoResolve (ResolveContext ec)
110    {
111      return this;
112    }
113
114    public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
115    {
116      return this;
117    }
118
119    public override void Emit (EmitContext ec)
120    {
121      throw new NotImplementedException ();
122    }
123
124    #region IAssignMethod Members
125
126    public void Emit (EmitContext ec, bool leave_copy)
127    {
128      throw new NotImplementedException ();
129    }
130
131    public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
132    {
133      throw new NotImplementedException ();
134    }
135
136    #endregion
137
138    public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
139    {
140      return obj.Expression;
141    }
142
143    public override SLE.Expression MakeExpression (BuilderContext ctx)
144    {
145#if STATIC
146      return base.MakeExpression (ctx);
147#else
148
149#if NET_4_0 || MOBILE_DYNAMIC
150        if (type.IsStruct && !obj.Expression.Type.IsValueType)
151          return SLE.Expression.Unbox (obj.Expression, type.GetMetaInfo ());
152
153        if (obj.Expression.NodeType == SLE.ExpressionType.Parameter) {
154          if (((SLE.ParameterExpression) obj.Expression).IsByRef)
155            return obj.Expression;
156        }
157  #endif
158
159        return SLE.Expression.Convert (obj.Expression, type.GetMetaInfo ());
160#endif
161    }
162  }
163
164  //
165  // Wraps runtime dynamic expression into expected type. Needed
166  // to satify expected type check by dynamic binder and no conversion
167  // is required (ResultDiscarded).
168  //
169  public class DynamicResultCast : ShimExpression
170  {
171    public DynamicResultCast (TypeSpec type, Expression expr)
172      : base (expr)
173    {
174      this.type = type;
175    }
176
177    protected override Expression DoResolve (ResolveContext ec)
178    {
179      expr = expr.Resolve (ec);
180      eclass = ExprClass.Value;
181      return this;
182    }
183
184#if NET_4_0 || MOBILE_DYNAMIC
185    public override SLE.Expression MakeExpression (BuilderContext ctx)
186    {
187#if STATIC
188      return base.MakeExpression (ctx);
189#else
190      return SLE.Expression.Block (expr.MakeExpression (ctx), SLE.Expression.Default (type.GetMetaInfo ()));
191#endif
192    }
193#endif
194  }
195
196  #endregion
197
198  //
199  // Creates dynamic binder expression
200  //
201  interface IDynamicBinder
202  {
203    Expression CreateCallSiteBinder (ResolveContext ec, Arguments args);
204  }
205
206  //
207  // Extends standard assignment interface for expressions
208  // supported by dynamic resolver
209  //
210  interface IDynamicAssign : IAssignMethod
211  {
212    SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
213  }
214
215  //
216  // Base dynamic expression statement creator
217  //
218  class DynamicExpressionStatement : ExpressionStatement
219  {
220    //
221    // Binder flag dynamic constant, the value is combination of
222    // flags known at resolve stage and flags known only at emit
223    // stage
224    //
225    protected class BinderFlags : EnumConstant
226    {
227      readonly DynamicExpressionStatement statement;
228      readonly CSharpBinderFlags flags;
229
230      public BinderFlags (CSharpBinderFlags flags, DynamicExpressionStatement statement)
231        : base (statement.loc)
232      {
233        this.flags = flags;
234        this.statement = statement;
235        eclass = 0;
236      }
237
238      protected override Expression DoResolve (ResolveContext ec)
239      {
240        Child = new IntConstant (ec.BuiltinTypes, (int) (flags | statement.flags), statement.loc);
241
242        type = ec.Module.PredefinedTypes.BinderFlags.Resolve ();
243        eclass = Child.eclass;
244        return this;
245      }
246    }
247
248    readonly Arguments arguments;
249    protected IDynamicBinder binder;
250    protected Expression binder_expr;
251
252    // Used by BinderFlags
253    protected CSharpBinderFlags flags;
254
255    TypeSpec binder_type;
256    TypeParameters context_mvars;
257
258    public DynamicExpressionStatement (IDynamicBinder binder, Arguments args, Location loc)
259    {
260      this.binder = binder;
261      this.arguments = args;
262      this.loc = loc;
263    }
264
265    public Arguments Arguments {
266      get {
267        return arguments;
268      }
269    }
270
271    public override bool ContainsEmitWithAwait ()
272    {
273      return arguments.ContainsEmitWithAwait ();
274    }
275
276    public override Expression CreateExpressionTree (ResolveContext ec)
277    {
278      ec.Report.Error (1963, loc, "An expression tree cannot contain a dynamic operation");
279      return null;
280    }
281
282    protected override Expression DoResolve (ResolveContext rc)
283    {
284      if (DoResolveCore (rc))
285        binder_expr = binder.CreateCallSiteBinder (rc, arguments);
286
287      return this;
288    }
289
290    protected bool DoResolveCore (ResolveContext rc)
291    {
292      if (rc.CurrentTypeParameters != null && rc.CurrentTypeParameters[0].IsMethodTypeParameter)
293        context_mvars = rc.CurrentTypeParameters;
294
295      int errors = rc.Report.Errors;
296      var pt = rc.Module.PredefinedTypes;
297
298      binder_type = pt.Binder.Resolve ();
299      pt.CallSite.Resolve ();
300      pt.CallSiteGeneric.Resolve ();
301
302      eclass = ExprClass.Value;
303
304      if (type == null)
305        type = rc.BuiltinTypes.Dynamic;
306
307      if (rc.Report.Errors == errors)
308        return true;
309
310      rc.Report.Error (1969, loc,
311        "Dynamic operation cannot be compiled without `Microsoft.CSharp.dll' assembly reference");
312      return false;
313    }
314
315    public override void Emit (EmitContext ec)
316    {
317      EmitCall (ec, binder_expr, arguments,  false);
318    }
319
320    public override void EmitStatement (EmitContext ec)
321    {
322      EmitCall (ec, binder_expr, arguments, true);
323    }
324
325    protected void EmitCall (EmitContext ec, Expression binder, Arguments arguments, bool isStatement)
326    {
327      //
328      // This method generates all internal infrastructure for a dynamic call. The
329      // reason why it's quite complicated is the mixture of dynamic and anonymous
330      // methods. Dynamic itself requires a temporary class (ContainerX) and anonymous
331      // methods can generate temporary storey as well (AnonStorey). Handling MVAR
332      // type parameters rewrite is non-trivial in such case as there are various
333      // combinations possible therefore the mutator is not straightforward. Secondly
334      // we need to keep both MVAR(possibly VAR for anon storey) and type VAR to emit
335      // correct Site field type and its access from EmitContext.
336      //
337
338      int dyn_args_count = arguments == null ? 0 : arguments.Count;
339      int default_args = isStatement ? 1 : 2;
340      var module = ec.Module;
341
342      bool has_ref_out_argument = false;
343      var targs = new TypeExpression[dyn_args_count + default_args];
344      targs[0] = new TypeExpression (module.PredefinedTypes.CallSite.TypeSpec, loc);
345
346      TypeExpression[] targs_for_instance = null;
347      TypeParameterMutator mutator;
348
349      var site_container = ec.CreateDynamicSite ();
350
351      if (context_mvars != null) {
352        TypeParameters tparam;
353        TypeContainer sc = site_container;
354        do {
355          tparam = sc.CurrentTypeParameters;
356          sc = sc.Parent;
357        } while (tparam == null);
358
359        mutator = new TypeParameterMutator (context_mvars, tparam);
360
361        if (!ec.IsAnonymousStoreyMutateRequired) {
362          targs_for_instance = new TypeExpression[targs.Length];
363          targs_for_instance[0] = targs[0];
364        }
365      } else {
366        mutator = null;
367      }
368
369      for (int i = 0; i < dyn_args_count; ++i) {
370        Argument a = arguments[i];
371        if (a.ArgType == Argument.AType.Out || a.ArgType == Argument.AType.Ref)
372          has_ref_out_argument = true;
373
374        var t = a.Type;
375
376        // Convert any internal type like dynamic or null to object
377        if (t.Kind == MemberKind.InternalCompilerType)
378          t = ec.BuiltinTypes.Object;
379
380        if (targs_for_instance != null)
381          targs_for_instance[i + 1] = new TypeExpression (t, loc);
382
383        if (mutator != null)
384          t = t.Mutate (mutator);
385
386        targs[i + 1] = new TypeExpression (t, loc);
387      }
388
389      TypeExpr del_type = null;
390      TypeExpr del_type_instance_access = null;
391      if (!has_ref_out_argument) {
392        string d_name = isStatement ? "Action" : "Func";
393
394        TypeSpec te = null;
395        Namespace type_ns = module.GlobalRootNamespace.GetNamespace ("System", true);
396        if (type_ns != null) {
397          te = type_ns.LookupType (module, d_name, dyn_args_count + default_args, LookupMode.Normal, loc);
398        }
399
400        if (te != null) {
401          if (!isStatement) {
402            var t = type;
403            if (t.Kind == MemberKind.InternalCompilerType)
404              t = ec.BuiltinTypes.Object;
405
406            if (targs_for_instance != null)
407              targs_for_instance[targs_for_instance.Length - 1] = new TypeExpression (t, loc);
408
409            if (mutator != null)
410              t = t.Mutate (mutator);
411
412            targs[targs.Length - 1] = new TypeExpression (t, loc);
413          }
414
415          del_type = new GenericTypeExpr (te, new TypeArguments (targs), loc);
416          if (targs_for_instance != null)
417            del_type_instance_access = new GenericTypeExpr (te, new TypeArguments (targs_for_instance), loc);
418          else
419            del_type_instance_access = del_type;
420        }
421      }
422
423      //
424      // Create custom delegate when no appropriate predefined delegate has been found
425      //
426      Delegate d;
427      if (del_type == null) {
428        TypeSpec rt = isStatement ? ec.BuiltinTypes.Void : type;
429        Parameter[] p = new Parameter[dyn_args_count + 1];
430        p[0] = new Parameter (targs[0], "p0", Parameter.Modifier.NONE, null, loc);
431
432        var site = ec.CreateDynamicSite ();
433        int index = site.Containers == null ? 0 : site.Containers.Count;
434
435        if (mutator != null)
436          rt = mutator.Mutate (rt);
437
438        for (int i = 1; i < dyn_args_count + 1; ++i) {
439          p[i] = new Parameter (targs[i], "p" + i.ToString ("X"), arguments[i - 1].Modifier, null, loc);
440        }
441
442        d = new Delegate (site, new TypeExpression (rt, loc),
443          Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED,
444          new MemberName ("Container" + index.ToString ("X")),
445          new ParametersCompiled (p), null);
446
447        d.CreateContainer ();
448        d.DefineContainer ();
449        d.Define ();
450        d.PrepareEmit ();
451
452        site.AddTypeContainer (d);
453
454        //
455        // Add new container to inflated site container when the
456        // member cache already exists
457        //
458        if (site.CurrentType is InflatedTypeSpec && index > 0)
459          site.CurrentType.MemberCache.AddMember (d.CurrentType);
460
461        del_type = new TypeExpression (d.CurrentType, loc);
462        if (targs_for_instance != null) {
463          del_type_instance_access = null;
464        } else {
465          del_type_instance_access = del_type;
466        }
467      } else {
468        d = null;
469      }
470
471      var site_type_decl = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec, new TypeArguments (del_type), loc);
472      var field = site_container.CreateCallSiteField (site_type_decl, loc);
473      if (field == null)
474        return;
475
476      if (del_type_instance_access == null) {
477        var dt = d.CurrentType.DeclaringType.MakeGenericType (module, context_mvars.Types);
478        del_type_instance_access = new TypeExpression (MemberCache.GetMember (dt, d.CurrentType), loc);
479      }
480
481      var instanceAccessExprType = new GenericTypeExpr (module.PredefinedTypes.CallSiteGeneric.TypeSpec,
482        new TypeArguments (del_type_instance_access), loc);
483
484      if (instanceAccessExprType.ResolveAsType (ec.MemberContext) == null)
485        return;
486
487      bool inflate_using_mvar = context_mvars != null && ec.IsAnonymousStoreyMutateRequired;
488
489      TypeSpec gt;
490      if (inflate_using_mvar || context_mvars == null) {
491        gt = site_container.CurrentType;
492      } else {
493        gt = site_container.CurrentType.MakeGenericType (module, context_mvars.Types);
494      }
495
496      // When site container already exists the inflated version has to be
497      // updated manually to contain newly created field
498      if (gt is InflatedTypeSpec && site_container.AnonymousMethodsCounter > 1) {
499        var tparams = gt.MemberDefinition.TypeParametersCount > 0 ? gt.MemberDefinition.TypeParameters : TypeParameterSpec.EmptyTypes;
500        var inflator = new TypeParameterInflator (module, gt, tparams, gt.TypeArguments);
501        gt.MemberCache.AddMember (field.InflateMember (inflator));
502      }
503
504      FieldExpr site_field_expr = new FieldExpr (MemberCache.GetMember (gt, field), loc);
505
506      BlockContext bc = new BlockContext (ec.MemberContext, null, ec.BuiltinTypes.Void);
507
508      Arguments args = new Arguments (1);
509      args.Add (new Argument (binder));
510      StatementExpression s = new StatementExpression (new SimpleAssign (site_field_expr, new Invocation (new MemberAccess (instanceAccessExprType, "Create"), args)));
511
512      using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
513        if (s.Resolve (bc)) {
514          Statement init = new If (new Binary (Binary.Operator.Equality, site_field_expr, new NullLiteral (loc)), s, loc);
515          init.Emit (ec);
516        }
517
518        args = new Arguments (1 + dyn_args_count);
519        args.Add (new Argument (site_field_expr));
520        if (arguments != null) {
521          int arg_pos = 1;
522          foreach (Argument a in arguments) {
523            if (a is NamedArgument) {
524              // Name is not valid in this context
525              args.Add (new Argument (a.Expr, a.ArgType));
526            } else {
527              args.Add (a);
528            }
529
530            if (inflate_using_mvar && a.Type != targs[arg_pos].Type)
531              a.Expr.Type = targs[arg_pos].Type;
532
533            ++arg_pos;
534          }
535        }
536
537        Expression target = new DelegateInvocation (new MemberAccess (site_field_expr, "Target", loc).Resolve (bc), args, false, loc).Resolve (bc);
538        if (target != null)
539          target.Emit (ec);
540      }
541    }
542
543    public override void FlowAnalysis (FlowAnalysisContext fc)
544    {
545      arguments.FlowAnalysis (fc);
546    }
547
548    public static MemberAccess GetBinderNamespace (Location loc)
549    {
550      return new MemberAccess (new MemberAccess (
551        new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "Microsoft", loc), "CSharp", loc), "RuntimeBinder", loc);
552    }
553
554    protected MemberAccess GetBinder (string name, Location loc)
555    {
556      return new MemberAccess (new TypeExpression (binder_type, loc), name, loc);
557    }
558  }
559
560  //
561  // Dynamic member access compound assignment for events
562  //
563  class DynamicEventCompoundAssign : ExpressionStatement
564  {
565    class IsEvent : DynamicExpressionStatement, IDynamicBinder
566    {
567      string name;
568
569      public IsEvent (string name, Arguments args, Location loc)
570        : base (null, args, loc)
571      {
572        this.name = name;
573        binder = this;
574      }
575
576      public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
577      {
578        type = ec.BuiltinTypes.Bool;
579
580        Arguments binder_args = new Arguments (3);
581
582        binder_args.Add (new Argument (new BinderFlags (0, this)));
583        binder_args.Add (new Argument (new StringLiteral (ec.BuiltinTypes, name, loc)));
584        binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
585
586        return new Invocation (GetBinder ("IsEvent", loc), binder_args);
587      }
588    }
589
590    Expression condition;
591    ExpressionStatement invoke, assign;
592
593    public DynamicEventCompoundAssign (string name, Arguments args, ExpressionStatement assignment, ExpressionStatement invoke, Location loc)
594    {
595      condition = new IsEvent (name, args, loc);
596      this.invoke = invoke;
597      this.assign = assignment;
598      this.loc = loc;
599    }
600
601    public override Expression CreateExpressionTree (ResolveContext ec)
602    {
603      return condition.CreateExpressionTree (ec);
604    }
605
606    protected override Expression DoResolve (ResolveContext rc)
607    {
608      type = rc.BuiltinTypes.Dynamic;
609      eclass = ExprClass.Value;
610      condition = condition.Resolve (rc);
611      return this;
612    }
613
614    public override void Emit (EmitContext ec)
615    {
616      var rc = new ResolveContext (ec.MemberContext);
617      var expr = new Conditional (new BooleanExpression (condition), invoke, assign, loc).Resolve (rc);
618      expr.Emit (ec);
619    }
620
621    public override void EmitStatement (EmitContext ec)
622    {
623      var stmt = new If (condition, new StatementExpression (invoke), new StatementExpression (assign), loc);
624      using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
625        stmt.Emit (ec);
626      }
627    }
628
629    public override void FlowAnalysis (FlowAnalysisContext fc)
630    {
631      invoke.FlowAnalysis (fc);
632    }
633  }
634
635  class DynamicConversion : DynamicExpressionStatement, IDynamicBinder
636  {
637    public DynamicConversion (TypeSpec targetType, CSharpBinderFlags flags, Arguments args, Location loc)
638      : base (null, args, loc)
639    {
640      type = targetType;
641      base.flags = flags;
642      base.binder = this;
643    }
644
645    public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
646    {
647      Arguments binder_args = new Arguments (3);
648
649      flags |= ec.HasSet (ResolveContext.Options.CheckedScope) ? CSharpBinderFlags.CheckedContext : 0;
650
651      binder_args.Add (new Argument (new BinderFlags (flags, this)));
652      binder_args.Add (new Argument (new TypeOf (type, loc)));
653      binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
654      return new Invocation (GetBinder ("Convert", loc), binder_args);
655    }
656  }
657
658  class DynamicConstructorBinder : DynamicExpressionStatement, IDynamicBinder
659  {
660    public DynamicConstructorBinder (TypeSpec type, Arguments args, Location loc)
661      : base (null, args, loc)
662    {
663      this.type = type;
664      base.binder = this;
665    }
666
667    public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
668    {
669      Arguments binder_args = new Arguments (3);
670
671      binder_args.Add (new Argument (new BinderFlags (0, this)));
672      binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
673      binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
674
675      return new Invocation (GetBinder ("InvokeConstructor", loc), binder_args);
676    }
677  }
678
679  class DynamicIndexBinder : DynamicMemberAssignable
680  {
681    bool can_be_mutator;
682
683    public DynamicIndexBinder (Arguments args, Location loc)
684      : base (args, loc)
685    {
686    }
687
688    public DynamicIndexBinder (CSharpBinderFlags flags, Arguments args, Location loc)
689      : this (args, loc)
690    {
691      base.flags = flags;
692    }
693
694    protected override Expression DoResolve (ResolveContext ec)
695    {
696      can_be_mutator = true;
697      return base.DoResolve (ec);
698    }
699
700    protected override Expression CreateCallSiteBinder (ResolveContext ec, Arguments args, bool isSet)
701    {
702      Arguments binder_args = new Arguments (3);
703
704      binder_args.Add (new Argument (new BinderFlags (flags, this)));
705      binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
706      binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
707
708      isSet |= (flags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0;
709      return new Invocation (GetBinder (isSet ? "SetIndex" : "GetIndex", loc), binder_args);
710    }
711
712    protected override Arguments CreateSetterArguments (ResolveContext rc, Expression rhs)
713    {
714      //
715      // Indexer has arguments which complicates things as the setter and getter
716      // are called in two steps when unary mutator is used. We have to make a
717      // copy of all variable arguments to not duplicate any side effect.
718      //
719      // ++d[++arg, Foo ()]
720      //
721
722      if (!can_be_mutator)
723        return base.CreateSetterArguments (rc, rhs);
724
725      var setter_args = new Arguments (Arguments.Count + 1);
726      for (int i = 0; i < Arguments.Count; ++i) {
727        var expr = Arguments[i].Expr;
728
729        if (expr is Constant || expr is VariableReference || expr is This) {
730          setter_args.Add (Arguments [i]);
731          continue;
732        }
733
734        LocalVariable temp = LocalVariable.CreateCompilerGenerated (expr.Type, rc.CurrentBlock, loc);
735        expr = new SimpleAssign (temp.CreateReferenceExpression (rc, expr.Location), expr).Resolve (rc);
736        Arguments[i].Expr = temp.CreateReferenceExpression (rc, expr.Location).Resolve (rc);
737        setter_args.Add (Arguments [i].Clone (expr));
738      }
739
740      setter_args.Add (new Argument (rhs));
741      return setter_args;
742    }
743  }
744
745  class DynamicInvocation : DynamicExpressionStatement, IDynamicBinder
746  {
747    readonly ATypeNameExpression member;
748
749    public DynamicInvocation (ATypeNameExpression member, Arguments args, Location loc)
750      : base (null, args, loc)
751    {
752      base.binder = this;
753      this.member = member;
754    }
755
756    public static DynamicInvocation CreateSpecialNameInvoke (ATypeNameExpression member, Arguments args, Location loc)
757    {
758      return new DynamicInvocation (member, args, loc) {
759        flags = CSharpBinderFlags.InvokeSpecialName
760      };
761    }
762
763    public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
764    {
765      Arguments binder_args = new Arguments (member != null ? 5 : 3);
766      bool is_member_access = member is MemberAccess;
767
768      CSharpBinderFlags call_flags;
769      if (!is_member_access && member is SimpleName) {
770        call_flags = CSharpBinderFlags.InvokeSimpleName;
771        is_member_access = true;
772      } else {
773        call_flags = 0;
774      }
775
776      binder_args.Add (new Argument (new BinderFlags (call_flags, this)));
777
778      if (is_member_access)
779        binder_args.Add (new Argument (new StringLiteral (ec.BuiltinTypes, member.Name, member.Location)));
780
781      if (member != null && member.HasTypeArguments) {
782        TypeArguments ta = member.TypeArguments;
783        if (ta.Resolve (ec)) {
784          var targs = new ArrayInitializer (ta.Count, loc);
785          foreach (TypeSpec t in ta.Arguments)
786            targs.Add (new TypeOf (t, loc));
787
788          binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (targs, loc)));
789        }
790      } else if (is_member_access) {
791        binder_args.Add (new Argument (new NullLiteral (loc)));
792      }
793
794      binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
795
796      Expression real_args;
797      if (args == null) {
798        // Cannot be null because .NET trips over
799        real_args = new ArrayCreation (
800          new MemberAccess (GetBinderNamespace (loc), "CSharpArgumentInfo", loc),
801          new ArrayInitializer (0, loc), loc);
802      } else {
803        real_args = new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc);
804      }
805
806      binder_args.Add (new Argument (real_args));
807
808      return new Invocation (GetBinder (is_member_access ? "InvokeMember" : "Invoke", loc), binder_args);
809    }
810
811    public override void EmitStatement (EmitContext ec)
812    {
813      flags |= CSharpBinderFlags.ResultDiscarded;
814      base.EmitStatement (ec);
815    }
816  }
817
818  class DynamicMemberBinder : DynamicMemberAssignable
819  {
820    readonly string name;
821
822    public DynamicMemberBinder (string name, Arguments args, Location loc)
823      : base (args, loc)
824    {
825      this.name = name;
826    }
827
828    public DynamicMemberBinder (string name, CSharpBinderFlags flags, Arguments args, Location loc)
829      : this (name, args, loc)
830    {
831      base.flags = flags;
832    }
833
834    protected override Expression CreateCallSiteBinder (ResolveContext ec, Arguments args, bool isSet)
835    {
836      Arguments binder_args = new Arguments (4);
837
838      binder_args.Add (new Argument (new BinderFlags (flags, this)));
839      binder_args.Add (new Argument (new StringLiteral (ec.BuiltinTypes, name, loc)));
840      binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
841      binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
842
843      isSet |= (flags & CSharpBinderFlags.ValueFromCompoundAssignment) != 0;
844      return new Invocation (GetBinder (isSet ? "SetMember" : "GetMember", loc), binder_args);
845    }
846  }
847
848  //
849  // Any member binder which can be source and target of assignment
850  //
851  abstract class DynamicMemberAssignable : DynamicExpressionStatement, IDynamicBinder, IAssignMethod
852  {
853    Expression setter;
854    Arguments setter_args;
855
856    protected DynamicMemberAssignable (Arguments args, Location loc)
857      : base (null, args, loc)
858    {
859      base.binder = this;
860    }
861
862    public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
863    {
864      //
865      // DoResolve always uses getter
866      //
867      return CreateCallSiteBinder (ec, args, false);
868    }
869
870    protected abstract Expression CreateCallSiteBinder (ResolveContext ec, Arguments args, bool isSet);
871
872    protected virtual Arguments CreateSetterArguments (ResolveContext rc, Expression rhs)
873    {
874      var setter_args = new Arguments (Arguments.Count + 1);
875      setter_args.AddRange (Arguments);
876      setter_args.Add (new Argument (rhs));
877      return setter_args;
878    }
879
880    public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
881    {
882      if (right_side == EmptyExpression.OutAccess) {
883        right_side.DoResolveLValue (rc, this);
884        return null;
885      }
886
887      if (DoResolveCore (rc)) {
888        setter_args = CreateSetterArguments (rc, right_side);
889        setter = CreateCallSiteBinder (rc, setter_args, true);
890      }
891
892      eclass = ExprClass.Variable;
893      return this;
894    }
895
896    public override void Emit (EmitContext ec)
897    {
898      // It's null for ResolveLValue used without assignment
899      if (binder_expr == null)
900        EmitCall (ec, setter, Arguments, false);
901      else
902        base.Emit (ec);
903    }
904
905    public override void EmitStatement (EmitContext ec)
906    {
907      // It's null for ResolveLValue used without assignment
908      if (binder_expr == null)
909        EmitCall (ec, setter, Arguments, true);
910      else
911        base.EmitStatement (ec);
912    }
913
914    #region IAssignMethod Members
915
916    public void Emit (EmitContext ec, bool leave_copy)
917    {
918      throw new NotImplementedException ();
919    }
920
921    public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
922    {
923      EmitCall (ec, setter, setter_args, !leave_copy);
924    }
925
926    #endregion
927  }
928
929  class DynamicUnaryConversion : DynamicExpressionStatement, IDynamicBinder
930  {
931    readonly string name;
932
933    public DynamicUnaryConversion (string name, Arguments args, Location loc)
934      : base (null, args, loc)
935    {
936      this.name = name;
937      base.binder = this;
938    }
939
940    public static DynamicUnaryConversion CreateIsTrue (ResolveContext rc, Arguments args, Location loc)
941    {
942      return new DynamicUnaryConversion ("IsTrue", args, loc) { type = rc.BuiltinTypes.Bool };
943    }
944
945    public static DynamicUnaryConversion CreateIsFalse (ResolveContext rc, Arguments args, Location loc)
946    {
947      return new DynamicUnaryConversion ("IsFalse", args, loc) { type = rc.BuiltinTypes.Bool };
948    }
949
950    public Expression CreateCallSiteBinder (ResolveContext ec, Arguments args)
951    {
952      Arguments binder_args = new Arguments (4);
953
954      MemberAccess sle = new MemberAccess (new MemberAccess (
955        new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Linq", loc), "Expressions", loc);
956
957      var flags = ec.HasSet (ResolveContext.Options.CheckedScope) ? CSharpBinderFlags.CheckedContext : 0;
958
959      binder_args.Add (new Argument (new BinderFlags (flags, this)));
960      binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), name, loc)));
961      binder_args.Add (new Argument (new TypeOf (ec.CurrentType, loc)));
962      binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
963
964      return new Invocation (GetBinder ("UnaryOperation", loc), binder_args);
965    }
966  }
967
968  sealed class DynamicSiteClass : HoistedStoreyClass
969  {
970    public DynamicSiteClass (TypeDefinition parent, MemberBase host, TypeParameters tparams)
971      : base (parent, MakeMemberName (host, "DynamicSite", parent.DynamicSitesCounter, tparams, Location.Null), tparams, Modifiers.STATIC, MemberKind.Class)
972    {
973      parent.DynamicSitesCounter++;
974    }
975
976    public FieldSpec CreateCallSiteField (FullNamedExpression type, Location loc)
977    {
978      int index = AnonymousMethodsCounter++;
979      Field f = new HoistedField (this, type, Modifiers.PUBLIC | Modifiers.STATIC, "Site" + index.ToString ("X"), null, loc);
980      f.Define ();
981
982      AddField (f);
983      return f.Spec;
984    }
985  }
986}
Note: See TracBrowser for help on using the repository browser.