Ejemplo n.º 1
0
        public override Completion InternalConstruct(IReadOnlyList <IValue> arguments, Object?newTarget)
        {
            var pattern = arguments.At(0, UndefinedValue.Instance);
            var flags   = arguments.At(1, UndefinedValue.Instance);

            var patternIsRegExpComp = IsRegExp(pattern);

            if (patternIsRegExpComp.IsAbrupt())
            {
                return(patternIsRegExpComp);
            }
            var patternIsRegExp = patternIsRegExpComp.Other;

            if (newTarget == null)
            {
                newTarget = this;
                if (patternIsRegExp && flags == UndefinedValue.Instance)
                {
                    var patternObject      = (pattern as Object) !;
                    var patternConstructor = patternObject.Get("constructor");
                    if (patternConstructor.IsAbrupt())
                    {
                        return(patternConstructor);
                    }
                    if (patternObject == newTarget)
                    {
                        return(Completion.NormalCompletion(pattern));
                    }
                }
            }
            IValue P, F;

            if (pattern is RegExpObject r)
            {
                P = new StringValue(r.OriginalSource);
                if (flags == UndefinedValue.Instance)
                {
                    F = new StringValue(r.OriginalFlags);
                }
                else
                {
                    F = flags;
                }
            }
            else if (patternIsRegExp)
            {
                var patternObject = (pattern as Object) !;
                var PComp         = patternObject.Get("source");
                if (PComp.IsAbrupt())
                {
                    return(PComp);
                }
                P = PComp.value !;
                if (flags == UndefinedValue.Instance)
                {
                    var FComp = patternObject.Get("flags");
                    if (FComp.IsAbrupt())
                    {
                        return(FComp);
                    }
                    F = FComp.value !;
                }
                else
                {
                    F = flags;
                }
            }
            else
            {
                P = pattern;
                F = flags;
            }
            return(RegExpObject.RegExpAllocAndInitialize(P, F));
        }
Ejemplo n.º 2
0
        public static Completion RegExpAllocAndInitialize(string P, string F)
        {
            var         allowedFlags = "gimsuy";
            List <char> invalidFlags;

            if ((invalidFlags = F.Where(c => !allowedFlags.Contains(c, StringComparison.Ordinal)).ToList()).Any())
            {
                if (invalidFlags.Count == 1)
                {
                    return(Completion.ThrowTypeError($"'{invalidFlags[0]}' is not a valid RegExp flag."));
                }
                else
                {
                    return(Completion.ThrowTypeError($"These flags not valid RegExp flags: {{ {string.Join(", ", invalidFlags.Select(f => $"'{f}'"))} }}"));
                }
            }
            else if (F.Distinct().Count() != F.Length)
            {
                return(Completion.ThrowTypeError($"RegExp flags should not contain duplicates."));
            }

            var BMP = !F.Contains('u', StringComparison.Ordinal);

            var options = RegexOptions.ECMAScript;

            if (F.Contains('m', StringComparison.Ordinal))
            {
                options |= RegexOptions.Multiline;
            }
            if (F.Contains('s', StringComparison.Ordinal))
            {
                options |= RegexOptions.Singleline;
                options &= ~RegexOptions.ECMAScript;
            }
            if (F.Contains('i', StringComparison.Ordinal))
            {
                options |= RegexOptions.IgnoreCase;
            }

            if (options.HasFlag(RegexOptions.Multiline))
            {
                int index      = 0;
                var newPattern = P;
                while ((index = newPattern.IndexOf("$", index, StringComparison.Ordinal)) != -1)
                {
                    if (index > 0 && newPattern[index - 1] != '\\')
                    {
                        newPattern = newPattern.Substring(0, index) + @"\r?" + newPattern.Substring(index);
                        index     += 4;
                    }
                }

                P = newPattern;
            }
            Regex regex;

            try
            {
                regex = new Regex(P, options);
            }
            catch
            {
                return(Completion.ThrowSyntaxError("Invalid RegEx"));
            }

            var obj = new RegExpObject(P, F, regex);
            var set = obj.Set("lastIndex", new NumberValue(0), true);

            if (set.IsAbrupt())
            {
                return(set);
            }
            return(Completion.NormalCompletion(obj));
        }
