Ignore:
Timestamp:
Nov 28, 2010, 4:45:16 PM (15 years ago)
Author:
[email protected]
Message:

Bug 48101 - Yarr gives different results for /(?:a*?){2,}/

Reviewed by Sam Weinig.

JavaScriptCore:

The test cases in the linked mozilla bug demostrate a couple of
problems in subpattern matching. These bugs lie in the optimized
cases - for matching parentheses with a quantity count of 1, and
for matching greedy quantified parentheses at the end of a regex
(which do not backtrack).

In both of these cases we are failing to correctly handle empty
matches. In the case of parenthese-single matches (quantity count
one) we are failing to test for empty matches at all. In the case
of terminal subpattern matches we do currenty check, however there
is a subtler bug here too. In the case of an empty match we will
presently immediately fall through to the next alternative (or
complete the regex match), whereas upon a failed match we should
be backtracking into the failing alternative, to give it a chance
to match further (e.g. consider /a??b?|a/.exec("ab") - upon first
attempting to match the first alternative this will match the empty
string - since a?? is non-greedy, however rather than moving on to
the second alternative we should be re-matching the first one, at
which point the non-greedy a?? will match, and as such the result
should be "ab", not "a").

Terminal sunpattern matching contains a second bug, too. The frame
location values in the subpattern should be being allocated with
the outer disjunction's frame (as we do for the parentheses-single
optimization). Consider the following three regexes:

/a*(?:b*)*c*/
/a*(?:b*)c*/
/a*(?:b*)*/

Considering only the frame location required by the atoms a,b, and
c, (ignoring space associated with the nested subpattern) the first
regex (a normal subpattern match) requires a frame size of 2 for
the outer disjunction, (to backtrack terms a & c), with each
iteration of the subpattern requiring a frame of size 1 (in order
to backtrack b). In the case of the second regex (where the
parentheses-single optimization will kick in) the outer frame must
be set up with a frame size of 3, since the outer frame will also
be used when running the nested subpattern. We will currently only
allocate a farme of size 1 for the outer disjuntion (to contain a),
howver the frame size should be 2 (since the subpattern will be
evaluated in the outer frame). In addition to failing to allocate
frame space the frame offsets are also presently invalid - in the
case of the last regex b's frame location will be set assuming it
to be the first term in the frame, whereas in this case b lies
after the term a, and should be taking a separate frame location.

In order to correctly allocate the frame for terminal subpattern
matches we must move this optimization back up from the JIT into
the compiler (and thus interpreter too), since this is where the
frame allocation takes place.

  • yarr/RegexCompiler.cpp:

(JSC::Yarr::RegexPatternConstructor::setupAlternativeOffsets):
(JSC::Yarr::RegexPatternConstructor::checkForTerminalParentheses):
(JSC::Yarr::compileRegex):

  • yarr/RegexInterpreter.cpp:

(JSC::Yarr::Interpreter::matchParenthesesOnceBegin):
(JSC::Yarr::Interpreter::matchParenthesesOnceEnd):
(JSC::Yarr::Interpreter::backtrackParenthesesOnceBegin):
(JSC::Yarr::Interpreter::backtrackParenthesesOnceEnd):
(JSC::Yarr::Interpreter::matchParenthesesTerminalBegin):
(JSC::Yarr::Interpreter::matchParenthesesTerminalEnd):
(JSC::Yarr::Interpreter::backtrackParenthesesTerminalBegin):
(JSC::Yarr::Interpreter::backtrackParenthesesTerminalEnd):
(JSC::Yarr::Interpreter::matchDisjunction):
(JSC::Yarr::ByteCompiler::atomParenthesesOnceBegin):
(JSC::Yarr::ByteCompiler::atomParenthesesTerminalBegin):
(JSC::Yarr::ByteCompiler::atomParenthesesSubpatternBegin):
(JSC::Yarr::ByteCompiler::atomParentheticalAssertionEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesSubpatternEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesOnceEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesTerminalEnd):
(JSC::Yarr::ByteCompiler::emitDisjunction):

  • yarr/RegexInterpreter.h:
  • yarr/RegexJIT.cpp:

(JSC::Yarr::RegexGenerator::generateParenthesesSingle):
(JSC::Yarr::RegexGenerator::generateParenthesesGreedyNoBacktrack):
(JSC::Yarr::RegexGenerator::generateTerm):

  • yarr/RegexPattern.h:

(JSC::Yarr::PatternTerm::PatternTerm):

LayoutTests:

Add layout tests for corner cases of repeat matches in regular expressions,
and of the examples documented in the ECMA-262 spec .

  • fast/regex/ecma-regex-examples-expected.txt: Added.
  • fast/regex/ecma-regex-examples.html: Added.
  • fast/regex/repeat-match-waldemar-expected.txt: Added.
  • fast/regex/repeat-match-waldemar.html: Added.
  • fast/regex/script-tests/ecma-regex-examples.js: Added.
  • fast/regex/script-tests/repeat-match-waldemar.js: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/yarr/RegexInterpreter.cpp

    r72489 r72781  
    6161    };
    6262    struct BackTrackInfoParenthesesOnce {
    63         uintptr_t inParentheses;
     63        uintptr_t begin;
     64    };
     65    struct BackTrackInfoParenthesesTerminal {
     66        uintptr_t begin;
    6467    };
    6568    struct BackTrackInfoParentheses {
     
    632635        case QuantifierGreedy: {
    633636            // set this speculatively; if we get to the parens end this will be true.
    634             backTrack->inParentheses = 1;
     637            backTrack->begin = input.getPos();
    635638            break;
    636639        }
    637640        case QuantifierNonGreedy: {
    638             backTrack->inParentheses = 0;
     641            backTrack->begin = notFound;
    639642            context->term += term.atom.parenthesesWidth;
    640643            return true;
     
    652655    }
    653656
    654     bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext*)
     657    bool matchParenthesesOnceEnd(ByteTerm& term, DisjunctionContext* context)
    655658    {
    656659        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternOnceEnd);
     
    661664            output[(subpatternId << 1) + 1] = input.getPos() + term.inputPosition;
    662665        }
    663         return true;
     666
     667        if (term.atom.quantityType == QuantifierFixedCount)
     668            return true;
     669
     670        BackTrackInfoParenthesesOnce* backTrack = reinterpret_cast<BackTrackInfoParenthesesOnce*>(context->frame + term.frameLocation);
     671        return backTrack->begin != input.getPos();
    664672    }
    665673
     
    680688        case QuantifierGreedy:
    681689            // if we backtrack to this point, there is another chance - try matching nothing.
    682             ASSERT(backTrack->inParentheses);
    683             backTrack->inParentheses = 0;
     690            ASSERT(backTrack->begin != notFound);
     691            backTrack->begin = notFound;
    684692            context->term += term.atom.parenthesesWidth;
    685693            return true;
    686694        case QuantifierNonGreedy:
    687             ASSERT(backTrack->inParentheses);
     695            ASSERT(backTrack->begin != notFound);
    688696        case QuantifierFixedCount:
    689697            break;
     
    702710        switch (term.atom.quantityType) {
    703711        case QuantifierGreedy:
    704             if (!backTrack->inParentheses) {
     712            if (backTrack->begin == notFound) {
    705713                context->term -= term.atom.parenthesesWidth;
    706714                return false;
    707715            }
    708716        case QuantifierNonGreedy:
    709             if (!backTrack->inParentheses) {
    710                 // now try to match the parens; set this speculatively.
    711                 backTrack->inParentheses = 1;
     717            if (backTrack->begin == notFound) {
     718                backTrack->begin = input.getPos();
    712719                if (term.capture()) {
     720                    // Technically this access to inputPosition should be accessing the begin term's
     721                    // inputPosition, but for repeats other than fixed these values should be
     722                    // the same anyway! (we don't pre-check for greedy or non-greedy matches.)
     723                    ASSERT((&term - term.atom.parenthesesWidth)->type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
     724                    ASSERT((&term - term.atom.parenthesesWidth)->inputPosition == term.inputPosition);
    713725                    unsigned subpatternId = term.atom.subpatternId;
    714726                    output[subpatternId << 1] = input.getPos() + term.inputPosition;
     
    721733        }
    722734
     735        return false;
     736    }
     737
     738    bool matchParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
     739    {
     740        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
     741        ASSERT(term.atom.quantityType == QuantifierGreedy);
     742        ASSERT(term.atom.quantityCount == UINT_MAX);
     743        ASSERT(!term.capture());
     744
     745        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast<BackTrackInfoParenthesesTerminal*>(context->frame + term.frameLocation);
     746        backTrack->begin = input.getPos();
     747        return true;
     748    }
     749
     750    bool matchParenthesesTerminalEnd(ByteTerm& term, DisjunctionContext* context)
     751    {
     752        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalEnd);
     753
     754        BackTrackInfoParenthesesTerminal* backTrack = reinterpret_cast<BackTrackInfoParenthesesTerminal*>(context->frame + term.frameLocation);
     755        // Empty match is a failed match.
     756        if (backTrack->begin == input.getPos())
     757            return false;
     758
     759        // Successful match! Okay, what's next? - loop around and try to match moar!
     760        context->term -= (term.atom.parenthesesWidth + 1);
     761        return true;
     762    }
     763
     764    bool backtrackParenthesesTerminalBegin(ByteTerm& term, DisjunctionContext* context)
     765    {
     766        ASSERT(term.type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
     767        ASSERT(term.atom.quantityType == QuantifierGreedy);
     768        ASSERT(term.atom.quantityCount == UINT_MAX);
     769        ASSERT(!term.capture());
     770
     771        // If we backtrack to this point, we have failed to match this iteration of the parens.
     772        // Since this is greedy / zero minimum a failed is also accepted as a match!
     773        context->term += term.atom.parenthesesWidth;
     774        return true;
     775    }
     776
     777    bool backtrackParenthesesTerminalEnd(ByteTerm&, DisjunctionContext*)
     778    {
     779        // 'Terminal' parentheses are at the end of the regex, and as such a match past end
     780        // should always be returned as a successful match - we should never becktrack to here.
     781        ASSERT_NOT_REACHED();
    723782        return false;
    724783    }
     
    11701229        case ByteTerm::TypeParenthesesSubpatternOnceEnd:
    11711230            if (matchParenthesesOnceEnd(currentTerm(), context))
     1231                MATCH_NEXT();
     1232            BACKTRACK();
     1233        case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
     1234            if (matchParenthesesTerminalBegin(currentTerm(), context))
     1235                MATCH_NEXT();
     1236            BACKTRACK();
     1237        case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
     1238            if (matchParenthesesTerminalEnd(currentTerm(), context))
    11721239                MATCH_NEXT();
    11731240            BACKTRACK();
     
    12851352                    MATCH_NEXT();
    12861353                BACKTRACK();
     1354            case ByteTerm::TypeParenthesesSubpatternTerminalBegin:
     1355                if (backtrackParenthesesTerminalBegin(currentTerm(), context))
     1356                    MATCH_NEXT();
     1357                BACKTRACK();
     1358            case ByteTerm::TypeParenthesesSubpatternTerminalEnd:
     1359                if (backtrackParenthesesTerminalEnd(currentTerm(), context))
     1360                    MATCH_NEXT();
     1361                BACKTRACK();
    12871362            case ByteTerm::TypeParentheticalAssertionBegin:
    12881363                if (backtrackParentheticalAssertionBegin(currentTerm(), context))
     
    14461521    }
    14471522
    1448     void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
     1523    void atomParenthesesOnceBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
    14491524    {
    14501525        int beginTerm = m_bodyDisjunction->terms.size();
     
    14591534    }
    14601535
     1536    void atomParenthesesTerminalBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
     1537    {
     1538        int beginTerm = m_bodyDisjunction->terms.size();
     1539
     1540        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalBegin, subpatternId, capture, inputPosition));
     1541        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
     1542        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
     1543        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
     1544
     1545        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
     1546        m_currentAlternativeIndex = beginTerm + 1;
     1547    }
     1548
     1549    void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation)
     1550    {
     1551        // Errrk! - this is a little crazy, we initially generate as a TypeParenthesesSubpatternOnceBegin,
     1552        // then fix this up at the end! - simplifying this should make it much clearer.
     1553        // https://bugs.webkit.org/show_bug.cgi?id=50136
     1554
     1555        int beginTerm = m_bodyDisjunction->terms.size();
     1556
     1557        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, inputPosition));
     1558        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation;
     1559        m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin());
     1560        m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation;
     1561
     1562        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
     1563        m_currentAlternativeIndex = beginTerm + 1;
     1564    }
     1565
    14611566    void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation)
    14621567    {
     
    14701575        m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex));
    14711576        m_currentAlternativeIndex = beginTerm + 1;
     1577    }
     1578
     1579    void atomParentheticalAssertionEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
     1580    {
     1581        unsigned beginTerm = popParenthesesStack();
     1582        closeAlternative(beginTerm + 1);
     1583        unsigned endTerm = m_bodyDisjunction->terms.size();
     1584
     1585        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin);
     1586
     1587        bool invertOrCapture = m_bodyDisjunction->terms[beginTerm].invertOrCapture;
     1588        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
     1589
     1590        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionEnd, subpatternId, invertOrCapture, inputPosition));
     1591        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
     1592        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
     1593        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
     1594
     1595        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
     1596        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
     1597        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
     1598        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
    14721599    }
    14731600
     
    15431670    }
    15441671
    1545     void atomParenthesesEnd(bool doInline, unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
     1672    void atomParenthesesSubpatternEnd(unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0)
    15461673    {
    15471674        unsigned beginTerm = popParenthesesStack();
     
    15491676        unsigned endTerm = m_bodyDisjunction->terms.size();
    15501677
    1551         bool isAssertion = m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin;
     1678        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
     1679
     1680        ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
     1681
     1682        bool invertOrCapture = parenthesesBegin.invertOrCapture;
     1683        unsigned subpatternId = parenthesesBegin.atom.subpatternId;
     1684
     1685        unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
     1686        ByteDisjunction* parenthesesDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize);
     1687
     1688        parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
     1689        for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
     1690            parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
     1691        parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
     1692
     1693        m_bodyDisjunction->terms.shrink(beginTerm);
     1694
     1695        m_allParenthesesInfo.append(parenthesesDisjunction);
     1696        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, invertOrCapture, inputPosition));
     1697
     1698        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
     1699        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
     1700        m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
     1701    }
     1702
     1703    void atomParenthesesOnceEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
     1704    {
     1705        unsigned beginTerm = popParenthesesStack();
     1706        closeAlternative(beginTerm + 1);
     1707        unsigned endTerm = m_bodyDisjunction->terms.size();
     1708
     1709        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
     1710
    15521711        bool invertOrCapture = m_bodyDisjunction->terms[beginTerm].invertOrCapture;
    15531712        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
    15541713
    1555         m_bodyDisjunction->terms.append(ByteTerm(isAssertion ? ByteTerm::TypeParentheticalAssertionEnd : ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, invertOrCapture, inputPosition));
     1714        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, invertOrCapture, inputPosition));
    15561715        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
    15571716        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
    15581717        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
    15591718
    1560         if (doInline) {
    1561             m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
    1562             m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
    1563             m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
    1564             m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
    1565         } else {
    1566             ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm];
    1567             ASSERT(parenthesesBegin.type == ByteTerm::TypeParenthesesSubpatternOnceBegin);
    1568 
    1569             bool invertOrCapture = parenthesesBegin.invertOrCapture;
    1570             unsigned subpatternId = parenthesesBegin.atom.subpatternId;
    1571 
    1572             unsigned numSubpatterns = lastSubpatternId - subpatternId + 1;
    1573             ByteDisjunction* parenthesesDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize);
    1574 
    1575             parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin());
    1576             for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses)
    1577                 parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]);
    1578             parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd());
    1579 
    1580             m_bodyDisjunction->terms.shrink(beginTerm);
    1581 
    1582             m_allParenthesesInfo.append(parenthesesDisjunction);
    1583             m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, invertOrCapture, inputPosition));
    1584 
    1585             m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
    1586             m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
    1587             m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation;
    1588         }
     1719        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
     1720        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
     1721        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
     1722        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
     1723    }
     1724
     1725    void atomParenthesesTerminalEnd(int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType)
     1726    {
     1727        unsigned beginTerm = popParenthesesStack();
     1728        closeAlternative(beginTerm + 1);
     1729        unsigned endTerm = m_bodyDisjunction->terms.size();
     1730
     1731        ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParenthesesSubpatternTerminalBegin);
     1732
     1733        bool invertOrCapture = m_bodyDisjunction->terms[beginTerm].invertOrCapture;
     1734        unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId;
     1735
     1736        m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternTerminalEnd, subpatternId, invertOrCapture, inputPosition));
     1737        m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm;
     1738        m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm;
     1739        m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation;
     1740
     1741        m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount;
     1742        m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType;
     1743        m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount;
     1744        m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType;
    15891745    }
    15901746
     
    16811837                case PatternTerm::TypeParenthesesSubpattern: {
    16821838                    unsigned disjunctionAlreadyCheckedCount = 0;
    1683                     if ((term.quantityCount == 1) && !term.parentheses.isCopy) {
    1684                         if (term.quantityType == QuantifierFixedCount) {
     1839                    if (term.quantityCount == 1 && !term.parentheses.isCopy) {
     1840                        unsigned alternativeFrameLocation = term.frameLocation;
     1841                        // For QuantifierFixedCount we pre-check the minimum size; for greedy/non-greedy we reserve a slot in the frame.
     1842                        if (term.quantityType == QuantifierFixedCount)
    16851843                            disjunctionAlreadyCheckedCount = term.parentheses.disjunction->m_minimumSize;
    1686                             unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
    1687                             atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation);
    1688                             emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, term.parentheses.disjunction->m_minimumSize);
    1689                             atomParenthesesEnd(true, term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
    1690                         } else {
    1691                             unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
    1692                             atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + RegexStackSpaceForBackTrackInfoParenthesesOnce);
    1693                             emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
    1694                             atomParenthesesEnd(true, term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
    1695                         }
     1844                        else
     1845                            alternativeFrameLocation += RegexStackSpaceForBackTrackInfoParenthesesOnce;
     1846                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
     1847                        atomParenthesesOnceBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, alternativeFrameLocation);
     1848                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
     1849                        atomParenthesesOnceEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
     1850                    } else if (term.parentheses.isTerminal) {
     1851                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
     1852                        atomParenthesesTerminalBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, term.frameLocation + RegexStackSpaceForBackTrackInfoParenthesesOnce);
     1853                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, disjunctionAlreadyCheckedCount);
     1854                        atomParenthesesTerminalEnd(delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType);
    16961855                    } else {
    16971856                        unsigned delegateEndInputOffset = term.inputPosition - currentCountAlreadyChecked;
    16981857                        atomParenthesesSubpatternBegin(term.parentheses.subpatternId, term.invertOrCapture, delegateEndInputOffset - disjunctionAlreadyCheckedCount, term.frameLocation, 0);
    16991858                        emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0);
    1700                         atomParenthesesEnd(false, term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
     1859                        atomParenthesesSubpatternEnd(term.parentheses.lastSubpatternId, delegateEndInputOffset, term.frameLocation, term.quantityCount, term.quantityType, term.parentheses.disjunction->m_callFrameSize);
    17011860                    }
    17021861                    break;
     
    17111870                    atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invertOrCapture, term.frameLocation, alternativeFrameLocation);
    17121871                    emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, positiveInputOffset, true);
    1713                     atomParenthesesEnd(true, term.parentheses.lastSubpatternId, 0, term.frameLocation, term.quantityCount, term.quantityType);
     1872                    atomParentheticalAssertionEnd(0, term.frameLocation, term.quantityCount, term.quantityType);
    17141873                    break;
    17151874                }
Note: See TracChangeset for help on using the changeset viewer.