internal static bool UsualArithmeticConversion(object left, object right, out object leftConverted, out object rightConverted) { left = PSObject.Unwrap(left); right = PSObject.Unwrap(right); leftConverted = null; rightConverted = null; // 6.15 Usual arithmetic conversions // If neither operand designates a value having numeric type, then if (( left == null || right == null || // one operand is null => it needs to be converted to a number (!left.GetType().IsNumeric() && !right.GetType().IsNumeric()) // if both aren't numbers, convert ) && !UsualArithmeticConversionOneOperand(ref left, ref right)) // actually convert { return(false); } Type leftType = left.GetType(); Type rightType = right.GetType(); // Numeric conversions: // Otherwise, if one operand designates a value of type float, the values designated by both operands are // converted to type double, if necessary. The result has type double. if (leftType == typeof(float) || rightType == typeof(float)) { return(TryConvertToAnyNumericWithLeastType(left, typeof(double), out leftConverted) && TryConvertToAnyNumericWithLeastType(right, typeof(double), out rightConverted)); } // If one operand designates a value of type decimal, the value designated by the other operand is converted // to that type, if necessary. The result has type decimal. // Otherwise, if one operand designates a value of type double, the value designated by the // other operand is converted to that type, if necessary. The result has type double. // Otherwise, if one operand designates a value of type long, the value designated by the other operand // value is converted to that type, if necessary. The result has the type first in the sequence long and // double that can represent its value. // Otherwise, the values designated by both operands are converted to type int, if necessary. foreach (var type in new [] { typeof(decimal), typeof(double), typeof(long), typeof(int) }) { // NOTE: the specification tells us, that if e.g. the left is int, the right should be // converted to int. However, if it doesn't fit in an int, we need to try more! if (leftType == type) { leftConverted = left; return(TryConvertToAnyNumericWithLeastType(right, type, out rightConverted)); } if (rightType == type) { rightConverted = right; return(TryConvertToAnyNumericWithLeastType(left, type, out leftConverted)); } } // shouldn't happen as one operand should be of one of the numeric types return(false); }
/// <summary> /// Returns an IEnumerable for a given object compatable with the shell. /// </summary> /// <param name="obj">The object to use.</param> /// <returns>The enumerator if it can work, null otherwise.</returns> public static IEnumerable GetEnumerable(object obj) { obj = PSObject.Unwrap(obj); // Powershell seems to exclude a few types from from being enumerables if (ShouldPreventEnumeration(obj)) { return(null); } // either return it as enumerable or null return(obj as IEnumerable); }
/// <summary> /// Returns an IEnumerable for a given object compatable with the shell. /// </summary> /// <param name="obj">The object to use.</param> /// <returns>The enumerator if it can work, null otherwise.</returns> public static IEnumerable GetEnumerable(object obj) { obj = PSObject.Unwrap(obj); // Powershell seems to exclude a few types from from being enumerables if (obj is IDictionary || obj is string || obj is XmlDocument) { return(null); } // either return it as enumerable or null return(obj as IEnumerable); }
/// <summary> /// The parse currently adds each parameter without value and each value without parameter name, because /// it doesn't know at parse time whether the value belongs to the paramater or if the parameter is a switch /// parameter and the value is just a positional parameter. As we now know more abot the parameters, we can /// merge all parameters with the upcoming value if it's not a switch parameter /// </summary> private void MergeParameters() { var oldParameters = new Collection <CommandParameter>(new List <CommandParameter>(Parameters)); Parameters.Clear(); int numParams = oldParameters.Count; for (int i = 0; i < numParams; i++) { var current = oldParameters[i]; var peek = (i < numParams - 1) ? oldParameters[i + 1] : null; var hasValidName = !String.IsNullOrEmpty(current.Name); // if we have a switch parameter, set default value or pre-convert to bool if numeric if (hasValidName && IsSwitchParameter(current.Name)) { // if null (=unset) it's true; even if it's explicitly set to null object value = current.Value; if (current.Value == null) { Parameters.Add(current.Name, true); continue; } // strange thing in PS: While LanguagePrimitives aren't able to convert from numerics to // SwitchParameter, it does work with parameters. So we check it here else if (PSObject.Unwrap(current.Value).GetType().IsNumeric()) { value = LanguagePrimitives.ConvertTo <bool>(current.Value); } Parameters.Add(current.Name, value); } // if the current parameter has no argument (and not explicilty set to null), try to merge the next else if (peek != null && hasValidName && current.Value == null && String.IsNullOrEmpty(peek.Name)) { Parameters.Add(current.Name, peek.Value); i++; // skip next element as it was merged } // otherwise we have a usual parameter/argument set else { Parameters.Add(current); } } }
private static bool ConvertToBool(object rawValue) { rawValue = PSObject.Unwrap(rawValue); // just make this sure if (rawValue == null) { return(false); } if (rawValue is bool) { return((bool)rawValue); } else if (rawValue is string) { return(((string)rawValue).Length != 0); } else if (rawValue is IList) { var list = rawValue as IList; if (list.Count > 1) { return(true); } else if (list.Count == 1) { return(ConvertToBool(list[0])); } else // empty list { return(false); } } else if (rawValue.GetType().IsNumeric()) { return(((dynamic)rawValue) != 0); } else if (rawValue is char) { return(((char)rawValue) != ((char)0)); } else if (rawValue is SwitchParameter) { return(((SwitchParameter)rawValue).IsPresent); } return(true); // any object that's not null }
/// <summary> /// Returns an enumerator for a given object compatable with the shell. /// </summary> /// <param name="obj">The object to use.</param> /// <returns>The enumerator if it can work, null otherwise.</returns> public static IEnumerator GetEnumerator(object obj) { obj = PSObject.Unwrap(obj); // Powershell seems to exclude a few types from from being enumerables if (ShouldPreventEnumeration(obj)) { return(null); } var enumerable = GetEnumerable(obj); if (enumerable != null) { return(enumerable.GetEnumerator()); } if (obj is IEnumerator) { return(obj as IEnumerator); } return(null); }
/// <summary> /// Returns an enumerator for a given object compatable with the shell. /// </summary> /// <param name="obj">The object to use.</param> /// <returns>The enumerator if it can work, null otherwise.</returns> public static IEnumerator GetEnumerator(object obj) { obj = PSObject.Unwrap(obj); // Powershell seems to exclude dictionaries and strings from being enumerables if (obj is IDictionary || obj is string) { return(null); } var enumerable = GetEnumerable(obj); if (enumerable != null) { return(enumerable.GetEnumerator()); } if (obj is IEnumerator) { return(obj as IEnumerator); } return(null); }
private static string ConvertToString(object rawValue, IFormatProvider formatProvider) { rawValue = PSObject.Unwrap(rawValue); // A value of null type is converted to the empty string. if (rawValue == null) { return(string.Empty); } // The bool value $false is converted to "False"; the bool value $true is converted to "True". if (rawValue is bool) { return((bool)rawValue ? "True" : "False"); } // A char type value is converted to a 1-character string containing that char. if (rawValue is char) { return(new string((char)rawValue, 1)); } // A numeric type value is converted to a string having the form of a corresponding numeric literal. // However, the result has no leading or trailing spaces, no leading plus sign, integers have base 10, and // there is no type suffix. For a decimal conversion, the scale is preserved. For values of -∞, +∞, and // NaN, the resulting strings are "-Infinity", "Infinity", and "NaN", respectively. if (rawValue is byte || rawValue is short || rawValue is int || rawValue is long) { return(Convert.ToInt64(rawValue).ToString(formatProvider)); } if (rawValue is decimal) { return(((decimal)rawValue).ToString(formatProvider)); } if (rawValue is float) { return(((float)rawValue).ToString(formatProvider)); } if (rawValue is double) { return(((double)rawValue).ToString(formatProvider)); } // For an enumeration type value, the result is a string containing the name of each enumeration // constant encoded in that value, separated by commas. if (rawValue is Enum) { // Nicely enough, this is the format specified by the G format specifier. Except for the spaces // after the comma. But PowerShell seems to do exactly the same. return(((Enum)rawValue).ToString("G")); } // For a 1-dimensional array, the result is a string containing the value of each element in that array, from // start to end, converted to string, with elements being separated by the current Output Field // Separator (§2.3.2.2). For an array having elements that are themselves arrays, only the top-level // elements are converted. The string used to represent the value of an element that is an array, is // implementation defined. For a multi-dimensional array, it is flattened (§9.12) and then treated as a // 1-dimensional array. // Windows PowerShell: For other enumerable types, the source value is treated like a 1-dimensional // array. IEnumerable enumerable = GetEnumerable(rawValue); if (enumerable != null) { var runspace = Runspaces.Runspace.DefaultRunspace; var ofsV = runspace.SessionStateProxy.GetVariable("OFS"); var ofs = ofsV != null?ofsV.ToString() : " "; // Linq handles flattening return(String.Join(ofs, from o in enumerable.Cast <object>() select o == null ? "" : PSObject.Unwrap(o).ToString())); } // A scriptblock type value is converted to a string containing the text of that block without the // delimiting { and } characters. if (rawValue is ScriptBlock) { var scriptBlock = (ScriptBlock)rawValue; var ast = (ScriptBlockAst)scriptBlock.Ast; // TODO: I would have thought ast.EndBlock.Extent.Text would suffice here, but this corresponds to only the first token in the script block } // For other reference type values, if the reference type supports such a conversion, that conversion is // used; otherwise, the conversion is in error. // Windows PowerShell: The string used to represent the value of an element that is an array has the // form System.type[], System.type[,], and so on. // Windows PowerShell: For other reference types, the method ToString is called. return(Convert.ToString(rawValue, formatProvider)); }