Ejemplo n.º 3
0
        private static Completion RegExpBuiltinExec(RegExpObject R, string S)
        {
            var length = S.Length;
            int lastIndex;
            {
                var lastIndexComp = R.Get("lastIndex");
                if (lastIndexComp.IsAbrupt())
                {
                    return(lastIndexComp);
                }
                var lastIndexLength = lastIndexComp.value !.ToLength();
                if (lastIndexLength.IsAbrupt())
                {
                    return(lastIndexLength);
                }
                lastIndex = (int)lastIndexLength.Other;
            }
            var flags  = R.OriginalFlags;
            var global = flags.Contains('g', StringComparison.Ordinal);
            var sticky = flags.Contains('y', StringComparison.Ordinal);

            if (!global && !sticky)
            {
                lastIndex = 0;
            }
            var   matcher        = R.RegExpMatcher;
            var   fullUnicode    = flags.Contains('u', StringComparison.Ordinal);
            var   matchSucceeded = false;
            Match?r = null;

            while (!matchSucceeded)
            {
                if (lastIndex > length)
                {
                    if (global || sticky)
                    {
                        var set = R.Set("lastIndex", NumberValue.PositiveZero, true);
                        if (set.IsAbrupt())
                        {
                            return(set);
                        }
                    }
                    return(Completion.NormalCompletion(NullValue.Instance));
                }
                r = matcher.Match(S, lastIndex);
                if (!r.Success)
                {
                    if (sticky)
                    {
                        var set = R.Set("lastIndex", NumberValue.PositiveZero, true);
                        if (set.IsAbrupt())
                        {
                            return(set);
                        }
                        return(Completion.NormalCompletion(NullValue.Instance));
                    }
                    lastIndex = AdvanceStringIndex(S, lastIndex, fullUnicode);
                }
                else
                {
                    matchSucceeded = true;
                }
            }

            var e = r !.Index + r.Length;

            if (fullUnicode)
            {
                // e is an index into the Input character list, derived from S, matched by matcher.
                // Let eUTF be the smallest index into S that corresponds to the character at element e of Input.
                // If e is greater than or equal to the number of elements in Input, then eUTF is the number of code units in S.
                // Set e to eUTF.
                var indexes = StringInfo.ParseCombiningCharacters(S);
                if (r.Index < indexes.Length)
                {
                    var sub = StringInfo.GetNextTextElement(S, r.Index);
                    e += sub.Length - 1;
                }
            }
            if (global || sticky)
            {
                var set = R.Set("lastIndex", new NumberValue(e), true);
                if (set.IsAbrupt())
                {
                    return(set);
                }
            }
            var n = r.Groups.Count;
            var A = ArrayObject.ArrayCreate(n + 1);

            Utils.CreateDataProperty(A, "index", new NumberValue(lastIndex));
            Utils.CreateDataProperty(A, "input", new StringValue(S));
            Utils.CreateDataProperty(A, "0", new StringValue(r.Value));
            IValue groups;

            if (R.RegExpMatcher.GetGroupNames().Any())
            {
                groups = Utils.ObjectCreate(null);
            }
            else
            {
                groups = UndefinedValue.Instance;
            }
            Utils.CreateDataProperty(A, "groups", groups);
            for (int i = 0; i <= n; i++)
            {
                var    captureI = r.Groups[i];
                IValue capturedValue;
                if (captureI.Success)
                {
                    if (fullUnicode)
                    {
                        capturedValue = new StringValue(StringInfo.GetNextTextElement(S, captureI.Index));
                    }
                    else
                    {
                        capturedValue = new StringValue(captureI.Value);
                    }
                }
                else
                {
                    capturedValue = UndefinedValue.Instance;
                }
                Utils.CreateDataProperty(A, i.ToString(CultureInfo.InvariantCulture), capturedValue);
                if (!string.IsNullOrEmpty(captureI.Name))
                {
                    Utils.CreateDataProperty(groups, captureI.Name, capturedValue);
                }
            }
            return(Completion.NormalCompletion(A));
        }