Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
parserutils.cs2011 linesDownload Raw Back to lang
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.Collections;5using System.Collections.Concurrent;6using System.Collections.Generic;7using System.Diagnostics.CodeAnalysis;8using System.Globalization;9using System.Management.Automation.Internal;10using System.Management.Automation.Internal.Host;11using System.Management.Automation.Language;12using System.Management.Automation.Runspaces;13using System.Runtime.CompilerServices;14using System.Runtime.Serialization;15using System.Text.RegularExpressions;16 17using Dbg = System.Management.Automation.Diagnostics;18 19#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings20 21namespace System.Management.Automation22{23    #region Flow Control Exceptions24 25    /// <summary>26    /// FlowControlException, base class for flow control exceptions.27    /// </summary>28    public abstract class FlowControlException : SystemException29    {30        internal FlowControlException() { }31    }32 33    /// <summary>34    /// LoopFlowException, base class for loop control exceptions.35    /// </summary>36    public abstract class LoopFlowException : FlowControlException37    {38        internal LoopFlowException(string label)39        {40            this.Label = label ?? string.Empty;41        }42 43        internal LoopFlowException() { }44 45        /// <summary>46        /// Label, indicates nested loop level affected by exception.47        /// No label means most nested loop is affected.48        /// </summary>49        public string Label50        {51            get;52            internal set;53        }54 55        internal bool MatchLabel(string loopLabel)56        {57            return MatchLoopLabel(Label, loopLabel);58        }59 60        internal static bool MatchLoopLabel(string flowLabel, string loopLabel)61        {62            // If the flow statement has no label, it always matches (because it just means, break or continue from63            // the most nested loop.)  Otherwise, compare the labels.64 65            return string.IsNullOrEmpty(flowLabel) || flowLabel.Equals(loopLabel, StringComparison.OrdinalIgnoreCase);66        }67    }68 69    /// <summary>70    /// Flow control BreakException.71    /// </summary>72    public sealed class BreakException : LoopFlowException73    {74        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]75        internal BreakException(string label)76            : base(label)77        {78        }79 80        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]81        internal BreakException() { }82 83        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]84        internal BreakException(string label, Exception innerException)85            : base(label)86        {87        }88    }89 90    /// <summary>91    /// Flow control ContinueException.92    /// </summary>93    public sealed class ContinueException : LoopFlowException94    {95        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]96        internal ContinueException(string label)97            : base(label)98        {99        }100 101        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]102        internal ContinueException() { }103 104        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]105        internal ContinueException(string label, Exception innerException)106            : base(label)107        {108        }109    }110 111    internal class ReturnException : FlowControlException112    {113        internal ReturnException(object argument)114        {115            this.Argument = argument;116        }117 118        internal object Argument { get; set; }119    }120 121    /// <summary>122    /// Implements the exit keyword.123    /// </summary>124    public class ExitException : FlowControlException125    {126        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]127        internal ExitException(object argument)128        {129            this.Argument = argument;130        }131 132        /// <summary>133        /// Argument.134        /// </summary>135        public object Argument { get; internal set; }136 137        [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Justification = "This exception should only be thrown from SMA.dll")]138        internal ExitException() { }139    }140 141    /// <summary>142    /// Used by InternalHost.ExitNestedPrompt() to pop out of an interpreter level...143    /// </summary>144    internal class ExitNestedPromptException : FlowControlException145    {146    }147 148    /// <summary>149    /// Used by the debugger to terminate the execution of the current command.150    /// </summary>151    public sealed class TerminateException : FlowControlException152    {153    }154 155    /// <summary>156    /// Used by Select-Object cmdlet to stop all the upstream cmdlets, but continue157    /// executing downstream cmdlets.  The semantics of stopping is intended to mimic158    /// a user pressing Ctrl-C [but which only affects upstream cmdlets].159    /// </summary>160    internal class StopUpstreamCommandsException : FlowControlException161    {162        public StopUpstreamCommandsException(InternalCommand requestingCommand)163        {164            this.RequestingCommandProcessor = requestingCommand.Context.CurrentCommandProcessor;165        }166 167        public CommandProcessorBase RequestingCommandProcessor { get; }168    }169 170    #endregion Flow Control Exceptions171 172    /// <summary>173    /// A enum corresponding to the options on the -split operator.174    /// </summary>175    [Flags]176    public enum SplitOptions177    {178        /// <summary>179        /// Use simple string comparison when evaluating the delimiter.180        /// Cannot be used with RegexMatch.181        /// </summary>182        SimpleMatch = 0x01,183        /// <summary>184        /// Use regular expression matching to evaluate the delimiter.185        /// This is the default behavior. Cannot be used with SimpleMatch.186        /// </summary>187        RegexMatch = 0x02,188        /// <summary>189        /// CultureInvariant: Ignores cultural differences in language when evaluating the delimiter.190        /// Valid only with RegexMatch.191        /// </summary>192        CultureInvariant = 0x04,193        /// <summary>194        /// Ignores unescaped whitespace and comments marked with #.195        /// Valid only with RegexMatch.196        /// </summary>197        [SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "Whitespace")]198        IgnorePatternWhitespace = 0x08,199        /// <summary>200        /// Regex multiline mode, which recognizes the start and end of lines,201        /// as well as the start and end of strings.202        /// Valid only with RegexMatch.203        /// Singleline is the default.204        /// </summary>205        Multiline = 0x10,206        /// <summary>207        /// Regex Singleline mode, which recognizes only the start and end of strings.208        /// Valid only with RegexMatch.209        /// Singleline is the default.210        /// </summary>211        Singleline = 0x20,212        /// <summary>213        /// Forces case-insensitive matching, even if -cSplit is specified.214        /// </summary>215        IgnoreCase = 0x40,216        /// <summary>217        /// Ignores non-named match groups, so that only explicit capture groups218        /// are returned in the result list.219        /// </summary>220        ExplicitCapture = 0x80,221    }222 223    #region ParserOps224 225    internal delegate object PowerShellBinaryOperator(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval);226 227    /// <summary>228    /// A static class holding various operations specific to the PowerShell interpreter such as229    /// various math operations, ToString() and a routine to extract the base object from an230    /// PSObject in a canonical fashion.231    /// </summary>232    internal static class ParserOps233    {234        internal const string MethodNotFoundErrorId = "MethodNotFound";235 236        /// <summary>237        /// Construct the various caching structures used by the runtime routines...238        /// </summary>239        static ParserOps()240        {241            // Cache for ints and chars to avoid overhead of boxing every time...242            for (int i = 0; i < (_MaxCache - _MinCache); i++)243            {244                s_integerCache[i] = (object)(i + _MinCache);245            }246 247            for (char ch = (char)0; ch < 255; ch++)248            {249                s_chars[ch] = new string(ch, 1);250            }251        }252 253        private const int _MinCache = -100;254        private const int _MaxCache = 1000;255 256        private static readonly object[] s_integerCache = new object[_MaxCache - _MinCache];257        private static readonly string[] s_chars = new string[255];258        internal static readonly object _TrueObject = (object)true;259        internal static readonly object _FalseObject = (object)false;260 261        internal static string CharToString(char ch)262        {263            if (ch < 255) return s_chars[ch];264            return new string(ch, 1);265        }266 267        internal static object BoolToObject(bool value)268        {269            return value ? _TrueObject : _FalseObject;270        }271 272        /// <summary>273        /// Convert an object into an int, avoiding boxing small integers...274        /// </summary>275        /// <param name="value">The int to convert.</param>276        /// <returns>The reference equivalent.</returns>277        internal static object IntToObject(int value)278        {279            if (value < _MaxCache && value >= _MinCache)280            {281                return s_integerCache[value - _MinCache];282            }283 284            return (object)value;285        }286 287        internal static PSObject WrappedNumber(object data, string text)288        {289            PSObject wrapped = new PSObject(data);290            wrapped.TokenText = text;291            return wrapped;292        }293 294        /// <summary>295        /// A helper routine that turns the argument object into an296        /// integer. It handles PSObject and conversions.297        /// </summary>298        /// <param name="obj"></param>299        /// <param name="errorPosition">The position to use for error reporting.</param>300        /// <returns></returns>301        /// <exception cref="RuntimeException">The result could not be represented as an integer.</exception>302        internal static int FixNum(object obj, IScriptExtent errorPosition)303        {304            obj = PSObject.Base(obj);305 306            if (obj == null)307                return 0;308            if (obj is int)309                return (int)obj;310            int result = ConvertTo<int>(obj, errorPosition);311            return result;312        }313 314        /// <summary>315        /// This is a helper function for converting an object to a particular type.316        ///317        /// It will throw exception with information about token representing the object.318        /// </summary>319        internal static T ConvertTo<T>(object obj, IScriptExtent errorPosition)320        {321            T result;322 323            try324            {325                result = (T)LanguagePrimitives.ConvertTo(obj, typeof(T), CultureInfo.InvariantCulture);326            }327            catch (PSInvalidCastException mice)328            {329                RuntimeException re = new RuntimeException(mice.Message, mice);330                re.ErrorRecord.SetInvocationInfo(new InvocationInfo(null, errorPosition));331                throw re;332            }333 334            return result;335        }336 337        /// <summary>338        /// Private method used to call the op_* operations for the math operators.339        /// </summary>340        /// <param name="lval">Left operand.</param>341        /// <param name="rval">Right operand.</param>342        /// <param name="op">Name of the operation method to perform.</param>343        /// <param name="errorPosition">The position to use for error reporting.</param>344        /// <param name="errorOp">The string to use in error messages representing the op.</param>345        /// <returns>The result of the operation.</returns>346        /// <exception cref="RuntimeException">An error occurred performing the operation, see inner exception.</exception>347        internal static object ImplicitOp(object lval, object rval, string op, IScriptExtent errorPosition, string errorOp)348        {349            // Get the base object. At somepoint, we may allow users to dynamically extend350            // the implicit operators at which point, we'll need to change this to find the351            // extension method...352            lval = PSObject.Base(lval);353            rval = PSObject.Base(rval);354 355            Type lvalType = lval?.GetType();356            Type rvalType = rval?.GetType();357            Type opType;358            if (lvalType == null || (lvalType.IsPrimitive))359            {360                // Prefer the LHS type when looking for the operator, but attempt the right361                // the lhs can't have an operator.362                //363                // This logic is overly simplified and doesn't match other languages which364                // would look for overloads in both types, but this logic covers the most common365                // cases.366 367                opType = (rvalType == null || rvalType.IsPrimitive) ? null : rvalType;368            }369            else370            {371                opType = lvalType;372            }373 374            if (opType == null)375            {376                throw InterpreterError.NewInterpreterException(lval, typeof(RuntimeException), errorPosition,377                    "NotADefinedOperationForType", ParserStrings.NotADefinedOperationForType,378                    lvalType == null ? "$null" : lvalType.FullName,379                    errorOp,380                    rvalType == null ? "$null" : rvalType.FullName);381            }382 383            // None of the explicit conversions worked so try and invoke a method instead...384            object[] parms = new object[2];385            parms[0] = lval;386            parms[1] = rval;387            return CallMethod(388                errorPosition,389                opType,390                op, /* methodName */391                null, /* invocationConstraints */392                parms,393                true,394                AutomationNull.Value);395        }396 397        [Flags]398        private enum SplitImplOptions399        {400            None = 0x00,401            TrimContent = 0x01,402        }403 404        private static object[] unfoldTuple(ExecutionContext context, IScriptExtent errorPosition, object tuple)405        {406            List<object> result = new List<object>();407 408            IEnumerator enumerator = LanguagePrimitives.GetEnumerator(tuple);409            if (enumerator != null)410            {411                while (ParserOps.MoveNext(context, errorPosition, enumerator))412                {413                    object element = ParserOps.Current(errorPosition, enumerator);414                    result.Add(element);415                }416            }417            else418            {419                // Not a tuple at all, just a single item. Treat it420                // as a 1-tuple.421                result.Add(tuple);422            }423 424            return result.ToArray();425        }426 427        // uses "yield" from C# 2.0, which automatically creates428        // an enumerable out of the loop code. See429        // https://msdn.microsoft.com/msdnmag/issues/04/05/C20/ for430        // more details.431        private static IEnumerable<string> enumerateContent(ExecutionContext context, IScriptExtent errorPosition, SplitImplOptions implOptions, object tuple)432        {433            IEnumerator enumerator = LanguagePrimitives.GetEnumerator(tuple) ?? new object[] { tuple }.GetEnumerator();434 435            while (ParserOps.MoveNext(context, errorPosition, enumerator))436            {437                string strValue = PSObject.ToStringParser(context, enumerator.Current);438                if ((implOptions & SplitImplOptions.TrimContent) != 0)439                    strValue = strValue.Trim();440 441                yield return strValue;442            }443        }444 445        private static RegexOptions parseRegexOptions(SplitOptions options)446        {447            RegexOptions result = RegexOptions.None;448            if ((options & SplitOptions.CultureInvariant) != 0)449            {450                result |= RegexOptions.CultureInvariant;451            }452 453            if ((options & SplitOptions.IgnorePatternWhitespace) != 0)454            {455                result |= RegexOptions.IgnorePatternWhitespace;456            }457 458            if ((options & SplitOptions.Multiline) != 0)459            {460                result |= RegexOptions.Multiline;461            }462 463            if ((options & SplitOptions.Singleline) != 0)464            {465                result |= RegexOptions.Singleline;466            }467 468            if ((options & SplitOptions.IgnoreCase) != 0)469            {470                result |= RegexOptions.IgnoreCase;471            }472 473            if ((options & SplitOptions.ExplicitCapture) != 0)474            {475                result |= RegexOptions.ExplicitCapture;476            }477 478            return result;479        }480 481        internal static object UnarySplitOperator(ExecutionContext context, IScriptExtent errorPosition, object lval)482        {483            // unary split does a little extra processing to make484            // whitespace processing more convenient. Specifically,485            // it will ignore leading/trailing whitespace.486            return SplitOperatorImpl(context, errorPosition, lval, new object[] { @"\s+" }, SplitImplOptions.TrimContent, false);487        }488 489        internal static object SplitOperator(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval, bool ignoreCase)490        {491            return SplitOperatorImpl(context, errorPosition, lval, rval, SplitImplOptions.None, ignoreCase);492        }493 494        private static IReadOnlyList<string> SplitOperatorImpl(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval, SplitImplOptions implOptions, bool ignoreCase)495        {496            IEnumerable<string> content = enumerateContent(context, errorPosition, implOptions, lval);497 498            ScriptBlock predicate = null;499            string separatorPattern = null;500            int limit = 0;501            SplitOptions options = 0;502 503            object[] args = unfoldTuple(context, errorPosition, rval);504            if (args.Length >= 1)505            {506                predicate = args[0] as ScriptBlock;507                if (predicate == null)508                {509                    separatorPattern = PSObject.ToStringParser(context, args[0]);510                }511            }512            else513            {514                // The first argument to split is always required.515                throw InterpreterError.NewInterpreterException(rval, typeof(RuntimeException), errorPosition,516                    "BadOperatorArgument", ParserStrings.BadOperatorArgument, "-split", rval);517            }518 519            if (args.Length >= 2)520                limit = FixNum(args[1], errorPosition);521            if (args.Length >= 3 && args[2] != null)522            {523                string args2asString = args[2] as string;524                if (args2asString == null || !string.IsNullOrEmpty(args2asString))525                {526                    options = ConvertTo<SplitOptions>(args[2], errorPosition);527                    if (predicate != null)528                    {529                        throw InterpreterError.NewInterpreterException(null, typeof(ParseException),530                            errorPosition, "InvalidSplitOptionWithPredicate", ParserStrings.InvalidSplitOptionWithPredicate);531                    }532 533                    if (ignoreCase && (options & SplitOptions.IgnoreCase) == 0)534                    {535                        options |= SplitOptions.IgnoreCase;536                    }537                }538            }539            else if (ignoreCase)540            {541                options |= SplitOptions.IgnoreCase;542            }543 544            if (predicate == null)545            {546                return SplitWithPattern(context, errorPosition, content, separatorPattern, limit, options);547            }548            else if (limit >= 0)549            {550                return SplitWithPredicate(context, errorPosition, content, predicate, limit);551            }552            else553            {554                return NegativeSplitWithPredicate(context, errorPosition, content, predicate, limit);555            }556        }557 558        private static IReadOnlyList<string> NegativeSplitWithPredicate(ExecutionContext context, IScriptExtent errorPosition, IEnumerable<string> content, ScriptBlock predicate, int limit)559        {560            var results = new List<string>();561 562            if (limit == -1)563            {564                // If the user just wants 1 string565                // then just return the content566                return new List<string>(content);567            }568 569            foreach (string item in content)570            {571                var split = new List<string>();572 573                // Used to traverse through the item574                int cursor = item.Length - 1;575 576                int subStringLength = 0;577 578                for (int charCount = 0; charCount < item.Length; charCount++)579                {580                    // Evaluate the predicate using the character at cursor.581                    object predicateResult = predicate.DoInvokeReturnAsIs(582                        useLocalScope: true,583                        errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,584                        dollarUnder: CharToString(item[cursor]),585                        input: AutomationNull.Value,586                        scriptThis: AutomationNull.Value,587                        args: new object[] { item, cursor });588 589                    if (!LanguagePrimitives.IsTrue(predicateResult))590                    {591                        subStringLength++;592                        cursor -= 1;593                        continue;594                    }595 596                    split.Add(item.Substring(cursor + 1, subStringLength));597 598                    subStringLength = 0;599 600                    cursor -= 1;601 602                    if (System.Math.Abs(limit) == (split.Count + 1))603                    {604                        break;605                    }606                }607 608                if (cursor == -1)609                {610                    // Used when the limit is negative611                    // and the cursor was allowed to go612                    // all the way to the start of the613                    // string.614                    split.Add(item.Substring(0, subStringLength));615                }616                else617                {618                    // Used to get the rest of the string619                    // when using a negative limit and620                    // the cursor doesn't reach the end621                    // of the string.622                    split.Add(item.Substring(0, cursor + 1));623                }624 625                split.Reverse();626 627                results.AddRange(split);628            }629 630            return results.ToArray();631        }632 633        private static IReadOnlyList<string> SplitWithPredicate(ExecutionContext context, IScriptExtent errorPosition, IEnumerable<string> content, ScriptBlock predicate, int limit)634        {635            var results = new List<string>();636 637            if (limit == 1)638            {639                // If the user just wants 1 string640                // then just return the content641                return new List<string>(content);642            }643 644            foreach (string item in content)645            {646                var split = new List<string>();647 648                // Used to traverse through the item649                int cursor = 0;650 651                // This is used to calculate how much to split from item.652                int subStringLength = 0;653 654                for (int charCount = 0; charCount < item.Length; charCount++)655                {656                    // Evaluate the predicate using the character at cursor.657                    object predicateResult = predicate.DoInvokeReturnAsIs(658                        useLocalScope: true,659                        errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,660                        dollarUnder: CharToString(item[cursor]),661                        input: AutomationNull.Value,662                        scriptThis: AutomationNull.Value,663                        args: new object[] { item, cursor });664 665                    // If the current character is not a delimiter666                    // then it must be included into a substring.667                    if (!LanguagePrimitives.IsTrue(predicateResult))668                    {669                        subStringLength++;670 671                        cursor += 1;672 673                        continue;674                    }675 676                    // Else, if the character is a delimiter677                    // then add a substring to the split list.678                    split.Add(item.Substring(cursor - subStringLength, subStringLength));679 680                    subStringLength = 0;681 682                    cursor += 1;683 684                    if (limit == (split.Count + 1))685                    {686                        break;687                    }688                }689 690                if (cursor == item.Length)691                {692                    // Used to get the rest of the string693                    // when the limit is not negative and694                    // the cursor is allowed to make it to695                    // the end of the string.696                    split.Add(item.Substring(cursor - subStringLength, subStringLength));697                }698                else699                {700                    // Used to get the rest of the string701                    // when the limit is not negative and702                    // the cursor is not at the end of the703                    // string.704                    split.Add(item.Substring(cursor, item.Length - cursor));705                }706 707                results.AddRange(split);708            }709 710            return results.ToArray();711        }712 713        private static IReadOnlyList<string> SplitWithPattern(ExecutionContext context, IScriptExtent errorPosition, IEnumerable<string> content, string separatorPattern, int limit, SplitOptions options)714        {715            // Default to Regex matching if no match specified.716            if ((options & SplitOptions.SimpleMatch) == 0 &&717                (options & SplitOptions.RegexMatch) == 0)718            {719                options |= SplitOptions.RegexMatch;720            }721 722            if ((options & SplitOptions.SimpleMatch) != 0)723            {724                if ((options & ~(SplitOptions.SimpleMatch | SplitOptions.IgnoreCase)) != 0)725                {726                    throw InterpreterError.NewInterpreterException(null, typeof(ParseException),727                        errorPosition, "InvalidSplitOptionCombination", ParserStrings.InvalidSplitOptionCombination);728                }729            }730 731            if ((options & SplitOptions.SimpleMatch) != 0)732            {733                separatorPattern = Regex.Escape(separatorPattern);734            }735 736            RegexOptions regexOptions = parseRegexOptions(options);737 738            int calculatedLimit = limit;739 740            // If the limit is negative then set Regex to read from right to left741            if (calculatedLimit < 0)742            {743                regexOptions |= RegexOptions.RightToLeft;744                calculatedLimit *= -1;745            }746 747            Regex regex = NewRegex(separatorPattern, regexOptions);748 749            var results = new List<string>();750 751            foreach (string item in content)752            {753                string[] split = regex.Split(item, calculatedLimit);754                results.AddRange(split);755            }756 757            return results.ToArray();758        }759 760        /// <summary>761        /// Implementation of the PowerShell unary -join operator...762        /// </summary>763        /// <param name="context">The execution context to use.</param>764        /// <param name="errorPosition">The position to use for error reporting.</param>765        /// <param name="lval">Left operand.</param>766        /// <returns>The result of the operator.</returns>767        internal static object UnaryJoinOperator(ExecutionContext context, IScriptExtent errorPosition, object lval)768        {769            return JoinOperator(context, errorPosition, lval, string.Empty);770        }771 772        /// <summary>773        /// Implementation of the PowerShell binary -join operator.774        /// </summary>775        /// <param name="context">The execution context to use.</param>776        /// <param name="errorPosition">The position to use for error reporting.</param>777        /// <param name="lval">Left operand.</param>778        /// <param name="rval">Right operand.</param>779        /// <returns>The result of the operator.</returns>780        internal static object JoinOperator(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval)781        {782            string separator = PSObject.ToStringParser(context, rval);783 784            // PSObject already has join functionality; just expose it785            // as an operator.786            IEnumerable enumerable = LanguagePrimitives.GetEnumerable(lval);787            if (enumerable != null)788            {789                return PSObject.ToStringEnumerable(context, enumerable, separator, null, null);790            }791            else792            {793                return PSObject.ToStringParser(context, lval);794            }795        }796 797        /// <summary>798        /// The implementation of the PowerShell range operator.799        /// </summary>800        /// <param name="lval">The object on which to start.</param>801        /// <param name="rval">The object on which to stop.</param>802        /// <returns>The array of objects.</returns>803        internal static object RangeOperator(object lval, object rval)804        {805            var lbase = PSObject.Base(lval);806            var rbase = PSObject.Base(rval);807 808            // If both arguments is [char] type or [string] type with length==1809            // return objects of [char] type.810            // In special case "0".."9" return objects of [int] type.811            if (AsChar(lbase) is char lc && AsChar(rbase) is char rc)812            {813                return CharOps.Range(lc, rc);814            }815 816            // As a last resort, the range operator tries to return objects of [int] type.817            //    1..10818            //    "1".."10"819            //    [int]"1"..[int]"10"820            var l = Convert.ToInt32(lbase);821            var r = Convert.ToInt32(rbase);822 823            return IntOps.Range(l, r);824        }825 826        /// <summary>827        /// The implementation of an enumerator for the PowerShell range operator.828        /// </summary>829        /// <param name="lval">The object on which to start.</param>830        /// <param name="rval">The object on which to stop.</param>831        /// <returns>The enumerator.</returns>832        internal static IEnumerator GetRangeEnumerator(object lval, object rval)833        {834            var lbase = PSObject.Base(lval);835            var rbase = PSObject.Base(rval);836 837            // If both arguments is [char] type or [string] type with length==1838            // return objects of [char] type.839            // In special case "0".."9" return objects of [int] type.840            if (AsChar(lbase) is char lc && AsChar(rbase) is char rc)841            {842                return new CharRangeEnumerator(lc, rc);843            }844 845            // As a last resort, the range operator tries to return objects of [int] type.846            //    1..10847            //    "1".."10"848            //    [int]"1"..[int]"10"849            var l = Convert.ToInt32(lbase);850            var r = Convert.ToInt32(rbase);851 852            return new RangeEnumerator(l, r);853        }854 855        // Help function for Range operator.856        //857        // In common case:858        //      for [char] type859        //      for [string] type and length == 1860        // return objects of [char] type:861        //     [char]'A'..[char]'Z'862        //     [char]'A'..'Z'863        //     [char]'A'.."Z"864        //     'A'..[char]'Z'865        //     "A"..[char]'Z'866        //     "A".."Z"867        //     [char]"A"..[string]"Z"868        //     "A"..[char]"Z"869        //     [string]"A".."Z"870        // and so on.871        //872        // In special case:873        //     "0".."9"874        // return objects of [int] type.875        private static object AsChar(object obj)876        {877            if (obj is char) return obj;878            if (obj is string str && str.Length == 1 && !char.IsDigit(str, 0)) return str[0];879            return null;880        }881 882        /// <summary>883        /// The implementation of the PowerShell -replace operator....884        /// </summary>885        /// <param name="context">The execution context in which to evaluate the expression.</param>886        /// <param name="errorPosition">The position to use for error reporting.</param>887        /// <param name="lval">The object on which to replace the values.</param>888        /// <param name="rval">The replacement description.</param>889        /// <param name="ignoreCase">True for -ireplace/-replace, false for -creplace.</param>890        /// <returns>The result of the operator.</returns>891        internal static object ReplaceOperator(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval, bool ignoreCase)892        {893            object pattern = string.Empty;894            object substitute = string.Empty;895 896            rval = PSObject.Base(rval);897            IList rList = rval as IList;898            if (rList != null)899            {900                if (rList.Count > 2)901                {902                    // only allow 1 or 2 arguments to -replace903                    throw InterpreterError.NewInterpreterException(rval, typeof(RuntimeException), errorPosition,904                        "BadReplaceArgument", ParserStrings.BadReplaceArgument, errorPosition.Text, rList.Count);905                }906 907                if (rList.Count > 0)908                {909                    pattern = rList[0];910                    if (rList.Count > 1)911                    {912                        substitute = PSObject.Base(rList[1]);913                    }914                }915            }916            else917            {918                pattern = rval;919            }920 921            RegexOptions rreOptions = RegexOptions.None;922 923            if (ignoreCase)924            {925                rreOptions = RegexOptions.IgnoreCase;926            }927 928            Regex rr = pattern as Regex;929            if (rr == null)930            {931                try932                {933                    rr = NewRegex((string)PSObject.ToStringParser(context, pattern), rreOptions);934                }935                catch (ArgumentException ae)936                {937                    throw InterpreterError.NewInterpreterExceptionWithInnerException(pattern, typeof(RuntimeException),938                        null, "InvalidRegularExpression", ParserStrings.InvalidRegularExpression, ae, pattern);939                }940            }941 942            var replacer = ReplaceOperatorImpl.Create(context, rr, substitute);943            IEnumerator list = LanguagePrimitives.GetEnumerator(lval);944            if (list == null)945            {946                string lvalString = PSObject.ToStringParser(context, lval) ?? string.Empty;947 948                return replacer.Replace(lvalString);949            }950            else951            {952                List<object> resultList = new List<object>();953                while (ParserOps.MoveNext(context, errorPosition, list))954                {955                    string lvalString = PSObject.ToStringParser(context, ParserOps.Current(errorPosition, list));956                    resultList.Add(replacer.Replace(lvalString));957                }958 959                return resultList.ToArray();960            }961        }962 963        private struct ReplaceOperatorImpl964        {965            public static ReplaceOperatorImpl Create(ExecutionContext context, Regex regex, object substitute)966            {967                return new ReplaceOperatorImpl(context, regex, substitute);968            }969 970            private readonly Regex _regex;971            private readonly string _cachedReplacementString;972            private readonly MatchEvaluator _cachedMatchEvaluator;973 974            private ReplaceOperatorImpl(975                ExecutionContext context,976                Regex regex,977                object substitute)978            {979                _regex = regex;980                _cachedReplacementString = null;981                _cachedMatchEvaluator = null;982 983                switch (substitute)984                {985                    case string replacement:986                        _cachedReplacementString = replacement;987                        break;988 989                    case ScriptBlock sb:990                        _cachedMatchEvaluator = GetMatchEvaluator(context, sb);991                        break;992 993                    case object val when LanguagePrimitives.TryConvertTo(val, out _cachedMatchEvaluator):994                        break;995 996                    default:997                        _cachedReplacementString = PSObject.ToStringParser(context, substitute);998                        break;999                }1000            }1001 1002            // Local helper function to avoid creating an instance of the generated delegate helper class1003            // every time 'ReplaceOperatorImpl' is invoked.1004            private static MatchEvaluator GetMatchEvaluator(ExecutionContext context, ScriptBlock sb)1005            {1006                return match =>1007                {1008                    var result = sb.DoInvokeReturnAsIs(1009                        useLocalScope: false, /* Use current scope to be consistent with 'ForEach/Where-Object {}' and 'collection.ForEach{}/Where{}' */1010                        errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToCurrentErrorPipe,1011                        dollarUnder: match,1012                        input: AutomationNull.Value,1013                        scriptThis: AutomationNull.Value,1014                        args: Array.Empty<object>());1015 1016                    return PSObject.ToStringParser(context, result);1017                };1018            }1019 1020            /// <summary>1021            /// ReplaceOperator implementation.1022            /// Abstracts away conversion of the optional substitute parameter to either a string or a MatchEvaluator delegate1023            /// and finally returns the result of the final Regex.Replace operation.1024            /// </summary>1025            public object Replace(string input)1026            {1027                if (_cachedReplacementString is not null)1028                {1029                    return _regex.Replace(input, _cachedReplacementString);1030                }1031 1032                Dbg.Assert(_cachedMatchEvaluator is not null, "_cachedMatchEvaluator should be not null when code reach here.");1033                return _regex.Replace(input, _cachedMatchEvaluator);1034            }1035        }1036 1037        /// <summary>1038        /// Implementation of the PowerShell type operators...1039        /// </summary>1040        /// <param name="context">The execution context to use.</param>1041        /// <param name="errorPosition">The position to use for error reporting.</param>1042        /// <param name="left">Left operand.</param>1043        /// <param name="right">Right operand.</param>1044        /// <returns>The result of the operator.</returns>1045        internal static object IsOperator(ExecutionContext context, IScriptExtent errorPosition, object left, object right)1046        {1047            object lval = PSObject.Base(left);1048            object rval = PSObject.Base(right);1049 1050            Type rType = rval as Type;1051 1052            if (rType == null)1053            {1054                rType = ConvertTo<Type>(rval, errorPosition);1055 1056                if (rType == null)1057                {1058                    // "the right operand of '-is' must be a type"1059                    throw InterpreterError.NewInterpreterException(rval, typeof(RuntimeException),1060                        errorPosition, "IsOperatorRequiresType", ParserStrings.IsOperatorRequiresType);1061                }1062            }1063 1064            if (rType == typeof(PSCustomObject) && lval is PSObject)1065            {1066                Diagnostics.Assert(rType.IsInstanceOfType(((PSObject)lval).ImmediateBaseObject), "Unexpect PSObject");1067                return _TrueObject;1068            }1069 1070            if (rType.Equals(typeof(PSObject)) && left is PSObject)1071            {1072                return _TrueObject;1073            }1074 1075            return BoolToObject(rType.IsInstanceOfType(lval));1076        }1077 1078        /// <summary>1079        /// Implementation of the PowerShell type operators...1080        /// </summary>1081        /// <param name="context">The execution context to use.</param>1082        /// <param name="errorPosition">The position to use for error reporting.</param>1083        /// <param name="left">Left operand.</param>1084        /// <param name="right">Right operand.</param>1085        /// <returns>The result of the operator.</returns>1086        internal static object IsNotOperator(ExecutionContext context, IScriptExtent errorPosition, object left, object right)1087        {1088            object lval = PSObject.Base(left);1089            object rval = PSObject.Base(right);1090 1091            Type rType = rval as Type;1092 1093            if (rType == null)1094            {1095                rType = ConvertTo<Type>(rval, errorPosition);1096 1097                if (rType == null)1098                {1099                    // "the right operand of '-is' must be a type"1100                    throw InterpreterError.NewInterpreterException(rval, typeof(RuntimeException),1101                        errorPosition, "IsOperatorRequiresType", ParserStrings.IsOperatorRequiresType);1102                }1103            }1104 1105            if (rType == typeof(PSCustomObject) && lval is PSObject)1106            {1107                Diagnostics.Assert(rType.IsInstanceOfType(((PSObject)lval).ImmediateBaseObject), "Unexpect PSObject");1108                return _FalseObject;1109            }1110 1111            if (rType.Equals(typeof(PSObject)) && left is PSObject)1112            {1113                return _FalseObject;1114            }1115 1116            return BoolToObject(!rType.IsInstanceOfType(lval));1117        }1118 1119        /// <summary>1120        /// Implementation of the PowerShell -like operator.1121        /// </summary>1122        /// <param name="context">The execution context to use.</param>1123        /// <param name="errorPosition">The position to use for error reporting.</param>1124        /// <param name="lval">Left operand.</param>1125        /// <param name="rval">Right operand.</param>1126        /// <param name="operator">The operator.</param>1127        /// <returns>The result of the operator.</returns>1128        internal static object LikeOperator(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval, TokenKind @operator)1129        {1130            var wcp = rval as WildcardPattern;1131            if (wcp == null)1132            {1133                var ignoreCase = @operator == TokenKind.Ilike || @operator == TokenKind.Inotlike;1134                wcp = WildcardPattern.Get(PSObject.ToStringParser(context, rval),1135                    ignoreCase ? WildcardOptions.IgnoreCase : WildcardOptions.None);1136            }1137 1138            bool notLike = @operator == TokenKind.Inotlike || @operator == TokenKind.Cnotlike;1139            IEnumerator list = LanguagePrimitives.GetEnumerator(lval);1140            if (list == null)1141            {1142                string lvalString = lval == null ? string.Empty : PSObject.ToStringParser(context, lval);1143 1144                return BoolToObject(wcp.IsMatch(lvalString) ^ notLike);1145            }1146 1147            List<object> resultList = new List<object>();1148 1149            while (ParserOps.MoveNext(context, errorPosition, list))1150            {1151                object val = ParserOps.Current(errorPosition, list);1152 1153                string lvalString = val == null ? string.Empty : PSObject.ToStringParser(context, val);1154 1155                if (wcp.IsMatch(lvalString) ^ notLike)1156                {1157                    resultList.Add(lvalString);1158                }1159            }1160 1161            return resultList.ToArray();1162        }1163 1164        /// <summary>1165        /// Implementation of the PowerShell -match operator.1166        /// </summary>1167        /// <param name="context">The execution context to use.</param>1168        /// <param name="errorPosition">The position to use for error reporting.</param>1169        /// <param name="lval">Left operand.</param>1170        /// <param name="rval">Right operand.</param>1171        /// <param name="ignoreCase">Ignore case?</param>1172        /// <param name="notMatch">True for -notmatch, false for -match.</param>1173        /// <returns>The result of the operator.</returns>1174        internal static object MatchOperator(ExecutionContext context, IScriptExtent errorPosition, object lval, object rval, bool notMatch, bool ignoreCase)1175        {1176            RegexOptions reOptions = ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None;1177 1178            // if passed an explicit regex, just use it1179            // otherwise compile the expression.1180            // In this situation, creation of Regex should not fail. We are not1181            // processing ArgumentException in this case.1182            Regex r = PSObject.Base(rval) as Regex1183                ?? NewRegex(PSObject.ToStringParser(context, rval), reOptions);1184 1185            IEnumerator list = LanguagePrimitives.GetEnumerator(lval);1186            if (list == null)1187            {1188                string lvalString = lval == null ? string.Empty : PSObject.ToStringParser(context, lval);1189 1190                // Find a match in the string.1191                Match m = r.Match(lvalString);1192 1193                if (m.Success)1194                {1195                    GroupCollection groups = m.Groups;1196                    if (groups.Count > 0)1197                    {1198                        Hashtable h = new Hashtable(StringComparer.CurrentCultureIgnoreCase);1199 1200                        foreach (string groupName in r.GetGroupNames())

Showing the first 1,200 of 2011 lines. Download the file for the rest.