PageRenderTime 74ms CodeModel.GetById 40ms app.highlight 16ms RepoModel.GetById 14ms app.codeStats 0ms

/Microsoft.Scripting/Actions/CallSignature.cs

https://bitbucket.org/stefanrusek/xronos
C# | 333 lines | 240 code | 58 blank | 35 comment | 77 complexity | 65287e634ed938897676b69ee0c60395 MD5 | raw file
  1/* ****************************************************************************
  2 *
  3 * Copyright (c) Microsoft Corporation. 
  4 *
  5 * This source code is subject to terms and conditions of the Microsoft Public License. A 
  6 * copy of the license can be found in the License.html file at the root of this distribution. If 
  7 * you cannot locate the  Microsoft Public License, please send an email to 
  8 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
  9 * by the terms of the Microsoft Public License.
 10 *
 11 * You must not remove this notice, or any other, from this software.
 12 *
 13 *
 14 * ***************************************************************************/
 15
 16#if CODEPLEX_40
 17using System;
 18#else
 19using System; using Microsoft;
 20#endif
 21using System.Collections.Generic;
 22using System.Diagnostics;
 23#if CODEPLEX_40
 24using System.Linq.Expressions;
 25#else
 26using Microsoft.Linq.Expressions;
 27#endif
 28using Microsoft.Scripting.Utils;
 29using System.Text;
 30using Microsoft.Contracts;
 31using Microsoft.Scripting.Generation;
 32using AstUtils = Microsoft.Scripting.Ast.Utils;
 33
 34namespace Microsoft.Scripting.Actions {
 35    /// <summary>
 36    /// Richly represents the signature of a callsite.
 37    /// </summary>
 38    public struct CallSignature : IEquatable<CallSignature> {
 39        // TODO: invariant _infos != null ==> _argumentCount == _infos.Length
 40        
 41        /// <summary>
 42        /// Array of additional meta information about the arguments, such as named arguments.
 43        /// Null for a simple signature that's just an expression list. eg: foo(a*b,c,d)
 44        /// </summary>
 45        private readonly Argument[] _infos;
 46
 47        /// <summary>
 48        /// Number of arguments in the signature.
 49        /// </summary>
 50        private readonly int _argumentCount;
 51
 52        /// <summary>
 53        /// All arguments are unnamed and matched by position. 
 54        /// </summary>
 55        public bool IsSimple {
 56            get { return _infos == null; }
 57        }
 58
 59        public int ArgumentCount {
 60            get {
 61                Debug.Assert(_infos == null || _infos.Length == _argumentCount);
 62                return _argumentCount; 
 63            }
 64        }
 65
 66        #region Construction
 67
 68        public CallSignature(CallSignature signature) {
 69            _infos = signature.GetArgumentInfos();
 70            _argumentCount = signature._argumentCount;
 71        }
 72        
 73        public CallSignature(int argumentCount) {
 74            ContractUtils.Requires(argumentCount >= 0, "argumentCount");
 75            _argumentCount = argumentCount;
 76            _infos = null;
 77        }
 78
 79        public CallSignature(params Argument[] infos) {
 80            bool simple = true;
 81
 82            if (infos != null) {
 83                _argumentCount = infos.Length;
 84                for (int i = 0; i < infos.Length; i++) {
 85                    if (infos[i].Kind != ArgumentType.Simple) {
 86                        simple = false;
 87                        break;
 88                    }
 89                }
 90            } else {
 91                _argumentCount = 0;
 92            }
 93
 94            _infos = (!simple) ? infos : null;
 95        }
 96
 97        public CallSignature(params ArgumentType[] kinds) {
 98            bool simple = true;
 99
100            if (kinds != null) {
101                _argumentCount = kinds.Length;
102                for (int i = 0; i < kinds.Length; i++) {
103                    if (kinds[i] != ArgumentType.Simple) {
104                        simple = false;
105                        break;
106                    }
107                }
108            } else {
109                _argumentCount = 0;
110            }
111
112            if (!simple) {
113                _infos = new Argument[kinds.Length];
114                for (int i = 0; i < kinds.Length; i++) {
115                    _infos[i] = new Argument(kinds[i]);
116                }
117            } else {
118                _infos = null;
119            }
120        }
121
122        #endregion
123
124        #region IEquatable<CallSignature> Members
125
126        [StateIndependent]
127        public bool Equals(CallSignature other) {
128            if (_infos == null) {
129                return other._infos == null && other._argumentCount == _argumentCount;
130            } else if (other._infos == null) {
131                return false;
132            }
133
134            if (_infos.Length != other._infos.Length) return false;
135
136            for (int i = 0; i < _infos.Length; i++) {
137                if (!_infos[i].Equals(other._infos[i])) return false;
138            }
139
140            return true;
141        }
142
143        #endregion
144
145        #region Overrides
146
147        public override bool Equals(object obj) {
148            return obj is CallSignature && Equals((CallSignature)obj);
149        }
150
151        public static bool operator ==(CallSignature left, CallSignature right) {
152            return left.Equals(right);
153        }
154
155        public static bool operator !=(CallSignature left, CallSignature right) {
156            return !left.Equals(right);
157        }
158
159        public override string ToString() {
160            if (_infos == null) {
161                return "Simple";
162            }
163            
164            StringBuilder sb = new StringBuilder("(");
165            for (int i = 0; i < _infos.Length; i++) {
166                if (i > 0) {
167                    sb.Append(", ");
168                }
169                sb.Append(_infos[i].ToString());
170            }
171            sb.Append(")");
172            return sb.ToString();
173        }
174
175        public override int GetHashCode() {
176            int h = 6551;
177            if (_infos != null) {
178                foreach (Argument info in _infos) {
179                    h ^= (h << 5) ^ info.GetHashCode();
180                }
181            }
182            return h;
183        }
184
185        #endregion
186
187        #region Helpers
188
189        public Argument[] GetArgumentInfos() {
190            return (_infos != null) ? ArrayUtils.Copy(_infos) : CompilerHelpers.MakeRepeatedArray(Argument.Simple, _argumentCount);
191        }
192
193        public CallSignature InsertArgument(Argument info) {
194            return InsertArgumentAt(0, info);
195        }
196
197        public CallSignature InsertArgumentAt(int index, Argument info) {
198            if (this.IsSimple) {
199                if (info.IsSimple) {
200                    return new CallSignature(_argumentCount + 1);
201                }
202                
203                return new CallSignature(ArrayUtils.InsertAt(GetArgumentInfos(), index, info));
204            }
205
206            return new CallSignature(ArrayUtils.InsertAt(_infos, index, info));
207        }
208
209        public CallSignature RemoveFirstArgument() {
210            return RemoveArgumentAt(0);
211        }
212
213        public CallSignature RemoveArgumentAt(int index) {
214            if (_argumentCount == 0) {
215                throw new InvalidOperationException();
216            }
217
218            if (IsSimple) {
219                return new CallSignature(_argumentCount - 1);
220            }
221
222            return new CallSignature(ArrayUtils.RemoveAt(_infos, index));
223        }
224
225        public int IndexOf(ArgumentType kind) {
226            if (_infos == null) {
227                return (kind == ArgumentType.Simple && _argumentCount > 0) ? 0 : -1;
228            }
229
230            for (int i = 0; i < _infos.Length; i++) {
231                if (_infos[i].Kind == kind) {
232                    return i;
233                }
234            }
235            return -1;
236        }
237
238        public bool HasDictionaryArgument() {
239            return IndexOf(ArgumentType.Dictionary) > -1;
240        }
241
242        public bool HasInstanceArgument() {
243            return IndexOf(ArgumentType.Instance) > -1;
244        }
245
246        public bool HasListArgument() {
247            return IndexOf(ArgumentType.List) > -1;
248        }
249
250        internal bool HasNamedArgument() {
251            return IndexOf(ArgumentType.Named) > -1;
252        }
253
254        /// <summary>
255        /// True if the OldCallAction includes an ArgumentInfo of ArgumentKind.Dictionary or ArgumentKind.Named.
256        /// </summary>
257        public bool HasKeywordArgument() {
258            if (_infos != null) {
259                foreach (Argument info in _infos) {
260                    if (info.Kind == ArgumentType.Dictionary || info.Kind == ArgumentType.Named) {
261                        return true;
262                    }
263                }
264            }
265            return false;
266        }
267        
268        public ArgumentType GetArgumentKind(int index) {
269            // TODO: Contract.Requires(index >= 0 && index < _argumentCount, "index");
270            return _infos != null ? _infos[index].Kind : ArgumentType.Simple;
271        }
272
273        public string GetArgumentName(int index) {
274            ContractUtils.Requires(index >= 0 && index < _argumentCount);
275            return _infos != null ? _infos[index].Name : null;
276        }
277
278        /// <summary>
279        /// Gets the number of positional arguments the user provided at the call site.
280        /// </summary>
281        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
282        public int GetProvidedPositionalArgumentCount() {
283            int result = _argumentCount;
284
285            if (_infos != null) {
286                for (int i = 0; i < _infos.Length; i++) {
287                    ArgumentType kind = _infos[i].Kind;
288
289                    if (kind == ArgumentType.Dictionary || kind == ArgumentType.List || kind == ArgumentType.Named) {
290                        result--;
291                    }
292                }
293            }
294
295            return result;
296        }
297
298        public string[] GetArgumentNames() {
299            if (_infos == null) {
300                return ArrayUtils.EmptyStrings;
301            }
302
303            List<string> result = new List<string>();
304            foreach (Argument info in _infos) {
305                if (info.Name != null) {
306                    result.Add(info.Name);
307                }
308            }
309
310            return result.ToArray();
311        }
312
313        public Expression CreateExpression() {            
314            if (_infos == null) {
315                return Expression.New(
316                    typeof(CallSignature).GetConstructor(new Type[] { typeof(int) }),
317                    AstUtils.Constant(ArgumentCount)
318                );
319            } else {
320                Expression[] args = new Expression[_infos.Length];
321                for (int i = 0; i < args.Length; i++) {
322                    args[i] = _infos[i].CreateExpression();
323                }
324                return Expression.New(
325                    typeof(CallSignature).GetConstructor(new Type[] { typeof(Argument[]) }), 
326                    Expression.NewArrayInit(typeof(Argument), args)
327                );
328            }
329        }
330
331        #endregion
332    }
333}