Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Resolver/CSharpOperators.cs

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

#2077: created branch and added first version

File size: 35.2 KB
Line 
1// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4// software and associated documentation files (the "Software"), to deal in the Software
5// without restriction, including without limitation the rights to use, copy, modify, merge,
6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7// to whom the Software is furnished to do so, subject to the following conditions:
8//
9// The above copyright notice and this permission notice shall be included in all copies or
10// substantial portions of the Software.
11//
12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17// DEALINGS IN THE SOFTWARE.
18
19using System;
20using System.Collections.Generic;
21using System.Linq;
22using System.Text;
23using ICSharpCode.NRefactory.TypeSystem;
24using ICSharpCode.NRefactory.TypeSystem.Implementation;
25using ICSharpCode.NRefactory.Utils;
26
27namespace ICSharpCode.NRefactory.CSharp.Resolver
28{
29  sealed class CSharpOperators
30  {
31    readonly ICompilation compilation;
32   
33    private CSharpOperators(ICompilation compilation)
34    {
35      this.compilation = compilation;
36      InitParameterArrays();
37    }
38   
39    /// <summary>
40    /// Gets the CSharpOperators instance for the specified <see cref="ICompilation"/>.
41    /// This will make use of the context's cache manager (if available) to reuse the CSharpOperators instance.
42    /// </summary>
43    public static CSharpOperators Get(ICompilation compilation)
44    {
45      CacheManager cache = compilation.CacheManager;
46      CSharpOperators operators = (CSharpOperators)cache.GetShared(typeof(CSharpOperators));
47      if (operators == null) {
48        operators = (CSharpOperators)cache.GetOrAddShared(typeof(CSharpOperators), new CSharpOperators(compilation));
49      }
50      return operators;
51    }
52   
53    #region class OperatorMethod
54    OperatorMethod[] Lift(params OperatorMethod[] methods)
55    {
56      List<OperatorMethod> result = new List<OperatorMethod>(methods);
57      foreach (OperatorMethod method in methods) {
58        OperatorMethod lifted = method.Lift(this);
59        if (lifted != null)
60          result.Add(lifted);
61      }
62      return result.ToArray();
63    }
64   
65    IParameter[] normalParameters = new IParameter[(int)(TypeCode.String + 1 - TypeCode.Object)];
66    IParameter[] nullableParameters = new IParameter[(int)(TypeCode.Decimal + 1 - TypeCode.Boolean)];
67   
68    void InitParameterArrays()
69    {
70      for (TypeCode i = TypeCode.Object; i <= TypeCode.String; i++) {
71        normalParameters[i - TypeCode.Object] = new DefaultParameter(compilation.FindType(i), string.Empty);
72      }
73      for (TypeCode i = TypeCode.Boolean; i <= TypeCode.Decimal; i++) {
74        IType type = NullableType.Create(compilation, compilation.FindType(i));
75        nullableParameters[i - TypeCode.Boolean] = new DefaultParameter(type, string.Empty);
76      }
77    }
78   
79    IParameter MakeParameter(TypeCode code)
80    {
81      return normalParameters[code - TypeCode.Object];
82    }
83   
84    IParameter MakeNullableParameter(IParameter normalParameter)
85    {
86      for (TypeCode i = TypeCode.Boolean; i <= TypeCode.Decimal; i++) {
87        if (normalParameter == normalParameters[i - TypeCode.Object])
88          return nullableParameters[i - TypeCode.Boolean];
89      }
90      throw new ArgumentException();
91    }
92   
93    internal class OperatorMethod : IParameterizedMember
94    {
95      readonly ICompilation compilation;
96      readonly IList<IParameter> parameters = new List<IParameter>();
97     
98      protected OperatorMethod(ICompilation compilation)
99      {
100        this.compilation = compilation;
101      }
102     
103      public IList<IParameter> Parameters {
104        get { return parameters; }
105      }
106     
107      public IType ReturnType { get; internal set; }
108     
109      public ICompilation Compilation {
110        get { return compilation; }
111      }
112     
113      public virtual OperatorMethod Lift(CSharpOperators operators)
114      {
115        return null;
116      }
117     
118      ITypeDefinition IEntity.DeclaringTypeDefinition {
119        get { return null; }
120      }
121     
122      IType IEntity.DeclaringType {
123        get { return SpecialType.UnknownType; }
124      }
125     
126      IMember IMember.MemberDefinition {
127        get { return this; }
128      }
129     
130      IUnresolvedMember IMember.UnresolvedMember {
131        get { return null; }
132      }
133     
134      IList<IMember> IMember.ImplementedInterfaceMembers {
135        get { return EmptyList<IMember>.Instance; }
136      }
137     
138      bool IMember.IsVirtual {
139        get { return false; }
140      }
141     
142      bool IMember.IsOverride {
143        get { return false; }
144      }
145     
146      bool IMember.IsOverridable {
147        get { return false; }
148      }
149     
150      SymbolKind ISymbol.SymbolKind {
151        get { return SymbolKind.Operator; }
152      }
153     
154      [Obsolete("Use the SymbolKind property instead.")]
155      EntityType IEntity.EntityType {
156        get { return EntityType.Operator; }
157      }
158     
159      DomRegion IEntity.Region {
160        get { return DomRegion.Empty; }
161      }
162     
163      DomRegion IEntity.BodyRegion {
164        get { return DomRegion.Empty; }
165      }
166     
167      IList<IAttribute> IEntity.Attributes {
168        get { return EmptyList<IAttribute>.Instance; }
169      }
170     
171      Documentation.DocumentationComment IEntity.Documentation {
172        get { return null; }
173      }
174     
175      Accessibility IHasAccessibility.Accessibility {
176        get { return Accessibility.Public; }
177      }
178     
179      bool IEntity.IsStatic {
180        get { return true; }
181      }
182     
183      bool IEntity.IsAbstract {
184        get { return false; }
185      }
186     
187      bool IEntity.IsSealed {
188        get { return false; }
189      }
190     
191      bool IEntity.IsShadowing {
192        get { return false; }
193      }
194     
195      bool IEntity.IsSynthetic {
196        get { return true; }
197      }
198     
199      bool IHasAccessibility.IsPrivate {
200        get { return false; }
201      }
202     
203      bool IHasAccessibility.IsPublic {
204        get { return true; }
205      }
206     
207      bool IHasAccessibility.IsProtected {
208        get { return false; }
209      }
210     
211      bool IHasAccessibility.IsInternal {
212        get { return false; }
213      }
214     
215      bool IHasAccessibility.IsProtectedOrInternal {
216        get { return false; }
217      }
218     
219      bool IHasAccessibility.IsProtectedAndInternal {
220        get { return false; }
221      }
222     
223      bool IMember.IsExplicitInterfaceImplementation {
224        get { return false; }
225      }
226     
227      IAssembly IEntity.ParentAssembly {
228        get { return compilation.MainAssembly; }
229      }
230     
231      IMemberReference IMember.ToMemberReference()
232      {
233        throw new NotSupportedException();
234      }
235     
236      ISymbolReference ISymbol.ToReference()
237      {
238        throw new NotSupportedException();
239      }
240     
241      IMemberReference IMember.ToReference()
242      {
243        throw new NotSupportedException();
244      }
245
246      TypeParameterSubstitution IMember.Substitution {
247        get {
248          return TypeParameterSubstitution.Identity;
249        }
250      }
251
252      IMember IMember.Specialize(TypeParameterSubstitution substitution)
253      {
254        if (TypeParameterSubstitution.Identity.Equals(substitution))
255          return this;
256        throw new NotSupportedException();
257      }
258
259      string INamedElement.FullName {
260        get { return "operator"; }
261      }
262     
263      public string Name {
264        get { return "operator"; }
265      }
266     
267      string INamedElement.Namespace {
268        get { return string.Empty; }
269      }
270     
271      string INamedElement.ReflectionName {
272        get { return "operator"; }
273      }
274     
275      public override string ToString()
276      {
277        StringBuilder b = new StringBuilder();
278        b.Append(ReturnType + " operator(");
279        for (int i = 0; i < parameters.Count; i++) {
280          if (i > 0)
281            b.Append(", ");
282          b.Append(parameters[i].Type);
283        }
284        b.Append(')');
285        return b.ToString();
286      }
287    }
288    #endregion
289   
290    #region Unary operator class definitions
291    internal class UnaryOperatorMethod : OperatorMethod
292    {
293      public virtual bool CanEvaluateAtCompileTime { get { return false; } }
294     
295      public virtual object Invoke(CSharpResolver resolver, object input)
296      {
297        throw new NotSupportedException();
298      }
299     
300      public UnaryOperatorMethod(ICompilation compilaton) : base(compilaton)
301      {
302      }
303    }
304   
305    sealed class LambdaUnaryOperatorMethod<T> : UnaryOperatorMethod
306    {
307      readonly Func<T, T> func;
308     
309      public LambdaUnaryOperatorMethod(CSharpOperators operators, Func<T, T> func)
310        : base(operators.compilation)
311      {
312        TypeCode typeCode = Type.GetTypeCode(typeof(T));
313        this.ReturnType = operators.compilation.FindType(typeCode);
314        this.Parameters.Add(operators.MakeParameter(typeCode));
315        this.func = func;
316      }
317     
318      public override bool CanEvaluateAtCompileTime {
319        get { return true; }
320      }
321     
322      public override object Invoke(CSharpResolver resolver, object input)
323      {
324        if (input == null)
325          return null;
326        return func((T)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T)), input));
327      }
328     
329      public override OperatorMethod Lift(CSharpOperators operators)
330      {
331        return new LiftedUnaryOperatorMethod(operators, this);
332      }
333    }
334   
335    sealed class LiftedUnaryOperatorMethod : UnaryOperatorMethod, OverloadResolution.ILiftedOperator
336    {
337      UnaryOperatorMethod baseMethod;
338     
339      public LiftedUnaryOperatorMethod(CSharpOperators operators, UnaryOperatorMethod baseMethod) : base(operators.compilation)
340      {
341        this.baseMethod = baseMethod;
342        this.ReturnType = NullableType.Create(baseMethod.Compilation, baseMethod.ReturnType);
343        this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[0]));
344      }
345     
346      public IList<IParameter> NonLiftedParameters {
347        get { return baseMethod.Parameters; }
348      }
349    }
350    #endregion
351   
352    #region Unary operator definitions
353    // C# 4.0 spec: §7.7.1 Unary plus operator
354    OperatorMethod[] unaryPlusOperators;
355   
356    public OperatorMethod[] UnaryPlusOperators {
357      get {
358        OperatorMethod[] ops = LazyInit.VolatileRead(ref unaryPlusOperators);
359        if (ops != null) {
360          return ops;
361        } else {
362          return LazyInit.GetOrSet(ref unaryPlusOperators, Lift(
363            new LambdaUnaryOperatorMethod<int>    (this, i => +i),
364            new LambdaUnaryOperatorMethod<uint>   (this, i => +i),
365            new LambdaUnaryOperatorMethod<long>   (this, i => +i),
366            new LambdaUnaryOperatorMethod<ulong>  (this, i => +i),
367            new LambdaUnaryOperatorMethod<float>  (this, i => +i),
368            new LambdaUnaryOperatorMethod<double> (this, i => +i),
369            new LambdaUnaryOperatorMethod<decimal>(this, i => +i)
370          ));
371        }
372      }
373    }
374   
375    // C# 4.0 spec: §7.7.2 Unary minus operator
376    OperatorMethod[] uncheckedUnaryMinusOperators;
377   
378    public OperatorMethod[] UncheckedUnaryMinusOperators {
379      get {
380        OperatorMethod[] ops = LazyInit.VolatileRead(ref uncheckedUnaryMinusOperators);
381        if (ops != null) {
382          return ops;
383        } else {
384          return LazyInit.GetOrSet(ref uncheckedUnaryMinusOperators, Lift(
385            new LambdaUnaryOperatorMethod<int>    (this, i => unchecked(-i)),
386            new LambdaUnaryOperatorMethod<long>   (this, i => unchecked(-i)),
387            new LambdaUnaryOperatorMethod<float>  (this, i => unchecked(-i)),
388            new LambdaUnaryOperatorMethod<double> (this, i => unchecked(-i)),
389            new LambdaUnaryOperatorMethod<decimal>(this, i => unchecked(-i))
390          ));
391        }
392      }
393    }
394   
395    OperatorMethod[] checkedUnaryMinusOperators;
396   
397    public OperatorMethod[] CheckedUnaryMinusOperators {
398      get {
399        OperatorMethod[] ops = LazyInit.VolatileRead(ref checkedUnaryMinusOperators);
400        if (ops != null) {
401          return ops;
402        } else {
403          return LazyInit.GetOrSet(ref checkedUnaryMinusOperators, Lift(
404            new LambdaUnaryOperatorMethod<int>    (this, i => checked(-i)),
405            new LambdaUnaryOperatorMethod<long>   (this, i => checked(-i)),
406            new LambdaUnaryOperatorMethod<float>  (this, i => checked(-i)),
407            new LambdaUnaryOperatorMethod<double> (this, i => checked(-i)),
408            new LambdaUnaryOperatorMethod<decimal>(this, i => checked(-i))
409          ));
410        }
411      }
412    }
413   
414    // C# 4.0 spec: §7.7.3 Logical negation operator
415    OperatorMethod[] logicalNegationOperators;
416   
417    public OperatorMethod[] LogicalNegationOperators {
418      get {
419        OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalNegationOperators);
420        if (ops != null) {
421          return ops;
422        } else {
423          return LazyInit.GetOrSet(ref logicalNegationOperators, Lift(
424            new LambdaUnaryOperatorMethod<bool>(this, b => !b)
425          ));
426        }
427      }
428    }
429   
430    // C# 4.0 spec: §7.7.4 Bitwise complement operator
431    OperatorMethod[] bitwiseComplementOperators;
432   
433    public OperatorMethod[] BitwiseComplementOperators {
434      get {
435        OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseComplementOperators);
436        if (ops != null) {
437          return ops;
438        } else {
439          return LazyInit.GetOrSet(ref bitwiseComplementOperators, Lift(
440            new LambdaUnaryOperatorMethod<int>  (this, i => ~i),
441            new LambdaUnaryOperatorMethod<uint> (this, i => ~i),
442            new LambdaUnaryOperatorMethod<long> (this, i => ~i),
443            new LambdaUnaryOperatorMethod<ulong>(this, i => ~i)
444          ));
445        }
446      }
447    }
448    #endregion
449   
450    #region Binary operator class definitions
451    internal class BinaryOperatorMethod : OperatorMethod
452    {
453      public virtual bool CanEvaluateAtCompileTime { get { return false; } }
454      public virtual object Invoke(CSharpResolver resolver, object lhs, object rhs) {
455        throw new NotSupportedException();
456      }
457     
458      public BinaryOperatorMethod(ICompilation compilation) : base(compilation) {}
459    }
460   
461    sealed class LambdaBinaryOperatorMethod<T1, T2> : BinaryOperatorMethod
462    {
463      readonly Func<T1, T2, T1> checkedFunc;
464      readonly Func<T1, T2, T1> uncheckedFunc;
465     
466      public LambdaBinaryOperatorMethod(CSharpOperators operators, Func<T1, T2, T1> func)
467        : this(operators, func, func)
468      {
469      }
470     
471      public LambdaBinaryOperatorMethod(CSharpOperators operators, Func<T1, T2, T1> checkedFunc, Func<T1, T2, T1> uncheckedFunc)
472        : base(operators.compilation)
473      {
474        TypeCode t1 = Type.GetTypeCode(typeof(T1));
475        this.ReturnType = operators.compilation.FindType(t1);
476        this.Parameters.Add(operators.MakeParameter(t1));
477        this.Parameters.Add(operators.MakeParameter(Type.GetTypeCode(typeof(T2))));
478        this.checkedFunc = checkedFunc;
479        this.uncheckedFunc = uncheckedFunc;
480      }
481     
482      public override bool CanEvaluateAtCompileTime {
483        get { return true; }
484      }
485     
486      public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
487      {
488        if (lhs == null || rhs == null)
489          return null;
490        Func<T1, T2, T1> func = resolver.CheckForOverflow ? checkedFunc : uncheckedFunc;
491        return func((T1)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T1)), lhs),
492                    (T2)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T2)), rhs));
493      }
494     
495      public override OperatorMethod Lift(CSharpOperators operators)
496      {
497        return new LiftedBinaryOperatorMethod(operators, this);
498      }
499    }
500   
501    sealed class LiftedBinaryOperatorMethod : BinaryOperatorMethod, OverloadResolution.ILiftedOperator
502    {
503      readonly BinaryOperatorMethod baseMethod;
504     
505      public LiftedBinaryOperatorMethod(CSharpOperators operators, BinaryOperatorMethod baseMethod)
506        : base(operators.compilation)
507      {
508        this.baseMethod = baseMethod;
509        this.ReturnType = NullableType.Create(operators.compilation, baseMethod.ReturnType);
510        this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[0]));
511        this.Parameters.Add(operators.MakeNullableParameter(baseMethod.Parameters[1]));
512      }
513     
514      public IList<IParameter> NonLiftedParameters {
515        get { return baseMethod.Parameters; }
516      }
517    }
518    #endregion
519   
520    #region Arithmetic operators
521    // C# 4.0 spec: §7.8.1 Multiplication operator
522   
523    OperatorMethod[] multiplicationOperators;
524   
525    public OperatorMethod[] MultiplicationOperators {
526      get {
527        OperatorMethod[] ops = LazyInit.VolatileRead(ref multiplicationOperators);
528        if (ops != null) {
529          return ops;
530        } else {
531          return LazyInit.GetOrSet(ref multiplicationOperators, Lift(
532            new LambdaBinaryOperatorMethod<int,     int>    (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
533            new LambdaBinaryOperatorMethod<uint,    uint>   (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
534            new LambdaBinaryOperatorMethod<long,    long>   (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
535            new LambdaBinaryOperatorMethod<ulong,   ulong>  (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
536            new LambdaBinaryOperatorMethod<float,   float>  (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
537            new LambdaBinaryOperatorMethod<double,  double> (this, (a, b) => checked(a * b), (a, b) => unchecked(a * b)),
538            new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a * b), (a, b) => unchecked(a * b))
539          ));
540        }
541      }
542    }
543   
544    // C# 4.0 spec: §7.8.2 Division operator
545    OperatorMethod[] divisionOperators;
546   
547    public OperatorMethod[] DivisionOperators {
548      get {
549        OperatorMethod[] ops = LazyInit.VolatileRead(ref divisionOperators);
550        if (ops != null) {
551          return ops;
552        } else {
553          return LazyInit.GetOrSet(ref divisionOperators, Lift(
554            new LambdaBinaryOperatorMethod<int,     int>    (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
555            new LambdaBinaryOperatorMethod<uint,    uint>   (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
556            new LambdaBinaryOperatorMethod<long,    long>   (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
557            new LambdaBinaryOperatorMethod<ulong,   ulong>  (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
558            new LambdaBinaryOperatorMethod<float,   float>  (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
559            new LambdaBinaryOperatorMethod<double,  double> (this, (a, b) => checked(a / b), (a, b) => unchecked(a / b)),
560            new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a / b), (a, b) => unchecked(a / b))
561          ));
562        }
563      }
564    }
565   
566    // C# 4.0 spec: §7.8.3 Remainder operator
567    OperatorMethod[] remainderOperators;
568   
569    public OperatorMethod[] RemainderOperators {
570      get {
571        OperatorMethod[] ops = LazyInit.VolatileRead(ref remainderOperators);
572        if (ops != null) {
573          return ops;
574        } else {
575          return LazyInit.GetOrSet(ref remainderOperators, Lift(
576            new LambdaBinaryOperatorMethod<int,     int>    (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
577            new LambdaBinaryOperatorMethod<uint,    uint>   (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
578            new LambdaBinaryOperatorMethod<long,    long>   (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
579            new LambdaBinaryOperatorMethod<ulong,   ulong>  (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
580            new LambdaBinaryOperatorMethod<float,   float>  (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
581            new LambdaBinaryOperatorMethod<double,  double> (this, (a, b) => checked(a % b), (a, b) => unchecked(a % b)),
582            new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a % b), (a, b) => unchecked(a % b))
583          ));
584        }
585      }
586    }
587   
588    // C# 4.0 spec: §7.8.3 Addition operator
589    OperatorMethod[] additionOperators;
590   
591    public OperatorMethod[] AdditionOperators {
592      get {
593        OperatorMethod[] ops = LazyInit.VolatileRead(ref additionOperators);
594        if (ops != null) {
595          return ops;
596        } else {
597          return LazyInit.GetOrSet(ref additionOperators, Lift(
598            new LambdaBinaryOperatorMethod<int,     int>    (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
599            new LambdaBinaryOperatorMethod<uint,    uint>   (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
600            new LambdaBinaryOperatorMethod<long,    long>   (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
601            new LambdaBinaryOperatorMethod<ulong,   ulong>  (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
602            new LambdaBinaryOperatorMethod<float,   float>  (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
603            new LambdaBinaryOperatorMethod<double,  double> (this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
604            new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a + b), (a, b) => unchecked(a + b)),
605            new StringConcatenation(this, TypeCode.String, TypeCode.String),
606            new StringConcatenation(this, TypeCode.String, TypeCode.Object),
607            new StringConcatenation(this, TypeCode.Object, TypeCode.String)
608          ));
609        }
610      }
611    }
612   
613    // not in this list, but handled manually: enum addition, delegate combination
614    sealed class StringConcatenation : BinaryOperatorMethod
615    {
616      bool canEvaluateAtCompileTime;
617     
618      public StringConcatenation(CSharpOperators operators, TypeCode p1, TypeCode p2)
619        : base(operators.compilation)
620      {
621        this.canEvaluateAtCompileTime = p1 == TypeCode.String && p2 == TypeCode.String;
622        this.ReturnType = operators.compilation.FindType(KnownTypeCode.String);
623        this.Parameters.Add(operators.MakeParameter(p1));
624        this.Parameters.Add(operators.MakeParameter(p2));
625      }
626     
627      public override bool CanEvaluateAtCompileTime {
628        get { return canEvaluateAtCompileTime; }
629      }
630     
631      public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
632      {
633        return string.Concat(lhs, rhs);
634      }
635    }
636   
637    // C# 4.0 spec: §7.8.4 Subtraction operator
638    OperatorMethod[] subtractionOperators;
639   
640    public OperatorMethod[] SubtractionOperators {
641      get {
642        OperatorMethod[] ops = LazyInit.VolatileRead(ref subtractionOperators);
643        if (ops != null) {
644          return ops;
645        } else {
646          return LazyInit.GetOrSet(ref subtractionOperators, Lift(
647            new LambdaBinaryOperatorMethod<int,     int>    (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
648            new LambdaBinaryOperatorMethod<uint,    uint>   (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
649            new LambdaBinaryOperatorMethod<long,    long>   (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
650            new LambdaBinaryOperatorMethod<ulong,   ulong>  (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
651            new LambdaBinaryOperatorMethod<float,   float>  (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
652            new LambdaBinaryOperatorMethod<double,  double> (this, (a, b) => checked(a - b), (a, b) => unchecked(a - b)),
653            new LambdaBinaryOperatorMethod<decimal, decimal>(this, (a, b) => checked(a - b), (a, b) => unchecked(a - b))
654          ));
655        }
656      }
657    }
658   
659    // C# 4.0 spec: §7.8.5 Shift operators
660    OperatorMethod[] shiftLeftOperators;
661   
662    public OperatorMethod[] ShiftLeftOperators {
663      get {
664        OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftLeftOperators);
665        if (ops != null) {
666          return ops;
667        } else {
668          return LazyInit.GetOrSet(ref shiftLeftOperators, Lift(
669            new LambdaBinaryOperatorMethod<int,   int>(this, (a, b) => a << b),
670            new LambdaBinaryOperatorMethod<uint,  int>(this, (a, b) => a << b),
671            new LambdaBinaryOperatorMethod<long,  int>(this, (a, b) => a << b),
672            new LambdaBinaryOperatorMethod<ulong, int>(this, (a, b) => a << b)
673          ));
674        }
675      }
676    }
677   
678    OperatorMethod[] shiftRightOperators;
679   
680    public OperatorMethod[] ShiftRightOperators {
681      get {
682        OperatorMethod[] ops = LazyInit.VolatileRead(ref shiftRightOperators);
683        if (ops != null) {
684          return ops;
685        } else {
686          return LazyInit.GetOrSet(ref shiftRightOperators, Lift(
687            new LambdaBinaryOperatorMethod<int,   int>(this, (a, b) => a >> b),
688            new LambdaBinaryOperatorMethod<uint,  int>(this, (a, b) => a >> b),
689            new LambdaBinaryOperatorMethod<long,  int>(this, (a, b) => a >> b),
690            new LambdaBinaryOperatorMethod<ulong, int>(this, (a, b) => a >> b)
691          ));
692        }
693      }
694    }
695    #endregion
696   
697    #region Equality operators
698    sealed class EqualityOperatorMethod : BinaryOperatorMethod
699    {
700      public readonly TypeCode Type;
701      public readonly bool Negate;
702     
703      public EqualityOperatorMethod(CSharpOperators operators, TypeCode type, bool negate)
704        : base(operators.compilation)
705      {
706        this.Negate = negate;
707        this.Type = type;
708        this.ReturnType = operators.compilation.FindType(KnownTypeCode.Boolean);
709        this.Parameters.Add(operators.MakeParameter(type));
710        this.Parameters.Add(operators.MakeParameter(type));
711      }
712     
713      public override bool CanEvaluateAtCompileTime {
714        get { return Type != TypeCode.Object; }
715      }
716     
717      public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
718      {
719        if (lhs == null && rhs == null)
720          return !Negate; // ==: true; !=: false
721        if (lhs == null || rhs == null)
722          return Negate; // ==: false; !=: true
723        lhs = resolver.CSharpPrimitiveCast(Type, lhs);
724        rhs = resolver.CSharpPrimitiveCast(Type, rhs);
725        bool equal;
726        if (Type == TypeCode.Single) {
727          equal = (float)lhs == (float)rhs;
728        } else if (Type == TypeCode.Double) {
729          equal = (double)lhs == (double)rhs;
730        } else {
731          equal = object.Equals(lhs, rhs);
732        }
733        return equal ^ Negate;
734      }
735     
736      public override OperatorMethod Lift(CSharpOperators operators)
737      {
738        if (Type == TypeCode.Object || Type == TypeCode.String)
739          return null;
740        else
741          return new LiftedEqualityOperatorMethod(operators, this);
742      }
743    }
744   
745    sealed class LiftedEqualityOperatorMethod : BinaryOperatorMethod, OverloadResolution.ILiftedOperator
746    {
747      readonly EqualityOperatorMethod baseMethod;
748     
749      public LiftedEqualityOperatorMethod(CSharpOperators operators, EqualityOperatorMethod baseMethod)
750        : base(operators.compilation)
751      {
752        this.baseMethod = baseMethod;
753        this.ReturnType = baseMethod.ReturnType;
754        IParameter p = operators.MakeNullableParameter(baseMethod.Parameters[0]);
755        this.Parameters.Add(p);
756        this.Parameters.Add(p);
757      }
758     
759      public override bool CanEvaluateAtCompileTime {
760        get { return baseMethod.CanEvaluateAtCompileTime; }
761      }
762     
763      public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
764      {
765        return baseMethod.Invoke(resolver, lhs, rhs);
766      }
767     
768      public IList<IParameter> NonLiftedParameters {
769        get { return baseMethod.Parameters; }
770      }
771    }
772   
773    // C# 4.0 spec: §7.10 Relational and type-testing operators
774    static readonly TypeCode[] valueEqualityOperatorsFor = {
775      TypeCode.Int32, TypeCode.UInt32,
776      TypeCode.Int64, TypeCode.UInt64,
777      TypeCode.Single, TypeCode.Double,
778      TypeCode.Decimal,
779      TypeCode.Boolean
780    };
781   
782    OperatorMethod[] valueEqualityOperators;
783   
784    public OperatorMethod[] ValueEqualityOperators {
785      get {
786        OperatorMethod[] ops = LazyInit.VolatileRead(ref valueEqualityOperators);
787        if (ops != null) {
788          return ops;
789        } else {
790          return LazyInit.GetOrSet(ref valueEqualityOperators, Lift(
791            valueEqualityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, false)).ToArray()
792          ));
793        }
794      }
795    }
796   
797    OperatorMethod[] valueInequalityOperators;
798   
799    public OperatorMethod[] ValueInequalityOperators {
800      get {
801        OperatorMethod[] ops = LazyInit.VolatileRead(ref valueInequalityOperators);
802        if (ops != null) {
803          return ops;
804        } else {
805          return LazyInit.GetOrSet(ref valueInequalityOperators, Lift(
806            valueEqualityOperatorsFor.Select(c => new EqualityOperatorMethod(this, c, true)).ToArray()
807          ));
808        }
809      }
810    }
811   
812    OperatorMethod[] referenceEqualityOperators;
813   
814    public OperatorMethod[] ReferenceEqualityOperators {
815      get {
816        OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceEqualityOperators);
817        if (ops != null) {
818          return ops;
819        } else {
820          return LazyInit.GetOrSet(ref referenceEqualityOperators, Lift(
821            new EqualityOperatorMethod(this, TypeCode.Object, false),
822            new EqualityOperatorMethod(this, TypeCode.String, false)
823          ));
824        }
825      }
826    }
827   
828    OperatorMethod[] referenceInequalityOperators;
829   
830    public OperatorMethod[] ReferenceInequalityOperators {
831      get {
832        OperatorMethod[] ops = LazyInit.VolatileRead(ref referenceInequalityOperators);
833        if (ops != null) {
834          return ops;
835        } else {
836          return LazyInit.GetOrSet(ref referenceInequalityOperators, Lift(
837            new EqualityOperatorMethod(this, TypeCode.Object, true),
838            new EqualityOperatorMethod(this, TypeCode.String, true)
839          ));
840        }
841      }
842    }
843    #endregion
844   
845    #region Relational Operators
846    sealed class RelationalOperatorMethod<T1, T2> : BinaryOperatorMethod
847    {
848      readonly Func<T1, T2, bool> func;
849     
850      public RelationalOperatorMethod(CSharpOperators operators, Func<T1, T2, bool> func)
851        : base(operators.compilation)
852      {
853        this.ReturnType = operators.compilation.FindType(KnownTypeCode.Boolean);
854        this.Parameters.Add(operators.MakeParameter(Type.GetTypeCode(typeof(T1))));
855        this.Parameters.Add(operators.MakeParameter(Type.GetTypeCode(typeof(T2))));
856        this.func = func;
857      }
858     
859      public override bool CanEvaluateAtCompileTime {
860        get { return true; }
861      }
862     
863      public override object Invoke(CSharpResolver resolver, object lhs, object rhs)
864      {
865        if (lhs == null || rhs == null)
866          return null;
867        return func((T1)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T1)), lhs),
868                    (T2)resolver.CSharpPrimitiveCast(Type.GetTypeCode(typeof(T2)), rhs));
869      }
870     
871      public override OperatorMethod Lift(CSharpOperators operators)
872      {
873        var lifted = new LiftedBinaryOperatorMethod(operators, this);
874        lifted.ReturnType = this.ReturnType; // don't lift the return type for relational operators
875        return lifted;
876      }
877    }
878   
879    OperatorMethod[] lessThanOperators;
880   
881    public OperatorMethod[] LessThanOperators {
882      get {
883        OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOperators);
884        if (ops != null) {
885          return ops;
886        } else {
887          return LazyInit.GetOrSet(ref lessThanOperators, Lift(
888            new RelationalOperatorMethod<int, int>        (this, (a, b) => a < b),
889            new RelationalOperatorMethod<uint, uint>      (this, (a, b) => a < b),
890            new RelationalOperatorMethod<long, long>      (this, (a, b) => a < b),
891            new RelationalOperatorMethod<ulong, ulong>    (this, (a, b) => a < b),
892            new RelationalOperatorMethod<float, float>    (this, (a, b) => a < b),
893            new RelationalOperatorMethod<double, double>  (this, (a, b) => a < b),
894            new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a < b)
895          ));
896        }
897      }
898    }
899   
900    OperatorMethod[] lessThanOrEqualOperators;
901   
902    public OperatorMethod[] LessThanOrEqualOperators {
903      get {
904        OperatorMethod[] ops = LazyInit.VolatileRead(ref lessThanOrEqualOperators);
905        if (ops != null) {
906          return ops;
907        } else {
908          return LazyInit.GetOrSet(ref lessThanOrEqualOperators, Lift(
909            new RelationalOperatorMethod<int, int>        (this, (a, b) => a <= b),
910            new RelationalOperatorMethod<uint, uint>      (this, (a, b) => a <= b),
911            new RelationalOperatorMethod<long, long>      (this, (a, b) => a <= b),
912            new RelationalOperatorMethod<ulong, ulong>    (this, (a, b) => a <= b),
913            new RelationalOperatorMethod<float, float>    (this, (a, b) => a <= b),
914            new RelationalOperatorMethod<double, double>  (this, (a, b) => a <= b),
915            new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a <= b)
916          ));
917        }
918      }
919    }
920   
921    OperatorMethod[] greaterThanOperators;
922   
923    public OperatorMethod[] GreaterThanOperators {
924      get {
925        OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOperators);
926        if (ops != null) {
927          return ops;
928        } else {
929          return LazyInit.GetOrSet(ref greaterThanOperators, Lift(
930            new RelationalOperatorMethod<int, int>        (this, (a, b) => a > b),
931            new RelationalOperatorMethod<uint, uint>      (this, (a, b) => a > b),
932            new RelationalOperatorMethod<long, long>      (this, (a, b) => a > b),
933            new RelationalOperatorMethod<ulong, ulong>    (this, (a, b) => a > b),
934            new RelationalOperatorMethod<float, float>    (this, (a, b) => a > b),
935            new RelationalOperatorMethod<double, double>  (this, (a, b) => a > b),
936            new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a > b)
937          ));
938        }
939      }
940    }
941   
942    OperatorMethod[] greaterThanOrEqualOperators;
943   
944    public OperatorMethod[] GreaterThanOrEqualOperators {
945      get {
946        OperatorMethod[] ops = LazyInit.VolatileRead(ref greaterThanOrEqualOperators);
947        if (ops != null) {
948          return ops;
949        } else {
950          return LazyInit.GetOrSet(ref greaterThanOrEqualOperators, Lift(
951            new RelationalOperatorMethod<int, int>        (this, (a, b) => a >= b),
952            new RelationalOperatorMethod<uint, uint>      (this, (a, b) => a >= b),
953            new RelationalOperatorMethod<long, long>      (this, (a, b) => a >= b),
954            new RelationalOperatorMethod<ulong, ulong>    (this, (a, b) => a >= b),
955            new RelationalOperatorMethod<float, float>    (this, (a, b) => a >= b),
956            new RelationalOperatorMethod<double, double>  (this, (a, b) => a >= b),
957            new RelationalOperatorMethod<decimal, decimal>(this, (a, b) => a >= b)
958          ));
959        }
960      }
961    }
962    #endregion
963   
964    #region Bitwise operators
965    OperatorMethod[] logicalAndOperators;
966   
967    public OperatorMethod[] LogicalAndOperators {
968      get {
969        OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalAndOperators);
970        if (ops != null) {
971          return ops;
972        } else {
973          return LazyInit.GetOrSet(ref logicalAndOperators, new OperatorMethod[] {
974                                    new LambdaBinaryOperatorMethod<bool, bool>(this, (a, b) => a & b)
975                                   });
976        }
977      }
978    }
979   
980   
981    OperatorMethod[] bitwiseAndOperators;
982   
983    public OperatorMethod[] BitwiseAndOperators {
984      get {
985        OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseAndOperators);
986        if (ops != null) {
987          return ops;
988        } else {
989          return LazyInit.GetOrSet(ref bitwiseAndOperators, Lift(
990            new LambdaBinaryOperatorMethod<int, int>    (this, (a, b) => a & b),
991            new LambdaBinaryOperatorMethod<uint, uint>  (this, (a, b) => a & b),
992            new LambdaBinaryOperatorMethod<long, long>  (this, (a, b) => a & b),
993            new LambdaBinaryOperatorMethod<ulong, ulong>(this, (a, b) => a & b),
994            this.LogicalAndOperators[0]
995          ));
996        }
997      }
998    }
999   
1000   
1001    OperatorMethod[] logicalOrOperators;
1002   
1003    public OperatorMethod[] LogicalOrOperators {
1004      get {
1005        OperatorMethod[] ops = LazyInit.VolatileRead(ref logicalOrOperators);
1006        if (ops != null) {
1007          return ops;
1008        } else {
1009          return LazyInit.GetOrSet(ref logicalOrOperators, new OperatorMethod[] {
1010                                    new LambdaBinaryOperatorMethod<bool, bool>(this, (a, b) => a | b)
1011                                   });
1012        }
1013      }
1014    }
1015   
1016    OperatorMethod[] bitwiseOrOperators;
1017   
1018    public OperatorMethod[] BitwiseOrOperators {
1019      get {
1020        OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseOrOperators);
1021        if (ops != null) {
1022          return ops;
1023        } else {
1024          return LazyInit.GetOrSet(ref bitwiseOrOperators, Lift(
1025            new LambdaBinaryOperatorMethod<int, int>    (this, (a, b) => a | b),
1026            new LambdaBinaryOperatorMethod<uint, uint>  (this, (a, b) => a | b),
1027            new LambdaBinaryOperatorMethod<long, long>  (this, (a, b) => a | b),
1028            new LambdaBinaryOperatorMethod<ulong, ulong>(this, (a, b) => a | b),
1029            this.LogicalOrOperators[0]
1030          ));
1031        }
1032      }
1033    }
1034   
1035    // Note: the logic for the lifted bool? bitwise operators is wrong;
1036    // we produce "true | null" = "null" when it should be true. However, this is irrelevant
1037    // because bool? cannot be a compile-time type.
1038   
1039    OperatorMethod[] bitwiseXorOperators;
1040
1041    public OperatorMethod[] BitwiseXorOperators {
1042      get {
1043        OperatorMethod[] ops = LazyInit.VolatileRead(ref bitwiseXorOperators);
1044        if (ops != null) {
1045          return ops;
1046        } else {
1047          return LazyInit.GetOrSet(ref bitwiseXorOperators, Lift(
1048            new LambdaBinaryOperatorMethod<int, int>    (this, (a, b) => a ^ b),
1049            new LambdaBinaryOperatorMethod<uint, uint>  (this, (a, b) => a ^ b),
1050            new LambdaBinaryOperatorMethod<long, long>  (this, (a, b) => a ^ b),
1051            new LambdaBinaryOperatorMethod<ulong, ulong>(this, (a, b) => a ^ b),
1052            new LambdaBinaryOperatorMethod<bool, bool>  (this, (a, b) => a ^ b)
1053          ));
1054        }
1055      }
1056    }
1057    #endregion
1058  }
1059}
Note: See TracBrowser for help on using the repository browser.