Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,396 @@
//------------------------------------------------------------------------------
// <copyright file="RegexBoyerMoore.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// The RegexBoyerMoore object precomputes the Boyer-Moore
// tables for fast string scanning. These tables allow
// you to scan for the first occurance of a string within
// a large body of text without examining every character.
// The performance of the heuristic depends on the actual
// string and the text being searched, but usually, the longer
// the string that is being searched for, the fewer characters
// need to be examined.
namespace System.Text.RegularExpressions
{
using System.Collections;
using System.Diagnostics;
using System.Globalization;
internal sealed class RegexBoyerMoore {
internal int[] _positive;
internal int[] _negativeASCII;
internal int[][] _negativeUnicode;
internal String _pattern;
internal int _lowASCII;
internal int _highASCII;
internal bool _rightToLeft;
internal bool _caseInsensitive;
internal CultureInfo _culture;
internal const int infinite = 0x7FFFFFFF;
/*
* Constructs a Boyer-Moore state machine for searching for the string
* pattern. The string must not be zero-length.
*/
internal RegexBoyerMoore(String pattern, bool caseInsensitive, bool rightToLeft, CultureInfo culture) {
/*
* Sorry, you just can't use Boyer-Moore to find an empty pattern.
* We're doing this for your own protection. (Really, for speed.)
*/
Debug.Assert(pattern.Length != 0, "RegexBoyerMoore called with an empty string. This is bad for perf");
int beforefirst;
int last;
int bump;
int examine;
int scan;
int match;
char ch;
// We do the ToLower character by character for consistency. With surrogate chars, doing
// a ToLower on the entire string could actually change the surrogate pair. This is more correct
// linguistically, but since Regex doesn't support surrogates, it's more important to be
// consistent.
if (caseInsensitive) {
StringBuilder sb = new StringBuilder(pattern.Length);
for (int i=0; i<pattern.Length; i++)
sb.Append(Char.ToLower(pattern[i], culture));
pattern = sb.ToString();
}
_pattern = pattern;
_rightToLeft = rightToLeft;
_caseInsensitive = caseInsensitive;
_culture = culture;
if (!rightToLeft) {
beforefirst = -1;
last = pattern.Length - 1;
bump = 1;
}
else {
beforefirst = pattern.Length;
last = 0;
bump = -1;
}
/*
* PART I - the good-suffix shift table
*
* compute the positive requirement:
* if char "i" is the first one from the right that doesn't match,
* then we know the matcher can advance by _positive[i].
*
* <
*/
_positive = new int[pattern.Length];
examine = last;
ch = pattern[examine];
_positive[examine] = bump;
examine -= bump;
for (;;) {
// find an internal char (examine) that matches the tail
for (;;) {
if (examine == beforefirst)
goto OuterloopBreak;
if (pattern[examine] == ch)
break;
examine -= bump;
}
match = last;
scan = examine;
// find the length of the match
for (;;) {
if (scan == beforefirst || pattern[match] != pattern[scan]) {
// at the end of the match, note the difference in _positive
// this is not the length of the match, but the distance from the internal match
// to the tail suffix.
if (_positive[match] == 0)
_positive[match] = match - scan;
// System.Diagnostics.Debug.WriteLine("Set positive[" + match + "] to " + (match - scan));
break;
}
scan -= bump;
match -= bump;
}
examine -= bump;
}
OuterloopBreak:
match = last - bump;
// scan for the chars for which there are no shifts that yield a different candidate
/* <
*/
while (match != beforefirst) {
if (_positive[match] == 0)
_positive[match] = bump;
match -= bump;
}
//System.Diagnostics.Debug.WriteLine("good suffix shift table:");
//for (int i=0; i<_positive.Length; i++)
// System.Diagnostics.Debug.WriteLine("\t_positive[" + i + "] = " + _positive[i]);
/*
* PART II - the bad-character shift table
*
* compute the negative requirement:
* if char "ch" is the reject character when testing position "i",
* we can slide up by _negative[ch];
* (_negative[ch] = str.Length - 1 - str.LastIndexOf(ch))
*
* the lookup table is divided into ASCII and Unicode portions;
* only those parts of the Unicode 16-bit code set that actually
* appear in the string are in the table. (Maximum size with
* Unicode is 65K; ASCII only case is 512 bytes.)
*/
_negativeASCII = new int[128];
for (int i = 0; i < 128; i++)
_negativeASCII[i] = last - beforefirst;
_lowASCII = 127;
_highASCII = 0;
for (examine = last; examine != beforefirst; examine -= bump) {
ch = pattern[examine];
if (ch < 128) {
if (_lowASCII > ch)
_lowASCII = ch;
if (_highASCII < ch)
_highASCII = ch;
if (_negativeASCII[ch] == last - beforefirst)
_negativeASCII[ch] = last - examine;
}
else {
int i = ch >> 8;
int j = ch & 0xFF;
if (_negativeUnicode == null) {
_negativeUnicode = new int[256][];
}
if (_negativeUnicode[i] == null) {
int[] newarray = new int[256];
for (int k = 0; k < 256; k++)
newarray[k] = last - beforefirst;
if (i == 0) {
System.Array.Copy(_negativeASCII, newarray, 128);
_negativeASCII = newarray;
}
_negativeUnicode[i] = newarray;
}
if (_negativeUnicode[i][j] == last - beforefirst)
_negativeUnicode[i][j] = last - examine;
}
}
}
private bool MatchPattern(string text, int index) {
if (_caseInsensitive) {
if( text.Length - index < _pattern.Length) {
return false;
}
TextInfo textinfo = _culture.TextInfo;
for( int i = 0; i < _pattern.Length; i++) {
Debug.Assert(textinfo.ToLower(_pattern[i]) == _pattern[i], "pattern should be converted to lower case in constructor!");
if( textinfo.ToLower(text[index + i]) != _pattern[i]) {
return false;
}
}
return true;
}
else {
return(0 == String.CompareOrdinal(_pattern, 0, text, index, _pattern.Length));
}
}
/*
* When a regex is anchored, we can do a quick IsMatch test instead of a Scan
*/
internal bool IsMatch(String text, int index, int beglimit, int endlimit) {
if (!_rightToLeft) {
if (index < beglimit || endlimit - index < _pattern.Length)
return false;
return MatchPattern(text, index);
}
else {
if (index > endlimit || index - beglimit < _pattern.Length)
return false;
return MatchPattern(text, index - _pattern.Length);
}
}
/*
* Scan uses the Boyer-Moore algorithm to find the first occurrance
* of the specified string within text, beginning at index, and
* constrained within beglimit and endlimit.
*
* The direction and case-sensitivity of the match is determined
* by the arguments to the RegexBoyerMoore constructor.
*/
internal int Scan(String text, int index, int beglimit, int endlimit) {
int test;
int test2;
int match;
int startmatch;
int endmatch;
int advance;
int defadv;
int bump;
char chMatch;
char chTest;
int[] unicodeLookup;
if (!_rightToLeft) {
defadv = _pattern.Length;
startmatch = _pattern.Length - 1;
endmatch = 0;
test = index + defadv - 1;
bump = 1;
}
else {
defadv = -_pattern.Length;
startmatch = 0;
endmatch = -defadv - 1;
test = index + defadv;
bump = -1;
}
chMatch = _pattern[startmatch];
for (;;) {
if (test >= endlimit || test < beglimit)
return -1;
chTest = text[test];
if (_caseInsensitive)
chTest = Char.ToLower(chTest, _culture);
if (chTest != chMatch) {
if (chTest < 128)
advance = _negativeASCII[chTest];
else if (null != _negativeUnicode && (null != (unicodeLookup = _negativeUnicode[chTest >> 8])))
advance = unicodeLookup[chTest & 0xFF];
else
advance = defadv;
test += advance;
}
else { // if (chTest == chMatch)
test2 = test;
match = startmatch;
for (;;) {
if (match == endmatch)
return(_rightToLeft ? test2 + 1 : test2);
match -= bump;
test2 -= bump;
chTest = text[test2];
if (_caseInsensitive)
chTest = Char.ToLower(chTest, _culture);
if (chTest != _pattern[match]) {
advance = _positive[match];
if ((chTest & 0xFF80) == 0)
test2 = (match - startmatch) + _negativeASCII[chTest];
else if (null != _negativeUnicode && (null != (unicodeLookup = _negativeUnicode[chTest >> 8])))
test2 = (match - startmatch) + unicodeLookup[chTest & 0xFF];
else {
test += advance;
break;
}
if (_rightToLeft ? test2 < advance : test2 > advance)
advance = test2;
test += advance;
break;
}
}
}
}
}
/*
* Used when dumping for debugging.
*/
public override String ToString() {
return _pattern;
}
#if DBG
public String Dump(String indent) {
StringBuilder sb = new StringBuilder();
sb.Append(indent + "BM Pattern: " + _pattern + "\n");
sb.Append(indent + "Positive: ");
for (int i = 0; i < _positive.Length; i++) {
sb.Append(_positive[i].ToString(CultureInfo.InvariantCulture) + " ");
}
sb.Append("\n");
if (_negativeASCII != null) {
sb.Append(indent + "Negative table\n");
for (int i = 0; i < _negativeASCII.Length; i++) {
if (_negativeASCII[i] != _pattern.Length) {
sb.Append(indent + " " + Regex.Escape(Convert.ToString((char)i, CultureInfo.InvariantCulture)) + " " + _negativeASCII[i].ToString(CultureInfo.InvariantCulture) + "\n");
}
}
}
return sb.ToString();
}
#endif
}
}

