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)); }
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)); }
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)); }