bool Parser::parseCharacterClassQuantifier(JumpList& failures, const CharacterClass& charClass, bool invert) { Quantifier q = consumeQuantifier(); switch (q.type) { case Quantifier::None: { m_generator.generateCharacterClass(failures, charClass, invert); break; } case Quantifier::Greedy: { GenerateCharacterClassFunctor functor(&charClass, invert); m_generator.generateGreedyQuantifier(failures, functor, q.min, q.max); break; } case Quantifier::NonGreedy: { GenerateCharacterClassFunctor functor(&charClass, invert); m_generator.generateNonGreedyQuantifier(failures, functor, q.min, q.max); break; } case Quantifier::Error: return false; } return true; }
bool Parser::parseParentheses(JumpList& failures) { ParenthesesType type = consumeParenthesesType(); // FIXME: WREC originally failed to backtrack correctly in cases such as // "c".match(/(.*)c/). Now, most parentheses handling is disabled. For // unsupported parentheses, we fall back on PCRE. switch (type) { case Generator::Assertion: { m_generator.generateParenthesesAssertion(failures); if (consume() != ')') { setError(ParenthesesUnmatched); return false; } Quantifier quantifier = consumeQuantifier(); if (quantifier.type != Quantifier::None && quantifier.min == 0) { setError(ParenthesesNotSupported); return false; } return true; } case Generator::InvertedAssertion: { m_generator.generateParenthesesInvertedAssertion(failures); if (consume() != ')') { setError(ParenthesesUnmatched); return false; } Quantifier quantifier = consumeQuantifier(); if (quantifier.type != Quantifier::None && quantifier.min == 0) { setError(ParenthesesNotSupported); return false; } return true; } default: setError(ParenthesesNotSupported); return false; } }
bool Parser::parseParentheses(JumpList& failures) { ParenthesesType type = consumeParenthesesType(); // FIXME: WREC originally failed to backtrack correctly in cases such as // "c".match(/(.*)c/). Now, most parentheses handling is disabled. For // unsupported parentheses, we fall back on PCRE. switch (type) { case Generator::Assertion: m_generator.generateParenthesesAssertion(failures); if (consume() != ')') { setError(ParenthesesUnmatched); return false; } // A quantifier after an assertion is meaningless, since assertions // don't move index forward. So, we discard it. consumeQuantifier(); break; case Generator::InvertedAssertion: m_generator.generateParenthesesInvertedAssertion(failures); if (consume() != ')') { setError(ParenthesesUnmatched); return false; } // A quantifier after an assertion is meaningless, since assertions // don't move index forward. So, we discard it. consumeQuantifier(); break; default: setError(ParenthesesNotSupported); return false; } return true; }
bool Parser::parseBackreferenceQuantifier(JumpList& failures, unsigned subpatternId) { Quantifier q = consumeQuantifier(); switch (q.type) { case Quantifier::None: { m_generator.generateBackreference(failures, subpatternId); break; } case Quantifier::Greedy: case Quantifier::NonGreedy: m_generator.generateBackreferenceQuantifier(failures, q.type, subpatternId, q.min, q.max); return true; case Quantifier::Error: return false; } return true; }
void Parser::parseAlternative(JumpList& failures) { PatternCharacterSequence sequence(m_generator, failures); while (1) { switch (peek()) { case EndOfPattern: case '|': case ')': sequence.flush(); return; case '*': case '+': case '?': case '{': { Quantifier q = consumeQuantifier(); if (q.type == Quantifier::None) { sequence.append(consume()); continue; } if (q.type == Quantifier::Error) return; if (!sequence.size()) { setError(QuantifierWithoutAtom); return; } sequence.flush(q); continue; } case '^': consume(); sequence.flush(); m_generator.generateAssertionBOL(failures); continue; case '$': consume(); sequence.flush(); m_generator.generateAssertionEOL(failures); continue; case '.': consume(); sequence.flush(); if (!parseCharacterClassQuantifier(failures, CharacterClass::newline(), true)) return; continue; case '[': consume(); sequence.flush(); if (!parseCharacterClass(failures)) return; continue; case '(': consume(); sequence.flush(); if (!parseParentheses(failures)) return; continue; case '\\': { consume(); Escape escape = consumeEscape(false); if (escape.type() == Escape::PatternCharacter) { sequence.append(PatternCharacterEscape::cast(escape).character()); continue; } sequence.flush(); if (!parseNonCharacterEscape(failures, escape)) return; continue; } default: sequence.append(consume()); continue; } } }