View File

@@ -0,0 +1,121 @@
//------------------------------------------------------------------------------
// <copyright file="RegexCapture.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// Capture is just a location/length pair that indicates the
// location of a regular expression match. A single regexp
// search may return multiple Capture within each capturing
// RegexGroup.
namespace System.Text.RegularExpressions {
/// <devdoc>
/// <para>
/// Represents the results from a single subexpression capture. The object represents
/// one substring for a single successful capture.</para>
/// </devdoc>
#if !SILVERLIGHT
[ Serializable() ]
#endif
public class Capture {
internal String _text;
internal int _index;
internal int _length;
internal Capture(String text, int i, int l) {
_text = text;
_index = i;
_length = l;
}
/*
* The index of the beginning of the matched capture
*/
/// <devdoc>
/// <para>Returns the position in the original string where the first character of
/// captured substring was found.</para>
/// </devdoc>
public int Index {
get {
return _index;
}
}
/*
* The length of the matched capture
*/
/// <devdoc>
/// <para>
/// Returns the length of the captured substring.
/// </para>
/// </devdoc>
public int Length {
get {
return _length;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public string Value {
get {
return _text.Substring(_index, _length);
}
}
/*
* The capture as a string
*/
/// <devdoc>
/// <para>
/// Returns
/// the substring that was matched.
/// </para>
/// </devdoc>
override public String ToString() {
return Value;
}
/*
* The original string
*/
internal String GetOriginalString() {
return _text;
}
/*
* The substring to the left of the capture
*/
internal String GetLeftSubstring() {
return _text.Substring(0, _index);
}
/*
* The substring to the right of the capture
*/
internal String GetRightSubstring() {
return _text.Substring(_index + _length, _text.Length - _index - _length);
}
#if DBG
internal virtual String Description() {
StringBuilder Sb = new StringBuilder();
Sb.Append("(I = ");
Sb.Append(_index);
Sb.Append(", L = ");
Sb.Append(_length);
Sb.Append("): ");
Sb.Append(_text, _index, _length);
return Sb.ToString();
}
#endif
}
}

View File

@@ -0,0 +1,219 @@
//------------------------------------------------------------------------------
// <copyright file="RegexCaptureCollection.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// The CaptureCollection lists the captured Capture numbers
// contained in a compiled Regex.
namespace System.Text.RegularExpressions {
using System.Collections;
/*
* This collection returns the Captures for a group
* in the order in which they were matched (left to right
* or right to left). It is created by Group.Captures
*/
/// <devdoc>
/// <para>
/// Represents a sequence of capture substrings. The object is used
/// to return the set of captures done by a single capturing group.
/// </para>
/// </devdoc>
#if !SILVERLIGHT
[ Serializable() ]
#endif
public class CaptureCollection : ICollection {
internal Group _group;
internal int _capcount;
internal Capture[] _captures;
/*
* Nonpublic constructor
*/
internal CaptureCollection(Group group) {
_group = group;
_capcount = _group._capcount;
}
/*
* The object on which to synchronize
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Object SyncRoot {
get {
return _group;
}
}
/*
* ICollection
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsSynchronized {
get {
return false;
}
}
/*
* ICollection
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return true;
}
}
/*
* The number of captures for the group
*/
/// <devdoc>
/// <para>
/// Returns the number of captures.
/// </para>
/// </devdoc>
public int Count {
get {
return _capcount;
}
}
/*
* The ith capture in the group
*/
/// <devdoc>
/// <para>
/// Provides a means of accessing a specific capture in the collection.
/// </para>
/// </devdoc>
public Capture this[int i]
{
get {
return GetCapture(i);
}
}
/*
* As required by ICollection
*/
/// <devdoc>
/// <para>
/// Copies all the elements of the collection to the given array
/// beginning at the given index.
/// </para>
/// </devdoc>
public void CopyTo(Array array, int arrayIndex) {
if (array == null)
throw new ArgumentNullException("array");
for (int i = arrayIndex, j = 0; j < Count; i++, j++) {
array.SetValue(this[j], i);
}
}
/*
* As required by ICollection
*/
/// <devdoc>
/// <para>
/// Provides an enumerator in the same order as Item[].
/// </para>
/// </devdoc>
public IEnumerator GetEnumerator() {
return new CaptureEnumerator(this);
}
/*
* Nonpublic code to return set of captures for the group
*/
internal Capture GetCapture(int i) {
if (i == _capcount - 1 && i >= 0)
return _group;
if (i >= _capcount || i < 0)
throw new ArgumentOutOfRangeException("i");
// first time a capture is accessed, compute them all
if (_captures == null) {
_captures = new Capture[_capcount];
for (int j = 0; j < _capcount - 1; j++) {
_captures[j] = new Capture(_group._text, _group._caps[j * 2], _group._caps[j * 2 + 1]);
}
}
return _captures[i];
}
}
/*
* This non-public enumerator lists all the captures
* Should it be public?
*/
#if !SILVERLIGHT
[ Serializable() ]
#endif
internal class CaptureEnumerator : IEnumerator {
internal CaptureCollection _rcc;
internal int _curindex;
/*
* Nonpublic constructor
*/
internal CaptureEnumerator(CaptureCollection rcc) {
_curindex = -1;
_rcc = rcc;
}
/*
* As required by IEnumerator
*/
public bool MoveNext() {
int size = _rcc.Count;
if (_curindex >= size)
return false;
_curindex++;
return(_curindex < size);
}
/*
* As required by IEnumerator
*/
public Object Current {
get { return Capture;}
}
/*
* Returns the current capture
*/
public Capture Capture {
get {
if (_curindex < 0 || _curindex >= _rcc.Count)
throw new InvalidOperationException(SR.GetString(SR.EnumNotStarted));
return _rcc[_curindex];
}
}
/*
* Reset to before the first item
*/
public void Reset() {
_curindex = -1;
}
}
}

View File

@@ -0,0 +1,393 @@
//------------------------------------------------------------------------------
// <copyright file="RegexCode.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// This RegexCode class is internal to the regular expression package.
// It provides operator constants for use by the Builder and the Machine.
// Implementation notes:
//
// Regexps are built into RegexCodes, which contain an operation array,
// a string table, and some constants.
//
// Each operation is one of the codes below, followed by the integer
// operands specified for each op.
//
// Strings and sets are indices into a string table.
namespace System.Text.RegularExpressions {
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
internal sealed class RegexCode {
// the following primitive operations come directly from the parser
// lef/back operands description
internal const int Onerep = 0; // lef,back char,min,max a {n}
internal const int Notonerep = 1; // lef,back char,min,max .{n}
internal const int Setrep = 2; // lef,back set,min,max [\d]{n}
internal const int Oneloop = 3; // lef,back char,min,max a {,n}
internal const int Notoneloop = 4; // lef,back char,min,max .{,n}
internal const int Setloop = 5; // lef,back set,min,max [\d]{,n}
internal const int Onelazy = 6; // lef,back char,min,max a {,n}?
internal const int Notonelazy = 7; // lef,back char,min,max .{,n}?
internal const int Setlazy = 8; // lef,back set,min,max [\d]{,n}?
internal const int One = 9; // lef char a
internal const int Notone = 10; // lef char [^a]
internal const int Set = 11; // lef set [a-z\s] \w \s \d
internal const int Multi = 12; // lef string abcd
internal const int Ref = 13; // lef group \#
internal const int Bol = 14; // ^
internal const int Eol = 15; // $
internal const int Boundary = 16; // \b
internal const int Nonboundary = 17; // \B
internal const int Beginning = 18; // \A
internal const int Start = 19; // \G
internal const int EndZ = 20; // \Z
internal const int End = 21; // \Z
internal const int Nothing = 22; // Reject!
// primitive control structures
internal const int Lazybranch = 23; // back jump straight first
internal const int Branchmark = 24; // back jump branch first for loop
internal const int Lazybranchmark = 25; // back jump straight first for loop
internal const int Nullcount = 26; // back val set counter, null mark
internal const int Setcount = 27; // back val set counter, make mark
internal const int Branchcount = 28; // back jump,limit branch++ if zero<=c<limit
internal const int Lazybranchcount= 29; // back jump,limit same, but straight first
internal const int Nullmark = 30; // back save position
internal const int Setmark = 31; // back save position
internal const int Capturemark = 32; // back group define group
internal const int Getmark = 33; // back recall position
internal const int Setjump = 34; // back save backtrack state
internal const int Backjump = 35; // zap back to saved state
internal const int Forejump = 36; // zap backtracking state
internal const int Testref = 37; // backtrack if ref undefined
internal const int Goto = 38; // jump just go
internal const int Prune = 39; // prune it baby
internal const int Stop = 40; // done!
internal const int ECMABoundary = 41; // \b
internal const int NonECMABoundary= 42; // \B
// modifiers for alternate modes
internal const int Mask = 63; // Mask to get unmodified ordinary operator
internal const int Rtl = 64; // bit to indicate that we're reverse scanning.
internal const int Back = 128; // bit to indicate that we're backtracking.
internal const int Back2 = 256; // bit to indicate that we're backtracking on a second branch.
internal const int Ci = 512; // bit to indicate that we're case-insensitive.
// the code
internal int[] _codes; // the code
internal String[] _strings; // the string/set table
// not used! internal int[] _sparseIndex; // a list of the groups that are used
internal int _trackcount; // how many instructions use backtracking
#if SILVERLIGHT
internal Dictionary<Int32, Int32> _caps; // mapping of user group numbers -> impl group slots
#else
internal Hashtable _caps; // mapping of user group numbers -> impl group slots
#endif
internal int _capsize; // number of impl group slots
internal RegexPrefix _fcPrefix; // the set of candidate first characters (may be null)
internal RegexBoyerMoore _bmPrefix; // the fixed prefix string as a Boyer-Moore machine (may be null)
internal int _anchors; // the set of zero-length start anchors (RegexFCD.Bol, etc)
internal bool _rightToLeft; // true if right to left
// optimizations
// constructor
internal RegexCode(int [] codes, List<String> stringlist, int trackcount,
#if SILVERLIGHT
Dictionary<Int32, Int32> caps, int capsize,
#else
Hashtable caps, int capsize,
#endif
RegexBoyerMoore bmPrefix, RegexPrefix fcPrefix,
int anchors, bool rightToLeft) {
_codes = codes;
_strings = new String[stringlist.Count];
_trackcount = trackcount;
_caps = caps;
_capsize = capsize;
_bmPrefix = bmPrefix;
_fcPrefix = fcPrefix;
_anchors = anchors;
_rightToLeft = rightToLeft;
stringlist.CopyTo(0, _strings, 0, stringlist.Count);
}
internal static bool OpcodeBacktracks(int Op) {
Op &= Mask;
switch (Op) {
case Oneloop:
case Notoneloop:
case Setloop:
case Onelazy:
case Notonelazy:
case Setlazy:
case Lazybranch:
case Branchmark:
case Lazybranchmark:
case Nullcount:
case Setcount:
case Branchcount:
case Lazybranchcount:
case Setmark:
case Capturemark:
case Getmark:
case Setjump:
case Backjump:
case Forejump:
case Goto:
return true;
default:
return false;
}
}
internal static int OpcodeSize(int Opcode) {
Opcode &= Mask;
switch (Opcode) {
case Nothing:
case Bol:
case Eol:
case Boundary:
case Nonboundary:
case ECMABoundary:
case NonECMABoundary:
case Beginning:
case Start:
case EndZ:
case End:
case Nullmark:
case Setmark:
case Getmark:
case Setjump:
case Backjump:
case Forejump:
case Stop:
return 1;
case One:
case Notone:
case Multi:
case Ref:
case Testref:
case Goto:
case Nullcount:
case Setcount:
case Lazybranch:
case Branchmark:
case Lazybranchmark:
case Prune:
case Set:
return 2;
case Capturemark:
case Branchcount:
case Lazybranchcount:
case Onerep:
case Notonerep:
case Oneloop:
case Notoneloop:
case Onelazy:
case Notonelazy:
case Setlazy:
case Setrep:
case Setloop:
return 3;
default:
throw MakeException(SR.GetString(SR.UnexpectedOpcode, Opcode.ToString(CultureInfo.CurrentCulture)));
}
}
internal static ArgumentException MakeException(String message) {
return new ArgumentException(message);
}
// Debug only code below
#if DBG
internal static String[] CodeStr = new String[]
{
"Onerep", "Notonerep", "Setrep",
"Oneloop", "Notoneloop", "Setloop",
"Onelazy", "Notonelazy", "Setlazy",
"One", "Notone", "Set",
"Multi", "Ref",
"Bol", "Eol", "Boundary", "Nonboundary", "Beginning", "Start", "EndZ", "End",
"Nothing",
"Lazybranch", "Branchmark", "Lazybranchmark",
"Nullcount", "Setcount", "Branchcount", "Lazybranchcount",
"Nullmark", "Setmark", "Capturemark", "Getmark",
"Setjump", "Backjump", "Forejump", "Testref", "Goto",
"Prune", "Stop",
#if ECMA
"ECMABoundary", "NonECMABoundary",
#endif
};
internal static String OperatorDescription(int Opcode) {
bool isCi = ((Opcode & Ci) != 0);
bool isRtl = ((Opcode & Rtl) != 0);
bool isBack = ((Opcode & Back) != 0);
bool isBack2 = ((Opcode & Back2) != 0);
return CodeStr[Opcode & Mask] +
(isCi ? "-Ci" : "") + (isRtl ? "-Rtl" : "") + (isBack ? "-Back" : "") + (isBack2 ? "-Back2" : "");
}
internal String OpcodeDescription(int offset) {
StringBuilder sb = new StringBuilder();
int opcode = _codes[offset];
sb.AppendFormat("{0:D6} ", offset);
sb.Append(OpcodeBacktracks(opcode & Mask) ? '*' : ' ');
sb.Append(OperatorDescription(opcode));
sb.Append('(');
opcode &= Mask;
switch (opcode) {
case One:
case Notone:
case Onerep:
case Notonerep:
case Oneloop:
case Notoneloop:
case Onelazy:
case Notonelazy:
sb.Append("Ch = ");
sb.Append(RegexCharClass.CharDescription((char)_codes[offset+1]));
break;
case Set:
case Setrep:
case Setloop:
case Setlazy:
sb.Append("Set = ");
sb.Append(RegexCharClass.SetDescription(_strings[_codes[offset+1]]));
break;
case Multi:
sb.Append("String = ");
sb.Append(_strings[_codes[offset+1]]);
break;
case Ref:
case Testref:
sb.Append("Index = ");
sb.Append(_codes[offset+1]);
break;
case Capturemark:
sb.Append("Index = ");
sb.Append(_codes[offset+1]);
if (_codes[offset+2] != -1) {
sb.Append(", Unindex = ");
sb.Append(_codes[offset+2]);
}
break;
case Nullcount:
case Setcount:
sb.Append("Value = ");
sb.Append(_codes[offset+1]);
break;
case Goto:
case Lazybranch:
case Branchmark:
case Lazybranchmark:
case Branchcount:
case Lazybranchcount:
sb.Append("Addr = ");
sb.Append(_codes[offset+1]);
break;
}
switch (opcode) {
case Onerep:
case Notonerep:
case Oneloop:
case Notoneloop:
case Onelazy:
case Notonelazy:
case Setrep:
case Setloop:
case Setlazy:
sb.Append(", Rep = ");
if (_codes[offset + 2] == Int32.MaxValue)
sb.Append("inf");
else
sb.Append(_codes[offset + 2]);
break;
case Branchcount:
case Lazybranchcount:
sb.Append(", Limit = ");
if (_codes[offset + 2] == Int32.MaxValue)
sb.Append("inf");
else
sb.Append(_codes[offset + 2]);
break;
}
sb.Append(")");
return sb.ToString();
}
internal void Dump() {
int i;
Debug.WriteLine("Direction: " + (_rightToLeft ? "right-to-left" : "left-to-right"));
Debug.WriteLine("Firstchars: " + (_fcPrefix == null ? "n/a" : RegexCharClass.SetDescription(_fcPrefix.Prefix)));
Debug.WriteLine("Prefix: " + (_bmPrefix == null ? "n/a" : Regex.Escape(_bmPrefix.ToString())));
Debug.WriteLine("Anchors: " + RegexFCD.AnchorDescription(_anchors));
Debug.WriteLine("");
if (_bmPrefix != null) {
Debug.WriteLine("BoyerMoore:");
Debug.WriteLine(_bmPrefix.Dump(" "));
}
for (i = 0; i < _codes.Length;) {
Debug.WriteLine(OpcodeDescription(i));
i += OpcodeSize(_codes[i]);
}
Debug.WriteLine("");
}
#endif
}
}

View File

@@ -0,0 +1,131 @@
//------------------------------------------------------------------------------
// <copyright file="RegexCompilationInfo.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
#if !SILVERLIGHT
using System;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
namespace System.Text.RegularExpressions {
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
[ Serializable() ]
public class RegexCompilationInfo {
private String pattern;
private RegexOptions options;
private String name;
private String nspace;
private bool isPublic;
[OptionalField(VersionAdded = 2)]
private TimeSpan matchTimeout;
[OnDeserializing]
private void InitMatchTimeoutDefaultForOldVersionDeserialization(StreamingContext unusedContext) {
matchTimeout = Regex.DefaultMatchTimeout;
}
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
public RegexCompilationInfo(String pattern, RegexOptions options, String name, String fullnamespace, bool ispublic)
: this(pattern, options, name, fullnamespace, ispublic, Regex.DefaultMatchTimeout) {
}
public RegexCompilationInfo(String pattern, RegexOptions options, String name, String fullnamespace, bool ispublic, TimeSpan matchTimeout) {
Pattern = pattern;
Name = name;
Namespace = fullnamespace;
this.options = options;
isPublic = ispublic;
MatchTimeout = matchTimeout;
}
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
public String Pattern {
get { return pattern; }
set {
if (value == null)
throw new ArgumentNullException("value");
pattern = value;
}
}
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
public RegexOptions Options {
get { return options; }
set { options = value;}
}
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
public String Name {
get { return name; }
set {
if (value == null) {
throw new ArgumentNullException("value");
}
if (value.Length == 0) {
throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "value"), "value");
}
name = value;
}
}
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
public String Namespace {
get { return nspace; }
set {
if (value == null)
throw new ArgumentNullException("value");
nspace = value;
}
}
/// <devdoc>
/// <para>
/// [To be supplied]
/// </para>
/// </devdoc>
public bool IsPublic {
get { return isPublic; }
set { isPublic = value;}
}
public TimeSpan MatchTimeout {
get { return matchTimeout; }
set { Regex.ValidateMatchTimeout(value); matchTimeout = value; }
}
}
}
#endif

