MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections.Generic;5using System.Diagnostics;6using System.Dynamic;7using System.Linq;8using System.Linq.Expressions;9using System.Reflection;10using System.Threading;11 12using AstUtils = System.Management.Automation.Interpreter.Utils;13 14namespace System.Management.Automation.Interpreter15{16 internal static class TypeUtils17 {18 internal static Type GetNonNullableType(this Type type)19 {20 if (IsNullableType(type))21 {22 return type.GetGenericArguments()[0];23 }24 25 return type;26 }27 28 internal static Type GetNullableType(Type type)29 {30 Debug.Assert(type != null, "type cannot be null");31 if (type.IsValueType && !IsNullableType(type))32 {33 return typeof(Nullable<>).MakeGenericType(type);34 }35 36 return type;37 }38 39 internal static bool IsNullableType(Type type)40 {41 return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);42 }43 44 internal static bool IsBool(Type type)45 {46 return GetNonNullableType(type) == typeof(bool);47 }48 49 internal static bool IsNumeric(Type type)50 {51 type = GetNonNullableType(type);52 if (!type.IsEnum)53 {54 switch (type.GetTypeCode())55 {56 case TypeCode.Char:57 case TypeCode.SByte:58 case TypeCode.Byte:59 case TypeCode.Int16:60 case TypeCode.Int32:61 case TypeCode.Int64:62 case TypeCode.Double:63 case TypeCode.Single:64 case TypeCode.UInt16:65 case TypeCode.UInt32:66 case TypeCode.UInt64:67 return true;68 }69 }70 71 return false;72 }73 74 internal static bool IsNumeric(TypeCode typeCode)75 {76 switch (typeCode)77 {78 case TypeCode.Char:79 case TypeCode.SByte:80 case TypeCode.Byte:81 case TypeCode.Int16:82 case TypeCode.Int32:83 case TypeCode.Int64:84 case TypeCode.Double:85 case TypeCode.Single:86 case TypeCode.UInt16:87 case TypeCode.UInt32:88 case TypeCode.UInt64:89 return true;90 }91 92 return false;93 }94 95 internal static bool IsArithmetic(Type type)96 {97 type = GetNonNullableType(type);98 if (!type.IsEnum)99 {100 switch (type.GetTypeCode())101 {102 case TypeCode.Int16:103 case TypeCode.Int32:104 case TypeCode.Int64:105 case TypeCode.Double:106 case TypeCode.Single:107 case TypeCode.UInt16:108 case TypeCode.UInt32:109 case TypeCode.UInt64:110 return true;111 }112 }113 114 return false;115 }116 }117 118 internal static class ArrayUtils119 {120 internal static T[] AddLast<T>(this IList<T> list, T item)121 {122 T[] res = new T[list.Count + 1];123 list.CopyTo(res, 0);124 res[list.Count] = item;125 return res;126 }127 }128 129 internal static class DelegateHelpers130 {131 #region Generated Maximum Delegate Arity132 133 // *** BEGIN GENERATED CODE ***134 // generated by function: gen_max_delegate_arity from: generate_dynsites.py135 136 private const int MaximumArity = 17;137 138 // *** END GENERATED CODE ***139 140 #endregion141 142 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]143 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]144 internal static Type MakeDelegate(Type[] types)145 {146 Debug.Assert(types != null && types.Length > 0);147 148 // Can only used predefined delegates if we have no byref types and149 // the arity is small enough to fit in Func<...> or Action<...>150 if (types.Length > MaximumArity || types.Any(static t => t.IsByRef))151 {152 throw Assert.Unreachable;153 // return MakeCustomDelegate(types);154 }155 156 Type returnType = types[types.Length - 1];157 if (returnType == typeof(void))158 {159 Array.Resize(ref types, types.Length - 1);160 switch (types.Length)161 {162 case 0: return typeof(Action);163 #region Generated Delegate Action Types164 165 // *** BEGIN GENERATED CODE ***166 // generated by function: gen_delegate_action from: generate_dynsites.py167 168 case 1: return typeof(Action<>).MakeGenericType(types);169 case 2: return typeof(Action<,>).MakeGenericType(types);170 case 3: return typeof(Action<,,>).MakeGenericType(types);171 case 4: return typeof(Action<,,,>).MakeGenericType(types);172 case 5: return typeof(Action<,,,,>).MakeGenericType(types);173 case 6: return typeof(Action<,,,,,>).MakeGenericType(types);174 case 7: return typeof(Action<,,,,,,>).MakeGenericType(types);175 case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types);176 case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types);177 case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types);178 case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types);179 case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types);180 case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types);181 case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types);182 case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types);183 case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types);184 185 // *** END GENERATED CODE ***186 187 #endregion188 }189 }190 else191 {192 switch (types.Length)193 {194 #region Generated Delegate Func Types195 196 // *** BEGIN GENERATED CODE ***197 // generated by function: gen_delegate_func from: generate_dynsites.py198 199 case 1: return typeof(Func<>).MakeGenericType(types);200 case 2: return typeof(Func<,>).MakeGenericType(types);201 case 3: return typeof(Func<,,>).MakeGenericType(types);202 case 4: return typeof(Func<,,,>).MakeGenericType(types);203 case 5: return typeof(Func<,,,,>).MakeGenericType(types);204 case 6: return typeof(Func<,,,,,>).MakeGenericType(types);205 case 7: return typeof(Func<,,,,,,>).MakeGenericType(types);206 case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types);207 case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types);208 case 10: return typeof(Func<,,,,,,,,,>).MakeGenericType(types);209 case 11: return typeof(Func<,,,,,,,,,,>).MakeGenericType(types);210 case 12: return typeof(Func<,,,,,,,,,,,>).MakeGenericType(types);211 case 13: return typeof(Func<,,,,,,,,,,,,>).MakeGenericType(types);212 case 14: return typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(types);213 case 15: return typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(types);214 case 16: return typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(types);215 case 17: return typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(types);216 217 // *** END GENERATED CODE ***218 219 #endregion220 }221 }222 223 throw Assert.Unreachable;224 }225 }226 227 internal static class ScriptingRuntimeHelpers228 {229 internal static object Int32ToObject(int i)230 {231 return i;232 }233 234 internal static object BooleanToObject(bool b)235 {236 return b ? True : False;237 }238 239 internal static readonly MethodInfo BooleanToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("BooleanToObject");240 internal static readonly MethodInfo Int32ToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("Int32ToObject");241 242 internal static readonly object True = true;243 internal static readonly object False = false;244 245 internal static object GetPrimitiveDefaultValue(Type type)246 {247 switch (type.GetTypeCode())248 {249 case TypeCode.Boolean: return ScriptingRuntimeHelpers.False;250 case TypeCode.SByte: return default(sbyte);251 case TypeCode.Byte: return default(byte);252 case TypeCode.Char: return default(char);253 case TypeCode.Int16: return default(Int16);254 case TypeCode.Int32: return ScriptingRuntimeHelpers.Int32ToObject(0);255 case TypeCode.Int64: return default(Int64);256 case TypeCode.UInt16: return default(UInt16);257 case TypeCode.UInt32: return default(UInt32);258 case TypeCode.UInt64: return default(UInt64);259 case TypeCode.Single: return default(Single);260 case TypeCode.Double: return default(double);261 case TypeCode.DateTime: return default(DateTime);262 case TypeCode.Decimal: return default(Decimal);263 // TypeCode.Empty: null;264 // TypeCode.Object: default(object) == null;265 // TypeCode.DBNull: default(DBNull) == null;266 // TypeCode.String: default(string) == null;267 default: return null;268 }269 }270 }271 272 /// <summary>273 /// Wraps all arguments passed to a dynamic site with more arguments than can be accepted by a Func/Action delegate.274 /// The binder generating a rule for such a site should unwrap the arguments first and then perform a binding to them.275 /// </summary>276 internal sealed class ArgumentArray277 {278 private readonly object[] _arguments;279 280 // the index of the first item _arguments that represents an argument:281 private readonly int _first;282 283 // the number of items in _arguments that represent the arguments:284 285 internal ArgumentArray(object[] arguments, int first, int count)286 {287 _arguments = arguments;288 _first = first;289 Count = count;290 }291 292 public int Count { get; }293 294 public object GetArgument(int index)295 {296 // ContractUtils.RequiresArrayIndex(_arguments, index, "index");297 return _arguments[_first + index];298 }299 300 public DynamicMetaObject GetMetaObject(Expression parameter, int index)301 {302 return DynamicMetaObject.Create(303 GetArgument(index),304 Expression.Call(305 s_getArgMethod,306 AstUtils.Convert(parameter, typeof(ArgumentArray)),307 AstUtils.Constant(index)308 )309 );310 }311 312 // [CLSCompliant(false)]313 public static object GetArg(ArgumentArray array, int index)314 {315 return array._arguments[array._first + index];316 }317 318 private static readonly MethodInfo s_getArgMethod = new Func<ArgumentArray, int, object>(GetArg).GetMethodInfo();319 }320 321 internal static class ExceptionHelpers322 {323 private const string prevStackTraces = "PreviousStackTraces";324 325 /// <summary>326 /// Updates an exception before it's getting re-thrown so327 /// we can present a reasonable stack trace to the user.328 /// </summary>329 public static Exception UpdateForRethrow(Exception rethrow)330 {331#if !SILVERLIGHT332 List<StackTrace> prev;333 334 // we don't have any dynamic stack trace data, capture the data we can335 // from the raw exception object.336 StackTrace st = new StackTrace(rethrow, true);337 338 if (!TryGetAssociatedStackTraces(rethrow, out prev))339 {340 prev = new List<StackTrace>();341 AssociateStackTraces(rethrow, prev);342 }343 344 prev.Add(st);345#endif346 return rethrow;347 }348 349 /// <summary>350 /// Returns all the stack traces associates with an exception.351 /// </summary>352 public static IList<StackTrace> GetExceptionStackTraces(Exception rethrow)353 {354 List<StackTrace> result;355 return TryGetAssociatedStackTraces(rethrow, out result) ? result : null;356 }357 358 private static void AssociateStackTraces(Exception e, List<StackTrace> traces)359 {360 e.Data[prevStackTraces] = traces;361 }362 363 private static bool TryGetAssociatedStackTraces(Exception e, out List<StackTrace> traces)364 {365 traces = e.Data[prevStackTraces] as List<StackTrace>;366 return traces != null;367 }368 }369 370 /// <summary>371 /// A hybrid dictionary which compares based upon object identity.372 /// </summary>373 internal class HybridReferenceDictionary<TKey, TValue> where TKey : class374 {375 private KeyValuePair<TKey, TValue>[] _keysAndValues;376 private Dictionary<TKey, TValue> _dict;377 private int _count;378 379 private const int _arraySize = 10;380 381 public HybridReferenceDictionary()382 {383 }384 385 public HybridReferenceDictionary(int initialCapacity)386 {387 if (initialCapacity > _arraySize)388 {389 _dict = new Dictionary<TKey, TValue>(initialCapacity);390 }391 else392 {393 _keysAndValues = new KeyValuePair<TKey, TValue>[initialCapacity];394 }395 }396 397 public bool TryGetValue(TKey key, out TValue value)398 {399 Debug.Assert(key != null);400 401 if (_dict != null)402 {403 return _dict.TryGetValue(key, out value);404 }405 else if (_keysAndValues != null)406 {407 for (int i = 0; i < _keysAndValues.Length; i++)408 {409 if (_keysAndValues[i].Key == key)410 {411 value = _keysAndValues[i].Value;412 return true;413 }414 }415 }416 417 value = default(TValue);418 return false;419 }420 421 public bool Remove(TKey key)422 {423 Debug.Assert(key != null);424 425 if (_dict != null)426 {427 return _dict.Remove(key);428 }429 else if (_keysAndValues != null)430 {431 for (int i = 0; i < _keysAndValues.Length; i++)432 {433 if (_keysAndValues[i].Key == key)434 {435 _keysAndValues[i] = new KeyValuePair<TKey, TValue>();436 _count--;437 return true;438 }439 }440 }441 442 return false;443 }444 445 public bool ContainsKey(TKey key)446 {447 Debug.Assert(key != null);448 449 if (_dict != null)450 {451 return _dict.ContainsKey(key);452 }453 else if (_keysAndValues != null)454 {455 for (int i = 0; i < _keysAndValues.Length; i++)456 {457 if (_keysAndValues[i].Key == key)458 {459 return true;460 }461 }462 }463 464 return false;465 }466 467 public int Count468 {469 get470 {471 if (_dict != null)472 {473 return _dict.Count;474 }475 476 return _count;477 }478 }479 480 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()481 {482 if (_dict != null)483 {484 return _dict.GetEnumerator();485 }486 487 return GetEnumeratorWorker();488 }489 490 private IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorWorker()491 {492 if (_keysAndValues != null)493 {494 for (int i = 0; i < _keysAndValues.Length; i++)495 {496 if (_keysAndValues[i].Key != null)497 {498 yield return _keysAndValues[i];499 }500 }501 }502 }503 504 public TValue this[TKey key]505 {506 get507 {508 Debug.Assert(key != null);509 510 TValue res;511 if (TryGetValue(key, out res))512 {513 return res;514 }515 516 throw new KeyNotFoundException();517 }518 519 set520 {521 Debug.Assert(key != null);522 523 if (_dict != null)524 {525 _dict[key] = value;526 }527 else528 {529 int index;530 if (_keysAndValues != null)531 {532 index = -1;533 for (int i = 0; i < _keysAndValues.Length; i++)534 {535 if (_keysAndValues[i].Key == key)536 {537 _keysAndValues[i] = new KeyValuePair<TKey, TValue>(key, value);538 return;539 }540 else if (_keysAndValues[i].Key == null)541 {542 index = i;543 }544 }545 }546 else547 {548 _keysAndValues = new KeyValuePair<TKey, TValue>[_arraySize];549 index = 0;550 }551 552 if (index != -1)553 {554 _count++;555 _keysAndValues[index] = new KeyValuePair<TKey, TValue>(key, value);556 }557 else558 {559 _dict = new Dictionary<TKey, TValue>();560 for (int i = 0; i < _keysAndValues.Length; i++)561 {562 _dict[_keysAndValues[i].Key] = _keysAndValues[i].Value;563 }564 565 _keysAndValues = null;566 567 _dict[key] = value;568 }569 }570 }571 }572 }573 574 /// <summary>575 /// Provides a dictionary-like object used for caches which holds onto a maximum576 /// number of elements specified at construction time.577 ///578 /// This class is not thread safe.579 /// </summary>580 internal class CacheDict<TKey, TValue>581 {582 private readonly Dictionary<TKey, KeyInfo> _dict = new Dictionary<TKey, KeyInfo>();583 private readonly LinkedList<TKey> _list = new LinkedList<TKey>();584 private readonly int _maxSize;585 586 /// <summary>587 /// Creates a dictionary-like object used for caches.588 /// </summary>589 /// <param name="maxSize">The maximum number of elements to store.</param>590 public CacheDict(int maxSize)591 {592 _maxSize = maxSize;593 }594 595 /// <summary>596 /// Tries to get the value associated with 'key', returning true if it's found and597 /// false if it's not present.598 /// </summary>599 public bool TryGetValue(TKey key, out TValue value)600 {601 KeyInfo storedValue;602 if (_dict.TryGetValue(key, out storedValue))603 {604 LinkedListNode<TKey> node = storedValue.List;605 if (node.Previous != null)606 {607 // move us to the head of the list...608 _list.Remove(node);609 _list.AddFirst(node);610 }611 612 value = storedValue.Value;613 return true;614 }615 616 value = default(TValue);617 return false;618 }619 620 /// <summary>621 /// Adds a new element to the cache, replacing and moving it to the front if the622 /// element is already present.623 /// </summary>624 public void Add(TKey key, TValue value)625 {626 KeyInfo keyInfo;627 if (_dict.TryGetValue(key, out keyInfo))628 {629 // remove original entry from the linked list630 _list.Remove(keyInfo.List);631 }632 else if (_list.Count == _maxSize)633 {634 // we've reached capacity, remove the last used element...635 LinkedListNode<TKey> node = _list.Last;636 _list.RemoveLast();637 bool res = _dict.Remove(node.Value);638 Debug.Assert(res);639 }640 641 // add the new entry to the head of the list and into the dictionary642 LinkedListNode<TKey> listNode = new LinkedListNode<TKey>(key);643 _list.AddFirst(listNode);644 _dict[key] = new CacheDict<TKey, TValue>.KeyInfo(value, listNode);645 }646 647 /// <summary>648 /// Returns the value associated with the given key, or throws KeyNotFoundException649 /// if the key is not present.650 /// </summary>651 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]652 public TValue this[TKey key]653 {654 get655 {656 TValue res;657 if (TryGetValue(key, out res))658 {659 return res;660 }661 662 throw new KeyNotFoundException();663 }664 665 set666 {667 Add(key, value);668 }669 }670 671 private readonly struct KeyInfo672 {673 internal readonly TValue Value;674 internal readonly LinkedListNode<TKey> List;675 676 internal KeyInfo(TValue value, LinkedListNode<TKey> list)677 {678 Value = value;679 List = list;680 }681 }682 }683 684 internal class ThreadLocal<T>685 {686 private StorageInfo[] _stores; // array of storage indexed by managed thread ID687 private static readonly StorageInfo[] s_updating = Array.Empty<StorageInfo>(); // a marker used when updating the array688 private readonly bool _refCounted;689 690 public ThreadLocal()691 {692 }693 694 /// <summary>695 /// True if the caller will guarantee that all cleanup happens as the thread696 /// unwinds.697 ///698 /// This is typically used in a case where the thread local is surrounded by699 /// a try/finally block. The try block pushes some state, the finally block700 /// restores the previous state. Therefore when the thread exits the thread701 /// local is back to it's original state. This allows the ThreadLocal object702 /// to not check the current owning thread on retrieval.703 /// </summary>704 public ThreadLocal(bool refCounted)705 {706 _refCounted = refCounted;707 }708 709 #region Public API710 711 /// <summary>712 /// Gets or sets the value for the current thread.713 /// </summary>714 public T Value715 {716 get717 {718 return GetStorageInfo().Value;719 }720 721 set722 {723 GetStorageInfo().Value = value;724 }725 }726 727 /// <summary>728 /// Gets the current value if its not == null or calls the provided function729 /// to create a new value.730 /// </summary>731 public T GetOrCreate(Func<T> func)732 {733 Assert.NotNull(func);734 735 StorageInfo si = GetStorageInfo();736 T res = si.Value;737 if (res == null)738 {739 si.Value = res = func();740 }741 742 return res;743 }744 745 /// <summary>746 /// Calls the provided update function with the current value and747 /// replaces the current value with the result of the function.748 /// </summary>749 public T Update(Func<T, T> updater)750 {751 Assert.NotNull(updater);752 753 StorageInfo si = GetStorageInfo();754 return si.Value = updater(si.Value);755 }756 757 /// <summary>758 /// Replaces the current value with a new one and returns the old value.759 /// </summary>760 public T Update(T newValue)761 {762 StorageInfo si = GetStorageInfo();763 var oldValue = si.Value;764 si.Value = newValue;765 return oldValue;766 }767 768 #endregion769 770 #region Storage implementation771 772 /// <summary>773 /// Gets the StorageInfo for the current thread.774 /// </summary>775 public StorageInfo GetStorageInfo()776 {777 return GetStorageInfo(_stores);778 }779 780 private StorageInfo GetStorageInfo(StorageInfo[] curStorage)781 {782 int threadId = Environment.CurrentManagedThreadId;783 784 // fast path if we already have a value in the array785 if (curStorage != null && curStorage.Length > threadId)786 {787 StorageInfo res = curStorage[threadId];788 789 if (res != null && (_refCounted || res.Thread == Thread.CurrentThread))790 {791 return res;792 }793 }794 795 return RetryOrCreateStorageInfo(curStorage);796 }797 798 /// <summary>799 /// Called when the fast path storage lookup fails. if we encountered the Empty storage800 /// during the initial fast check then spin until we hit non-empty storage and try the fast801 /// path again.802 /// </summary>803 private StorageInfo RetryOrCreateStorageInfo(StorageInfo[] curStorage)804 {805 if (curStorage == s_updating)806 {807 // we need to retry808 while ((curStorage = _stores) == s_updating)809 {810 Thread.Sleep(0);811 }812 813 // we now have a non-empty storage info to retry with814 return GetStorageInfo(curStorage);815 }816 817 // we need to mutate the StorageInfo[] array or create a new StorageInfo818 return CreateStorageInfo();819 }820 821 /// <summary>822 /// Creates the StorageInfo for the thread when one isn't already present.823 /// </summary>824 private StorageInfo CreateStorageInfo()825 {826 // we do our own locking, tell hosts this is a bad time to interrupt us.827 Thread.BeginCriticalRegion();828 829 StorageInfo[] curStorage = s_updating;830 try831 {832 int threadId = Environment.CurrentManagedThreadId;833 StorageInfo newInfo = new StorageInfo(Thread.CurrentThread);834 835 // set to updating while potentially resizing/mutating, then we'll836 // set back to the current value.837 while ((curStorage = Interlocked.Exchange(ref _stores, s_updating)) == s_updating)838 {839 // another thread is already updating...840 Thread.Sleep(0);841 }842 843 // check and make sure we have a space in the array for our value844 if (curStorage == null)845 {846 curStorage = new StorageInfo[threadId + 1];847 }848 else if (curStorage.Length <= threadId)849 {850 StorageInfo[] newStorage = new StorageInfo[threadId + 1];851 for (int i = 0; i < curStorage.Length; i++)852 {853 // leave out the threads that have exited854 if (curStorage[i] != null && curStorage[i].Thread.IsAlive)855 {856 newStorage[i] = curStorage[i];857 }858 }859 860 curStorage = newStorage;861 }862 863 // create our StorageInfo in the array, the empty check ensures we're only here864 // when we need to create.865 Debug.Assert(curStorage[threadId] == null || curStorage[threadId].Thread != Thread.CurrentThread);866 867 return curStorage[threadId] = newInfo;868 }869 finally870 {871 if (curStorage != s_updating)872 {873 // let others access the storage again874 Interlocked.Exchange(ref _stores, curStorage);875 }876 877 Thread.EndCriticalRegion();878 }879 }880 881 /// <summary>882 /// Helper class for storing the value. We need to track if a ManagedThreadId883 /// has been re-used so we also store the thread which owns the value.884 /// </summary>885 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] // TODO886 internal sealed class StorageInfo887 {888 internal readonly Thread Thread; // the thread that owns the StorageInfo889 public T Value; // the current value for the owning thread890 891 internal StorageInfo(Thread curThread)892 {893 Assert.NotNull(curThread);894 895 Thread = curThread;896 }897 }898 899 #endregion900 }901 902 internal static class Assert903 {904 internal static Exception Unreachable905 {906 get907 {908 Debug.Fail("Unreachable");909 return new InvalidOperationException("Code supposed to be unreachable");910 }911 }912 913 [Conditional("DEBUG")]914 public static void NotNull(object var)915 {916 Debug.Assert(var != null);917 }918 919 [Conditional("DEBUG")]920 public static void NotNull(object var1, object var2)921 {922 Debug.Assert(var1 != null && var2 != null);923 }924 925 [Conditional("DEBUG")]926 public static void NotNull(object var1, object var2, object var3)927 {928 Debug.Assert(var1 != null && var2 != null && var3 != null);929 }930 931 [Conditional("DEBUG")]932 public static void NotNullItems<T>(IEnumerable<T> items) where T : class933 {934 Debug.Assert(items != null);935 foreach (object item in items)936 {937 Debug.Assert(item != null);938 }939 }940 941 [Conditional("DEBUG")]942 public static void NotEmpty(string str)943 {944 Debug.Assert(!string.IsNullOrEmpty(str));945 }946 }947 948 [Flags]949 internal enum ExpressionAccess950 {951 None = 0,952 Read = 1,953 Write = 2,954 ReadWrite = Read | Write,955 }956 957 internal static class Utils958 {959 internal static Expression Constant(object value)960 {961 return Expression.Constant(value);962 }963 964 private static readonly DefaultExpression s_voidInstance = Expression.Empty();965 966 public static DefaultExpression Empty()967 {968 return s_voidInstance;969 }970 971 public static Expression Void(Expression expression)972 {973 // ContractUtils.RequiresNotNull(expression, "expression");974 if (expression.Type == typeof(void))975 {976 return expression;977 }978 979 return Expression.Block(expression, Utils.Empty());980 }981 982 public static DefaultExpression Default(Type type)983 {984 if (type == typeof(void))985 {986 return Empty();987 }988 989 return Expression.Default(type);990 }991 992 public static Expression Convert(Expression expression, Type type)993 {994 // ContractUtils.RequiresNotNull(expression, "expression");995 996 if (expression.Type == type)997 {998 return expression;999 }1000 1001 if (expression.Type == typeof(void))1002 {1003 return Expression.Block(expression, Utils.Default(type));1004 }1005 1006 if (type == typeof(void))1007 {1008 return Void(expression);1009 }1010 1011 // TODO: this is not the right level for this to be at. It should1012 // be pushed into languages if they really want this behavior.1013 if (type == typeof(object))1014 {1015 return Box(expression);1016 }1017 1018 return Expression.Convert(expression, type);1019 }1020 1021 public static Expression Box(Expression expression)1022 {1023 MethodInfo m;1024 if (expression.Type == typeof(int))1025 {1026 m = ScriptingRuntimeHelpers.Int32ToObjectMethod;1027 }1028 else if (expression.Type == typeof(bool))1029 {1030 m = ScriptingRuntimeHelpers.BooleanToObjectMethod;1031 }1032 else1033 {1034 m = null;1035 }1036 1037 return Expression.Convert(expression, typeof(object), m);1038 }1039 1040 public static bool IsReadWriteAssignment(this ExpressionType type)1041 {1042 switch (type)1043 {1044 // unary:1045 case ExpressionType.PostDecrementAssign:1046 case ExpressionType.PostIncrementAssign:1047 case ExpressionType.PreDecrementAssign:1048 case ExpressionType.PreIncrementAssign:1049 1050 // binary - compound:1051 case ExpressionType.AddAssign:1052 case ExpressionType.AddAssignChecked:1053 case ExpressionType.AndAssign:1054 case ExpressionType.DivideAssign:1055 case ExpressionType.ExclusiveOrAssign:1056 case ExpressionType.LeftShiftAssign:1057 case ExpressionType.ModuloAssign:1058 case ExpressionType.MultiplyAssign:1059 case ExpressionType.MultiplyAssignChecked:1060 case ExpressionType.OrAssign:1061 case ExpressionType.PowerAssign:1062 case ExpressionType.RightShiftAssign:1063 case ExpressionType.SubtractAssign:1064 case ExpressionType.SubtractAssignChecked:1065 return true;1066 }1067 1068 return false;1069 }1070 }1071 1072 internal static class CollectionExtension1073 {1074 internal static bool TrueForAll<T>(this IEnumerable<T> collection, Predicate<T> predicate)1075 {1076 // ContractUtils.RequiresNotNull(collection, "collection");1077 // ContractUtils.RequiresNotNull(predicate, "predicate");1078 1079 foreach (T item in collection)1080 {1081 if (!predicate(item))1082 {1083 return false;1084 }1085 }1086 1087 return true;1088 }1089 1090 internal static TResult[] Map<TSource, TResult>(this ICollection<TSource> source, Func<TSource, TResult> selector)1091 {1092 int count = source.Count;1093 TResult[] result = new TResult[count];1094 count = 0;1095 foreach (TSource t in source)1096 {1097 result[count++] = selector(t);1098 }1099 1100 return result;1101 }1102 1103 // We could probably improve the hashing here1104 internal static int ListHashCode<T>(this IEnumerable<T> list)1105 {1106 var cmp = EqualityComparer<T>.Default;1107 int h = 6551;1108 foreach (T t in list)1109 {1110 h ^= (h << 5) ^ cmp.GetHashCode(t);1111 }1112 1113 return h;1114 }1115 1116 internal static bool ListEquals<T>(this ICollection<T> first, ICollection<T> second)1117 {1118 if (first.Count != second.Count)1119 {1120 return false;1121 }1122 1123 var cmp = EqualityComparer<T>.Default;1124 var f = first.GetEnumerator();1125 var s = second.GetEnumerator();1126 while (f.MoveNext())1127 {1128 s.MoveNext();1129 1130 if (!cmp.Equals(f.Current, s.Current))1131 {1132 return false;1133 }1134 }1135 1136 return true;1137 }1138 }1139 1140 internal sealed class ListEqualityComparer<T> : EqualityComparer<ICollection<T>>1141 {1142 internal static readonly ListEqualityComparer<T> Instance = new ListEqualityComparer<T>();1143 1144 private ListEqualityComparer() { }1145 1146 // EqualityComparer<T> handles null and object identity for us1147 public override bool Equals(ICollection<T> x, ICollection<T> y)1148 {1149 return x.ListEquals(y);1150 }1151 1152 public override int GetHashCode(ICollection<T> obj)1153 {1154 return obj.ListHashCode();1155 }1156 }1157}1158 