private bool ParseAssertionType(ExpressionAssertion assertion) { if (pattern[ptr] == '<') { switch (pattern[ptr + 1]) { case '=': assertion.Negate = false; break; case '!': assertion.Negate = true; break; default: return(false); } assertion.Reverse = true; ptr += 2; } else { switch (pattern[ptr]) { case '=': assertion.Negate = false; break; case '!': assertion.Negate = true; break; default: return(false); } assertion.Reverse = false; ptr += 1; } return(true); }
private Expression ParseGroupingConstruct(ref RegexOptions options) { if (pattern[ptr] != '?') { Group group; if (IsExplicitCapture(options)) { group = new Group(); } else { group = new CapturingGroup(); caps.Add(group); } ParseGroup(group, options, null); return(group); } else { ++ptr; } switch (pattern[ptr]) { case ':': { // non-capturing group ++ptr; Group group = new Group(); ParseGroup(group, options, null); return(group); } case '>': { // non-backtracking group ++ptr; Group group = new NonBacktrackingGroup(); ParseGroup(group, options, null); return(group); } case 'i': case 'm': case 'n': case 's': case 'x': case '-': { // options RegexOptions o = options; ParseOptions(ref o, false); if (pattern[ptr] == '-') { ++ptr; ParseOptions(ref o, true); } if (pattern[ptr] == ':') // pass options to child group { ++ptr; Group group = new Group(); ParseGroup(group, o, null); return(group); } else if (pattern[ptr] == ')') // change options of enclosing group { ++ptr; options = o; return(null); } else { throw NewParseException("Bad options"); } } case '<': case '=': case '!': { // lookahead/lookbehind ExpressionAssertion asn = new ExpressionAssertion(); if (!ParseAssertionType(asn)) { goto case '\''; // it's a (?<name> ) construct } Group test = new Group(); ParseGroup(test, options, null); asn.TestExpression = test; return(asn); } case '\'': { // named/balancing group char delim; if (pattern[ptr] == '<') { delim = '>'; } else { delim = '\''; } ++ptr; string name = ParseName(); if (pattern[ptr] == delim) { // capturing group if (name == null) { throw NewParseException("Bad group name."); } ++ptr; CapturingGroup cap = new CapturingGroup(); cap.Name = name; caps.Add(cap); ParseGroup(cap, options, null); return(cap); } else if (pattern[ptr] == '-') { // balancing group ++ptr; string balance_name = ParseName(); if (balance_name == null || pattern[ptr] != delim) { throw NewParseException("Bad balancing group name."); } ++ptr; BalancingGroup bal = new BalancingGroup(); bal.Name = name; if (bal.IsNamed) { caps.Add(bal); } refs.Add(bal, balance_name); ParseGroup(bal, options, null); return(bal); } else { throw NewParseException("Bad group name."); } } case '(': { // expression/capture test Assertion asn; ++ptr; int p = ptr; string name = ParseName(); if (name == null || pattern[ptr] != ')') // expression test // FIXME MS implementation doesn't seem to // implement this version of (?(x) ...) { ptr = p; ExpressionAssertion expr_asn = new ExpressionAssertion(); if (pattern[ptr] == '?') { ++ptr; if (!ParseAssertionType(expr_asn)) { throw NewParseException("Bad conditional."); } } else { expr_asn.Negate = false; expr_asn.Reverse = false; } Group test = new Group(); ParseGroup(test, options, null); expr_asn.TestExpression = test; asn = expr_asn; } else // capture test { ++ptr; asn = new CaptureAssertion(new Literal(name, IsIgnoreCase(options))); refs.Add(asn, name); } Group group = new Group(); ParseGroup(group, options, asn); return(group); } case '#': { // comment ++ptr; while (pattern[ptr++] != ')') { if (ptr >= pattern.Length) { throw NewParseException("Unterminated (?#...) comment."); } } return(null); } default: // error throw NewParseException("Bad grouping construct."); } }