View File

@@ -0,0 +1 @@
6f191129671672f5a0d3c58901385525b798814c

View File

@@ -0,0 +1,105 @@
//------------------------------------------------------------------------------
// <copyright file="RegexGroup.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// Group represents the substring or substrings that
// are captured by a single capturing group after one
// regular expression match.
namespace System.Text.RegularExpressions {
using System.Security.Permissions;
/// <devdoc>
/// Group
/// represents the results from a single capturing group. A capturing group can
/// capture zero, one, or more strings in a single match because of quantifiers, so
/// Group supplies a collection of Capture objects.
/// </devdoc>
#if !SILVERLIGHT
[ Serializable() ]
#endif
public class Group : Capture {
// the empty group object
internal static Group _emptygroup = new Group(String.Empty, new int[0], 0);
internal int[] _caps;
internal int _capcount;
internal CaptureCollection _capcoll;
internal Group(String text, int[] caps, int capcount)
: base(text, capcount == 0 ? 0 : caps[(capcount - 1) * 2],
capcount == 0 ? 0 : caps[(capcount * 2) - 1]) {
_caps = caps;
_capcount = capcount;
}
/*
* True if the match was successful
*/
/// <devdoc>
/// <para>Indicates whether the match is successful.</para>
/// </devdoc>
public bool Success {
get {
return _capcount != 0;
}
}
/*
* The collection of all captures for this group
*/
/// <devdoc>
/// <para>
/// Returns a collection of all the captures matched by the capturing
/// group, in innermost-leftmost-first order (or innermost-rightmost-first order if
/// compiled with the "r" option). The collection may have zero or more items.
/// </para>
/// </devdoc>
public CaptureCollection Captures {
get {
if (_capcoll == null)
_capcoll = new CaptureCollection(this);
return _capcoll;
}
}
/*
* Convert to a thread-safe object by precomputing cache contents
*/
/// <devdoc>
/// <para>Returns
/// a Group object equivalent to the one supplied that is safe to share between
/// multiple threads.</para>
/// </devdoc>
#if !SILVERLIGHT
#if FEATURE_MONO_CAS
[HostProtection(Synchronization=true)]
#endif
static public Group Synchronized(Group inner) {
#else
static internal Group Synchronized(Group inner) {
#endif
if (inner == null)
throw new ArgumentNullException("inner");
// force Captures to be computed.
CaptureCollection capcoll;
Capture dummy;
capcoll = inner.Captures;
if (inner._capcount > 0)
dummy = capcoll[0];
return inner;
}
}
}

View File

@@ -0,0 +1,246 @@
//------------------------------------------------------------------------------
// <copyright file="RegexGroupCollection.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// The GroupCollection lists the captured Capture numbers
// contained in a compiled Regex.
namespace System.Text.RegularExpressions {
using System.Collections;
using System.Collections.Generic;
/// <devdoc>
/// <para>
/// Represents a sequence of capture substrings. The object is used
/// to return the set of captures done by a single capturing group.
/// </para>
/// </devdoc>
#if !SILVERLIGHT
[ Serializable() ]
#endif
public class GroupCollection : ICollection {
internal Match _match;
#if SILVERLIGHT
internal Dictionary<Int32, Int32> _captureMap;
#else
internal Hashtable _captureMap;
#endif
// cache of Group objects fed to the user
internal Group[] _groups;
/*
* Nonpublic constructor
*/
#if SILVERLIGHT
internal GroupCollection(Match match, Dictionary<Int32, Int32> caps) {
#else
internal GroupCollection(Match match, Hashtable caps) {
#endif
_match = match;
_captureMap = caps;
}
/*
* The object on which to synchronize
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Object SyncRoot {
get {
return _match;
}
}
/*
* ICollection
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsSynchronized {
get {
return false;
}
}
/*
* ICollection
*/
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return true;
}
}
/// <devdoc>
/// <para>
/// Returns the number of groups.
/// </para>
/// </devdoc>
public int Count {
get {
return _match._matchcount.Length;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Group this[int groupnum]
{
get {
return GetGroup(groupnum);
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Group this[String groupname] {
get {
if (_match._regex == null)
return Group._emptygroup;
return GetGroup(_match._regex.GroupNumberFromName(groupname));
}
}
internal Group GetGroup(int groupnum) {
if (_captureMap != null) {
Object o;
o = _captureMap[groupnum];
if (o == null)
return Group._emptygroup;
//throw new ArgumentOutOfRangeException("groupnum");
return GetGroupImpl((int)o);
}
else {
//if (groupnum >= _match._regex.CapSize || groupnum < 0)
// throw new ArgumentOutOfRangeException("groupnum");
if (groupnum >= _match._matchcount.Length || groupnum < 0)
return Group._emptygroup;
return GetGroupImpl(groupnum);
}
}
/*
* Caches the group objects
*/
internal Group GetGroupImpl(int groupnum) {
if (groupnum == 0)
return _match;
// Construct all the Group objects the first time GetGroup is called
if (_groups == null) {
_groups = new Group[_match._matchcount.Length - 1];
for (int i = 0; i < _groups.Length; i++) {
_groups[i] = new Group(_match._text, _match._matches[i + 1], _match._matchcount[i + 1]);
}
}
return _groups[groupnum - 1];
}
/*
* As required by ICollection
*/
/// <devdoc>
/// <para>
/// Copies all the elements of the collection to the given array
/// beginning at the given index.
/// </para>
/// </devdoc>
public void CopyTo(Array array, int arrayIndex) {
if (array == null)
throw new ArgumentNullException("array");
for (int i = arrayIndex, j = 0; j < Count; i++, j++) {
array.SetValue(this[j], i);
}
}
/*
* As required by ICollection
*/
/// <devdoc>
/// <para>
/// Provides an enumerator in the same order as Item[].
/// </para>
/// </devdoc>
public IEnumerator GetEnumerator() {
return new GroupEnumerator(this);
}
}
/*
* This non-public enumerator lists all the captures
* Should it be public?
*/
internal class GroupEnumerator : IEnumerator {
internal GroupCollection _rgc;
internal int _curindex;
/*
* Nonpublic constructor
*/
internal GroupEnumerator(GroupCollection rgc) {
_curindex = -1;
_rgc = rgc;
}
/*
* As required by IEnumerator
*/
public bool MoveNext() {
int size = _rgc.Count;
if (_curindex >= size)
return false;
_curindex++;
return(_curindex < size);
}
/*
* As required by IEnumerator
*/
public Object Current {
get { return Capture;}
}
/*
* Returns the current capture
*/
public Capture Capture {
get {
if (_curindex < 0 || _curindex >= _rgc.Count)
throw new InvalidOperationException(SR.GetString(SR.EnumNotStarted));
return _rgc[_curindex];
}
}
/*
* Reset to before the first item
*/
public void Reset() {
_curindex = -1;
}
}
}

View File

@@ -0,0 +1,468 @@
//------------------------------------------------------------------------------
// <copyright file="RegexMatch.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// Match is the result class for a regex search.
// It returns the location, length, and substring for
// the entire match as well as every captured group.
// Match is also used during the search to keep track of each capture for each group. This is
// done using the "_matches" array. _matches[x] represents an array of the captures for group x.
// This array consists of start and length pairs, and may have empty entries at the end. _matchcount[x]
// stores how many captures a group has. Note that _matchcount[x]*2 is the length of all the valid
// values in _matches. _matchcount[x]*2-2 is the Start of the last capture, and _matchcount[x]*2-1 is the
// Length of the last capture
//
// For example, if group 2 has one capture starting at position 4 with length 6,
// _matchcount[2] == 1
// _matches[2][0] == 4
// _matches[2][1] == 6
//
// Values in the _matches array can also be negative. This happens when using the balanced match
// construct, "(?<start-end>...)". When the "end" group matches, a capture is added for both the "start"
// and "end" groups. The capture added for "start" receives the negative values, and these values point to
// the next capture to be balanced. They do NOT point to the capture that "end" just balanced out. The negative
// values are indices into the _matches array transformed by the formula -3-x. This formula also untransforms.
//
namespace System.Text.RegularExpressions {
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security.Permissions;
using System.Globalization;
/// <devdoc>
/// <para>
/// Represents
/// the results from a single regular expression match.
/// </para>
/// </devdoc>
#if !SILVERLIGHT
[ Serializable() ]
#endif
public class Match : Group {
internal static Match _empty = new Match(null, 1, String.Empty, 0, 0, 0);
internal GroupCollection _groupcoll;
// input to the match
internal Regex _regex;
internal int _textbeg;
internal int _textpos;
internal int _textend;
internal int _textstart;
// output from the match
internal int[][] _matches;
internal int[] _matchcount;
internal bool _balancing; // whether we've done any balancing with this match. If we
// have done balancing, we'll need to do extra work in Tidy().
/// <devdoc>
/// <para>
/// Returns an empty Match object.
/// </para>
/// </devdoc>
public static Match Empty {
get {
return _empty;
}
}
/*
* Nonpublic constructor
*/
internal Match(Regex regex, int capcount, String text, int begpos, int len, int startpos)
: base(text, new int[2], 0) {
_regex = regex;
_matchcount = new int[capcount];
_matches = new int[capcount][];
_matches[0] = _caps;
_textbeg = begpos;
_textend = begpos + len;
_textstart = startpos;
_balancing = false;
// No need for an exception here. This is only called internally, so we'll use an Assert instead
System.Diagnostics.Debug.Assert(!(_textbeg < 0 || _textstart < _textbeg || _textend < _textstart || _text.Length < _textend),
"The parameters are out of range.");
}
/*
* Nonpublic set-text method
*/
internal virtual void Reset(Regex regex, String text, int textbeg, int textend, int textstart) {
_regex = regex;
_text = text;
_textbeg = textbeg;
_textend = textend;
_textstart = textstart;
for (int i = 0; i < _matchcount.Length; i++) {
_matchcount[i] = 0;
}
_balancing = false;
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public virtual GroupCollection Groups {
get {
if (_groupcoll == null)
_groupcoll = new GroupCollection(this, null);
return _groupcoll;
}
}
/*
* Returns the next match
*/
/// <devdoc>
/// <para>Returns a new Match with the results for the next match, starting
/// at the position at which the last match ended (at the character beyond the last
/// matched character).</para>
/// </devdoc>
public Match NextMatch() {
if (_regex == null)
return this;
return _regex.Run(false, _length, _text, _textbeg, _textend - _textbeg, _textpos);
}
/*
* Return the result string (using the replacement pattern)
*/
/// <devdoc>
/// <para>
/// Returns the expansion of the passed replacement pattern. For
/// example, if the replacement pattern is ?$1$2?, Result returns the concatenation
/// of Group(1).ToString() and Group(2).ToString().
/// </para>
/// </devdoc>
public virtual String Result(String replacement) {
RegexReplacement repl;
if (replacement == null)
throw new ArgumentNullException("replacement");
if (_regex == null)
throw new NotSupportedException(SR.GetString(SR.NoResultOnFailed));
repl = (RegexReplacement)_regex.replref.Get();
if (repl == null || !repl.Pattern.Equals(replacement)) {
repl = RegexParser.ParseReplacement(replacement, _regex.caps, _regex.capsize, _regex.capnames, _regex.roptions);
_regex.replref.Cache(repl);
}
return repl.Replacement(this);
}
/*
* Used by the replacement code
*/
internal virtual String GroupToStringImpl(int groupnum) {
int c = _matchcount[groupnum];
if (c == 0)
return String.Empty;
int [] matches = _matches[groupnum];
return _text.Substring(matches[(c - 1) * 2], matches[(c * 2) - 1]);
}
/*
* Used by the replacement code
*/
internal String LastGroupToStringImpl() {
return GroupToStringImpl(_matchcount.Length - 1);
}
/*
* Convert to a thread-safe object by precomputing cache contents
*/
/// <devdoc>
/// <para>
/// Returns a Match instance equivalent to the one supplied that is safe to share
/// between multiple threads.
/// </para>
/// </devdoc>
#if !SILVERLIGHT
#if FEATURE_MONO_CAS
[HostProtection(Synchronization=true)]
#endif
static public Match Synchronized(Match inner) {
#else
static internal Match Synchronized(Match inner) {
#endif
if (inner == null)
throw new ArgumentNullException("inner");
int numgroups = inner._matchcount.Length;
// Populate all groups by looking at each one
for (int i = 0; i < numgroups; i++) {
Group group = inner.Groups[i];
// Depends on the fact that Group.Synchronized just
// operates on and returns the same instance
System.Text.RegularExpressions.Group.Synchronized(group);
}
return inner;
}
/*
* Nonpublic builder: add a capture to the group specified by "cap"
*/
internal virtual void AddMatch(int cap, int start, int len) {
int capcount;
if (_matches[cap] == null)
_matches[cap] = new int[2];
capcount = _matchcount[cap];
if (capcount * 2 + 2 > _matches[cap].Length) {
int[] oldmatches = _matches[cap];
int[] newmatches = new int[capcount * 8];
for (int j = 0; j < capcount * 2; j++)
newmatches[j] = oldmatches[j];
_matches[cap] = newmatches;
}
_matches[cap][capcount * 2] = start;
_matches[cap][capcount * 2 + 1] = len;
_matchcount[cap] = capcount + 1;
}
/*
* Nonpublic builder: Add a capture to balance the specified group. This is used by the
balanced match construct. (?<foo-foo2>...)
If there were no such thing as backtracking, this would be as simple as calling RemoveMatch(cap).
However, since we have backtracking, we need to keep track of everything.
*/
internal virtual void BalanceMatch(int cap) {
int capcount;
int target;
_balancing = true;
// we'll look at the last capture first
capcount = _matchcount[cap];
target = capcount * 2 - 2;
// first see if it is negative, and therefore is a reference to the next available
// capture group for balancing. If it is, we'll reset target to point to that capture.
if (_matches[cap][target] < 0)
target = -3 - _matches[cap][target];
// move back to the previous capture
target -= 2;
// if the previous capture is a reference, just copy that reference to the end. Otherwise, point to it.
if (target >= 0 && _matches[cap][target] < 0)
AddMatch(cap, _matches[cap][target], _matches[cap][target+1]);
else
AddMatch(cap, -3 - target, -4 - target /* == -3 - (target + 1) */ );
}
/*
* Nonpublic builder: removes a group match by capnum
*/
internal virtual void RemoveMatch(int cap) {
_matchcount[cap]--;
}
/*
* Nonpublic: tells if a group was matched by capnum
*/
internal virtual bool IsMatched(int cap) {
return cap < _matchcount.Length && _matchcount[cap] > 0 && _matches[cap][_matchcount[cap] * 2 - 1] != (-3 + 1);
}
/*
* Nonpublic: returns the index of the last specified matched group by capnum
*/
internal virtual int MatchIndex(int cap) {
int i = _matches[cap][_matchcount[cap] * 2 - 2];
if (i >= 0)
return i;
return _matches[cap][-3 - i];
}
/*
* Nonpublic: returns the length of the last specified matched group by capnum
*/
internal virtual int MatchLength(int cap) {
int i = _matches[cap][_matchcount[cap] * 2 - 1];
if (i >= 0)
return i;
return _matches[cap][-3 - i];
}
/*
* Nonpublic: tidy the match so that it can be used as an immutable result
*/
internal virtual void Tidy(int textpos) {
int[] interval;
interval = _matches[0];
_index = interval[0];
_length = interval[1];
_textpos = textpos;
_capcount = _matchcount[0];
if (_balancing) {
// The idea here is that we want to compact all of our unbalanced captures. To do that we
// use j basically as a count of how many unbalanced captures we have at any given time
// (really j is an index, but j/2 is the count). First we skip past all of the real captures
// until we find a balance captures. Then we check each subsequent entry. If it's a balance
// capture (it's negative), we decrement j. If it's a real capture, we increment j and copy
// it down to the last free position.
for (int cap = 0; cap < _matchcount.Length; cap++) {
int limit;
int[] matcharray;
limit = _matchcount[cap] * 2;
matcharray = _matches[cap];
int i = 0;
int j;
for (i = 0; i < limit; i++) {
if (matcharray[i] < 0)
break;
}
for (j = i; i < limit; i++) {
if (matcharray[i] < 0) {
// skip negative values
j--;
}
else {
// but if we find something positive (an actual capture), copy it back to the last
// unbalanced position.
if (i != j)
matcharray[j] = matcharray[i];
j++;
}
}
_matchcount[cap] = j / 2;
}
_balancing = false;
}
}
#if DBG
/// <internalonly/>
/// <devdoc>
/// </devdoc>
public bool Debug {
get {
if (_regex == null)
return false;
return _regex.Debug;
}
}
/// <internalonly/>
/// <devdoc>
/// </devdoc>
internal virtual void Dump() {
int i,j;
for (i = 0; i < _matchcount.Length; i++) {
System.Diagnostics.Debug.WriteLine("Capnum " + i.ToString(CultureInfo.InvariantCulture) + ":");
for (j = 0; j < _matchcount[i]; j++) {
String text = "";
if (_matches[i][j * 2] >= 0)
text = _text.Substring(_matches[i][j * 2], _matches[i][j * 2 + 1]);
System.Diagnostics.Debug.WriteLine(" (" + _matches[i][j * 2].ToString(CultureInfo.InvariantCulture) + "," + _matches[i][j * 2 + 1].ToString(CultureInfo.InvariantCulture) + ") " + text);
}
}
}
#endif
}
/*
* MatchSparse is for handling the case where slots are
* sparsely arranged (e.g., if somebody says use slot 100000)
*/
internal class MatchSparse : Match {
// the lookup hashtable
#if SILVERLIGHT
new internal Dictionary<Int32, Int32> _caps;
#else
new internal Hashtable _caps;
#endif
/*
* Nonpublic constructor
*/
#if SILVERLIGHT
internal MatchSparse(Regex regex, Dictionary<Int32, Int32> caps, int capcount,
#else
internal MatchSparse(Regex regex, Hashtable caps, int capcount,
#endif
String text, int begpos, int len, int startpos)
: base(regex, capcount, text, begpos, len, startpos) {
_caps = caps;
}
public override GroupCollection Groups {
get {
if (_groupcoll == null)
_groupcoll = new GroupCollection(this, _caps);
return _groupcoll;
}
}
#if DBG
internal override void Dump() {
if (_caps != null) {
#if SILVERLIGHT
IEnumerator<Int32> e = _caps.Keys.GetEnumerator();
#else
IEnumerator e = _caps.Keys.GetEnumerator();
#endif
while (e.MoveNext()) {
System.Diagnostics.Debug.WriteLine("Slot " + e.Current.ToString() + " -> " + _caps[e.Current].ToString());
}
}
base.Dump();
}
#endif
}
}

View File

@@ -0,0 +1,265 @@
//------------------------------------------------------------------------------
// <copyright file="RegexMatchCollection.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// The MatchCollection lists the successful matches that
// result when searching a string for a regular expression.
namespace System.Text.RegularExpressions {
using System.Collections;
using System.Collections.Generic;
/*
* This collection returns a sequence of successful match results, either
* from GetMatchCollection() or GetExecuteCollection(). It stops when the
* first failure is encountered (it does not return the failed match).
*/
/// <devdoc>
/// <para>
/// Represents the set of names appearing as capturing group
/// names in a regular expression.
/// </para>
/// </devdoc>
#if !SILVERLIGHT
[ Serializable() ]
#endif
public class MatchCollection : ICollection {
internal Regex _regex;
#if SILVERLIGHT
internal List<Match> _matches;
#else
internal ArrayList _matches;
#endif
internal bool _done;
internal String _input;
internal int _beginning;
internal int _length;
internal int _startat;
internal int _prevlen;
private static int infinite = 0x7FFFFFFF;
/*
* Nonpublic constructor
*/
internal MatchCollection(Regex regex, String input, int beginning, int length, int startat) {
if (startat < 0 || startat > input.Length)
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
_regex = regex;
_input = input;
_beginning = beginning;
_length = length;
_startat = startat;
_prevlen = -1;
#if SILVERLIGHT
_matches = new List<Match>();
#else
_matches = new ArrayList();
#endif
_done = false;
}
internal Match GetMatch(int i) {
if (i < 0)
return null;
if (_matches.Count > i)
return (Match)_matches[i];
if (_done)
return null;
Match match;
do {
match = _regex.Run(false, _prevlen, _input, _beginning, _length, _startat);
if (!match.Success) {
_done = true;
return null;
}
_matches.Add(match);
_prevlen = match._length;
_startat = match._textpos;
} while (_matches.Count <= i);
return match;
}
/// <devdoc>
/// <para>
/// Returns the number of captures.
/// </para>
/// </devdoc>
public int Count {
get {
if (_done)
return _matches.Count;
GetMatch(infinite);
return _matches.Count;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Object SyncRoot {
get {
return this;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsSynchronized {
get {
return false;
}
}
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return true;
}
}
/// <devdoc>
/// <para>
/// Returns the ith Match in the collection.
/// </para>
/// </devdoc>
public virtual Match this[int i]
{
get {
Match match;
match = GetMatch(i);
if (match == null)
throw new ArgumentOutOfRangeException("i");
return match;
}
}
/// <devdoc>
/// <para>
/// Copies all the elements of the collection to the given array
/// starting at the given index.
/// </para>
/// </devdoc>
public void CopyTo(Array array, int arrayIndex) {
if ((array != null) && (array.Rank != 1))
{
throw new ArgumentException(SR.GetString(SR.Arg_RankMultiDimNotSupported));
}
// property access to force computation of whole array
int count = Count;
try
{
#if SILVERLIGHT
// Array.Copy will check for null.
Array.Copy(_matches.ToArray(), 0, array, arrayIndex, count);
#else
_matches.CopyTo(array, arrayIndex);
#endif
}
catch (ArrayTypeMismatchException ex)
{
#if FEATURE_LEGACYNETCF
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
throw;
#endif
throw new ArgumentException(SR.GetString(SR.Arg_InvalidArrayType), ex);
}
}
/// <devdoc>
/// <para>
/// Provides an enumerator in the same order as Item[i].
/// </para>
/// </devdoc>
public IEnumerator GetEnumerator() {
return new MatchEnumerator(this);
}
}
/*
* This non-public enumerator lists all the group matches.
* Should it be public?
*/
#if !SILVERLIGHT
[ Serializable() ]
#endif
internal class MatchEnumerator : IEnumerator {
internal MatchCollection _matchcoll;
internal Match _match = null;
internal int _curindex;
internal bool _done;
/*
* Nonpublic constructor
*/
internal MatchEnumerator(MatchCollection matchcoll) {
_matchcoll = matchcoll;
}
/*
* Advance to the next match
*/
public bool MoveNext() {
if (_done)
return false;
_match = _matchcoll.GetMatch(_curindex);
_curindex++;
if (_match == null) {
_done = true;
return false;
}
return true;
}
/*
* The current match
*/
public Object Current {
get {
if (_match == null)
throw new InvalidOperationException(SR.GetString(SR.EnumNotStarted));
return _match;
}
}
/*
* Position before the first item
*/
public void Reset() {
_curindex = 0;
_done = false;
_match = null;
}
}
}

View File

@@ -0,0 +1,168 @@
///------------------------------------------------------------------------------
/// <copyright file="RegexMatchTimeoutException.cs" company="Microsoft">
/// Copyright (c) Microsoft Corporation. All rights reserved.
/// </copyright>
///
/// <owner>gpaperin</owner>
///------------------------------------------------------------------------------
using System;
using System.Runtime.Serialization;
using System.Security;
using System.Security.Permissions;
namespace System.Text.RegularExpressions {
/// <summary>
/// This is the exception that is thrown when a RegEx matching timeout occurs.
/// </summary>
#if SILVERLIGHT
#if FEATURE_NETCORE
public
#else
internal
#endif
class RegexMatchTimeoutException : TimeoutException {
#else
[Serializable]
public class RegexMatchTimeoutException : TimeoutException, ISerializable {
#endif
private string regexInput = null;
private string regexPattern = null;
private TimeSpan matchTimeout = TimeSpan.FromTicks(-1);
/// <summary>
/// This is the preferred constructor to use.
/// The other constructors are provided for compliance to Fx design guidelines.
/// </summary>
/// <param name="regexInput">Matching timeout occured during mathing within the specified input.</param>
/// <param name="regexPattern">Matching timeout occured during mathing to the specified pattern.</param>
/// <param name="matchTimeout">Matching timeout occured becasue matching took longer than the specified timeout.</param>
public RegexMatchTimeoutException(string regexInput, string regexPattern, TimeSpan matchTimeout) :
base(SR.GetString(SR.RegexMatchTimeoutException_Occurred)) {
Init(regexInput, regexPattern, matchTimeout);
}
/// <summary>
/// This constructor is provided in compliance with common NetFx design patterns;
/// developers should prefer using the constructor
/// <code>public RegexMatchTimeoutException(string input, string pattern, TimeSpan matchTimeout)</code>.
/// </summary>
public RegexMatchTimeoutException()
: base() {
Init();
}
/// <summary>
/// This constructor is provided in compliance with common NetFx design patterns;
/// developers should prefer using the constructor
/// <code>public RegexMatchTimeoutException(string input, string pattern, TimeSpan matchTimeout)</code>.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
public RegexMatchTimeoutException(string message)
: base(message) {
Init();
}
/// <summary>
/// This constructor is provided in compliance with common NetFx design patterns;
/// developers should prefer using the constructor
/// <code>public RegexMatchTimeoutException(string input, string pattern, TimeSpan matchTimeout)</code>.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="inner">The exception that is the cause of the current exception, or a <code>null</code>.</param>
public RegexMatchTimeoutException(string message, Exception inner)
: base(message, inner) {
Init();
}
#if !SILVERLIGHT
/// <summary>
/// Initializes a new RegexMatchTimeoutException with serialized data.
/// </summary>
/// <param name="info">The SerializationInfo that holds the serialized object data about the exception being thrown.</param>
/// <param name="context">The StreamingContext that contains contextual information about the source or destination.</param>
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
protected RegexMatchTimeoutException(SerializationInfo info, StreamingContext context) :
base(info, context) {
string input = info.GetString("regexInput");
string pattern = info.GetString("regexPattern");
TimeSpan timeout = TimeSpan.FromTicks(info.GetInt64("timeoutTicks"));
Init(input, pattern, timeout);
}
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter=true)]
void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) {
base.GetObjectData(si, context);
si.AddValue("regexInput", this.regexInput);
si.AddValue("regexPattern", this.regexPattern);
si.AddValue("timeoutTicks", this.matchTimeout.Ticks);
}
#endif // !SILVERLIGHT
private void Init() {
Init("", "", TimeSpan.FromTicks(-1));
}
private void Init(string input, string pattern, TimeSpan timeout) {
this.regexInput = input;
this.regexPattern = pattern;
this.matchTimeout = timeout;
}
#if SILVERLIGHT && !FEATURE_NETCORE
internal string Pattern {
#else
public string Pattern {
#endif
#if SILVERLIGHT
[SecurityCritical]
#else // SILVERLIGHT
[PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
#endif // SILVERLIGHT
get { return regexPattern; }
}
#if SILVERLIGHT && !FEATURE_NETCORE
internal string Input {
#else
public string Input {
#endif
#if SILVERLIGHT
[SecurityCritical]
#else // SILVERLIGHT
[PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
#endif // SILVERLIGHT
get { return regexInput; }
}
#if SILVERLIGHT && !FEATURE_NETCORE
internal TimeSpan MatchTimeout {
#else
public TimeSpan MatchTimeout {
#endif
#if SILVERLIGHT
[SecurityCritical]
#else // SILVERLIGHT
[PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
#endif // SILVERLIGHT
get { return matchTimeout; }
}
} // public class RegexMatchTimeoutException
} // namespace System.Text.RegularExpressions
// file RegexMatchTimeoutException.cs

View File

@@ -0,0 +1,78 @@
//------------------------------------------------------------------------------
// <copyright file="RegexOptions.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Text.RegularExpressions {
using System;
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[Flags]
public enum RegexOptions {
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
None = 0x0000,
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
IgnoreCase = 0x0001, // "i"
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
Multiline = 0x0002, // "m"
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
ExplicitCapture = 0x0004, // "n"
#if !SILVERLIGHT || FEATURE_LEGACYNETCF || MOBILE
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
Compiled = 0x0008, // "c"
#endif
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
Singleline = 0x0010, // "s"
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
IgnorePatternWhitespace = 0x0020, // "x"
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
RightToLeft = 0x0040, // "r"
#if DBG
/// <internalonly/>
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
Debug= 0x0080, // "d"
#endif
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
ECMAScript = 0x0100, // "e"
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
CultureInvariant = 0x0200,
}
}

View File

@@ -0,0 +1,426 @@
//------------------------------------------------------------------------------
// <copyright file="RegexReplacement.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
// The RegexReplacement class represents a substitution string for
// use when using regexs to search/replace, etc. It's logically
// a sequence intermixed (1) constant strings and (2) group numbers.
namespace System.Text.RegularExpressions {
using System.Collections;
using System.Collections.Generic;
internal sealed class RegexReplacement {
/*
* Since RegexReplacement shares the same parser as Regex,
* the constructor takes a RegexNode which is a concatenation
* of constant strings and backreferences.
*/
#if SILVERLIGHT
internal RegexReplacement(String rep, RegexNode concat, Dictionary<Int32, Int32> _caps) {
#else
internal RegexReplacement(String rep, RegexNode concat, Hashtable _caps) {
#endif
StringBuilder sb;
List<String> strings;
List<Int32> rules;
int slot;
_rep = rep;
if (concat.Type() != RegexNode.Concatenate)
throw new ArgumentException(SR.GetString(SR.ReplacementError));
sb = new StringBuilder();
strings = new List<String>();
rules = new List<Int32>();
for (int i = 0; i < concat.ChildCount(); i++) {
RegexNode child = concat.Child(i);
switch (child.Type()) {
case RegexNode.Multi:
sb.Append(child._str);
break;
case RegexNode.One:
sb.Append(child._ch);
break;
case RegexNode.Ref:
if (sb.Length > 0) {
rules.Add(strings.Count);
strings.Add(sb.ToString());
sb.Length = 0;
}
slot = child._m;
if (_caps != null && slot >= 0)
slot = (int)_caps[slot];
rules.Add(-Specials - 1 - slot);
break;
default:
throw new ArgumentException(SR.GetString(SR.ReplacementError));
}
}
if (sb.Length > 0) {
rules.Add(strings.Count);
strings.Add(sb.ToString());
}
_strings = strings;
_rules = rules;
}
internal String _rep;
internal List<String> _strings; // table of string constants
internal List<Int32> _rules; // negative -> group #, positive -> string #
// constants for special insertion patterns
internal const int Specials = 4;
internal const int LeftPortion = -1;
internal const int RightPortion = -2;
internal const int LastGroup = -3;
internal const int WholeString = -4;
/*
* Given a Match, emits into the StringBuilder the evaluated
* substitution pattern.
*/
private void ReplacementImpl(StringBuilder sb, Match match) {
for (int i = 0; i < _rules.Count; i++) {
int r = _rules[i];
if (r >= 0) // string lookup
sb.Append(_strings[r]);
else if (r < -Specials) // group lookup
sb.Append(match.GroupToStringImpl(-Specials - 1 - r));
else {
switch (-Specials - 1 - r) { // special insertion patterns
case LeftPortion:
sb.Append(match.GetLeftSubstring());
break;
case RightPortion:
sb.Append(match.GetRightSubstring());
break;
case LastGroup:
sb.Append(match.LastGroupToStringImpl());
break;
case WholeString:
sb.Append(match.GetOriginalString());
break;
}
}
}
}
/*
* Given a Match, emits into the List<String> the evaluated
* Right-to-Left substitution pattern.
*/
private void ReplacementImplRTL(List<String> al, Match match) {
for (int i = _rules.Count - 1; i >= 0; i--) {
int r = _rules[i];
if (r >= 0) // string lookup
al.Add(_strings[r]);
else if (r < -Specials) // group lookup
al.Add(match.GroupToStringImpl(-Specials - 1 - r));
else {
switch (-Specials - 1 - r) { // special insertion patterns
case LeftPortion:
al.Add(match.GetLeftSubstring());
break;
case RightPortion:
al.Add(match.GetRightSubstring());
break;
case LastGroup:
al.Add(match.LastGroupToStringImpl());
break;
case WholeString:
al.Add(match.GetOriginalString());
break;
}
}
}
}
/*
* The original pattern string
*/
internal String Pattern {
get {
return _rep;
}
}
/*
* Returns the replacement result for a single match
*/
internal String Replacement(Match match) {
StringBuilder sb = new StringBuilder();
ReplacementImpl(sb, match);
return sb.ToString();
}
/*
* Three very similar algorithms appear below: replace (pattern),
* replace (evaluator), and split.
*/
/*
* Replaces all ocurrances of the regex in the string with the
* replacement pattern.
*
* Note that the special case of no matches is handled on its own:
* with no matches, the input string is returned unchanged.
* The right-to-left case is split out because StringBuilder
* doesn't handle right-to-left string building directly very well.
*/
internal String Replace(Regex regex, String input, int count, int startat) {
Match match;
if (count < -1)
throw new ArgumentOutOfRangeException("count", SR.GetString(SR.CountTooSmall));
if (startat < 0 || startat > input.Length)
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
if (count == 0)
return input;
match = regex.Match(input, startat);
if (!match.Success) {
return input;
}
else {
StringBuilder sb;
if (!regex.RightToLeft) {
sb = new StringBuilder();
int prevat = 0;
do {
if (match.Index != prevat)
sb.Append(input, prevat, match.Index - prevat);
prevat = match.Index + match.Length;
ReplacementImpl(sb, match);
if (--count == 0)
break;
match = match.NextMatch();
} while (match.Success);
if (prevat < input.Length)
sb.Append(input, prevat, input.Length - prevat);
}
else {
List<String> al = new List<String>();
int prevat = input.Length;
do {
if (match.Index + match.Length != prevat)
al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
prevat = match.Index;
ReplacementImplRTL(al, match);
if (--count == 0)
break;
match = match.NextMatch();
} while (match.Success);
sb = new StringBuilder();
if (prevat > 0)
sb.Append(input, 0, prevat);
for (int i = al.Count - 1; i >= 0; i--) {
sb.Append(al[i]);
}
}
return sb.ToString();
}
}
/*
* Replaces all ocurrances of the regex in the string with the
* replacement evaluator.
*
* Note that the special case of no matches is handled on its own:
* with no matches, the input string is returned unchanged.
* The right-to-left case is split out because StringBuilder
* doesn't handle right-to-left string building directly very well.
*/
internal static String Replace(MatchEvaluator evaluator, Regex regex,
String input, int count, int startat) {
Match match;
if (evaluator == null)
throw new ArgumentNullException("evaluator");
if (count < -1)
throw new ArgumentOutOfRangeException("count", SR.GetString(SR.CountTooSmall));
if (startat < 0 || startat > input.Length)
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
if (count == 0)
return input;
match = regex.Match(input, startat);
if (!match.Success) {
return input;
}
else {
StringBuilder sb;
if (!regex.RightToLeft) {
sb = new StringBuilder();
int prevat = 0;
do {
if (match.Index != prevat)
sb.Append(input, prevat, match.Index - prevat);
prevat = match.Index + match.Length;
sb.Append(evaluator(match));
if (--count == 0)
break;
match = match.NextMatch();
} while (match.Success);
if (prevat < input.Length)
sb.Append(input, prevat, input.Length - prevat);
}
else {
List<String> al = new List<String>();
int prevat = input.Length;
do {
if (match.Index + match.Length != prevat)
al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
prevat = match.Index;
al.Add(evaluator(match));
if (--count == 0)
break;
match = match.NextMatch();
} while (match.Success);
sb = new StringBuilder();
if (prevat > 0)
sb.Append(input, 0, prevat);
for (int i = al.Count - 1; i >= 0; i--) {
sb.Append(al[i]);
}
}
return sb.ToString();
}
}
/*
* Does a split. In the right-to-left case we reorder the
* array to be forwards.
*/
internal static String[] Split(Regex regex, String input, int count, int startat) {
Match match;
String[] result;
if (count < 0)
throw new ArgumentOutOfRangeException("count", SR.GetString(SR.CountTooSmall));
if (startat < 0 || startat > input.Length)
throw new ArgumentOutOfRangeException("startat", SR.GetString(SR.BeginIndexNotNegative));
if (count == 1) {
result = new String[1];
result[0] = input;
return result;
}
count -= 1;
match = regex.Match(input, startat);
if (!match.Success) {
result = new String[1];
result[0] = input;
return result;
}
else {
List<String> al = new List<String>();
if (!regex.RightToLeft) {
int prevat = 0;
for (;;) {
al.Add(input.Substring(prevat, match.Index - prevat));
prevat = match.Index + match.Length;
// add all matched capture groups to the list.
for (int i=1; i<match.Groups.Count; i++) {
if (match.IsMatched(i))
al.Add(match.Groups[i].ToString());
}
if (--count == 0)
break;
match = match.NextMatch();
if (!match.Success)
break;
}
al.Add(input.Substring(prevat, input.Length - prevat));
}
else {
int prevat = input.Length;
for (;;) {
al.Add(input.Substring(match.Index + match.Length, prevat - match.Index - match.Length));
prevat = match.Index;
// add all matched capture groups to the list.
for (int i=1; i<match.Groups.Count; i++) {
if (match.IsMatched(i))
al.Add(match.Groups[i].ToString());
}
if (--count == 0)
break;
match = match.NextMatch();
if (!match.Success)
break;
}
al.Add(input.Substring(0, prevat));
al.Reverse(0, al.Count);
}
return al.ToArray();
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More