Coverage Report

Created: 2026-10-31 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/icu/icu4c/source/i18n/regexcmp.cpp
Line
Count
Source
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
//
4
//  file:  regexcmp.cpp
5
//
6
//  Copyright (C) 2002-2016 International Business Machines Corporation and others.
7
//  All Rights Reserved.
8
//
9
//  This file contains the ICU regular expression compiler, which is responsible
10
//  for processing a regular expression pattern into the compiled form that
11
//  is used by the match finding engine.
12
//
13
14
#include "unicode/utypes.h"
15
16
#if !UCONFIG_NO_REGULAR_EXPRESSIONS
17
18
#include "unicode/ustring.h"
19
#include "unicode/unistr.h"
20
#include "unicode/uniset.h"
21
#include "unicode/uchar.h"
22
#include "unicode/uchriter.h"
23
#include "unicode/parsepos.h"
24
#include "unicode/parseerr.h"
25
#include "unicode/regex.h"
26
#include "unicode/utf.h"
27
#include "unicode/utf16.h"
28
#include "patternprops.h"
29
#include "putilimp.h"
30
#include "cmemory.h"
31
#include "cstr.h"
32
#include "cstring.h"
33
#include "uvectr32.h"
34
#include "uvectr64.h"
35
#include "uassert.h"
36
#include "uinvchar.h"
37
38
#include "regeximp.h"
39
#include "regexcst.h"   // Contains state table for the regex pattern parser.
40
                        //   generated by a Perl script.
41
#include "regexcmp.h"
42
#include "regexst.h"
43
#include "regextxt.h"
44
45
46
47
U_NAMESPACE_BEGIN
48
49
50
//------------------------------------------------------------------------------
51
//
52
//  Constructor.
53
//
54
//------------------------------------------------------------------------------
55
RegexCompile::RegexCompile(RegexPattern *rxp, UErrorCode &status) :
56
21.7k
   fParenStack(status), fSetStack(uprv_deleteUObject, nullptr, status), fSetOpStack(status)
57
21.7k
{
58
    // Lazy init of all shared global sets (needed for init()'s empty text)
59
21.7k
    RegexStaticSets::initGlobals(&status);
60
61
21.7k
    fStatus           = &status;
62
63
21.7k
    fRXPat            = rxp;
64
21.7k
    fScanIndex        = 0;
65
21.7k
    fLastChar         = -1;
66
21.7k
    fPeekChar         = -1;
67
21.7k
    fLineNum          = 1;
68
21.7k
    fCharNum          = 0;
69
21.7k
    fQuoteMode        = false;
70
21.7k
    fInBackslashQuote = false;
71
21.7k
    fModeFlags        = fRXPat->fFlags | 0x80000000;
72
21.7k
    fEOLComments      = true;
73
74
21.7k
    fMatchOpenParen   = -1;
75
21.7k
    fMatchCloseParen  = -1;
76
21.7k
    fCaptureName      = nullptr;
77
21.7k
    fLastSetLiteral   = U_SENTINEL;
78
79
21.7k
    if (U_SUCCESS(status) && U_FAILURE(rxp->fDeferredStatus)) {
80
0
        status = rxp->fDeferredStatus;
81
0
    }
82
21.7k
}
83
84
static const char16_t   chAmp       = 0x26;      // '&'
85
static const char16_t   chDash      = 0x2d;      // '-'
86
87
88
//------------------------------------------------------------------------------
89
//
90
//  Destructor
91
//
92
//------------------------------------------------------------------------------
93
21.7k
RegexCompile::~RegexCompile() {
94
21.7k
    delete fCaptureName;         // Normally will be nullptr, but can exist if pattern
95
                                 //   compilation stops with a syntax error.
96
21.7k
}
97
98
917
static inline void addCategory(UnicodeSet *set, int32_t value, UErrorCode& ec) {
99
917
    set->addAll(UnicodeSet().applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, value, ec));
100
917
}
101
102
//------------------------------------------------------------------------------
103
//
104
//  Compile regex pattern.   The state machine for rexexp pattern parsing is here.
105
//                           The state tables are hand-written in the file regexcst.txt,
106
//                           and converted to the form used here by a perl
107
//                           script regexcst.pl
108
//
109
//------------------------------------------------------------------------------
110
void    RegexCompile::compile(
111
                         const UnicodeString &pat,   // Source pat to be compiled.
112
                         UParseError &pp,            // Error position info
113
                         UErrorCode &e)              // Error Code
114
11.3k
{
115
11.3k
    fRXPat->fPatternString = new UnicodeString(pat);
116
11.3k
    UText patternText = UTEXT_INITIALIZER;
117
11.3k
    utext_openConstUnicodeString(&patternText, fRXPat->fPatternString, &e);
118
119
11.3k
    if (U_SUCCESS(e)) {
120
11.3k
        compile(&patternText, pp, e);
121
11.3k
        utext_close(&patternText);
122
11.3k
    }
123
11.3k
}
124
125
//
126
//   compile, UText mode
127
//     All the work is actually done here.
128
//
129
void    RegexCompile::compile(
130
                         UText *pat,                 // Source pat to be compiled.
131
                         UParseError &pp,            // Error position info
132
                         UErrorCode &e)              // Error Code
133
21.7k
{
134
21.7k
    fStatus             = &e;
135
21.7k
    fParseErr           = &pp;
136
21.7k
    fStackPtr           = 0;
137
21.7k
    fStack[fStackPtr]   = 0;
138
139
21.7k
    if (U_FAILURE(*fStatus)) {
140
0
        return;
141
0
    }
142
143
    // There should be no pattern stuff in the RegexPattern object.  They can not be reused.
144
21.7k
    U_ASSERT(fRXPat->fPattern == nullptr || utext_nativeLength(fRXPat->fPattern) == 0);
145
146
    // Prepare the RegexPattern object to receive the compiled pattern.
147
21.7k
    fRXPat->fPattern        = utext_clone(fRXPat->fPattern, pat, false, true, fStatus);
148
21.7k
    if (U_FAILURE(*fStatus)) {
149
0
        return;
150
0
    }
151
152
    // Initialize the pattern scanning state machine
153
21.7k
    fPatternLength = utext_nativeLength(pat);
154
21.7k
    uint16_t                state = 1;
155
21.7k
    const RegexTableEl      *tableEl;
156
157
    // UREGEX_LITERAL force entire pattern to be treated as a literal string.
158
21.7k
    if (fModeFlags & UREGEX_LITERAL) {
159
0
        fQuoteMode = true;
160
0
    }
161
162
21.7k
    nextChar(fC);                        // Fetch the first char from the pattern string.
163
164
    //
165
    // Main loop for the regex pattern parsing state machine.
166
    //   Runs once per state transition.
167
    //   Each time through optionally performs, depending on the state table,
168
    //      - an advance to the next pattern char
169
    //      - an action to be performed.
170
    //      - pushing or popping a state to/from the local state return stack.
171
    //   file regexcst.txt is the source for the state table.  The logic behind
172
    //     recongizing the pattern syntax is there, not here.
173
    //
174
183M
    for (;;) {
175
        //  Bail out if anything has gone wrong.
176
        //  Regex pattern parsing stops on the first error encountered.
177
183M
        if (U_FAILURE(*fStatus)) {
178
281
            break;
179
281
        }
180
181
183M
        U_ASSERT(state != 0);
182
183
        // Find the state table element that matches the input char from the pattern, or the
184
        //    class of the input character.  Start with the first table row for this
185
        //    state, then linearly scan forward until we find a row that matches the
186
        //    character.  The last row for each state always matches all characters, so
187
        //    the search will stop there, if not before.
188
        //
189
183M
        tableEl = &gRuleParseStateTable[state];
190
183M
        REGEX_SCAN_DEBUG_PRINTF(("char, line, col = (\'%c\', %d, %d)    state=%s ",
191
183M
            fC.fChar, fLineNum, fCharNum, RegexStateNames[state]));
192
193
814M
        for (;;) {    // loop through table rows belonging to this state, looking for one
194
                      //   that matches the current input char.
195
814M
            REGEX_SCAN_DEBUG_PRINTF(("."));
196
814M
            if (tableEl->fCharClass < 127 && fC.fQuoted == false &&   tableEl->fCharClass == fC.fChar) {
197
                // Table row specified an individual character, not a set, and
198
                //   the input character is not quoted, and
199
                //   the input character matched it.
200
23.7M
                break;
201
23.7M
            }
202
791M
            if (tableEl->fCharClass == 255) {
203
                // Table row specified default, match anything character class.
204
111M
                break;
205
111M
            }
206
679M
            if (tableEl->fCharClass == 254 && fC.fQuoted)  {
207
                // Table row specified "quoted" and the char was quoted.
208
1.88M
                break;
209
1.88M
            }
210
677M
            if (tableEl->fCharClass == 253 && fC.fChar == static_cast<UChar32>(-1)) {
211
                // Table row specified eof and we hit eof on the input.
212
18.0k
                break;
213
18.0k
            }
214
215
677M
            if (tableEl->fCharClass >= 128 && tableEl->fCharClass < 240 &&   // Table specs a char class &&
216
67.1M
                fC.fQuoted == false &&                                       //   char is not escaped &&
217
67.1M
                fC.fChar != static_cast<UChar32>(-1)) {                      //   char is not EOF
218
67.1M
                U_ASSERT(tableEl->fCharClass <= 137);
219
67.1M
                if (RegexStaticSets::gStaticSets->fRuleSets[tableEl->fCharClass-128].contains(fC.fChar)) {
220
                    // Table row specified a character class, or set of characters,
221
                    //   and the current char matches it.
222
46.3M
                    break;
223
46.3M
                }
224
67.1M
            }
225
226
            // No match on this row, advance to the next  row for this state,
227
631M
            tableEl++;
228
631M
        }
229
183M
        REGEX_SCAN_DEBUG_PRINTF(("\n"));
230
231
        //
232
        // We've found the row of the state table that matches the current input
233
        //   character from the rules string.
234
        // Perform any action specified  by this row in the state table.
235
183M
        if (doParseActions(tableEl->fAction) == false) {
236
            // Break out of the state machine loop if the
237
            //   the action signalled some kind of error, or
238
            //   the action was to exit, occurs on normal end-of-rules-input.
239
21.4k
            break;
240
21.4k
        }
241
242
183M
        if (tableEl->fPushState != 0) {
243
948k
            fStackPtr++;
244
948k
            if (fStackPtr >= kStackSize) {
245
7
                error(U_REGEX_INTERNAL_ERROR);
246
7
                REGEX_SCAN_DEBUG_PRINTF(("RegexCompile::parse() - state stack overflow.\n"));
247
7
                fStackPtr--;
248
7
            }
249
948k
            fStack[fStackPtr] = tableEl->fPushState;
250
948k
        }
251
252
        //
253
        //  NextChar.  This is where characters are actually fetched from the pattern.
254
        //             Happens under control of the 'n' tag in the state table.
255
        //
256
183M
        if (tableEl->fNextChar) {
257
84.7M
            nextChar(fC);
258
84.7M
        }
259
260
        // Get the next state from the table entry, or from the
261
        //   state stack if the next state was specified as "pop".
262
183M
        if (tableEl->fNextState != 255) {
263
182M
            state = tableEl->fNextState;
264
182M
        } else {
265
925k
            state = fStack[fStackPtr];
266
925k
            fStackPtr--;
267
925k
            if (fStackPtr < 0) {
268
                // state stack underflow
269
                // This will occur if the user pattern has mis-matched parentheses,
270
                //   with extra close parens.
271
                //
272
0
                fStackPtr++;
273
0
                error(U_REGEX_MISMATCHED_PAREN);
274
0
            }
275
925k
        }
276
277
183M
    }
278
279
21.7k
    if (U_FAILURE(*fStatus)) {
280
        // Bail out if the pattern had errors.
281
8.02k
        return;
282
8.02k
    }
283
284
    //
285
    // The pattern has now been read and processed, and the compiled code generated.
286
    //
287
288
    //
289
    // The pattern's fFrameSize so far has accumulated the requirements for
290
    //   storage for capture parentheses, counters, etc. that are encountered
291
    //   in the pattern.  Add space for the two variables that are always
292
    //   present in the saved state:  the input string position (int64_t) and
293
    //   the position in the compiled pattern.
294
    //
295
13.7k
    allocateStackData(RESTACKFRAME_HDRCOUNT);
296
297
    //
298
    // Optimization pass 1: NOPs, back-references, and case-folding
299
    //
300
13.7k
    stripNOPs();
301
302
    //
303
    // Get bounds for the minimum and maximum length of a string that this
304
    //   pattern can match.  Used to avoid looking for matches in strings that
305
    //   are too short.
306
    //
307
13.7k
    fRXPat->fMinMatchLen = minMatchLength(3, fRXPat->fCompiledPat->size()-1);
308
309
    //
310
    // Optimization pass 2: match start type
311
    //
312
13.7k
    matchStartType();
313
314
    //
315
    // Set up fast latin-1 range sets
316
    //
317
13.7k
    int32_t numSets = fRXPat->fSets->size();
318
13.7k
    fRXPat->fSets8 = new Regex8BitSet[numSets];
319
    // Null pointer check.
320
13.7k
    if (fRXPat->fSets8 == nullptr) {
321
0
        e = *fStatus = U_MEMORY_ALLOCATION_ERROR;
322
0
        return;
323
0
    }
324
13.7k
    int32_t i;
325
214k
    for (i=0; i<numSets; i++) {
326
200k
        UnicodeSet* s = static_cast<UnicodeSet*>(fRXPat->fSets->elementAt(i));
327
200k
        fRXPat->fSets8[i].init(s);
328
200k
    }
329
330
13.7k
}
331
332
333
334
335
336
//------------------------------------------------------------------------------
337
//
338
//  doParseAction        Do some action during regex pattern parsing.
339
//                       Called by the parse state machine.
340
//
341
//                       Generation of the match engine PCode happens here, or
342
//                       in functions called from the parse actions defined here.
343
//
344
//
345
//------------------------------------------------------------------------------
346
UBool RegexCompile::doParseActions(int32_t action)
347
183M
{
348
183M
    UBool   returnVal = true;
349
350
183M
    switch (static_cast<Regex_PatternParseAction>(action)) {
351
352
21.6k
    case doPatStart:
353
        // Start of pattern compiles to:
354
        //0   SAVE   2        Fall back to position of FAIL
355
        //1   jmp    3
356
        //2   FAIL            Stop if we ever reach here.
357
        //3   NOP             Dummy, so start of pattern looks the same as
358
        //                    the start of an ( grouping.
359
        //4   NOP             Resreved, will be replaced by a save if there are
360
        //                    OR | operators at the top level
361
21.6k
        appendOp(URX_STATE_SAVE, 2);
362
21.6k
        appendOp(URX_JMP,  3);
363
21.6k
        appendOp(URX_FAIL, 0);
364
365
        // Standard open nonCapture paren action emits the two NOPs and
366
        //   sets up the paren stack frame.
367
21.6k
        doParseActions(doOpenNonCaptureParen);
368
21.6k
        break;
369
370
16.0k
    case doPatFinish:
371
        // We've scanned to the end of the pattern
372
        //  The end of pattern compiles to:
373
        //        URX_END
374
        //    which will stop the runtime match engine.
375
        //  Encountering end of pattern also behaves like a close paren,
376
        //   and forces fixups of the State Save at the beginning of the compiled pattern
377
        //   and of any OR operations at the top level.
378
        //
379
16.0k
        handleCloseParen();
380
16.0k
        if (fParenStack.size() > 0) {
381
            // Missing close paren in pattern.
382
2.27k
            error(U_REGEX_MISMATCHED_PAREN);
383
2.27k
        }
384
385
        // add the END operation to the compiled pattern.
386
16.0k
        appendOp(URX_END, 0);
387
388
        // Terminate the pattern compilation state machine.
389
16.0k
        returnVal = false;
390
16.0k
        break;
391
392
393
394
19.9M
    case doOrOperator:
395
        // Scanning a '|', as in (A|B)
396
19.9M
        {
397
            // Generate code for any pending literals preceding the '|'
398
19.9M
            fixLiterals(false);
399
400
            // Insert a SAVE operation at the start of the pattern section preceding
401
            //   this OR at this level.  This SAVE will branch the match forward
402
            //   to the right hand side of the OR in the event that the left hand
403
            //   side fails to match and backtracks.  Locate the position for the
404
            //   save from the location on the top of the parentheses stack.
405
19.9M
            int32_t savePosition = fParenStack.popi();
406
19.9M
            int32_t op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(savePosition));
407
19.9M
            U_ASSERT(URX_TYPE(op) == URX_NOP);  // original contents of reserved location
408
19.9M
            op = buildOp(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+1);
409
19.9M
            fRXPat->fCompiledPat->setElementAt(op, savePosition);
410
411
            // Append an JMP operation into the compiled pattern.  The operand for
412
            //  the JMP will eventually be the location following the ')' for the
413
            //  group.  This will be patched in later, when the ')' is encountered.
414
19.9M
            appendOp(URX_JMP, 0);
415
416
            // Push the position of the newly added JMP op onto the parentheses stack.
417
            // This registers if for fixup when this block's close paren is encountered.
418
19.9M
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);
419
420
            // Append a NOP to the compiled pattern.  This is the slot reserved
421
            //   for a SAVE in the event that there is yet another '|' following
422
            //   this one.
423
19.9M
            appendOp(URX_NOP, 0);
424
19.9M
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);
425
19.9M
        }
426
19.9M
        break;
427
428
429
705
    case doBeginNamedCapture:
430
        // Scanning (?<letter.
431
        //   The first letter of the name will come through again under doConinueNamedCapture.
432
705
        fCaptureName = new UnicodeString();
433
705
        if (fCaptureName == nullptr) {
434
0
            error(U_MEMORY_ALLOCATION_ERROR);
435
0
        }
436
705
        break;
437
438
2.54k
    case  doContinueNamedCapture:
439
2.54k
        fCaptureName->append(fC.fChar);
440
2.54k
        break;
441
442
38
    case doBadNamedCapture:
443
38
        error(U_REGEX_INVALID_CAPTURE_GROUP_NAME);
444
38
        break;
445
        
446
587k
    case doOpenCaptureParen:
447
        // Open Capturing Paren, possibly named.
448
        //   Compile to a
449
        //      - NOP, which later may be replaced by a save-state if the
450
        //         parenthesized group gets a * quantifier, followed by
451
        //      - START_CAPTURE  n    where n is stack frame offset to the capture group variables.
452
        //      - NOP, which may later be replaced by a save-state if there
453
        //             is an '|' alternation within the parens.
454
        //
455
        //    Each capture group gets three slots in the save stack frame:
456
        //         0: Capture Group start position (in input string being matched.)
457
        //         1: Capture Group end position.
458
        //         2: Start of Match-in-progress.
459
        //    The first two locations are for a completed capture group, and are
460
        //     referred to by back references and the like.
461
        //    The third location stores the capture start position when an START_CAPTURE is
462
        //      encountered.  This will be promoted to a completed capture when (and if) the corresponding
463
        //      END_CAPTURE is encountered.
464
587k
        {
465
587k
            fixLiterals();
466
587k
            appendOp(URX_NOP, 0);
467
587k
            int32_t  varsLoc = allocateStackData(3);    // Reserve three slots in match stack frame.
468
587k
            appendOp(URX_START_CAPTURE, varsLoc);
469
587k
            appendOp(URX_NOP, 0);
470
471
            // On the Parentheses stack, start a new frame and add the positions
472
            //   of the two NOPs.  Depending on what follows in the pattern, the
473
            //   NOPs may be changed to SAVE_STATE or JMP ops, with a target
474
            //   address of the end of the parenthesized group.
475
587k
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
476
587k
            fParenStack.push(capturing, *fStatus);                        // Frame type.
477
587k
            fParenStack.push(fRXPat->fCompiledPat->size()-3, *fStatus);   // The first  NOP location
478
587k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP loc
479
480
            // Save the mapping from group number to stack frame variable position.
481
587k
            fRXPat->fGroupMap->addElement(varsLoc, *fStatus);
482
483
            // If this is a named capture group, add the name->group number mapping.
484
587k
            if (fCaptureName != nullptr) {
485
690
                if (!fRXPat->initNamedCaptureMap()) {
486
0
                    if (U_SUCCESS(*fStatus)) {
487
0
                        error(fRXPat->fDeferredStatus);
488
0
                    }
489
0
                    break;
490
0
                }
491
690
                int32_t groupNumber = fRXPat->fGroupMap->size();
492
690
                int32_t previousMapping = uhash_puti(fRXPat->fNamedCaptureMap, fCaptureName, groupNumber, fStatus);
493
690
                fCaptureName = nullptr;    // hash table takes ownership of the name (key) string.
494
690
                if (previousMapping > 0 && U_SUCCESS(*fStatus)) {
495
36
                    error(U_REGEX_INVALID_CAPTURE_GROUP_NAME);
496
36
                }
497
690
            }
498
587k
        }
499
587k
        break;
500
501
587k
    case doOpenNonCaptureParen:
502
        // Open non-caputuring (grouping only) Paren.
503
        //   Compile to a
504
        //      - NOP, which later may be replaced by a save-state if the
505
        //         parenthesized group gets a * quantifier, followed by
506
        //      - NOP, which may later be replaced by a save-state if there
507
        //             is an '|' alternation within the parens.
508
22.4k
        {
509
22.4k
            fixLiterals();
510
22.4k
            appendOp(URX_NOP, 0);
511
22.4k
            appendOp(URX_NOP, 0);
512
513
            // On the Parentheses stack, start a new frame and add the positions
514
            //   of the two NOPs.
515
22.4k
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
516
22.4k
            fParenStack.push(plain,      *fStatus);                       // Begin a new frame.
517
22.4k
            fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The first  NOP location
518
22.4k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP loc
519
22.4k
        }
520
22.4k
         break;
521
522
523
900
    case doOpenAtomicParen:
524
        // Open Atomic Paren.  (?>
525
        //   Compile to a
526
        //      - NOP, which later may be replaced if the parenthesized group
527
        //         has a quantifier, followed by
528
        //      - STO_SP  save state stack position, so it can be restored at the ")"
529
        //      - NOP, which may later be replaced by a save-state if there
530
        //             is an '|' alternation within the parens.
531
900
        {
532
900
            fixLiterals();
533
900
            appendOp(URX_NOP, 0);
534
900
            int32_t  varLoc = allocateData(1);    // Reserve a data location for saving the state stack ptr.
535
900
            appendOp(URX_STO_SP, varLoc);
536
900
            appendOp(URX_NOP, 0);
537
538
            // On the Parentheses stack, start a new frame and add the positions
539
            //   of the two NOPs.  Depending on what follows in the pattern, the
540
            //   NOPs may be changed to SAVE_STATE or JMP ops, with a target
541
            //   address of the end of the parenthesized group.
542
900
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
543
900
            fParenStack.push(atomic, *fStatus);                           // Frame type.
544
900
            fParenStack.push(fRXPat->fCompiledPat->size()-3, *fStatus);   // The first NOP
545
900
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP
546
900
        }
547
900
        break;
548
549
550
1.40k
    case doOpenLookAhead:
551
        // Positive Look-ahead   (?=  stuff  )
552
        //
553
        //   Note:   Addition of transparent input regions, with the need to
554
        //           restore the original regions when failing out of a lookahead
555
        //           block, complicated this sequence.  Some combined opcodes
556
        //           might make sense - or might not, lookahead aren't that common.
557
        //
558
        //      Caution:  min match length optimization knows about this
559
        //               sequence; don't change without making updates there too.
560
        //
561
        // Compiles to
562
        //    1    LA_START     dataLoc     Saves SP, Input Pos, Active input region.
563
        //    2.   STATE_SAVE   4            on failure of lookahead, goto 4
564
        //    3    JMP          6           continue ...
565
        //
566
        //    4.   LA_END                   Look Ahead failed.  Restore regions.
567
        //    5.   BACKTRACK                and back track again.
568
        //
569
        //    6.   NOP              reserved for use by quantifiers on the block.
570
        //                          Look-ahead can't have quantifiers, but paren stack
571
        //                             compile time conventions require the slot anyhow.
572
        //    7.   NOP              may be replaced if there is are '|' ops in the block.
573
        //    8.     code for parenthesized stuff.
574
        //    9.   LA_END
575
        //
576
        //  Four data slots are reserved, for saving state on entry to the look-around
577
        //    0:   stack pointer on entry.
578
        //    1:   input position on entry.
579
        //    2:   fActiveStart, the active bounds start on entry.
580
        //    3:   fActiveLimit, the active bounds limit on entry.
581
1.40k
        {
582
1.40k
            fixLiterals();
583
1.40k
            int32_t dataLoc = allocateData(4);
584
1.40k
            appendOp(URX_LA_START, dataLoc);
585
1.40k
            appendOp(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+ 2);
586
1.40k
            appendOp(URX_JMP, fRXPat->fCompiledPat->size()+ 3);
587
1.40k
            appendOp(URX_LA_END, dataLoc);
588
1.40k
            appendOp(URX_BACKTRACK, 0);
589
1.40k
            appendOp(URX_NOP, 0);
590
1.40k
            appendOp(URX_NOP, 0);
591
592
            // On the Parentheses stack, start a new frame and add the positions
593
            //   of the NOPs.
594
1.40k
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
595
1.40k
            fParenStack.push(lookAhead, *fStatus);                        // Frame type.
596
1.40k
            fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The first  NOP location
597
1.40k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP location
598
1.40k
        }
599
1.40k
        break;
600
601
2.69k
    case doOpenLookAheadNeg:
602
        // Negated Lookahead.   (?! stuff )
603
        // Compiles to
604
        //    1.    LA_START    dataloc
605
        //    2.    SAVE_STATE  7         // Fail within look-ahead block restores to this state,
606
        //                                //   which continues with the match.
607
        //    3.    NOP                   // Std. Open Paren sequence, for possible '|'
608
        //    4.       code for parenthesized stuff.
609
        //    5.    LA_END                // Cut back stack, remove saved state from step 2.
610
        //    6.    BACKTRACK             // code in block succeeded, so neg. lookahead fails.
611
        //    7.    END_LA                // Restore match region, in case look-ahead was using
612
        //                                        an alternate (transparent) region.
613
        //  Four data slots are reserved, for saving state on entry to the look-around
614
        //    0:   stack pointer on entry.
615
        //    1:   input position on entry.
616
        //    2:   fActiveStart, the active bounds start on entry.
617
        //    3:   fActiveLimit, the active bounds limit on entry.
618
2.69k
        {
619
2.69k
            fixLiterals();
620
2.69k
            int32_t dataLoc = allocateData(4);
621
2.69k
            appendOp(URX_LA_START, dataLoc);
622
2.69k
            appendOp(URX_STATE_SAVE, 0);    // dest address will be patched later.
623
2.69k
            appendOp(URX_NOP, 0);
624
625
            // On the Parentheses stack, start a new frame and add the positions
626
            //   of the StateSave and NOP.
627
2.69k
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
628
2.69k
            fParenStack.push(negLookAhead, *fStatus);                    // Frame type
629
2.69k
            fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The STATE_SAVE location
630
2.69k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP location
631
632
            // Instructions #5 - #7 will be added when the ')' is encountered.
633
2.69k
        }
634
2.69k
        break;
635
636
3.76k
    case doOpenLookBehind:
637
3.76k
        {
638
            //   Compile a (?<= look-behind open paren.
639
            //
640
            //          Compiles to
641
            //              0       URX_LB_START     dataLoc
642
            //              1       URX_LB_CONT      dataLoc
643
            //              2                        MinMatchLen
644
            //              3                        MaxMatchLen
645
            //              4       URX_NOP          Standard '(' boilerplate.
646
            //              5       URX_NOP          Reserved slot for use with '|' ops within (block).
647
            //              6         <code for LookBehind expression>
648
            //              7       URX_LB_END       dataLoc    # Check match len, restore input  len
649
            //              8       URX_LA_END       dataLoc    # Restore stack, input pos
650
            //
651
            //          Allocate a block of matcher data, to contain (when running a match)
652
            //              0:    Stack ptr on entry
653
            //              1:    Input Index on entry
654
            //              2:    fActiveStart, the active bounds start on entry.
655
            //              3:    fActiveLimit, the active bounds limit on entry.
656
            //              4:    Start index of match current match attempt.
657
            //          The first four items must match the layout of data for LA_START / LA_END
658
659
            // Generate match code for any pending literals.
660
3.76k
            fixLiterals();
661
662
            // Allocate data space
663
3.76k
            int32_t dataLoc = allocateData(5);
664
665
            // Emit URX_LB_START
666
3.76k
            appendOp(URX_LB_START, dataLoc);
667
668
            // Emit URX_LB_CONT
669
3.76k
            appendOp(URX_LB_CONT, dataLoc);
670
3.76k
            appendOp(URX_RESERVED_OP, 0);    // MinMatchLength.  To be filled later.
671
3.76k
            appendOp(URX_RESERVED_OP, 0);    // MaxMatchLength.  To be filled later.
672
673
            // Emit the NOPs
674
3.76k
            appendOp(URX_NOP, 0);
675
3.76k
            appendOp(URX_NOP, 0);
676
677
            // On the Parentheses stack, start a new frame and add the positions
678
            //   of the URX_LB_CONT and the NOP.
679
3.76k
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
680
3.76k
            fParenStack.push(lookBehind, *fStatus);                       // Frame type
681
3.76k
            fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The first NOP location
682
3.76k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The 2nd   NOP location
683
684
            // The final two instructions will be added when the ')' is encountered.
685
3.76k
        }
686
687
3.76k
        break;
688
689
3.90k
    case doOpenLookBehindNeg:
690
3.90k
        {
691
            //   Compile a (?<! negated look-behind open paren.
692
            //
693
            //          Compiles to
694
            //              0       URX_LB_START     dataLoc    # Save entry stack, input len
695
            //              1       URX_LBN_CONT     dataLoc    # Iterate possible match positions
696
            //              2                        MinMatchLen
697
            //              3                        MaxMatchLen
698
            //              4                        continueLoc (9)
699
            //              5       URX_NOP          Standard '(' boilerplate.
700
            //              6       URX_NOP          Reserved slot for use with '|' ops within (block).
701
            //              7         <code for LookBehind expression>
702
            //              8       URX_LBN_END      dataLoc    # Check match len, cause a FAIL
703
            //              9       ...
704
            //
705
            //          Allocate a block of matcher data, to contain (when running a match)
706
            //              0:    Stack ptr on entry
707
            //              1:    Input Index on entry
708
            //              2:    fActiveStart, the active bounds start on entry.
709
            //              3:    fActiveLimit, the active bounds limit on entry.
710
            //              4:    Start index of match current match attempt.
711
            //          The first four items must match the layout of data for LA_START / LA_END
712
713
            // Generate match code for any pending literals.
714
3.90k
            fixLiterals();
715
716
            // Allocate data space
717
3.90k
            int32_t dataLoc = allocateData(5);
718
719
            // Emit URX_LB_START
720
3.90k
            appendOp(URX_LB_START, dataLoc);
721
722
            // Emit URX_LBN_CONT
723
3.90k
            appendOp(URX_LBN_CONT, dataLoc);
724
3.90k
            appendOp(URX_RESERVED_OP, 0);    // MinMatchLength.  To be filled later.
725
3.90k
            appendOp(URX_RESERVED_OP, 0);    // MaxMatchLength.  To be filled later.
726
3.90k
            appendOp(URX_RESERVED_OP, 0);    // Continue Loc.    To be filled later.
727
728
            // Emit the NOPs
729
3.90k
            appendOp(URX_NOP, 0);
730
3.90k
            appendOp(URX_NOP, 0);
731
732
            // On the Parentheses stack, start a new frame and add the positions
733
            //   of the URX_LB_CONT and the NOP.
734
3.90k
            fParenStack.push(fModeFlags, *fStatus);                       // Match mode state
735
3.90k
            fParenStack.push(lookBehindN, *fStatus);                      // Frame type
736
3.90k
            fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The first NOP location
737
3.90k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The 2nd   NOP location
738
739
            // The final two instructions will be added when the ')' is encountered.
740
3.90k
        }
741
3.90k
        break;
742
743
2
    case doConditionalExpr:
744
        // Conditionals such as (?(1)a:b)
745
4
    case doPerlInline:
746
        // Perl inline-conditionals.  (?{perl code}a|b) We're not perl, no way to do them.
747
4
        error(U_REGEX_UNIMPLEMENTED);
748
4
        break;
749
750
751
596k
    case doCloseParen:
752
596k
        handleCloseParen();
753
596k
        if (fParenStack.size() <= 0) {
754
            //  Extra close paren, or missing open paren.
755
26
            error(U_REGEX_MISMATCHED_PAREN);
756
26
        }
757
596k
        break;
758
759
98.8M
    case doNOP:
760
98.8M
        break;
761
762
763
45
    case doBadOpenParenType:
764
80
    case doRuleError:
765
80
        error(U_REGEX_RULE_SYNTAX);
766
80
        break;
767
768
769
13
    case doMismatchedParenErr:
770
13
        error(U_REGEX_MISMATCHED_PAREN);
771
13
        break;
772
773
31.0k
    case doPlus:
774
        //  Normal '+'  compiles to
775
        //     1.   stuff to be repeated  (already built)
776
        //     2.   jmp-sav 1
777
        //     3.   ...
778
        //
779
        //  Or, if the item to be repeated can match a zero length string,
780
        //     1.   STO_INP_LOC  data-loc
781
        //     2.      body of stuff to be repeated
782
        //     3.   JMP_SAV_X    2
783
        //     4.   ...
784
785
        //
786
        //  Or, if the item to be repeated is simple
787
        //     1.   Item to be repeated.
788
        //     2.   LOOP_SR_I    set number  (assuming repeated item is a set ref)
789
        //     3.   LOOP_C       stack location
790
31.0k
        {
791
31.0k
            int32_t  topLoc = blockTopLoc(false);        // location of item #1
792
31.0k
            int32_t  frameLoc;
793
794
            // Check for simple constructs, which may get special optimized code.
795
31.0k
            if (topLoc == fRXPat->fCompiledPat->size() - 1) {
796
29.6k
                int32_t repeatedOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(topLoc));
797
798
29.6k
                if (URX_TYPE(repeatedOp) == URX_SETREF) {
799
                    // Emit optimized code for [char set]+
800
676
                    appendOp(URX_LOOP_SR_I, URX_VAL(repeatedOp));
801
676
                    frameLoc = allocateStackData(1);
802
676
                    appendOp(URX_LOOP_C, frameLoc);
803
676
                    break;
804
676
                }
805
806
28.9k
                if (URX_TYPE(repeatedOp) == URX_DOTANY ||
807
24.4k
                    URX_TYPE(repeatedOp) == URX_DOTANY_ALL ||
808
23.9k
                    URX_TYPE(repeatedOp) == URX_DOTANY_UNIX) {
809
                    // Emit Optimized code for .+ operations.
810
6.01k
                    int32_t loopOpI = buildOp(URX_LOOP_DOT_I, 0);
811
6.01k
                    if (URX_TYPE(repeatedOp) == URX_DOTANY_ALL) {
812
                        // URX_LOOP_DOT_I operand is a flag indicating ". matches any" mode.
813
507
                        loopOpI |= 1;
814
507
                    }
815
6.01k
                    if (fModeFlags & UREGEX_UNIX_LINES) {
816
1.19k
                        loopOpI |= 2;
817
1.19k
                    }
818
6.01k
                    appendOp(loopOpI);
819
6.01k
                    frameLoc = allocateStackData(1);
820
6.01k
                    appendOp(URX_LOOP_C, frameLoc);
821
6.01k
                    break;
822
6.01k
                }
823
824
28.9k
            }
825
826
            // General case.
827
828
            // Check for minimum match length of zero, which requires
829
            //    extra loop-breaking code.
830
24.3k
            if (minMatchLength(topLoc, fRXPat->fCompiledPat->size()-1) == 0) {
831
                // Zero length match is possible.
832
                // Emit the code sequence that can handle it.
833
2.42k
                insertOp(topLoc);
834
2.42k
                frameLoc = allocateStackData(1);
835
836
2.42k
                int32_t op = buildOp(URX_STO_INP_LOC, frameLoc);
837
2.42k
                fRXPat->fCompiledPat->setElementAt(op, topLoc);
838
839
2.42k
                appendOp(URX_JMP_SAV_X, topLoc+1);
840
21.9k
            } else {
841
                // Simpler code when the repeated body must match something non-empty
842
21.9k
                appendOp(URX_JMP_SAV, topLoc);
843
21.9k
            }
844
24.3k
        }
845
0
        break;
846
847
2.89k
    case doNGPlus:
848
        //  Non-greedy '+?'  compiles to
849
        //     1.   stuff to be repeated  (already built)
850
        //     2.   state-save  1
851
        //     3.   ...
852
2.89k
        {
853
2.89k
            int32_t topLoc      = blockTopLoc(false);
854
2.89k
            appendOp(URX_STATE_SAVE, topLoc);
855
2.89k
        }
856
2.89k
        break;
857
858
859
19.1k
    case doOpt:
860
        // Normal (greedy) ? quantifier.
861
        //  Compiles to
862
        //     1. state save 3
863
        //     2.    body of optional block
864
        //     3. ...
865
        // Insert the state save into the compiled pattern, and we're done.
866
19.1k
        {
867
19.1k
            int32_t   saveStateLoc = blockTopLoc(true);
868
19.1k
            int32_t   saveStateOp  = buildOp(URX_STATE_SAVE, fRXPat->fCompiledPat->size());
869
19.1k
            fRXPat->fCompiledPat->setElementAt(saveStateOp, saveStateLoc);
870
19.1k
        }
871
19.1k
        break;
872
873
2.93k
    case doNGOpt:
874
        // Non-greedy ?? quantifier
875
        //   compiles to
876
        //    1.  jmp   4
877
        //    2.     body of optional block
878
        //    3   jmp   5
879
        //    4.  state save 2
880
        //    5    ...
881
        //  This code is less than ideal, with two jmps instead of one, because we can only
882
        //  insert one instruction at the top of the block being iterated.
883
2.93k
        {
884
2.93k
            int32_t  jmp1_loc = blockTopLoc(true);
885
2.93k
            int32_t  jmp2_loc = fRXPat->fCompiledPat->size();
886
887
2.93k
            int32_t  jmp1_op  = buildOp(URX_JMP, jmp2_loc+1);
888
2.93k
            fRXPat->fCompiledPat->setElementAt(jmp1_op, jmp1_loc);
889
890
2.93k
            appendOp(URX_JMP, jmp2_loc+2);
891
892
2.93k
            appendOp(URX_STATE_SAVE, jmp1_loc+1);
893
2.93k
        }
894
2.93k
        break;
895
896
897
334k
    case doStar:
898
        // Normal (greedy) * quantifier.
899
        // Compiles to
900
        //       1.   STATE_SAVE   4
901
        //       2.      body of stuff being iterated over
902
        //       3.   JMP_SAV      2
903
        //       4.   ...
904
        //
905
        // Or, if the body is a simple [Set],
906
        //       1.   LOOP_SR_I    set number
907
        //       2.   LOOP_C       stack location
908
        //       ...
909
        //
910
        // Or if this is a .*
911
        //       1.   LOOP_DOT_I    (. matches all mode flag)
912
        //       2.   LOOP_C        stack location
913
        //
914
        // Or, if the body can match a zero-length string, to inhibit infinite loops,
915
        //       1.   STATE_SAVE   5
916
        //       2.   STO_INP_LOC  data-loc
917
        //       3.      body of stuff
918
        //       4.   JMP_SAV_X    2
919
        //       5.   ...
920
334k
        {
921
            // location of item #1, the STATE_SAVE
922
334k
            int32_t   topLoc = blockTopLoc(false);
923
334k
            int32_t   dataLoc = -1;
924
925
            // Check for simple *, where the construct being repeated
926
            //   compiled to single opcode, and might be optimizable.
927
334k
            if (topLoc == fRXPat->fCompiledPat->size() - 1) {
928
156k
                int32_t repeatedOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(topLoc));
929
930
156k
                if (URX_TYPE(repeatedOp) == URX_SETREF) {
931
                    // Emit optimized code for a [char set]*
932
4.14k
                    int32_t loopOpI = buildOp(URX_LOOP_SR_I, URX_VAL(repeatedOp));
933
4.14k
                    fRXPat->fCompiledPat->setElementAt(loopOpI, topLoc);
934
4.14k
                    dataLoc = allocateStackData(1);
935
4.14k
                    appendOp(URX_LOOP_C, dataLoc);
936
4.14k
                    break;
937
4.14k
                }
938
939
152k
                if (URX_TYPE(repeatedOp) == URX_DOTANY ||
940
145k
                    URX_TYPE(repeatedOp) == URX_DOTANY_ALL ||
941
143k
                    URX_TYPE(repeatedOp) == URX_DOTANY_UNIX) {
942
                    // Emit Optimized code for .* operations.
943
9.60k
                    int32_t loopOpI = buildOp(URX_LOOP_DOT_I, 0);
944
9.60k
                    if (URX_TYPE(repeatedOp) == URX_DOTANY_ALL) {
945
                        // URX_LOOP_DOT_I operand is a flag indicating . matches any mode.
946
1.23k
                        loopOpI |= 1;
947
1.23k
                    }
948
9.60k
                    if ((fModeFlags & UREGEX_UNIX_LINES) != 0) {
949
1.07k
                        loopOpI |= 2;
950
1.07k
                    }
951
9.60k
                    fRXPat->fCompiledPat->setElementAt(loopOpI, topLoc);
952
9.60k
                    dataLoc = allocateStackData(1);
953
9.60k
                    appendOp(URX_LOOP_C, dataLoc);
954
9.60k
                    break;
955
9.60k
                }
956
152k
            }
957
958
            // Emit general case code for this *
959
            // The optimizations did not apply.
960
961
320k
            int32_t   saveStateLoc = blockTopLoc(true);
962
320k
            int32_t   jmpOp        = buildOp(URX_JMP_SAV, saveStateLoc+1);
963
964
            // Check for minimum match length of zero, which requires
965
            //    extra loop-breaking code.
966
320k
            if (minMatchLength(saveStateLoc, fRXPat->fCompiledPat->size()-1) == 0) {
967
91.9k
                insertOp(saveStateLoc);
968
91.9k
                dataLoc = allocateStackData(1);
969
970
91.9k
                int32_t op = buildOp(URX_STO_INP_LOC, dataLoc);
971
91.9k
                fRXPat->fCompiledPat->setElementAt(op, saveStateLoc+1);
972
91.9k
                jmpOp      = buildOp(URX_JMP_SAV_X, saveStateLoc+2);
973
91.9k
            }
974
975
            // Locate the position in the compiled pattern where the match will continue
976
            //   after completing the *.   (4 or 5 in the comment above)
977
320k
            int32_t continueLoc = fRXPat->fCompiledPat->size()+1;
978
979
            // Put together the save state op and store it into the compiled code.
980
320k
            int32_t saveStateOp = buildOp(URX_STATE_SAVE, continueLoc);
981
320k
            fRXPat->fCompiledPat->setElementAt(saveStateOp, saveStateLoc);
982
983
            // Append the URX_JMP_SAV or URX_JMPX operation to the compiled pattern.
984
320k
            appendOp(jmpOp);
985
320k
        }
986
0
        break;
987
988
1.24k
    case doNGStar:
989
        // Non-greedy *? quantifier
990
        // compiles to
991
        //     1.   JMP    3
992
        //     2.      body of stuff being iterated over
993
        //     3.   STATE_SAVE  2
994
        //     4    ...
995
1.24k
        {
996
1.24k
            int32_t     jmpLoc  = blockTopLoc(true);                   // loc  1.
997
1.24k
            int32_t     saveLoc = fRXPat->fCompiledPat->size();        // loc  3.
998
1.24k
            int32_t     jmpOp   = buildOp(URX_JMP, saveLoc);
999
1.24k
            fRXPat->fCompiledPat->setElementAt(jmpOp, jmpLoc);
1000
1.24k
            appendOp(URX_STATE_SAVE, jmpLoc+1);
1001
1.24k
        }
1002
1.24k
        break;
1003
1004
1005
93.9k
    case doIntervalInit:
1006
        // The '{' opening an interval quantifier was just scanned.
1007
        // Init the counter variables that will accumulate the values as the digits
1008
        //    are scanned.
1009
93.9k
        fIntervalLow = 0;
1010
93.9k
        fIntervalUpper = -1;
1011
93.9k
        break;
1012
1013
99.7k
    case doIntevalLowerDigit:
1014
        // Scanned a digit from the lower value of an {lower,upper} interval
1015
99.7k
        {
1016
99.7k
            int32_t digitValue = u_charDigitValue(fC.fChar);
1017
99.7k
            U_ASSERT(digitValue >= 0);
1018
99.7k
            int64_t val = static_cast<int64_t>(fIntervalLow) * 10 + digitValue;
1019
99.7k
            if (val > INT32_MAX) {
1020
3
                error(U_REGEX_NUMBER_TOO_BIG);
1021
99.7k
            } else {
1022
99.7k
                fIntervalLow = static_cast<int32_t>(val);
1023
99.7k
            }
1024
99.7k
        }
1025
99.7k
        break;
1026
1027
75.3k
    case doIntervalUpperDigit:
1028
        // Scanned a digit from the upper value of an {lower,upper} interval
1029
75.3k
        {
1030
75.3k
            if (fIntervalUpper < 0) {
1031
73.3k
                fIntervalUpper = 0;
1032
73.3k
            }
1033
75.3k
            int32_t digitValue = u_charDigitValue(fC.fChar);
1034
75.3k
            U_ASSERT(digitValue >= 0);
1035
75.3k
            int64_t val = static_cast<int64_t>(fIntervalUpper) * 10 + digitValue;
1036
75.3k
            if (val > INT32_MAX) {
1037
12
                error(U_REGEX_NUMBER_TOO_BIG);
1038
75.3k
            } else {
1039
75.3k
                fIntervalUpper = static_cast<int32_t>(val);
1040
75.3k
            }
1041
75.3k
        }
1042
75.3k
        break;
1043
1044
18.8k
    case doIntervalSame:
1045
        // Scanned a single value interval like {27}.  Upper = Lower.
1046
18.8k
        fIntervalUpper = fIntervalLow;
1047
18.8k
        break;
1048
1049
88.2k
    case doInterval:
1050
        // Finished scanning a normal {lower,upper} interval.  Generate the code for it.
1051
88.2k
        if (compileInlineInterval() == false) {
1052
4.94k
            compileInterval(URX_CTR_INIT, URX_CTR_LOOP);
1053
4.94k
        }
1054
88.2k
        break;
1055
1056
2.75k
    case doPossessiveInterval:
1057
        // Finished scanning a Possessive {lower,upper}+ interval.  Generate the code for it.
1058
2.75k
        {
1059
            // Remember the loc for the top of the block being looped over.
1060
            //   (Can not reserve a slot in the compiled pattern at this time, because
1061
            //    compileInterval needs to reserve also, and blockTopLoc can only reserve
1062
            //    once per block.)
1063
2.75k
            int32_t topLoc = blockTopLoc(false);
1064
1065
            // Produce normal looping code.
1066
2.75k
            compileInterval(URX_CTR_INIT, URX_CTR_LOOP);
1067
1068
            // Surround the just-emitted normal looping code with a STO_SP ... LD_SP
1069
            //  just as if the loop was inclosed in atomic parentheses.
1070
1071
            // First the STO_SP before the start of the loop
1072
2.75k
            insertOp(topLoc);
1073
1074
2.75k
            int32_t  varLoc = allocateData(1);   // Reserve a data location for saving the
1075
2.75k
            int32_t  op     = buildOp(URX_STO_SP, varLoc);
1076
2.75k
            fRXPat->fCompiledPat->setElementAt(op, topLoc);
1077
1078
2.75k
            int32_t loopOp = static_cast<int32_t>(fRXPat->fCompiledPat->popi());
1079
2.75k
            U_ASSERT(URX_TYPE(loopOp) == URX_CTR_LOOP && URX_VAL(loopOp) == topLoc);
1080
2.75k
            loopOp++;     // point LoopOp after the just-inserted STO_SP
1081
2.75k
            fRXPat->fCompiledPat->push(loopOp, *fStatus);
1082
1083
            // Then the LD_SP after the end of the loop
1084
2.75k
            appendOp(URX_LD_SP, varLoc);
1085
2.75k
        }
1086
1087
2.75k
        break;
1088
1089
2.71k
    case doNGInterval:
1090
        // Finished scanning a non-greedy {lower,upper}? interval.  Generate the code for it.
1091
2.71k
        compileInterval(URX_CTR_INIT_NG, URX_CTR_LOOP_NG);
1092
2.71k
        break;
1093
1094
128
    case doIntervalError:
1095
128
        error(U_REGEX_BAD_INTERVAL);
1096
128
        break;
1097
1098
47.9M
    case doLiteralChar:
1099
        // We've just scanned a "normal" character from the pattern,
1100
47.9M
        literalChar(fC.fChar);
1101
47.9M
        break;
1102
1103
1104
17.4k
    case doEscapedLiteralChar:
1105
        // We've just scanned an backslashed escaped character with  no
1106
        //   special meaning.  It represents itself.
1107
17.4k
        if ((fModeFlags & UREGEX_ERROR_ON_UNKNOWN_ESCAPES) != 0 &&
1108
0
            ((fC.fChar >= 0x41 && fC.fChar<= 0x5A) ||     // in [A-Z]
1109
0
            (fC.fChar >= 0x61 && fC.fChar <= 0x7a))) {   // in [a-z]
1110
0
               error(U_REGEX_BAD_ESCAPE_SEQUENCE);
1111
0
             }
1112
17.4k
        literalChar(fC.fChar);
1113
17.4k
        break;
1114
1115
1116
480k
    case doDotAny:
1117
        // scanned a ".",  match any single character.
1118
480k
        {
1119
480k
            fixLiterals(false);
1120
480k
            if (fModeFlags & UREGEX_DOTALL) {
1121
8.10k
                appendOp(URX_DOTANY_ALL, 0);
1122
472k
            } else if (fModeFlags & UREGEX_UNIX_LINES) {
1123
9.96k
                appendOp(URX_DOTANY_UNIX, 0);
1124
462k
            } else {
1125
462k
                appendOp(URX_DOTANY, 0);
1126
462k
            }
1127
480k
        }
1128
480k
        break;
1129
1130
8.81k
    case doCaret:
1131
8.81k
        {
1132
8.81k
            fixLiterals(false);
1133
8.81k
            if (       (fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
1134
5.07k
                appendOp(URX_CARET, 0);
1135
5.07k
            } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
1136
1.80k
                appendOp(URX_CARET_M, 0);
1137
1.94k
            } else if ((fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
1138
550
                appendOp(URX_CARET, 0);   // Only testing true start of input.
1139
1.39k
            } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
1140
1.39k
                appendOp(URX_CARET_M_UNIX, 0);
1141
1.39k
            }
1142
8.81k
        }
1143
8.81k
        break;
1144
1145
111k
    case doDollar:
1146
111k
        {
1147
111k
            fixLiterals(false);
1148
111k
            if (       (fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
1149
77.6k
                appendOp(URX_DOLLAR, 0);
1150
77.6k
            } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
1151
1.90k
                appendOp(URX_DOLLAR_M, 0);
1152
31.9k
            } else if ((fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
1153
30.1k
                appendOp(URX_DOLLAR_D, 0);
1154
30.1k
            } else if ((fModeFlags & UREGEX_MULTILINE) != 0 && (fModeFlags & UREGEX_UNIX_LINES) != 0) {
1155
1.77k
                appendOp(URX_DOLLAR_MD, 0);
1156
1.77k
            }
1157
111k
        }
1158
111k
        break;
1159
1160
298
    case doBackslashA:
1161
298
        fixLiterals(false);
1162
298
        appendOp(URX_CARET, 0);
1163
298
        break;
1164
1165
6.58k
    case doBackslashB:
1166
6.58k
        {
1167
            #if  UCONFIG_NO_BREAK_ITERATION==1
1168
            if (fModeFlags & UREGEX_UWORD) {
1169
                error(U_UNSUPPORTED_ERROR);
1170
            }
1171
            #endif
1172
6.58k
            fixLiterals(false);
1173
6.58k
            int32_t op = (fModeFlags & UREGEX_UWORD)? URX_BACKSLASH_BU : URX_BACKSLASH_B;
1174
6.58k
            appendOp(op, 1);
1175
6.58k
        }
1176
6.58k
        break;
1177
1178
1.46k
    case doBackslashb:
1179
1.46k
        {
1180
            #if  UCONFIG_NO_BREAK_ITERATION==1
1181
            if (fModeFlags & UREGEX_UWORD) {
1182
                error(U_UNSUPPORTED_ERROR);
1183
            }
1184
            #endif
1185
1.46k
            fixLiterals(false);
1186
1.46k
            int32_t op = (fModeFlags & UREGEX_UWORD)? URX_BACKSLASH_BU : URX_BACKSLASH_B;
1187
1.46k
            appendOp(op, 0);
1188
1.46k
        }
1189
1.46k
        break;
1190
1191
4.00k
    case doBackslashD:
1192
4.00k
        fixLiterals(false);
1193
4.00k
        appendOp(URX_BACKSLASH_D, 1);
1194
4.00k
        break;
1195
1196
3.29k
    case doBackslashd:
1197
3.29k
        fixLiterals(false);
1198
3.29k
        appendOp(URX_BACKSLASH_D, 0);
1199
3.29k
        break;
1200
1201
1.42k
    case doBackslashG:
1202
1.42k
        fixLiterals(false);
1203
1.42k
        appendOp(URX_BACKSLASH_G, 0);
1204
1.42k
        break;
1205
1206
5.13k
    case doBackslashH:
1207
5.13k
        fixLiterals(false);
1208
5.13k
        appendOp(URX_BACKSLASH_H, 1);
1209
5.13k
        break;
1210
1211
1.31k
    case doBackslashh:
1212
1.31k
        fixLiterals(false);
1213
1.31k
        appendOp(URX_BACKSLASH_H, 0);
1214
1.31k
        break;
1215
1216
1.46k
    case doBackslashR:
1217
1.46k
        fixLiterals(false);
1218
1.46k
        appendOp(URX_BACKSLASH_R, 0);
1219
1.46k
        break;
1220
1221
9.33k
    case doBackslashS:
1222
9.33k
        fixLiterals(false);
1223
9.33k
        appendOp(URX_STAT_SETREF_N, URX_ISSPACE_SET);
1224
9.33k
        break;
1225
1226
11.0k
    case doBackslashs:
1227
11.0k
        fixLiterals(false);
1228
11.0k
        appendOp(URX_STATIC_SETREF, URX_ISSPACE_SET);
1229
11.0k
        break;
1230
1231
5.69k
    case doBackslashV:
1232
5.69k
        fixLiterals(false);
1233
5.69k
        appendOp(URX_BACKSLASH_V, 1);
1234
5.69k
        break;
1235
1236
1.37k
    case doBackslashv:
1237
1.37k
        fixLiterals(false);
1238
1.37k
        appendOp(URX_BACKSLASH_V, 0);
1239
1.37k
        break;
1240
1241
3.68k
    case doBackslashW:
1242
3.68k
        fixLiterals(false);
1243
3.68k
        appendOp(URX_STAT_SETREF_N, URX_ISWORD_SET);
1244
3.68k
        break;
1245
1246
3.70k
    case doBackslashw:
1247
3.70k
        fixLiterals(false);
1248
3.70k
        appendOp(URX_STATIC_SETREF, URX_ISWORD_SET);
1249
3.70k
        break;
1250
1251
5.92k
    case doBackslashX:
1252
        #if  UCONFIG_NO_BREAK_ITERATION==1
1253
        // Grapheme Cluster Boundary requires ICU break iteration.
1254
        error(U_UNSUPPORTED_ERROR);
1255
        #endif
1256
5.92k
        fixLiterals(false);
1257
5.92k
        appendOp(URX_BACKSLASH_X, 0);
1258
5.92k
        break;
1259
1260
558
    case doBackslashZ:
1261
558
        fixLiterals(false);
1262
558
        appendOp(URX_DOLLAR, 0);
1263
558
        break;
1264
1265
3.66k
    case doBackslashz:
1266
3.66k
        fixLiterals(false);
1267
3.66k
        appendOp(URX_BACKSLASH_Z, 0);
1268
3.66k
        break;
1269
1270
56
    case doEscapeError:
1271
56
        error(U_REGEX_BAD_ESCAPE_SEQUENCE);
1272
56
        break;
1273
1274
0
    case doExit:
1275
0
        fixLiterals(false);
1276
0
        returnVal = false;
1277
0
        break;
1278
1279
1.67k
    case doProperty:
1280
1.67k
        {
1281
1.67k
            fixLiterals(false);
1282
1.67k
            UnicodeSet *theSet = scanProp();
1283
1.67k
            compileSet(theSet);
1284
1.67k
        }
1285
1.67k
        break;
1286
1287
1.54k
    case doNamedChar:
1288
1.54k
        {
1289
1.54k
            UChar32 c = scanNamedChar();
1290
1.54k
            literalChar(c);
1291
1.54k
        }
1292
1.54k
        break;
1293
1294
1295
8.65k
    case doBackRef:
1296
        // BackReference.  Somewhat unusual in that the front-end can not completely parse
1297
        //                 the regular expression, because the number of digits to be consumed
1298
        //                 depends on the number of capture groups that have been defined.  So
1299
        //                 we have to do it here instead.
1300
8.65k
        {
1301
8.65k
            int32_t  numCaptureGroups = fRXPat->fGroupMap->size();
1302
8.65k
            int32_t  groupNum = 0;
1303
8.65k
            UChar32  c        = fC.fChar;
1304
1305
9.38k
            for (;;) {
1306
                // Loop once per digit, for max allowed number of digits in a back reference.
1307
9.38k
                int32_t digit = u_charDigitValue(c);
1308
9.38k
                groupNum = groupNum * 10 + digit;
1309
9.38k
                if (groupNum >= numCaptureGroups) {
1310
3.45k
                    break;
1311
3.45k
                }
1312
5.92k
                c = peekCharLL();
1313
5.92k
                if (RegexStaticSets::gStaticSets->fRuleDigitsAlias->contains(c) == false) {
1314
5.19k
                    break;
1315
5.19k
                }
1316
732
                nextCharLL();
1317
732
            }
1318
1319
            // Scan of the back reference in the source regexp is complete.  Now generate
1320
            //  the compiled code for it.
1321
            // Because capture groups can be forward-referenced by back-references,
1322
            //  we fill the operand with the capture group number.  At the end
1323
            //  of compilation, it will be changed to the variable's location.
1324
8.65k
            U_ASSERT(groupNum > 0);  // Shouldn't happen.  '\0' begins an octal escape sequence,
1325
                                     //    and shouldn't enter this code path at all.
1326
8.65k
            fixLiterals(false);
1327
8.65k
            if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
1328
5.16k
                appendOp(URX_BACKREF_I, groupNum);
1329
5.16k
            } else {
1330
3.48k
                appendOp(URX_BACKREF, groupNum);
1331
3.48k
            }
1332
8.65k
        }
1333
8.65k
        break;
1334
1335
978
    case doBeginNamedBackRef:
1336
978
        U_ASSERT(fCaptureName == nullptr);
1337
978
        fCaptureName = new UnicodeString;
1338
978
        if (fCaptureName == nullptr) {
1339
0
            error(U_MEMORY_ALLOCATION_ERROR);
1340
0
        }
1341
978
        break;
1342
            
1343
2.24k
    case doContinueNamedBackRef:
1344
2.24k
        fCaptureName->append(fC.fChar);
1345
2.24k
        break;
1346
1347
958
    case doCompleteNamedBackRef:
1348
958
        {
1349
958
        int32_t groupNumber =
1350
958
            fRXPat->fNamedCaptureMap ? uhash_geti(fRXPat->fNamedCaptureMap, fCaptureName) : 0;
1351
958
        if (groupNumber == 0) {
1352
            // Group name has not been defined.
1353
            //   Could be a forward reference. If we choose to support them at some
1354
            //   future time, extra mechanism will be required at this point.
1355
34
            error(U_REGEX_INVALID_CAPTURE_GROUP_NAME);
1356
924
        } else {
1357
            // Given the number, handle identically to a \n numbered back reference.
1358
            // See comments above, under doBackRef
1359
924
            fixLiterals(false);
1360
924
            if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
1361
409
                appendOp(URX_BACKREF_I, groupNumber);
1362
515
            } else {
1363
515
                appendOp(URX_BACKREF, groupNumber);
1364
515
            }
1365
924
        }
1366
958
        delete fCaptureName;
1367
958
        fCaptureName = nullptr;
1368
958
        break;
1369
334k
        }
1370
       
1371
775
    case doPossessivePlus:
1372
        // Possessive ++ quantifier.
1373
        // Compiles to
1374
        //       1.   STO_SP
1375
        //       2.      body of stuff being iterated over
1376
        //       3.   STATE_SAVE 5
1377
        //       4.   JMP        2
1378
        //       5.   LD_SP
1379
        //       6.   ...
1380
        //
1381
        //  Note:  TODO:  This is pretty inefficient.  A mass of saved state is built up
1382
        //                then unconditionally discarded.  Perhaps introduce a new opcode.  Ticket 6056
1383
        //
1384
775
        {
1385
            // Emit the STO_SP
1386
775
            int32_t   topLoc = blockTopLoc(true);
1387
775
            int32_t   stoLoc = allocateData(1);  // Reserve the data location for storing save stack ptr.
1388
775
            int32_t   op     = buildOp(URX_STO_SP, stoLoc);
1389
775
            fRXPat->fCompiledPat->setElementAt(op, topLoc);
1390
1391
            // Emit the STATE_SAVE
1392
775
            appendOp(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+2);
1393
1394
            // Emit the JMP
1395
775
            appendOp(URX_JMP, topLoc+1);
1396
1397
            // Emit the LD_SP
1398
775
            appendOp(URX_LD_SP, stoLoc);
1399
775
        }
1400
775
        break;
1401
1402
21.6k
    case doPossessiveStar:
1403
        // Possessive *+ quantifier.
1404
        // Compiles to
1405
        //       1.   STO_SP       loc
1406
        //       2.   STATE_SAVE   5
1407
        //       3.      body of stuff being iterated over
1408
        //       4.   JMP          2
1409
        //       5.   LD_SP        loc
1410
        //       6    ...
1411
        // TODO:  do something to cut back the state stack each time through the loop.
1412
21.6k
        {
1413
            // Reserve two slots at the top of the block.
1414
21.6k
            int32_t   topLoc = blockTopLoc(true);
1415
21.6k
            insertOp(topLoc);
1416
1417
            // emit   STO_SP     loc
1418
21.6k
            int32_t   stoLoc = allocateData(1);    // Reserve the data location for storing save stack ptr.
1419
21.6k
            int32_t   op     = buildOp(URX_STO_SP, stoLoc);
1420
21.6k
            fRXPat->fCompiledPat->setElementAt(op, topLoc);
1421
1422
            // Emit the SAVE_STATE   5
1423
21.6k
            int32_t L7 = fRXPat->fCompiledPat->size()+1;
1424
21.6k
            op = buildOp(URX_STATE_SAVE, L7);
1425
21.6k
            fRXPat->fCompiledPat->setElementAt(op, topLoc+1);
1426
1427
            // Append the JMP operation.
1428
21.6k
            appendOp(URX_JMP, topLoc+1);
1429
1430
            // Emit the LD_SP       loc
1431
21.6k
            appendOp(URX_LD_SP, stoLoc);
1432
21.6k
        }
1433
21.6k
        break;
1434
1435
30.7k
    case doPossessiveOpt:
1436
        // Possessive  ?+ quantifier.
1437
        //  Compiles to
1438
        //     1. STO_SP      loc
1439
        //     2. SAVE_STATE  5
1440
        //     3.    body of optional block
1441
        //     4. LD_SP       loc
1442
        //     5. ...
1443
        //
1444
30.7k
        {
1445
            // Reserve two slots at the top of the block.
1446
30.7k
            int32_t   topLoc = blockTopLoc(true);
1447
30.7k
            insertOp(topLoc);
1448
1449
            // Emit the STO_SP
1450
30.7k
            int32_t   stoLoc = allocateData(1);   // Reserve the data location for storing save stack ptr.
1451
30.7k
            int32_t   op     = buildOp(URX_STO_SP, stoLoc);
1452
30.7k
            fRXPat->fCompiledPat->setElementAt(op, topLoc);
1453
1454
            // Emit the SAVE_STATE
1455
30.7k
            int32_t   continueLoc = fRXPat->fCompiledPat->size()+1;
1456
30.7k
            op = buildOp(URX_STATE_SAVE, continueLoc);
1457
30.7k
            fRXPat->fCompiledPat->setElementAt(op, topLoc+1);
1458
1459
            // Emit the LD_SP
1460
30.7k
            appendOp(URX_LD_SP, stoLoc);
1461
30.7k
        }
1462
30.7k
        break;
1463
1464
1465
15.3k
    case doBeginMatchMode:
1466
15.3k
        fNewModeFlags = fModeFlags;
1467
15.3k
        fSetModeFlag  = true;
1468
15.3k
        break;
1469
1470
18.3k
    case doMatchMode:   //  (?i)    and similar
1471
18.3k
        {
1472
18.3k
            int32_t  bit = 0;
1473
18.3k
            switch (fC.fChar) {
1474
5.46k
            case 0x69: /* 'i' */   bit = UREGEX_CASE_INSENSITIVE; break;
1475
1.00k
            case 0x64: /* 'd' */   bit = UREGEX_UNIX_LINES;       break;
1476
1.81k
            case 0x6d: /* 'm' */   bit = UREGEX_MULTILINE;        break;
1477
705
            case 0x73: /* 's' */   bit = UREGEX_DOTALL;           break;
1478
112
            case 0x75: /* 'u' */   bit = 0; /* Unicode casing */  break;
1479
3.39k
            case 0x77: /* 'w' */   bit = UREGEX_UWORD;            break;
1480
4.74k
            case 0x78: /* 'x' */   bit = UREGEX_COMMENTS;         break;
1481
1.08k
            case 0x2d: /* '-' */   fSetModeFlag = false;          break;
1482
0
            default:
1483
0
                UPRV_UNREACHABLE_EXIT;  // Should never happen.  Other chars are filtered out
1484
                                        // by the scanner.
1485
18.3k
            }
1486
18.3k
            if (fSetModeFlag) {
1487
16.3k
                fNewModeFlags |= bit;
1488
16.3k
            } else {
1489
1.95k
                fNewModeFlags &= ~bit;
1490
1.95k
            }
1491
18.3k
        }
1492
0
        break;
1493
1494
10.3k
    case doSetMatchMode:
1495
        // Emit code to match any pending literals, using the not-yet changed match mode.
1496
10.3k
        fixLiterals();
1497
1498
        // We've got a (?i) or similar.  The match mode is being changed, but
1499
        //   the change is not scoped to a parenthesized block.
1500
10.3k
        U_ASSERT(fNewModeFlags < 0);
1501
10.3k
        fModeFlags = fNewModeFlags;
1502
1503
10.3k
        break;
1504
1505
1506
4.95k
    case doMatchModeParen:
1507
        // We've got a (?i: or similar.  Begin a parenthesized block, save old
1508
        //   mode flags so they can be restored at the close of the block.
1509
        //
1510
        //   Compile to a
1511
        //      - NOP, which later may be replaced by a save-state if the
1512
        //         parenthesized group gets a * quantifier, followed by
1513
        //      - NOP, which may later be replaced by a save-state if there
1514
        //             is an '|' alternation within the parens.
1515
4.95k
        {
1516
4.95k
            fixLiterals(false);
1517
4.95k
            appendOp(URX_NOP, 0);
1518
4.95k
            appendOp(URX_NOP, 0);
1519
1520
            // On the Parentheses stack, start a new frame and add the positions
1521
            //   of the two NOPs (a normal non-capturing () frame, except for the
1522
            //   saving of the original mode flags.)
1523
4.95k
            fParenStack.push(fModeFlags, *fStatus);
1524
4.95k
            fParenStack.push(flags, *fStatus);                            // Frame Marker
1525
4.95k
            fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The first NOP
1526
4.95k
            fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP
1527
1528
            // Set the current mode flags to the new values.
1529
4.95k
            U_ASSERT(fNewModeFlags < 0);
1530
4.95k
            fModeFlags = fNewModeFlags;
1531
4.95k
        }
1532
4.95k
        break;
1533
1534
112
    case doBadModeFlag:
1535
112
        error(U_REGEX_INVALID_FLAG);
1536
112
        break;
1537
1538
30.0k
    case doSuppressComments:
1539
        // We have just scanned a '(?'.  We now need to prevent the character scanner from
1540
        // treating a '#' as a to-the-end-of-line comment.
1541
        //   (This Perl compatibility just gets uglier and uglier to do...)
1542
30.0k
        fEOLComments = false;
1543
30.0k
        break;
1544
1545
1546
1.42k
    case doSetAddAmp:
1547
1.42k
        {
1548
1.42k
          UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1549
1.42k
          set->add(chAmp);
1550
1.42k
        }
1551
1.42k
        break;
1552
1553
1.41k
    case doSetAddDash:
1554
1.41k
        {
1555
1.41k
          UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1556
1.41k
          set->add(chDash);
1557
1.41k
        }
1558
1.41k
        break;
1559
1560
586
     case doSetBackslash_s:
1561
586
        {
1562
586
         UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1563
586
         set->addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]);
1564
586
         break;
1565
18.3k
        }
1566
1567
4.00k
     case doSetBackslash_S:
1568
4.00k
        {
1569
4.00k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1570
4.00k
            UnicodeSet SSet;
1571
4.00k
            SSet.addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISSPACE_SET]).complement();
1572
4.00k
            set->addAll(SSet);
1573
4.00k
            break;
1574
18.3k
        }
1575
1576
917
    case doSetBackslash_d:
1577
917
        {
1578
917
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1579
            // TODO - make a static set, ticket 6058.
1580
917
            addCategory(set, U_GC_ND_MASK, *fStatus);
1581
917
            break;
1582
18.3k
        }
1583
1584
10.3k
    case doSetBackslash_D:
1585
10.3k
        {
1586
10.3k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1587
10.3k
            UnicodeSet digits;
1588
            // TODO - make a static set, ticket 6058.
1589
10.3k
            digits.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ND_MASK, *fStatus);
1590
10.3k
            digits.complement();
1591
10.3k
            set->addAll(digits);
1592
10.3k
            break;
1593
18.3k
        }
1594
1595
1.60k
    case doSetBackslash_h:
1596
1.60k
        {
1597
1.60k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1598
1.60k
            UnicodeSet h;
1599
1.60k
            h.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ZS_MASK, *fStatus);
1600
1.60k
            h.add(static_cast<UChar32>(9)); // Tab
1601
1.60k
            set->addAll(h);
1602
1.60k
            break;
1603
18.3k
        }
1604
1605
1.91k
    case doSetBackslash_H:
1606
1.91k
        {
1607
1.91k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1608
1.91k
            UnicodeSet h;
1609
1.91k
            h.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ZS_MASK, *fStatus);
1610
1.91k
            h.add(static_cast<UChar32>(9)); // Tab
1611
1.91k
            h.complement();
1612
1.91k
            set->addAll(h);
1613
1.91k
            break;
1614
18.3k
        }
1615
1616
1.53k
    case doSetBackslash_v:
1617
1.53k
        {
1618
1.53k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1619
1.53k
            set->add(static_cast<UChar32>(0x0a), static_cast<UChar32>(0x0d)); // add range
1620
1.53k
            set->add(static_cast<UChar32>(0x85));
1621
1.53k
            set->add(static_cast<UChar32>(0x2028), static_cast<UChar32>(0x2029));
1622
1.53k
            break;
1623
18.3k
        }
1624
1625
638
    case doSetBackslash_V:
1626
638
        {
1627
638
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1628
638
            UnicodeSet v;
1629
638
            v.add(static_cast<UChar32>(0x0a), static_cast<UChar32>(0x0d)); // add range
1630
638
            v.add(static_cast<UChar32>(0x85));
1631
638
            v.add(static_cast<UChar32>(0x2028), static_cast<UChar32>(0x2029));
1632
638
            v.complement();
1633
638
            set->addAll(v);
1634
638
            break;
1635
18.3k
        }
1636
1637
1.71k
    case doSetBackslash_w:
1638
1.71k
        {
1639
1.71k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1640
1.71k
            set->addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]);
1641
1.71k
            break;
1642
18.3k
        }
1643
1644
17.3k
    case doSetBackslash_W:
1645
17.3k
        {
1646
17.3k
            UnicodeSet* set = static_cast<UnicodeSet*>(fSetStack.peek());
1647
17.3k
            UnicodeSet SSet;
1648
17.3k
            SSet.addAll(RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET]).complement();
1649
17.3k
            set->addAll(SSet);
1650
17.3k
            break;
1651
18.3k
        }
1652
1653
271k
    case doSetBegin:
1654
271k
        {
1655
271k
            fixLiterals(false);
1656
271k
            LocalPointer<UnicodeSet> lpSet(new UnicodeSet(), *fStatus);
1657
271k
            fSetStack.push(lpSet.orphan(), *fStatus);
1658
271k
            fSetOpStack.push(setStart, *fStatus);
1659
271k
            if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
1660
217k
                fSetOpStack.push(setCaseClose, *fStatus);
1661
217k
            }
1662
271k
            break;
1663
18.3k
        }
1664
1665
1.37k
    case doSetBeginDifference1:
1666
        //  We have scanned something like [[abc]-[
1667
        //  Set up a new UnicodeSet for the set beginning with the just-scanned '['
1668
        //  Push a Difference operator, which will cause the new set to be subtracted from what
1669
        //    went before once it is created.
1670
1.37k
        setPushOp(setDifference1);
1671
1.37k
        fSetOpStack.push(setStart, *fStatus);
1672
1.37k
        if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
1673
772
            fSetOpStack.push(setCaseClose, *fStatus);
1674
772
        }
1675
1.37k
        break;
1676
1677
1.20k
    case doSetBeginIntersection1:
1678
        //  We have scanned something like  [[abc]&[
1679
        //   Need both the '&' operator and the open '[' operator.
1680
1.20k
        setPushOp(setIntersection1);
1681
1.20k
        fSetOpStack.push(setStart, *fStatus);
1682
1.20k
        if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
1683
787
            fSetOpStack.push(setCaseClose, *fStatus);
1684
787
        }
1685
1.20k
        break;
1686
1687
67.9k
    case doSetBeginUnion:
1688
        //  We have scanned something like  [[abc][
1689
        //     Need to handle the union operation explicitly [[abc] | [
1690
67.9k
        setPushOp(setUnion);
1691
67.9k
        fSetOpStack.push(setStart, *fStatus);
1692
67.9k
        if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
1693
44.3k
            fSetOpStack.push(setCaseClose, *fStatus);
1694
44.3k
        }
1695
67.9k
        break;
1696
1697
1.58k
    case doSetDifference2:
1698
        // We have scanned something like [abc--
1699
        //   Consider this to unambiguously be a set difference operator.
1700
1.58k
        setPushOp(setDifference2);
1701
1.58k
        break;
1702
1703
328k
    case doSetEnd:
1704
        // Have encountered the ']' that closes a set.
1705
        //    Force the evaluation of any pending operations within this set,
1706
        //    leave the completed set on the top of the set stack.
1707
328k
        setEval(setEnd);
1708
328k
        U_ASSERT(fSetOpStack.peeki()==setStart);
1709
328k
        fSetOpStack.popi();
1710
328k
        break;
1711
1712
267k
    case doSetFinish:
1713
267k
        {
1714
        // Finished a complete set expression, including all nested sets.
1715
        //   The close bracket has already triggered clearing out pending set operators,
1716
        //    the operator stack should be empty and the operand stack should have just
1717
        //    one entry, the result set.
1718
267k
        U_ASSERT(fSetOpStack.empty());
1719
267k
        UnicodeSet* theSet = static_cast<UnicodeSet*>(fSetStack.pop());
1720
267k
        U_ASSERT(fSetStack.empty());
1721
267k
        compileSet(theSet);
1722
267k
        break;
1723
18.3k
        }
1724
1725
6.27k
    case doSetIntersection2:
1726
        // Have scanned something like [abc&&
1727
6.27k
        setPushOp(setIntersection2);
1728
6.27k
        break;
1729
1730
13.0M
    case doSetLiteral:
1731
        // Union the just-scanned literal character into the set being built.
1732
        //    This operation is the highest precedence set operation, so we can always do
1733
        //    it immediately, without waiting to see what follows.  It is necessary to perform
1734
        //    any pending '-' or '&' operation first, because these have the same precedence
1735
        //    as union-ing in a literal'
1736
13.0M
        {
1737
13.0M
            setEval(setUnion);
1738
13.0M
            UnicodeSet* s = static_cast<UnicodeSet*>(fSetStack.peek());
1739
13.0M
            s->add(fC.fChar);
1740
13.0M
            fLastSetLiteral = fC.fChar;
1741
13.0M
            break;
1742
18.3k
        }
1743
1744
24.6k
    case doSetLiteralEscaped:
1745
        // A back-slash escaped literal character was encountered.
1746
        // Processing is the same as with setLiteral, above, with the addition of
1747
        //  the optional check for errors on escaped ASCII letters.
1748
24.6k
        {
1749
24.6k
            if ((fModeFlags & UREGEX_ERROR_ON_UNKNOWN_ESCAPES) != 0 &&
1750
0
                ((fC.fChar >= 0x41 && fC.fChar<= 0x5A) ||     // in [A-Z]
1751
0
                 (fC.fChar >= 0x61 && fC.fChar <= 0x7a))) {   // in [a-z]
1752
0
                error(U_REGEX_BAD_ESCAPE_SEQUENCE);
1753
0
            }
1754
24.6k
            setEval(setUnion);
1755
24.6k
            UnicodeSet* s = static_cast<UnicodeSet*>(fSetStack.peek());
1756
24.6k
            s->add(fC.fChar);
1757
24.6k
            fLastSetLiteral = fC.fChar;
1758
24.6k
            break;
1759
18.3k
        }
1760
1761
4.18k
        case doSetNamedChar:
1762
        // Scanning a \N{UNICODE CHARACTER NAME}
1763
        //  Aside from the source of the character, the processing is identical to doSetLiteral,
1764
        //    above.
1765
4.18k
        {
1766
4.18k
            UChar32  c = scanNamedChar();
1767
4.18k
            setEval(setUnion);
1768
4.18k
            UnicodeSet* s = static_cast<UnicodeSet*>(fSetStack.peek());
1769
4.18k
            s->add(c);
1770
4.18k
            fLastSetLiteral = c;
1771
4.18k
            break;
1772
18.3k
        }
1773
1774
764
    case doSetNamedRange:
1775
        // We have scanned literal-\N{CHAR NAME}.  Add the range to the set.
1776
        // The left character is already in the set, and is saved in fLastSetLiteral.
1777
        // The right side needs to be picked up, the scan is at the 'N'.
1778
        // Lower Limit > Upper limit being an error matches both Java
1779
        //        and ICU UnicodeSet behavior.
1780
764
        {
1781
764
            UChar32  c = scanNamedChar();
1782
764
            if (U_SUCCESS(*fStatus) && (fLastSetLiteral == U_SENTINEL || fLastSetLiteral > c)) {
1783
18
                error(U_REGEX_INVALID_RANGE);
1784
18
            }
1785
764
            UnicodeSet* s = static_cast<UnicodeSet*>(fSetStack.peek());
1786
764
            s->add(fLastSetLiteral, c);
1787
764
            fLastSetLiteral = c;
1788
764
            break;
1789
18.3k
        }
1790
1791
1792
8.91k
    case  doSetNegate:
1793
        // Scanned a '^' at the start of a set.
1794
        // Push the negation operator onto the set op stack.
1795
        // A twist for case-insensitive matching:
1796
        //   the case closure operation must happen _before_ negation.
1797
        //   But the case closure operation will already be on the stack if it's required.
1798
        //   This requires checking for case closure, and swapping the stack order
1799
        //    if it is present.
1800
8.91k
        {
1801
8.91k
            int32_t  tosOp = fSetOpStack.peeki();
1802
8.91k
            if (tosOp == setCaseClose) {
1803
6.71k
                fSetOpStack.popi();
1804
6.71k
                fSetOpStack.push(setNegation, *fStatus);
1805
6.71k
                fSetOpStack.push(setCaseClose, *fStatus);
1806
6.71k
            } else {
1807
2.19k
                fSetOpStack.push(setNegation, *fStatus);
1808
2.19k
            }
1809
8.91k
        }
1810
8.91k
        break;
1811
1812
2.02k
    case doSetNoCloseError:
1813
2.02k
        error(U_REGEX_MISSING_CLOSE_BRACKET);
1814
2.02k
        break;
1815
1816
2
    case doSetOpError:
1817
2
        error(U_REGEX_RULE_SYNTAX);   //  -- or && at the end of a set.  Illegal.
1818
2
        break;
1819
1820
109k
    case doSetPosixProp:
1821
109k
        {
1822
109k
            UnicodeSet *s = scanPosixProp();
1823
109k
            if (s != nullptr) {
1824
75.9k
                UnicodeSet* tos = static_cast<UnicodeSet*>(fSetStack.peek());
1825
75.9k
                tos->addAll(*s);
1826
75.9k
                delete s;
1827
75.9k
            }  // else error.  scanProp() reported the error status already.
1828
109k
        }
1829
109k
        break;
1830
1831
1.68k
    case doSetProp:
1832
        //  Scanned a \p \P within [brackets].
1833
1.68k
        {
1834
1.68k
            UnicodeSet *s = scanProp();
1835
1.68k
            if (s != nullptr) {
1836
1.67k
                UnicodeSet* tos = static_cast<UnicodeSet*>(fSetStack.peek());
1837
1.67k
                tos->addAll(*s);
1838
1.67k
                delete s;
1839
1.67k
            }  // else error.  scanProp() reported the error status already.
1840
1.68k
        }
1841
1.68k
        break;
1842
1843
1844
12.9k
    case doSetRange:
1845
        // We have scanned literal-literal.  Add the range to the set.
1846
        // The left character is already in the set, and is saved in fLastSetLiteral.
1847
        // The right side is the current character.
1848
        // Lower Limit > Upper limit being an error matches both Java
1849
        //        and ICU UnicodeSet behavior.
1850
12.9k
        {
1851
1852
12.9k
        if (fLastSetLiteral == U_SENTINEL || fLastSetLiteral > fC.fChar) {
1853
83
            error(U_REGEX_INVALID_RANGE);
1854
83
        }
1855
12.9k
        UnicodeSet* s = static_cast<UnicodeSet*>(fSetStack.peek());
1856
12.9k
        s->add(fLastSetLiteral, fC.fChar);
1857
12.9k
        break;
1858
18.3k
        }
1859
1860
0
    default:
1861
0
        UPRV_UNREACHABLE_EXIT;
1862
183M
    }
1863
1864
183M
    if (U_FAILURE(*fStatus)) {
1865
7.74k
        returnVal = false;
1866
7.74k
    }
1867
1868
183M
    return returnVal;
1869
183M
}
1870
1871
1872
1873
//------------------------------------------------------------------------------
1874
//
1875
//   literalChar           We've encountered a literal character from the pattern,
1876
//                             or an escape sequence that reduces to a character.
1877
//                         Add it to the string containing all literal chars/strings from
1878
//                             the pattern.
1879
//
1880
//------------------------------------------------------------------------------
1881
48.3M
void RegexCompile::literalChar(UChar32 c)  {
1882
48.3M
    fLiteralChars.append(c);
1883
48.3M
}
1884
1885
1886
//------------------------------------------------------------------------------
1887
//
1888
//    fixLiterals           When compiling something that can follow a literal
1889
//                          string in a pattern, emit the code to match the
1890
//                          accumulated literal string.
1891
//
1892
//                          Optionally, split the last char of the string off into
1893
//                          a single "ONE_CHAR" operation, so that quantifiers can
1894
//                          apply to that char alone.  Example:   abc*
1895
//                          The * must apply to the 'c' only.
1896
//
1897
//------------------------------------------------------------------------------
1898
23.8M
void    RegexCompile::fixLiterals(UBool split) {
1899
1900
    // If no literal characters have been scanned but not yet had code generated
1901
    //   for them, nothing needs to be done.
1902
23.8M
    if (fLiteralChars.length() == 0) {
1903
21.4M
        return;
1904
21.4M
    }
1905
1906
2.38M
    int32_t indexOfLastCodePoint = fLiteralChars.moveIndex32(fLiteralChars.length(), -1);
1907
2.38M
    UChar32 lastCodePoint = fLiteralChars.char32At(indexOfLastCodePoint);
1908
1909
    // Split:  We need to  ensure that the last item in the compiled pattern
1910
    //     refers only to the last literal scanned in the pattern, so that
1911
    //     quantifiers (*, +, etc.) affect only it, and not a longer string.
1912
    //     Split before case folding for case insensitive matches.
1913
1914
2.38M
    if (split) {
1915
406k
        fLiteralChars.truncate(indexOfLastCodePoint);
1916
406k
        fixLiterals(false);   // Recursive call, emit code to match the first part of the string.
1917
                              //  Note that the truncated literal string may be empty, in which case
1918
                              //  nothing will be emitted.
1919
1920
406k
        literalChar(lastCodePoint);  // Re-add the last code point as if it were a new literal.
1921
406k
        fixLiterals(false);          // Second recursive call, code for the final code point.
1922
406k
        return;
1923
406k
    }
1924
1925
    // If we are doing case-insensitive matching, case fold the string.  This may expand
1926
    //   the string, e.g. the German sharp-s turns into "ss"
1927
1.98M
    if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
1928
1.66M
        fLiteralChars.foldCase();
1929
1.66M
        indexOfLastCodePoint = fLiteralChars.moveIndex32(fLiteralChars.length(), -1);
1930
1.66M
        lastCodePoint = fLiteralChars.char32At(indexOfLastCodePoint);
1931
1.66M
    }
1932
1933
1.98M
    if (indexOfLastCodePoint == 0) {
1934
        // Single character, emit a URX_ONECHAR op to match it.
1935
481k
        if ((fModeFlags & UREGEX_CASE_INSENSITIVE) &&
1936
292k
                 u_hasBinaryProperty(lastCodePoint, UCHAR_CASE_SENSITIVE)) {
1937
26.3k
            appendOp(URX_ONECHAR_I, lastCodePoint);
1938
455k
        } else {
1939
455k
            appendOp(URX_ONECHAR, lastCodePoint);
1940
455k
        }
1941
1.50M
    } else {
1942
        // Two or more chars, emit a URX_STRING to match them.
1943
1.50M
        if (fLiteralChars.length() > 0x00ffffff || fRXPat->fLiteralText.length() > 0x00ffffff) {
1944
0
            error(U_REGEX_PATTERN_TOO_BIG);
1945
0
        }
1946
1.50M
        if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
1947
1.37M
            appendOp(URX_STRING_I, fRXPat->fLiteralText.length());
1948
1.37M
        } else {
1949
            // TODO here:  add optimization to split case sensitive strings of length two
1950
            //             into two single char ops, for efficiency.
1951
128k
            appendOp(URX_STRING, fRXPat->fLiteralText.length());
1952
128k
        }
1953
1.50M
        appendOp(URX_STRING_LEN, fLiteralChars.length());
1954
1955
        // Add this string into the accumulated strings of the compiled pattern.
1956
1.50M
        fRXPat->fLiteralText.append(fLiteralChars);
1957
1.50M
    }
1958
1959
1.98M
    fLiteralChars.remove();
1960
1.98M
}
1961
1962
1963
102M
int32_t RegexCompile::buildOp(int32_t type, int32_t val) {
1964
102M
    if (U_FAILURE(*fStatus)) {
1965
481k
        return 0;
1966
481k
    }
1967
102M
    if (type < 0 || type > 255) {
1968
0
        UPRV_UNREACHABLE_EXIT;
1969
0
    }
1970
102M
    if (val > 0x00ffffff) {
1971
0
        UPRV_UNREACHABLE_EXIT;
1972
0
    }
1973
102M
    if (val < 0) {
1974
0
        if (!(type == URX_RESERVED_OP_N || type == URX_RESERVED_OP)) {
1975
0
            UPRV_UNREACHABLE_EXIT;
1976
0
        }
1977
0
        if (URX_TYPE(val) != 0xff) {
1978
0
            UPRV_UNREACHABLE_EXIT;
1979
0
        }
1980
0
        type = URX_RESERVED_OP_N;
1981
0
    }
1982
102M
    return (type << 24) | val;
1983
102M
}
1984
1985
1986
//------------------------------------------------------------------------------
1987
//
1988
//   appendOp()             Append a new instruction onto the compiled pattern
1989
//                          Includes error checking, limiting the size of the
1990
//                          pattern to lengths that can be represented in the
1991
//                          24 bit operand field of an instruction.
1992
//
1993
//------------------------------------------------------------------------------
1994
48.5M
void RegexCompile::appendOp(int32_t op) {
1995
48.5M
    if (U_FAILURE(*fStatus)) {
1996
2.38k
        return;
1997
2.38k
    }
1998
48.5M
    fRXPat->fCompiledPat->addElement(op, *fStatus);
1999
48.5M
    if ((fRXPat->fCompiledPat->size() > 0x00fffff0) && U_SUCCESS(*fStatus)) {
2000
0
        error(U_REGEX_PATTERN_TOO_BIG);
2001
0
    }
2002
48.5M
}
2003
2004
46.9M
void RegexCompile::appendOp(int32_t type, int32_t val) {
2005
46.9M
    appendOp(buildOp(type, val));
2006
46.9M
}
2007
2008
2009
//------------------------------------------------------------------------------
2010
//
2011
//   insertOp()             Insert a slot for a new opcode into the already
2012
//                          compiled pattern code.
2013
//
2014
//                          Fill the slot with a NOP.  Our caller will replace it
2015
//                          with what they really wanted.
2016
//
2017
//------------------------------------------------------------------------------
2018
251k
void   RegexCompile::insertOp(int32_t where) {
2019
251k
    UVector64 *code = fRXPat->fCompiledPat;
2020
251k
    U_ASSERT(where>0 && where < code->size());
2021
2022
251k
    int32_t  nop = buildOp(URX_NOP, 0);
2023
251k
    code->insertElementAt(nop, where, *fStatus);
2024
2025
    // Walk through the pattern, looking for any ops with targets that
2026
    //  were moved down by the insert.  Fix them.
2027
251k
    int32_t loc;
2028
5.36G
    for (loc=0; loc<code->size(); loc++) {
2029
5.36G
        int32_t op = static_cast<int32_t>(code->elementAti(loc));
2030
5.36G
        int32_t opType = URX_TYPE(op);
2031
5.36G
        int32_t opValue = URX_VAL(op);
2032
5.36G
        if ((opType == URX_JMP         ||
2033
4.67G
            opType == URX_JMPX         ||
2034
4.67G
            opType == URX_STATE_SAVE   ||
2035
2.83G
            opType == URX_CTR_LOOP     ||
2036
2.83G
            opType == URX_CTR_LOOP_NG  ||
2037
2.83G
            opType == URX_JMP_SAV      ||
2038
2.78G
            opType == URX_JMP_SAV_X    ||
2039
2.69G
            opType == URX_RELOC_OPRND)    && opValue > where) {
2040
            // Target location for this opcode is after the insertion point and
2041
            //   needs to be incremented to adjust for the insertion.
2042
9.52M
            opValue++;
2043
9.52M
            op = buildOp(opType, opValue);
2044
9.52M
            code->setElementAt(op, loc);
2045
9.52M
        }
2046
5.36G
    }
2047
2048
    // Now fix up the parentheses stack.  All positive values in it are locations in
2049
    //  the compiled pattern.   (Negative values are frame boundaries, and don't need fixing.)
2050
602M
    for (loc=0; loc<fParenStack.size(); loc++) {
2051
602M
        int32_t x = fParenStack.elementAti(loc);
2052
602M
        U_ASSERT(x < code->size());
2053
602M
        if (x>where) {
2054
0
            x++;
2055
0
            fParenStack.setElementAt(x, loc);
2056
0
        }
2057
602M
    }
2058
2059
251k
    if (fMatchCloseParen > where) {
2060
14.9k
        fMatchCloseParen++;
2061
14.9k
    }
2062
251k
    if (fMatchOpenParen > where) {
2063
0
        fMatchOpenParen++;
2064
0
    }
2065
251k
}
2066
2067
2068
//------------------------------------------------------------------------------
2069
//
2070
//   allocateData()        Allocate storage in the matcher's static data area.
2071
//                         Return the index for the newly allocated data.
2072
//                         The storage won't actually exist until we are running a match
2073
//                         operation, but the storage indexes are inserted into various
2074
//                         opcodes while compiling the pattern.
2075
//
2076
//------------------------------------------------------------------------------
2077
68.5k
int32_t RegexCompile::allocateData(int32_t size) {
2078
68.5k
    if (U_FAILURE(*fStatus)) {
2079
31
        return 0;
2080
31
    }
2081
68.5k
    if (size <= 0 || size > 0x100 || fRXPat->fDataSize < 0) {
2082
0
        error(U_REGEX_INTERNAL_ERROR);
2083
0
        return 0;
2084
0
    }
2085
68.5k
    int32_t dataIndex = fRXPat->fDataSize;
2086
68.5k
    fRXPat->fDataSize += size;
2087
68.5k
    if (fRXPat->fDataSize >= 0x00fffff0) {
2088
0
        error(U_REGEX_INTERNAL_ERROR);
2089
0
    }
2090
68.5k
    return dataIndex;
2091
68.5k
}
2092
2093
2094
//------------------------------------------------------------------------------
2095
//
2096
//   allocateStackData()   Allocate space in the back-tracking stack frame.
2097
//                         Return the index for the newly allocated data.
2098
//                         The frame indexes are inserted into various
2099
//                         opcodes while compiling the pattern, meaning that frame
2100
//                         size must be restricted to the size that will fit
2101
//                         as an operand (24 bits).
2102
//
2103
//------------------------------------------------------------------------------
2104
726k
int32_t RegexCompile::allocateStackData(int32_t size) {
2105
726k
    if (U_FAILURE(*fStatus)) {
2106
0
        return 0;
2107
0
    }
2108
726k
    if (size <= 0 || size > 0x100 || fRXPat->fFrameSize < 0) {
2109
0
        error(U_REGEX_INTERNAL_ERROR);
2110
0
        return 0;
2111
0
    }
2112
726k
    int32_t dataIndex = fRXPat->fFrameSize;
2113
726k
    fRXPat->fFrameSize += size;
2114
726k
    if (fRXPat->fFrameSize >= 0x00fffff0) {
2115
0
        error(U_REGEX_PATTERN_TOO_BIG);
2116
0
    }
2117
726k
    return dataIndex;
2118
726k
}
2119
2120
2121
//------------------------------------------------------------------------------
2122
//
2123
//   blockTopLoc()          Find or create a location in the compiled pattern
2124
//                          at the start of the operation or block that has
2125
//                          just been compiled.  Needed when a quantifier (* or
2126
//                          whatever) appears, and we need to add an operation
2127
//                          at the start of the thing being quantified.
2128
//
2129
//                          (Parenthesized Blocks) have a slot with a NOP that
2130
//                          is reserved for this purpose.  .* or similar don't
2131
//                          and a slot needs to be added.
2132
//
2133
//       parameter reserveLoc   :  true -  ensure that there is space to add an opcode
2134
//                                         at the returned location.
2135
//                                 false - just return the address,
2136
//                                         do not reserve a location there.
2137
//
2138
//------------------------------------------------------------------------------
2139
863k
int32_t   RegexCompile::blockTopLoc(UBool reserveLoc) {
2140
863k
    int32_t   theLoc;
2141
863k
    fixLiterals(true);  // Emit code for any pending literals.
2142
                        //   If last item was a string, emit separate op for the its last char.
2143
863k
    if (fRXPat->fCompiledPat->size() == fMatchCloseParen)
2144
20.2k
    {
2145
        // The item just processed is a parenthesized block.
2146
20.2k
        theLoc = fMatchOpenParen;   // A slot is already reserved for us.
2147
20.2k
        U_ASSERT(theLoc > 0);
2148
20.2k
        U_ASSERT(URX_TYPE(((uint32_t)fRXPat->fCompiledPat->elementAti(theLoc))) == URX_NOP);
2149
20.2k
    }
2150
843k
    else {
2151
        // Item just compiled is a single thing, a ".", or a single char, a string or a set reference.
2152
        // No slot for STATE_SAVE was pre-reserved in the compiled code.
2153
        // We need to make space now.
2154
843k
        theLoc = fRXPat->fCompiledPat->size()-1;
2155
843k
        int32_t opAtTheLoc = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(theLoc));
2156
843k
        if (URX_TYPE(opAtTheLoc) == URX_STRING_LEN) {
2157
            // Strings take two opcode, we want the position of the first one.
2158
            // We can have a string at this point if a single character case-folded to two.
2159
346k
            theLoc--;
2160
346k
        }
2161
843k
        if (reserveLoc) {
2162
397k
            int32_t  nop = buildOp(URX_NOP, 0);
2163
397k
            fRXPat->fCompiledPat->insertElementAt(nop, theLoc, *fStatus);
2164
397k
        }
2165
843k
    }
2166
863k
    return theLoc;
2167
863k
}
2168
2169
2170
2171
//------------------------------------------------------------------------------
2172
//
2173
//    handleCloseParen      When compiling a close paren, we need to go back
2174
//                          and fix up any JMP or SAVE operations within the
2175
//                          parenthesized block that need to target the end
2176
//                          of the block.  The locations of these are kept on
2177
//                          the paretheses stack.
2178
//
2179
//                          This function is called both when encountering a
2180
//                          real ) and at the end of the pattern.
2181
//
2182
//------------------------------------------------------------------------------
2183
612k
void  RegexCompile::handleCloseParen() {
2184
612k
    int32_t   patIdx;
2185
612k
    int32_t   patOp;
2186
612k
    if (fParenStack.size() <= 0) {
2187
0
        error(U_REGEX_MISMATCHED_PAREN);
2188
0
        return;
2189
0
    }
2190
2191
    // Emit code for any pending literals.
2192
612k
    fixLiterals(false);
2193
2194
    // Fixup any operations within the just-closed parenthesized group
2195
    //    that need to reference the end of the (block).
2196
    //    (The first one popped from the stack is an unused slot for
2197
    //     alternation (OR) state save, but applying the fixup to it does no harm.)
2198
17.5M
    for (;;) {
2199
17.5M
        patIdx = fParenStack.popi();
2200
17.5M
        if (patIdx < 0) {
2201
            // value < 0 flags the start of the frame on the paren stack.
2202
612k
            break;
2203
612k
        }
2204
16.9M
        U_ASSERT(patIdx>0 && patIdx <= fRXPat->fCompiledPat->size());
2205
16.9M
        patOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(patIdx));
2206
16.9M
        U_ASSERT(URX_VAL(patOp) == 0);          // Branch target for JMP should not be set.
2207
16.9M
        patOp |= fRXPat->fCompiledPat->size();  // Set it now.
2208
16.9M
        fRXPat->fCompiledPat->setElementAt(patOp, patIdx);
2209
16.9M
        fMatchOpenParen     = patIdx;
2210
16.9M
    }
2211
2212
    //  At the close of any parenthesized block, restore the match mode flags  to
2213
    //  the value they had at the open paren.  Saved value is
2214
    //  at the top of the paren stack.
2215
612k
    fModeFlags = fParenStack.popi();
2216
612k
    U_ASSERT(fModeFlags < 0);
2217
2218
    // DO any additional fixups, depending on the specific kind of
2219
    // parentesized grouping this is
2220
2221
612k
    switch (patIdx) {
2222
14.4k
    case plain:
2223
18.5k
    case flags:
2224
        // No additional fixups required.
2225
        //   (Grouping-only parentheses)
2226
18.5k
        break;
2227
582k
    case capturing:
2228
        // Capturing Parentheses.
2229
        //   Insert a End Capture op into the pattern.
2230
        //   The frame offset of the variables for this cg is obtained from the
2231
        //       start capture op and put it into the end-capture op.
2232
582k
        {
2233
582k
            int32_t captureOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen + 1));
2234
582k
            U_ASSERT(URX_TYPE(captureOp) == URX_START_CAPTURE);
2235
2236
582k
            int32_t   frameVarLocation = URX_VAL(captureOp);
2237
582k
            appendOp(URX_END_CAPTURE, frameVarLocation);
2238
582k
        }
2239
582k
        break;
2240
661
    case atomic:
2241
        // Atomic Parenthesis.
2242
        //   Insert a LD_SP operation to restore the state stack to the position
2243
        //   it was when the atomic parens were entered.
2244
661
        {
2245
661
            int32_t stoOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen + 1));
2246
661
            U_ASSERT(URX_TYPE(stoOp) == URX_STO_SP);
2247
661
            int32_t   stoLoc = URX_VAL(stoOp);
2248
661
            appendOp(URX_LD_SP, stoLoc);
2249
661
        }
2250
661
        break;
2251
2252
1.26k
    case lookAhead:
2253
1.26k
        {
2254
1.26k
            int32_t startOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen - 5));
2255
1.26k
            U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
2256
1.26k
            int32_t dataLoc  = URX_VAL(startOp);
2257
1.26k
            appendOp(URX_LA_END, dataLoc);
2258
1.26k
        }
2259
1.26k
        break;
2260
2261
2.54k
    case negLookAhead:
2262
2.54k
        {
2263
            // See comment at doOpenLookAheadNeg
2264
2.54k
            int32_t startOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen - 1));
2265
2.54k
            U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
2266
2.54k
            int32_t dataLoc  = URX_VAL(startOp);
2267
2.54k
            appendOp(URX_LA_END, dataLoc);
2268
2.54k
            appendOp(URX_BACKTRACK, 0);
2269
2.54k
            appendOp(URX_LA_END, dataLoc);
2270
2271
            // Patch the URX_SAVE near the top of the block.
2272
            // The destination of the SAVE is the final LA_END that was just added.
2273
2.54k
            int32_t saveOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen));
2274
2.54k
            U_ASSERT(URX_TYPE(saveOp) == URX_STATE_SAVE);
2275
2.54k
            int32_t dest     = fRXPat->fCompiledPat->size()-1;
2276
2.54k
            saveOp           = buildOp(URX_STATE_SAVE, dest);
2277
2.54k
            fRXPat->fCompiledPat->setElementAt(saveOp, fMatchOpenParen);
2278
2.54k
        }
2279
2.54k
        break;
2280
2281
3.58k
    case lookBehind:
2282
3.58k
        {
2283
            // See comment at doOpenLookBehind.
2284
2285
            // Append the URX_LB_END and URX_LA_END to the compiled pattern.
2286
3.58k
            int32_t startOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen - 4));
2287
3.58k
            U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
2288
3.58k
            int32_t dataLoc  = URX_VAL(startOp);
2289
3.58k
            appendOp(URX_LB_END, dataLoc);
2290
3.58k
            appendOp(URX_LA_END, dataLoc);
2291
2292
            // Determine the min and max bounds for the length of the
2293
            //  string that the pattern can match.
2294
            //  An unbounded upper limit is an error.
2295
3.58k
            int32_t patEnd   = fRXPat->fCompiledPat->size() - 1;
2296
3.58k
            int32_t minML    = minMatchLength(fMatchOpenParen, patEnd);
2297
3.58k
            int32_t maxML    = maxMatchLength(fMatchOpenParen, patEnd);
2298
3.58k
            if (URX_TYPE(maxML) != 0) {
2299
158
                error(U_REGEX_LOOK_BEHIND_LIMIT);
2300
158
                break;
2301
158
            }
2302
3.42k
            if (maxML == INT32_MAX) {
2303
0
                error(U_REGEX_LOOK_BEHIND_LIMIT);
2304
0
                break;
2305
0
            }
2306
3.42k
            if (minML == INT32_MAX) {
2307
                // This condition happens when no match is possible, such as with a
2308
                // [set] expression containing no elements.
2309
                // In principle, the generated code to evaluate the expression could be deleted,
2310
                // but it's probably not worth the complication.
2311
545
                minML = 0;
2312
545
            }
2313
3.42k
            U_ASSERT(minML <= maxML);
2314
2315
            // Insert the min and max match len bounds into the URX_LB_CONT op that
2316
            //  appears at the top of the look-behind block, at location fMatchOpenParen+1
2317
3.42k
            fRXPat->fCompiledPat->setElementAt(minML,  fMatchOpenParen-2);
2318
3.42k
            fRXPat->fCompiledPat->setElementAt(maxML,  fMatchOpenParen-1);
2319
2320
3.42k
        }
2321
0
        break;
2322
2323
2324
2325
3.69k
    case lookBehindN:
2326
3.69k
        {
2327
            // See comment at doOpenLookBehindNeg.
2328
2329
            // Append the URX_LBN_END to the compiled pattern.
2330
3.69k
            int32_t startOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(fMatchOpenParen - 5));
2331
3.69k
            U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
2332
3.69k
            int32_t dataLoc  = URX_VAL(startOp);
2333
3.69k
            appendOp(URX_LBN_END, dataLoc);
2334
2335
            // Determine the min and max bounds for the length of the
2336
            //  string that the pattern can match.
2337
            //  An unbounded upper limit is an error.
2338
3.69k
            int32_t patEnd   = fRXPat->fCompiledPat->size() - 1;
2339
3.69k
            int32_t minML    = minMatchLength(fMatchOpenParen, patEnd);
2340
3.69k
            int32_t maxML    = maxMatchLength(fMatchOpenParen, patEnd);
2341
3.69k
            if (URX_TYPE(maxML) != 0) {
2342
135
                error(U_REGEX_LOOK_BEHIND_LIMIT);
2343
135
                break;
2344
135
            }
2345
3.55k
            if (maxML == INT32_MAX) {
2346
0
                error(U_REGEX_LOOK_BEHIND_LIMIT);
2347
0
                break;
2348
0
            }
2349
3.55k
            if (minML == INT32_MAX) {
2350
                // This condition happens when no match is possible, such as with a
2351
                // [set] expression containing no elements.
2352
                // In principle, the generated code to evaluate the expression could be deleted,
2353
                // but it's probably not worth the complication.
2354
364
                minML = 0;
2355
364
            }
2356
2357
3.55k
            U_ASSERT(minML <= maxML);
2358
2359
            // Insert the min and max match len bounds into the URX_LB_CONT op that
2360
            //  appears at the top of the look-behind block, at location fMatchOpenParen+1
2361
3.55k
            fRXPat->fCompiledPat->setElementAt(minML,  fMatchOpenParen-3);
2362
3.55k
            fRXPat->fCompiledPat->setElementAt(maxML,  fMatchOpenParen-2);
2363
2364
            // Insert the pattern location to continue at after a successful match
2365
            //  as the last operand of the URX_LBN_CONT
2366
3.55k
            int32_t op = buildOp(URX_RELOC_OPRND, fRXPat->fCompiledPat->size());
2367
3.55k
            fRXPat->fCompiledPat->setElementAt(op,  fMatchOpenParen-1);
2368
3.55k
        }
2369
0
        break;
2370
2371
2372
2373
0
    default:
2374
0
        UPRV_UNREACHABLE_EXIT;
2375
612k
    }
2376
2377
    // remember the next location in the compiled pattern.
2378
    // The compilation of Quantifiers will look at this to see whether its looping
2379
    //   over a parenthesized block or a single item
2380
612k
    fMatchCloseParen = fRXPat->fCompiledPat->size();
2381
612k
}
2382
2383
2384
2385
//------------------------------------------------------------------------------
2386
//
2387
//   compileSet       Compile the pattern operations for a reference to a
2388
//                    UnicodeSet.
2389
//
2390
//------------------------------------------------------------------------------
2391
void        RegexCompile::compileSet(UnicodeSet *theSet)
2392
269k
{
2393
269k
    if (theSet == nullptr) {
2394
211
        return;
2395
211
    }
2396
    //  Remove any strings from the set.
2397
    //  There shouldn't be any, but just in case.
2398
    //     (Case Closure can add them; if we had a simple case closure available that
2399
    //      ignored strings, that would be better.)
2400
268k
    theSet->removeAllStrings();
2401
268k
    int32_t  setSize = theSet->size();
2402
2403
268k
    switch (setSize) {
2404
7.29k
    case 0:
2405
7.29k
        {
2406
            // Set of no elements.   Always fails to match.
2407
7.29k
            appendOp(URX_BACKTRACK, 0);
2408
7.29k
            delete theSet;
2409
7.29k
        }
2410
7.29k
        break;
2411
2412
7.30k
    case 1:
2413
7.30k
        {
2414
            // The set contains only a single code point.  Put it into
2415
            //   the compiled pattern as a single char operation rather
2416
            //   than a set, and discard the set itself.
2417
7.30k
            literalChar(theSet->charAt(0));
2418
7.30k
            delete theSet;
2419
7.30k
        }
2420
7.30k
        break;
2421
2422
254k
    default:
2423
254k
        {
2424
            //  The set contains two or more chars.  (the normal case)
2425
            //  Put it into the compiled pattern as a set.
2426
254k
            theSet->freeze();
2427
254k
            int32_t setNumber = fRXPat->fSets->size();
2428
254k
            fRXPat->fSets->addElement(theSet, *fStatus);
2429
254k
            if (U_SUCCESS(*fStatus)) {
2430
254k
                appendOp(URX_SETREF, setNumber);
2431
254k
            } else {
2432
2
                delete theSet;
2433
2
            }
2434
254k
        }
2435
268k
    }
2436
268k
}
2437
2438
2439
//------------------------------------------------------------------------------
2440
//
2441
//   compileInterval    Generate the code for a {min, max} style interval quantifier.
2442
//                      Except for the specific opcodes used, the code is the same
2443
//                      for all three types (greedy, non-greedy, possessive) of
2444
//                      intervals.  The opcodes are supplied as parameters.
2445
//                      (There are two sets of opcodes - greedy & possessive use the
2446
//                      same ones, while non-greedy has it's own.)
2447
//
2448
//                      The code for interval loops has this form:
2449
//                         0  CTR_INIT   counter loc (in stack frame)
2450
//                         1             5  patt address of CTR_LOOP at bottom of block
2451
//                         2             min count
2452
//                         3             max count   (-1 for unbounded)
2453
//                         4  ...        block to be iterated over
2454
//                         5  CTR_LOOP
2455
//
2456
//                       In
2457
//------------------------------------------------------------------------------
2458
void        RegexCompile::compileInterval(int32_t InitOp,  int32_t LoopOp)
2459
10.4k
{
2460
    // The CTR_INIT op at the top of the block with the {n,m} quantifier takes
2461
    //   four slots in the compiled code.  Reserve them.
2462
10.4k
    int32_t   topOfBlock = blockTopLoc(true);
2463
10.4k
    insertOp(topOfBlock);
2464
10.4k
    insertOp(topOfBlock);
2465
10.4k
    insertOp(topOfBlock);
2466
2467
    // The operands for the CTR_INIT opcode include the index in the matcher data
2468
    //   of the counter.  Allocate it now. There are two data items
2469
    //        counterLoc   -->  Loop counter
2470
    //               +1    -->  Input index (for breaking non-progressing loops)
2471
    //                          (Only present if unbounded upper limit on loop)
2472
10.4k
    int32_t   dataSize = fIntervalUpper < 0 ? 2 : 1;
2473
10.4k
    int32_t   counterLoc = allocateStackData(dataSize);
2474
2475
10.4k
    int32_t   op = buildOp(InitOp, counterLoc);
2476
10.4k
    fRXPat->fCompiledPat->setElementAt(op, topOfBlock);
2477
2478
    // The second operand of CTR_INIT is the location following the end of the loop.
2479
    //   Must put in as a URX_RELOC_OPRND so that the value will be adjusted if the
2480
    //   compilation of something later on causes the code to grow and the target
2481
    //   position to move.
2482
10.4k
    int32_t loopEnd = fRXPat->fCompiledPat->size();
2483
10.4k
    op = buildOp(URX_RELOC_OPRND, loopEnd);
2484
10.4k
    fRXPat->fCompiledPat->setElementAt(op, topOfBlock+1);
2485
2486
    // Followed by the min and max counts.
2487
10.4k
    fRXPat->fCompiledPat->setElementAt(fIntervalLow, topOfBlock+2);
2488
10.4k
    fRXPat->fCompiledPat->setElementAt(fIntervalUpper, topOfBlock+3);
2489
2490
    // Append the CTR_LOOP op.  The operand is the location of the CTR_INIT op.
2491
    //   Goes at end of the block being looped over, so just append to the code so far.
2492
10.4k
    appendOp(LoopOp, topOfBlock);
2493
2494
10.4k
    if ((fIntervalLow & 0xff000000) != 0 ||
2495
10.3k
        (fIntervalUpper > 0 && (fIntervalUpper & 0xff000000) != 0)) {
2496
41
            error(U_REGEX_NUMBER_TOO_BIG);
2497
41
        }
2498
2499
10.4k
    if (fIntervalLow > fIntervalUpper && fIntervalUpper != -1) {
2500
28
        error(U_REGEX_MAX_LT_MIN);
2501
28
    }
2502
10.4k
}
2503
2504
2505
2506
88.2k
UBool RegexCompile::compileInlineInterval() {
2507
88.2k
    if (fIntervalUpper > 10 || fIntervalUpper < fIntervalLow) {
2508
        // Too big to inline.  Fail, which will cause looping code to be generated.
2509
        //   (Upper < Lower picks up unbounded upper and errors, both.)
2510
3.93k
        return false;
2511
3.93k
    }
2512
2513
84.3k
    int32_t   topOfBlock = blockTopLoc(false);
2514
84.3k
    if (fIntervalUpper == 0) {
2515
        // Pathological case.  Attempt no matches, as if the block doesn't exist.
2516
        // Discard the generated code for the block.
2517
        // If the block included parens, discard the info pertaining to them as well.
2518
1.70k
        fRXPat->fCompiledPat->setSize(topOfBlock);
2519
1.70k
        if (fMatchOpenParen >= topOfBlock) {
2520
298
            fMatchOpenParen = -1;
2521
298
        }
2522
1.70k
        if (fMatchCloseParen >= topOfBlock) {
2523
298
            fMatchCloseParen = -1;
2524
298
        }
2525
1.70k
        return true;
2526
1.70k
    }
2527
2528
82.6k
    if (topOfBlock != fRXPat->fCompiledPat->size()-1 && fIntervalUpper != 1) {
2529
        // The thing being repeated is not a single op, but some
2530
        //   more complex block.  Do it as a loop, not inlines.
2531
        //   Note that things "repeated" a max of once are handled as inline, because
2532
        //     the one copy of the code already generated is just fine.
2533
1.00k
        return false;
2534
1.00k
    }
2535
2536
    // Pick up the opcode that is to be repeated
2537
    //
2538
81.6k
    int32_t op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(topOfBlock));
2539
2540
    // Compute the pattern location where the inline sequence
2541
    //   will end, and set up the state save op that will be needed.
2542
    //
2543
81.6k
    int32_t endOfSequenceLoc = fRXPat->fCompiledPat->size()-1
2544
81.6k
                                + fIntervalUpper + (fIntervalUpper-fIntervalLow);
2545
81.6k
    int32_t saveOp = buildOp(URX_STATE_SAVE, endOfSequenceLoc);
2546
81.6k
    if (fIntervalLow == 0) {
2547
71.1k
        insertOp(topOfBlock);
2548
71.1k
        fRXPat->fCompiledPat->setElementAt(saveOp, topOfBlock);
2549
71.1k
    }
2550
2551
2552
2553
    //  Loop, emitting the op for the thing being repeated each time.
2554
    //    Loop starts at 1 because one instance of the op already exists in the pattern,
2555
    //    it was put there when it was originally encountered.
2556
81.6k
    int32_t i;
2557
720k
    for (i=1; i<fIntervalUpper; i++ ) {
2558
638k
        if (i >= fIntervalLow) {
2559
571k
            appendOp(saveOp);
2560
571k
        }
2561
638k
        appendOp(op);
2562
638k
    }
2563
81.6k
    return true;
2564
82.6k
}
2565
2566
2567
2568
//------------------------------------------------------------------------------
2569
//
2570
//   caseInsensitiveStart  given a single code point from a pattern string, determine the 
2571
//                         set of characters that could potentially begin a case-insensitive 
2572
//                         match of a string beginning with that character, using full Unicode
2573
//                         case insensitive matching.
2574
//
2575
//          This is used in optimizing find().
2576
//
2577
//          closeOver(USET_CASE_INSENSITIVE) does most of what is needed, but
2578
//          misses cases like this:
2579
//             A string from the pattern begins with 'ss' (although all we know
2580
//                 in this context is that it begins with 's')
2581
//             The pattern could match a string beginning with a German sharp-s
2582
//
2583
//           To the ordinary case closure for a character c, we add all other
2584
//           characters cx where the case closure of cx includes a string form that begins
2585
//           with the original character c.
2586
//
2587
//           This function could be made smarter. The full pattern string is available
2588
//           and it would be possible to verify that the extra characters being added
2589
//           to the starting set fully match, rather than having just a first-char of the
2590
//           folded form match.
2591
//
2592
//------------------------------------------------------------------------------
2593
548k
void  RegexCompile::findCaseInsensitiveStarters(UChar32 c, UnicodeSet *starterChars) {
2594
2595
// Machine Generated below.
2596
// It may need updating with new versions of Unicode.
2597
// Intltest test RegexTest::TestCaseInsensitiveStarters will fail if an update is needed.
2598
// The update tool is here:
2599
// https://github.com/unicode-org/icu/tree/main/tools/unicode/c/genregexcasing
2600
2601
// Machine Generated Data. Do not hand edit.
2602
548k
    static const UChar32 RECaseFixCodePoints[] = {
2603
548k
        0x61, 0x66, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x77, 0x79, 0x2bc, 
2604
548k
        0x3ac, 0x3ae, 0x3b1, 0x3b7, 0x3b9, 0x3c1, 0x3c5, 0x3c9, 0x3ce, 0x565, 
2605
548k
        0x574, 0x57e, 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 
2606
548k
        0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, 0x1f60, 0x1f61, 
2607
548k
        0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1f70, 0x1f74, 0x1f7c, 0x110000};
2608
2609
548k
    static const int16_t RECaseFixStringOffsets[] = {
2610
548k
        0x0, 0x1, 0x6, 0x7, 0x8, 0x9, 0xd, 0xe, 0xf, 0x10, 
2611
548k
        0x11, 0x12, 0x13, 0x17, 0x1b, 0x20, 0x21, 0x2a, 0x2e, 0x2f, 
2612
548k
        0x30, 0x34, 0x35, 0x37, 0x39, 0x3b, 0x3d, 0x3f, 0x41, 0x43, 
2613
548k
        0x45, 0x47, 0x49, 0x4b, 0x4d, 0x4f, 0x51, 0x53, 0x55, 0x57, 
2614
548k
        0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65, 0x66, 0x67, 0};
2615
2616
548k
    static const int16_t RECaseFixCounts[] = {
2617
548k
        0x1, 0x5, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x1, 0x1, 
2618
548k
        0x1, 0x1, 0x4, 0x4, 0x5, 0x1, 0x9, 0x4, 0x1, 0x1, 
2619
548k
        0x4, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 
2620
548k
        0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 
2621
548k
        0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x1, 0x1, 0};
2622
2623
548k
    static const char16_t RECaseFixData[] = {
2624
548k
        0x1e9a, 0xfb00, 0xfb01, 0xfb02, 0xfb03, 0xfb04, 0x1e96, 0x130, 0x1f0, 0xdf, 
2625
548k
        0x1e9e, 0xfb05, 0xfb06, 0x1e97, 0x1e98, 0x1e99, 0x149, 0x1fb4, 0x1fc4, 0x1fb3, 
2626
548k
        0x1fb6, 0x1fb7, 0x1fbc, 0x1fc3, 0x1fc6, 0x1fc7, 0x1fcc, 0x390, 0x1fd2, 0x1fd3, 
2627
548k
        0x1fd6, 0x1fd7, 0x1fe4, 0x3b0, 0x1f50, 0x1f52, 0x1f54, 0x1f56, 0x1fe2, 0x1fe3, 
2628
548k
        0x1fe6, 0x1fe7, 0x1ff3, 0x1ff6, 0x1ff7, 0x1ffc, 0x1ff4, 0x587, 0xfb13, 0xfb14, 
2629
548k
        0xfb15, 0xfb17, 0xfb16, 0x1f80, 0x1f88, 0x1f81, 0x1f89, 0x1f82, 0x1f8a, 0x1f83, 
2630
548k
        0x1f8b, 0x1f84, 0x1f8c, 0x1f85, 0x1f8d, 0x1f86, 0x1f8e, 0x1f87, 0x1f8f, 0x1f90, 
2631
548k
        0x1f98, 0x1f91, 0x1f99, 0x1f92, 0x1f9a, 0x1f93, 0x1f9b, 0x1f94, 0x1f9c, 0x1f95, 
2632
548k
        0x1f9d, 0x1f96, 0x1f9e, 0x1f97, 0x1f9f, 0x1fa0, 0x1fa8, 0x1fa1, 0x1fa9, 0x1fa2, 
2633
548k
        0x1faa, 0x1fa3, 0x1fab, 0x1fa4, 0x1fac, 0x1fa5, 0x1fad, 0x1fa6, 0x1fae, 0x1fa7, 
2634
548k
        0x1faf, 0x1fb2, 0x1fc2, 0x1ff2, 0};
2635
2636
// End of machine generated data.
2637
2638
548k
    if (c < UCHAR_MIN_VALUE || c > UCHAR_MAX_VALUE) {
2639
        // This function should never be called with an invalid input character.
2640
0
        UPRV_UNREACHABLE_EXIT;
2641
548k
    } else if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
2642
16.4k
        UChar32 caseFoldedC  = u_foldCase(c, U_FOLD_CASE_DEFAULT);
2643
16.4k
        starterChars->set(caseFoldedC, caseFoldedC);
2644
2645
16.4k
        int32_t i;
2646
278k
        for (i=0; RECaseFixCodePoints[i]<c ; i++) {
2647
            // Simple linear search through the sorted list of interesting code points.
2648
261k
        }
2649
2650
16.4k
        if (RECaseFixCodePoints[i] == c) {
2651
14.6k
            int32_t dataIndex = RECaseFixStringOffsets[i];
2652
14.6k
            int32_t numCharsToAdd = RECaseFixCounts[i];
2653
14.6k
            UChar32 cpToAdd = 0;
2654
89.8k
            for (int32_t j=0; j<numCharsToAdd; j++) {
2655
75.2k
                U16_NEXT_UNSAFE(RECaseFixData, dataIndex, cpToAdd);
2656
75.2k
                starterChars->add(cpToAdd);
2657
75.2k
            }
2658
14.6k
        }
2659
2660
16.4k
        starterChars->closeOver(USET_CASE_INSENSITIVE);
2661
16.4k
        starterChars->removeAllStrings();
2662
532k
    } else {
2663
        // Not a cased character. Just return it alone.
2664
532k
        starterChars->set(c, c);
2665
532k
    }
2666
548k
}
2667
2668
2669
// Increment with overflow check.
2670
// val and delta will both be positive.
2671
2672
6.08M
static int32_t safeIncrement(int32_t val, int32_t delta) {
2673
6.08M
    if (INT32_MAX - val > delta) {
2674
5.94M
        return val + delta;
2675
5.94M
    } else {
2676
146k
        return INT32_MAX;
2677
146k
    }
2678
6.08M
}
2679
2680
2681
//------------------------------------------------------------------------------
2682
//
2683
//   matchStartType    Determine how a match can start.
2684
//                     Used to optimize find() operations.
2685
//
2686
//                     Operation is very similar to minMatchLength().  Walk the compiled
2687
//                     pattern, keeping an on-going minimum-match-length.  For any
2688
//                     op where the min match coming in is zero, add that ops possible
2689
//                     starting matches to the possible starts for the overall pattern.
2690
//
2691
//------------------------------------------------------------------------------
2692
13.7k
void   RegexCompile::matchStartType() {
2693
13.7k
    if (U_FAILURE(*fStatus)) {
2694
80
        return;
2695
80
    }
2696
2697
2698
13.6k
    int32_t    loc;                    // Location in the pattern of the current op being processed.
2699
13.6k
    int32_t    op;                     // The op being processed
2700
13.6k
    int32_t    opType;                 // The opcode type of the op
2701
13.6k
    int32_t    currentLen = 0;         // Minimum length of a match to this point (loc) in the pattern
2702
13.6k
    int32_t    numInitialStrings = 0;  // Number of strings encountered that could match at start.
2703
2704
13.6k
    UBool      atStart = true;         // True if no part of the pattern yet encountered
2705
                                       //   could have advanced the position in a match.
2706
                                       //   (Maximum match length so far == 0)
2707
2708
    // forwardedLength is a vector holding minimum-match-length values that
2709
    //   are propagated forward in the pattern by JMP or STATE_SAVE operations.
2710
    //   It must be one longer than the pattern being checked because some  ops
2711
    //   will jmp to a end-of-block+1 location from within a block, and we must
2712
    //   count those when checking the block.
2713
13.6k
    int32_t end = fRXPat->fCompiledPat->size();
2714
13.6k
    UVector32  forwardedLength(end+1, *fStatus);
2715
13.6k
    forwardedLength.setSize(end+1);
2716
29.0M
    for (loc=3; loc<end; loc++) {
2717
29.0M
        forwardedLength.setElementAt(INT32_MAX, loc);
2718
29.0M
    }
2719
2720
23.6M
    for (loc = 3; loc<end; loc++) {
2721
23.6M
        op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
2722
23.6M
        opType = URX_TYPE(op);
2723
2724
        // The loop is advancing linearly through the pattern.
2725
        // If the op we are now at was the destination of a branch in the pattern,
2726
        // and that path has a shorter minimum length than the current accumulated value,
2727
        // replace the current accumulated value.
2728
23.6M
        if (forwardedLength.elementAti(loc) < currentLen) {
2729
952k
            currentLen = forwardedLength.elementAti(loc);
2730
952k
            U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
2731
952k
        }
2732
2733
23.6M
        switch (opType) {
2734
            // Ops that don't change the total length matched
2735
0
        case URX_RESERVED_OP:
2736
13.6k
        case URX_END:
2737
13.6k
        case URX_FAIL:
2738
13.6k
        case URX_STRING_LEN:
2739
13.6k
        case URX_NOP:
2740
88.0k
        case URX_START_CAPTURE:
2741
162k
        case URX_END_CAPTURE:
2742
164k
        case URX_BACKSLASH_B:
2743
169k
        case URX_BACKSLASH_BU:
2744
170k
        case URX_BACKSLASH_G:
2745
171k
        case URX_BACKSLASH_Z:
2746
240k
        case URX_DOLLAR:
2747
241k
        case URX_DOLLAR_M:
2748
271k
        case URX_DOLLAR_D:
2749
272k
        case URX_DOLLAR_MD:
2750
272k
        case URX_RELOC_OPRND:
2751
364k
        case URX_STO_INP_LOC:
2752
365k
        case URX_BACKREF:         // BackRef.  Must assume that it might be a zero length match
2753
368k
        case URX_BACKREF_I:
2754
2755
422k
        case URX_STO_SP:          // Setup for atomic or possessive blocks.  Doesn't change what can match.
2756
476k
        case URX_LD_SP:
2757
476k
            break;
2758
2759
4.28k
        case URX_CARET:
2760
4.28k
            if (atStart) {
2761
727
                fRXPat->fStartType = START_START;
2762
727
            }
2763
4.28k
            break;
2764
2765
1.20k
        case URX_CARET_M:
2766
1.95k
        case URX_CARET_M_UNIX:
2767
1.95k
            if (atStart) {
2768
554
                fRXPat->fStartType = START_LINE;
2769
554
            }
2770
1.95k
            break;
2771
2772
662k
        case URX_ONECHAR:
2773
662k
            if (currentLen == 0) {
2774
                // This character could appear at the start of a match.
2775
                //   Add it to the set of possible starting characters.
2776
66.6k
                fRXPat->fInitialChars->add(URX_VAL(op));
2777
66.6k
                numInitialStrings += 2;
2778
66.6k
            }
2779
662k
            currentLen = safeIncrement(currentLen, 1);
2780
662k
            atStart = false;
2781
662k
            break;
2782
2783
2784
183k
        case URX_SETREF:
2785
183k
            if (currentLen == 0) {
2786
2.84k
                int32_t  sn = URX_VAL(op);
2787
2.84k
                U_ASSERT(sn > 0 && sn < fRXPat->fSets->size());
2788
2.84k
                const UnicodeSet* s = static_cast<UnicodeSet*>(fRXPat->fSets->elementAt(sn));
2789
2.84k
                fRXPat->fInitialChars->addAll(*s);
2790
2.84k
                numInitialStrings += 2;
2791
2.84k
            }
2792
183k
            currentLen = safeIncrement(currentLen, 1);
2793
183k
            atStart = false;
2794
183k
            break;
2795
2796
4.04k
        case URX_LOOP_SR_I:
2797
            // [Set]*, like a SETREF, above, in what it can match,
2798
            //  but may not match at all, so currentLen is not incremented.
2799
4.04k
            if (currentLen == 0) {
2800
424
                int32_t  sn = URX_VAL(op);
2801
424
                U_ASSERT(sn > 0 && sn < fRXPat->fSets->size());
2802
424
                const UnicodeSet* s = static_cast<UnicodeSet*>(fRXPat->fSets->elementAt(sn));
2803
424
                fRXPat->fInitialChars->addAll(*s);
2804
424
                numInitialStrings += 2;
2805
424
            }
2806
4.04k
            atStart = false;
2807
4.04k
            break;
2808
2809
13.3k
        case URX_LOOP_DOT_I:
2810
13.3k
            if (currentLen == 0) {
2811
                // .* at the start of a pattern.
2812
                //    Any character can begin the match.
2813
3.03k
                fRXPat->fInitialChars->clear();
2814
3.03k
                fRXPat->fInitialChars->complement();
2815
3.03k
                numInitialStrings += 2;
2816
3.03k
            }
2817
13.3k
            atStart = false;
2818
13.3k
            break;
2819
2820
2821
9.44k
        case URX_STATIC_SETREF:
2822
9.44k
            if (currentLen == 0) {
2823
547
                int32_t  sn = URX_VAL(op);
2824
547
                U_ASSERT(sn>0 && sn<URX_LAST_SET);
2825
547
                const UnicodeSet &s = RegexStaticSets::gStaticSets->fPropSets[sn];
2826
547
                fRXPat->fInitialChars->addAll(s);
2827
547
                numInitialStrings += 2;
2828
547
            }
2829
9.44k
            currentLen = safeIncrement(currentLen, 1);
2830
9.44k
            atStart = false;
2831
9.44k
            break;
2832
2833
2834
2835
6.97k
        case URX_STAT_SETREF_N:
2836
6.97k
            if (currentLen == 0) {
2837
451
                int32_t  sn = URX_VAL(op);
2838
451
                UnicodeSet sc;
2839
451
                sc.addAll(RegexStaticSets::gStaticSets->fPropSets[sn]).complement();
2840
451
                fRXPat->fInitialChars->addAll(sc);
2841
451
                numInitialStrings += 2;
2842
451
            }
2843
6.97k
            currentLen = safeIncrement(currentLen, 1);
2844
6.97k
            atStart = false;
2845
6.97k
            break;
2846
2847
2848
2849
5.42k
        case URX_BACKSLASH_D:
2850
            // Digit Char
2851
5.42k
             if (currentLen == 0) {
2852
1.39k
                 UnicodeSet s;
2853
1.39k
                 s.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ND_MASK, *fStatus);
2854
1.39k
                 if (URX_VAL(op) != 0) {
2855
882
                     s.complement();
2856
882
                 }
2857
1.39k
                 fRXPat->fInitialChars->addAll(s);
2858
1.39k
                 numInitialStrings += 2;
2859
1.39k
            }
2860
5.42k
            currentLen = safeIncrement(currentLen, 1);
2861
5.42k
            atStart = false;
2862
5.42k
            break;
2863
2864
2865
6.11k
        case URX_BACKSLASH_H:
2866
            // Horiz white space
2867
6.11k
            if (currentLen == 0) {
2868
1.80k
                UnicodeSet s;
2869
1.80k
                s.applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, U_GC_ZS_MASK, *fStatus);
2870
1.80k
                s.add(static_cast<UChar32>(9)); // Tab
2871
1.80k
                if (URX_VAL(op) != 0) {
2872
1.20k
                    s.complement();
2873
1.20k
                }
2874
1.80k
                fRXPat->fInitialChars->addAll(s);
2875
1.80k
                numInitialStrings += 2;
2876
1.80k
            }
2877
6.11k
            currentLen = safeIncrement(currentLen, 1);
2878
6.11k
            atStart = false;
2879
6.11k
            break;
2880
2881
2882
1.44k
        case URX_BACKSLASH_R:       // Any line ending sequence
2883
7.05k
        case URX_BACKSLASH_V:       // Any line ending code point, with optional negation
2884
7.05k
            if (currentLen == 0) {
2885
937
                UnicodeSet s;
2886
937
                s.add(static_cast<UChar32>(0x0a), static_cast<UChar32>(0x0d)); // add range
2887
937
                s.add(static_cast<UChar32>(0x85));
2888
937
                s.add(static_cast<UChar32>(0x2028), static_cast<UChar32>(0x2029));
2889
937
                if (URX_VAL(op) != 0) {
2890
                     // Complement option applies to URX_BACKSLASH_V only.
2891
369
                     s.complement();
2892
369
                }
2893
937
                fRXPat->fInitialChars->addAll(s);
2894
937
                numInitialStrings += 2;
2895
937
            }
2896
7.05k
            currentLen = safeIncrement(currentLen, 1);
2897
7.05k
            atStart = false;
2898
7.05k
            break;
2899
2900
2901
2902
53.3k
        case URX_ONECHAR_I:
2903
            // Case Insensitive Single Character.
2904
53.3k
            if (currentLen == 0) {
2905
2.95k
                UChar32  c = URX_VAL(op);
2906
2.95k
                if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
2907
2.95k
                    UnicodeSet starters(c, c);
2908
2.95k
                    starters.closeOver(USET_CASE_INSENSITIVE);
2909
                    // findCaseInsensitiveStarters(c, &starters);
2910
                    //   For ONECHAR_I, no need to worry about text chars that expand on folding into strings.
2911
                    //   The expanded folding can't match the pattern.
2912
2.95k
                    fRXPat->fInitialChars->addAll(starters);
2913
2.95k
                } else {
2914
                    // Char has no case variants.  Just add it as-is to the
2915
                    //   set of possible starting chars.
2916
0
                    fRXPat->fInitialChars->add(c);
2917
0
                }
2918
2.95k
                numInitialStrings += 2;
2919
2.95k
            }
2920
53.3k
            currentLen = safeIncrement(currentLen, 1);
2921
53.3k
            atStart = false;
2922
53.3k
            break;
2923
2924
2925
4.43k
        case URX_BACKSLASH_X:   // Grapheme Cluster.  Minimum is 1, max unbounded.
2926
10.7k
        case URX_DOTANY_ALL:    // . matches one or two.
2927
429k
        case URX_DOTANY:
2928
437k
        case URX_DOTANY_UNIX:
2929
437k
            if (currentLen == 0) {
2930
                // These constructs are all bad news when they appear at the start
2931
                //   of a match.  Any character can begin the match.
2932
3.49k
                fRXPat->fInitialChars->clear();
2933
3.49k
                fRXPat->fInitialChars->complement();
2934
3.49k
                numInitialStrings += 2;
2935
3.49k
            }
2936
437k
            currentLen = safeIncrement(currentLen, 1);
2937
437k
            atStart = false;
2938
437k
            break;
2939
2940
2941
0
        case URX_JMPX:
2942
0
            loc++;             // Except for extra operand on URX_JMPX, same as URX_JMP.
2943
0
            U_FALLTHROUGH;
2944
9.72M
        case URX_JMP:
2945
9.72M
            {
2946
9.72M
                int32_t  jmpDest = URX_VAL(op);
2947
9.72M
                if (jmpDest < loc) {
2948
                    // Loop of some kind.  Can safely ignore, the worst that will happen
2949
                    //  is that we understate the true minimum length
2950
22.2k
                    currentLen = forwardedLength.elementAti(loc+1);
2951
2952
9.70M
                } else {
2953
                    // Forward jump.  Propagate the current min length to the target loc of the jump.
2954
9.70M
                    U_ASSERT(jmpDest <= end+1);
2955
9.70M
                    if (forwardedLength.elementAti(jmpDest) > currentLen) {
2956
8.98k
                        forwardedLength.setElementAt(currentLen, jmpDest);
2957
8.98k
                    }
2958
9.70M
                }
2959
9.72M
            }
2960
9.72M
            atStart = false;
2961
9.72M
            break;
2962
2963
225k
        case URX_JMP_SAV:
2964
317k
        case URX_JMP_SAV_X:
2965
            // Combo of state save to the next loc, + jmp backwards.
2966
            //   Net effect on min. length computation is nothing.
2967
317k
            atStart = false;
2968
317k
            break;
2969
2970
3.83k
        case URX_BACKTRACK:
2971
            // Fails are kind of like a branch, except that the min length was
2972
            //   propagated already, by the state save.
2973
3.83k
            currentLen = forwardedLength.elementAti(loc+1);
2974
3.83k
            atStart = false;
2975
3.83k
            break;
2976
2977
2978
10.4M
        case URX_STATE_SAVE:
2979
10.4M
            {
2980
                // State Save, for forward jumps, propagate the current minimum.
2981
                //             of the state save.
2982
10.4M
                int32_t  jmpDest = URX_VAL(op);
2983
10.4M
                if (jmpDest > loc) {
2984
10.4M
                    if (currentLen < forwardedLength.elementAti(jmpDest)) {
2985
10.1M
                        forwardedLength.setElementAt(currentLen, jmpDest);
2986
10.1M
                    }
2987
10.4M
                }
2988
10.4M
            }
2989
10.4M
            atStart = false;
2990
10.4M
            break;
2991
2992
2993
2994
2995
62.3k
        case URX_STRING:
2996
62.3k
            {
2997
62.3k
                loc++;
2998
62.3k
                int32_t stringLenOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
2999
62.3k
                int32_t stringLen   = URX_VAL(stringLenOp);
3000
62.3k
                U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
3001
62.3k
                U_ASSERT(stringLenOp >= 2);
3002
62.3k
                if (currentLen == 0) {
3003
                    // Add the starting character of this string to the set of possible starting
3004
                    //   characters for this pattern.
3005
12.2k
                    int32_t stringStartIdx = URX_VAL(op);
3006
12.2k
                    UChar32  c = fRXPat->fLiteralText.char32At(stringStartIdx);
3007
12.2k
                    fRXPat->fInitialChars->add(c);
3008
3009
                    // Remember this string.  After the entire pattern has been checked,
3010
                    //  if nothing else is identified that can start a match, we'll use it.
3011
12.2k
                    numInitialStrings++;
3012
12.2k
                    fRXPat->fInitialStringIdx = stringStartIdx;
3013
12.2k
                    fRXPat->fInitialStringLen = stringLen;
3014
12.2k
                }
3015
3016
62.3k
                currentLen = safeIncrement(currentLen, stringLen);
3017
62.3k
                atStart = false;
3018
62.3k
            }
3019
62.3k
            break;
3020
3021
1.21M
        case URX_STRING_I:
3022
1.21M
            {
3023
                // Case-insensitive string.  Unlike exact-match strings, we won't
3024
                //   attempt a string search for possible match positions.  But we
3025
                //   do update the set of possible starting characters.
3026
1.21M
                loc++;
3027
1.21M
                int32_t stringLenOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3028
1.21M
                int32_t stringLen   = URX_VAL(stringLenOp);
3029
1.21M
                U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
3030
1.21M
                U_ASSERT(stringLenOp >= 2);
3031
1.21M
                if (currentLen == 0) {
3032
                    // Add the starting character of this string to the set of possible starting
3033
                    //   characters for this pattern.
3034
548k
                    int32_t stringStartIdx = URX_VAL(op);
3035
548k
                    UChar32  c = fRXPat->fLiteralText.char32At(stringStartIdx);
3036
548k
                    UnicodeSet s;
3037
548k
                    findCaseInsensitiveStarters(c, &s);
3038
548k
                    fRXPat->fInitialChars->addAll(s);
3039
548k
                    numInitialStrings += 2;  // Matching on an initial string not possible.
3040
548k
                }
3041
1.21M
                currentLen = safeIncrement(currentLen, stringLen);
3042
1.21M
                atStart = false;
3043
1.21M
            }
3044
1.21M
            break;
3045
3046
3.71k
        case URX_CTR_INIT:
3047
4.94k
        case URX_CTR_INIT_NG:
3048
4.94k
            {
3049
                // Loop Init Ops.  These don't change the min length, but they are 4 word ops
3050
                //   so location must be updated accordingly.
3051
                // Loop Init Ops.
3052
                //   If the min loop count == 0
3053
                //      move loc forwards to the end of the loop, skipping over the body.
3054
                //   If the min count is > 0,
3055
                //      continue normal processing of the body of the loop.
3056
4.94k
                int32_t loopEndLoc = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc + 1));
3057
4.94k
                        loopEndLoc   = URX_VAL(loopEndLoc);
3058
4.94k
                int32_t minLoopCount = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc + 2));
3059
4.94k
                if (minLoopCount == 0) {
3060
                    // Min Loop Count of 0, treat like a forward branch and
3061
                    //   move the current minimum length up to the target
3062
                    //   (end of loop) location.
3063
2.84k
                    U_ASSERT(loopEndLoc <= end+1);
3064
2.84k
                    if (forwardedLength.elementAti(loopEndLoc) > currentLen) {
3065
2.48k
                        forwardedLength.setElementAt(currentLen, loopEndLoc);
3066
2.48k
                    }
3067
2.84k
                }
3068
4.94k
                loc+=3;  // Skips over operands of CTR_INIT
3069
4.94k
            }
3070
4.94k
            atStart = false;
3071
4.94k
            break;
3072
3073
3074
3.71k
        case URX_CTR_LOOP:
3075
4.94k
        case URX_CTR_LOOP_NG:
3076
            // Loop ops.
3077
            //  The jump is conditional, backwards only.
3078
4.94k
            atStart = false;
3079
4.94k
            break;
3080
3081
17.3k
        case URX_LOOP_C:
3082
            // More loop ops.  These state-save to themselves.
3083
            //   don't change the minimum match
3084
17.3k
            atStart = false;
3085
17.3k
            break;
3086
3087
3088
1.22k
        case URX_LA_START:
3089
3.12k
        case URX_LB_START:
3090
3.12k
            {
3091
                // Look-around.  Scan forward until the matching look-ahead end,
3092
                //   without processing the look-around block.  This is overly pessimistic.
3093
3094
                // Keep track of the nesting depth of look-around blocks.  Boilerplate code for
3095
                //   lookahead contains two LA_END instructions, so count goes up by two
3096
                //   for each LA_START.
3097
3.12k
                int32_t  depth = (opType == URX_LA_START? 2: 1);
3098
4.05M
                for (;;) {
3099
4.05M
                    loc++;
3100
4.05M
                    op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3101
4.05M
                    if (URX_TYPE(op) == URX_LA_START) {
3102
704
                        depth+=2;
3103
704
                    }
3104
4.05M
                    if (URX_TYPE(op) == URX_LB_START) {
3105
1.33k
                        depth++;
3106
1.33k
                    }
3107
4.05M
                    if (URX_TYPE(op) == URX_LA_END || URX_TYPE(op)==URX_LBN_END) {
3108
7.09k
                        depth--;
3109
7.09k
                        if (depth == 0) {
3110
3.12k
                            break;
3111
3.12k
                        }
3112
7.09k
                    }
3113
4.05M
                    if (URX_TYPE(op) == URX_STATE_SAVE) {
3114
                        // Need this because neg lookahead blocks will FAIL to outside
3115
                        //   of the block.
3116
1.97M
                        int32_t  jmpDest = URX_VAL(op);
3117
1.97M
                        if (jmpDest > loc) {
3118
1.97M
                            if (currentLen < forwardedLength.elementAti(jmpDest)) {
3119
1.88M
                                forwardedLength.setElementAt(currentLen, jmpDest);
3120
1.88M
                            }
3121
1.97M
                        }
3122
1.97M
                    }
3123
4.05M
                    U_ASSERT(loc <= end);
3124
4.05M
                }
3125
3.12k
            }
3126
3.12k
            break;
3127
3128
0
        case URX_LA_END:
3129
0
        case URX_LB_CONT:
3130
0
        case URX_LB_END:
3131
0
        case URX_LBN_CONT:
3132
0
        case URX_LBN_END:
3133
0
            UPRV_UNREACHABLE_EXIT;  // Shouldn't get here.  These ops should be
3134
                                    //  consumed by the scan in URX_LA_START and LB_START
3135
0
        default:
3136
0
            UPRV_UNREACHABLE_EXIT;
3137
23.6M
            }
3138
3139
23.6M
        }
3140
3141
3142
    // We have finished walking through the ops.  Check whether some forward jump
3143
    //   propagated a shorter length to location end+1.
3144
13.6k
    if (forwardedLength.elementAti(end+1) < currentLen) {
3145
11.5k
        currentLen = forwardedLength.elementAti(end+1);
3146
11.5k
    }
3147
3148
3149
13.6k
    fRXPat->fInitialChars8->init(fRXPat->fInitialChars);
3150
3151
3152
    // Sort out what we should check for when looking for candidate match start positions.
3153
    // In order of preference,
3154
    //     1.   Start of input text buffer.
3155
    //     2.   A literal string.
3156
    //     3.   Start of line in multi-line mode.
3157
    //     4.   A single literal character.
3158
    //     5.   A character from a set of characters.
3159
    //
3160
13.6k
    if (fRXPat->fStartType == START_START) {
3161
        // Match only at the start of an input text string.
3162
        //    start type is already set.  We're done.
3163
13.5k
    } else if (numInitialStrings == 1 && fRXPat->fMinMatchLen > 0) {
3164
        // Match beginning only with a literal string.
3165
442
        UChar32  c = fRXPat->fLiteralText.char32At(fRXPat->fInitialStringIdx);
3166
442
        U_ASSERT(fRXPat->fInitialChars->contains(c));
3167
442
        fRXPat->fStartType   = START_STRING;
3168
442
        fRXPat->fInitialChar = c;
3169
13.1k
    } else if (fRXPat->fStartType == START_LINE) {
3170
        // Match at start of line in Multi-Line mode.
3171
        // Nothing to do here; everything is already set.
3172
12.9k
    } else if (fRXPat->fMinMatchLen == 0) {
3173
        // Zero length match possible.  We could start anywhere.
3174
2.03k
        fRXPat->fStartType = START_NO_INFO;
3175
10.9k
    } else if (fRXPat->fInitialChars->size() == 1) {
3176
        // All matches begin with the same char.
3177
2.26k
        fRXPat->fStartType   = START_CHAR;
3178
2.26k
        fRXPat->fInitialChar = fRXPat->fInitialChars->charAt(0);
3179
2.26k
        U_ASSERT(fRXPat->fInitialChar != (UChar32)-1);
3180
8.65k
    } else if (fRXPat->fInitialChars->contains(static_cast<UChar32>(0), static_cast<UChar32>(0x10ffff)) == false &&
3181
4.78k
        fRXPat->fMinMatchLen > 0) {
3182
        // Matches start with a set of character smaller than the set of all chars.
3183
4.78k
        fRXPat->fStartType = START_SET;
3184
4.78k
    } else {
3185
        // Matches can start with anything
3186
3.86k
        fRXPat->fStartType = START_NO_INFO;
3187
3.86k
    }
3188
13.6k
}
3189
3190
3191
3192
//------------------------------------------------------------------------------
3193
//
3194
//   minMatchLength    Calculate the length of the shortest string that could
3195
//                     match the specified pattern.
3196
//                     Length is in 16 bit code units, not code points.
3197
//
3198
//                     The calculated length may not be exact.  The returned
3199
//                     value may be shorter than the actual minimum; it must
3200
//                     never be longer.
3201
//
3202
//                     start and end are the range of p-code operations to be
3203
//                     examined.  The endpoints are included in the range.
3204
//
3205
//------------------------------------------------------------------------------
3206
366k
int32_t   RegexCompile::minMatchLength(int32_t start, int32_t end) {
3207
366k
    if (U_FAILURE(*fStatus)) {
3208
80
        return 0;
3209
80
    }
3210
3211
366k
    U_ASSERT(start <= end);
3212
366k
    U_ASSERT(end < fRXPat->fCompiledPat->size());
3213
3214
3215
366k
    int32_t    loc;
3216
366k
    int32_t    op;
3217
366k
    int32_t    opType;
3218
366k
    int32_t    currentLen = 0;
3219
3220
3221
    // forwardedLength is a vector holding minimum-match-length values that
3222
    //   are propagated forward in the pattern by JMP or STATE_SAVE operations.
3223
    //   It must be one longer than the pattern being checked because some  ops
3224
    //   will jmp to a end-of-block+1 location from within a block, and we must
3225
    //   count those when checking the block.
3226
366k
    UVector32  forwardedLength(end+2, *fStatus);
3227
366k
    forwardedLength.setSize(end+2);
3228
40.9M
    for (loc=start; loc<=end+1; loc++) {
3229
40.5M
        forwardedLength.setElementAt(INT32_MAX, loc);
3230
40.5M
    }
3231
3232
30.6M
    for (loc = start; loc<=end; loc++) {
3233
30.2M
        op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3234
30.2M
        opType = URX_TYPE(op);
3235
3236
        // The loop is advancing linearly through the pattern.
3237
        // If the op we are now at was the destination of a branch in the pattern,
3238
        // and that path has a shorter minimum length than the current accumulated value,
3239
        // replace the current accumulated value.
3240
        // U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);  // MinLength == INT32_MAX for some
3241
                                                               //   no-match-possible cases.
3242
30.2M
        if (forwardedLength.elementAti(loc) < currentLen) {
3243
1.03M
            currentLen = forwardedLength.elementAti(loc);
3244
1.03M
            U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
3245
1.03M
        }
3246
3247
30.2M
        switch (opType) {
3248
            // Ops that don't change the total length matched
3249
0
        case URX_RESERVED_OP:
3250
13.6k
        case URX_END:
3251
13.6k
        case URX_STRING_LEN:
3252
570k
        case URX_NOP:
3253
759k
        case URX_START_CAPTURE:
3254
948k
        case URX_END_CAPTURE:
3255
949k
        case URX_BACKSLASH_B:
3256
955k
        case URX_BACKSLASH_BU:
3257
957k
        case URX_BACKSLASH_G:
3258
959k
        case URX_BACKSLASH_Z:
3259
966k
        case URX_CARET:
3260
1.08M
        case URX_DOLLAR:
3261
1.09M
        case URX_DOLLAR_M:
3262
1.15M
        case URX_DOLLAR_D:
3263
1.15M
        case URX_DOLLAR_MD:
3264
1.15M
        case URX_RELOC_OPRND:
3265
1.24M
        case URX_STO_INP_LOC:
3266
1.24M
        case URX_CARET_M:
3267
1.25M
        case URX_CARET_M_UNIX:
3268
1.25M
        case URX_BACKREF:         // BackRef.  Must assume that it might be a zero length match
3269
1.25M
        case URX_BACKREF_I:
3270
3271
1.31M
        case URX_STO_SP:          // Setup for atomic or possessive blocks.  Doesn't change what can match.
3272
1.36M
        case URX_LD_SP:
3273
3274
1.59M
        case URX_JMP_SAV:
3275
1.69M
        case URX_JMP_SAV_X:
3276
1.69M
            break;
3277
3278
3279
            // Ops that match a minimum of one character (one or two 16 bit code units.)
3280
            //
3281
895k
        case URX_ONECHAR:
3282
911k
        case URX_STATIC_SETREF:
3283
921k
        case URX_STAT_SETREF_N:
3284
1.10M
        case URX_SETREF:
3285
1.11M
        case URX_BACKSLASH_D:
3286
1.12M
        case URX_BACKSLASH_H:
3287
1.12M
        case URX_BACKSLASH_R:
3288
1.12M
        case URX_BACKSLASH_V:
3289
1.19M
        case URX_ONECHAR_I:
3290
1.19M
        case URX_BACKSLASH_X:   // Grapheme Cluster.  Minimum is 1, max unbounded.
3291
1.20M
        case URX_DOTANY_ALL:    // . matches one or two.
3292
1.63M
        case URX_DOTANY:
3293
1.64M
        case URX_DOTANY_UNIX:
3294
1.64M
            currentLen = safeIncrement(currentLen, 1);
3295
1.64M
            break;
3296
3297
3298
0
        case URX_JMPX:
3299
0
            loc++;              // URX_JMPX has an extra operand, ignored here,
3300
                                //   otherwise processed identically to URX_JMP.
3301
0
            U_FALLTHROUGH;
3302
12.2M
        case URX_JMP:
3303
12.2M
            {
3304
12.2M
                int32_t  jmpDest = URX_VAL(op);
3305
12.2M
                if (jmpDest < loc) {
3306
                    // Loop of some kind.  Can safely ignore, the worst that will happen
3307
                    //  is that we understate the true minimum length
3308
22.4k
                    currentLen = forwardedLength.elementAti(loc+1);
3309
12.2M
                } else {
3310
                    // Forward jump.  Propagate the current min length to the target loc of the jump.
3311
12.2M
                    U_ASSERT(jmpDest <= end+1);
3312
12.2M
                    if (forwardedLength.elementAti(jmpDest) > currentLen) {
3313
11.2k
                        forwardedLength.setElementAt(currentLen, jmpDest);
3314
11.2k
                    }
3315
12.2M
                }
3316
12.2M
            }
3317
12.2M
            break;
3318
3319
5.57k
        case URX_BACKTRACK:
3320
5.57k
            {
3321
                // Back-tracks are kind of like a branch, except that the min length was
3322
                //   propagated already, by the state save.
3323
5.57k
                currentLen = forwardedLength.elementAti(loc+1);
3324
5.57k
            }
3325
5.57k
            break;
3326
3327
3328
13.0M
        case URX_STATE_SAVE:
3329
13.0M
            {
3330
                // State Save, for forward jumps, propagate the current minimum.
3331
                //             of the state save.
3332
13.0M
                int32_t  jmpDest = URX_VAL(op);
3333
13.0M
                if (jmpDest > loc) {
3334
13.0M
                    if (currentLen < forwardedLength.elementAti(jmpDest)) {
3335
12.6M
                        forwardedLength.setElementAt(currentLen, jmpDest);
3336
12.6M
                    }
3337
13.0M
                }
3338
13.0M
            }
3339
13.0M
            break;
3340
3341
3342
89.5k
        case URX_STRING:
3343
89.5k
            {
3344
89.5k
                loc++;
3345
89.5k
                int32_t stringLenOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3346
89.5k
                currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
3347
89.5k
            }
3348
89.5k
            break;
3349
3350
3351
1.42M
        case URX_STRING_I:
3352
1.42M
            {
3353
1.42M
                loc++;
3354
                // TODO: with full case folding, matching input text may be shorter than
3355
                //       the string we have here.  More smarts could put some bounds on it.
3356
                //       Assume a min length of one for now.  A min length of zero causes
3357
                //        optimization failures for a pattern like "string"+
3358
                // currentLen += URX_VAL(stringLenOp);
3359
1.42M
                currentLen = safeIncrement(currentLen, 1);
3360
1.42M
            }
3361
1.42M
            break;
3362
3363
6.57k
        case URX_CTR_INIT:
3364
9.43k
        case URX_CTR_INIT_NG:
3365
9.43k
            {
3366
                // Loop Init Ops.
3367
                //   If the min loop count == 0
3368
                //      move loc forwards to the end of the loop, skipping over the body.
3369
                //   If the min count is > 0,
3370
                //      continue normal processing of the body of the loop.
3371
9.43k
                int32_t loopEndLoc = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc + 1));
3372
9.43k
                        loopEndLoc   = URX_VAL(loopEndLoc);
3373
9.43k
                int32_t minLoopCount = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc + 2));
3374
9.43k
                if (minLoopCount == 0) {
3375
5.15k
                    loc = loopEndLoc;
3376
5.15k
                } else {
3377
4.27k
                    loc+=3;  // Skips over operands of CTR_INIT
3378
4.27k
                }
3379
9.43k
            }
3380
9.43k
            break;
3381
3382
3383
2.79k
        case URX_CTR_LOOP:
3384
4.27k
        case URX_CTR_LOOP_NG:
3385
            // Loop ops.
3386
            //  The jump is conditional, backwards only.
3387
4.27k
            break;
3388
3389
3.99k
        case URX_LOOP_SR_I:
3390
17.3k
        case URX_LOOP_DOT_I:
3391
34.7k
        case URX_LOOP_C:
3392
            // More loop ops.  These state-save to themselves.
3393
            //   don't change the minimum match - could match nothing at all.
3394
34.7k
            break;
3395
3396
3397
2.03k
        case URX_LA_START:
3398
6.76k
        case URX_LB_START:
3399
6.76k
            {
3400
                // Look-around.  Scan forward until the matching look-ahead end,
3401
                //   without processing the look-around block.  This is overly pessimistic for look-ahead,
3402
                //   it assumes that the look-ahead match might be zero-length.
3403
                //   TODO:  Positive lookahead could recursively do the block, then continue
3404
                //          with the longer of the block or the value coming in.  Ticket 6060
3405
6.76k
                int32_t  depth = (opType == URX_LA_START? 2: 1);
3406
7.76M
                for (;;) {
3407
7.76M
                    loc++;
3408
7.76M
                    op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3409
7.76M
                    if (URX_TYPE(op) == URX_LA_START) {
3410
                        // The boilerplate for look-ahead includes two LA_END instructions,
3411
                        //    Depth will be decremented by each one when it is seen.
3412
2.20k
                        depth += 2;
3413
2.20k
                    }
3414
7.76M
                    if (URX_TYPE(op) == URX_LB_START) {
3415
4.84k
                        depth++;
3416
4.84k
                    }
3417
7.76M
                    if (URX_TYPE(op) == URX_LA_END) {
3418
12.2k
                        depth--;
3419
12.2k
                        if (depth == 0) {
3420
4.31k
                            break;
3421
4.31k
                        }
3422
12.2k
                    }
3423
7.75M
                    if (URX_TYPE(op)==URX_LBN_END) {
3424
5.79k
                        depth--;
3425
5.79k
                        if (depth == 0) {
3426
2.45k
                            break;
3427
2.45k
                        }
3428
5.79k
                    }
3429
7.75M
                    if (URX_TYPE(op) == URX_STATE_SAVE) {
3430
                        // Need this because neg lookahead blocks will FAIL to outside
3431
                        //   of the block.
3432
3.76M
                        int32_t  jmpDest = URX_VAL(op);
3433
3.76M
                        if (jmpDest > loc) {
3434
3.76M
                            if (currentLen < forwardedLength.elementAti(jmpDest)) {
3435
3.67M
                                forwardedLength.setElementAt(currentLen, jmpDest);
3436
3.67M
                            }
3437
3.76M
                        }
3438
3.76M
                    }
3439
7.75M
                    U_ASSERT(loc <= end);
3440
7.75M
                }
3441
6.76k
            }
3442
6.76k
            break;
3443
3444
3.58k
        case URX_LA_END:
3445
3.58k
        case URX_LB_CONT:
3446
7.16k
        case URX_LB_END:
3447
7.16k
        case URX_LBN_CONT:
3448
10.8k
        case URX_LBN_END:
3449
            // Only come here if the matching URX_LA_START or URX_LB_START was not in the
3450
            //   range being sized, which happens when measuring size of look-behind blocks.
3451
10.8k
            break;
3452
3453
0
        default:
3454
0
            UPRV_UNREACHABLE_EXIT;
3455
30.2M
            }
3456
3457
30.2M
        }
3458
3459
    // We have finished walking through the ops.  Check whether some forward jump
3460
    //   propagated a shorter length to location end+1.
3461
366k
    if (forwardedLength.elementAti(end+1) < currentLen) {
3462
329
        currentLen = forwardedLength.elementAti(end+1);
3463
329
        U_ASSERT(currentLen>=0 && currentLen < INT32_MAX);
3464
329
    }
3465
3466
366k
    return currentLen;
3467
366k
}
3468
3469
//------------------------------------------------------------------------------
3470
//
3471
//   maxMatchLength    Calculate the length of the longest string that could
3472
//                     match the specified pattern.
3473
//                     Length is in 16 bit code units, not code points.
3474
//
3475
//                     The calculated length may not be exact.  The returned
3476
//                     value may be longer than the actual maximum; it must
3477
//                     never be shorter.
3478
//
3479
//                     start, end: the range of the pattern to check.
3480
//                     end is inclusive.
3481
//
3482
//------------------------------------------------------------------------------
3483
11.0k
int32_t   RegexCompile::maxMatchLength(int32_t start, int32_t end) {
3484
11.0k
    if (U_FAILURE(*fStatus)) {
3485
0
        return 0;
3486
0
    }
3487
11.0k
    U_ASSERT(start <= end);
3488
11.0k
    U_ASSERT(end < fRXPat->fCompiledPat->size());
3489
3490
11.0k
    int32_t    loc;
3491
11.0k
    int32_t    op;
3492
11.0k
    int32_t    opType;
3493
11.0k
    int32_t    currentLen = 0;
3494
11.0k
    UVector32  forwardedLength(end+1, *fStatus);
3495
11.0k
    forwardedLength.setSize(end+1);
3496
3497
10.4M
    for (loc=start; loc<=end; loc++) {
3498
10.4M
        forwardedLength.setElementAt(0, loc);
3499
10.4M
    }
3500
3501
6.89M
    for (loc = start; loc<=end; loc++) {
3502
6.88M
        op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3503
6.88M
        opType = URX_TYPE(op);
3504
3505
        // The loop is advancing linearly through the pattern.
3506
        // If the op we are now at was the destination of a branch in the pattern,
3507
        // and that path has a longer maximum length than the current accumulated value,
3508
        // replace the current accumulated value.
3509
6.88M
        if (forwardedLength.elementAti(loc) > currentLen) {
3510
1.63M
            currentLen = forwardedLength.elementAti(loc);
3511
1.63M
        }
3512
3513
6.88M
        switch (opType) {
3514
            // Ops that don't change the total length matched
3515
0
        case URX_RESERVED_OP:
3516
0
        case URX_END:
3517
0
        case URX_STRING_LEN:
3518
168k
        case URX_NOP:
3519
244k
        case URX_START_CAPTURE:
3520
320k
        case URX_END_CAPTURE:
3521
320k
        case URX_BACKSLASH_B:
3522
321k
        case URX_BACKSLASH_BU:
3523
321k
        case URX_BACKSLASH_G:
3524
322k
        case URX_BACKSLASH_Z:
3525
323k
        case URX_CARET:
3526
323k
        case URX_DOLLAR:
3527
324k
        case URX_DOLLAR_M:
3528
324k
        case URX_DOLLAR_D:
3529
325k
        case URX_DOLLAR_MD:
3530
325k
        case URX_RELOC_OPRND:
3531
325k
        case URX_STO_INP_LOC:
3532
326k
        case URX_CARET_M:
3533
327k
        case URX_CARET_M_UNIX:
3534
3535
328k
        case URX_STO_SP:          // Setup for atomic or possessive blocks.  Doesn't change what can match.
3536
329k
        case URX_LD_SP:
3537
3538
333k
        case URX_LB_END:
3539
333k
        case URX_LB_CONT:
3540
333k
        case URX_LBN_CONT:
3541
336k
        case URX_LBN_END:
3542
336k
            break;
3543
3544
3545
            // Ops that increase that cause an unbounded increase in the length
3546
            //   of a matched string, or that increase it a hard to characterize way.
3547
            //   Call the max length unbounded, and stop further checking.
3548
405
        case URX_BACKREF:         // BackRef.  Must assume that it might be a zero length match
3549
600
        case URX_BACKREF_I:
3550
705
        case URX_BACKSLASH_X:   // Grapheme Cluster.  Minimum is 1, max unbounded.
3551
705
            currentLen = INT32_MAX;
3552
705
            break;
3553
3554
3555
            // Ops that match a max of one character (possibly two 16 bit code units.)
3556
            //
3557
4.64k
        case URX_STATIC_SETREF:
3558
5.74k
        case URX_STAT_SETREF_N:
3559
6.50k
        case URX_SETREF:
3560
7.73k
        case URX_BACKSLASH_D:
3561
8.08k
        case URX_BACKSLASH_H:
3562
8.40k
        case URX_BACKSLASH_R:
3563
8.76k
        case URX_BACKSLASH_V:
3564
10.7k
        case URX_ONECHAR_I:
3565
11.0k
        case URX_DOTANY_ALL:
3566
22.0k
        case URX_DOTANY:
3567
22.4k
        case URX_DOTANY_UNIX:
3568
22.4k
            currentLen = safeIncrement(currentLen, 2);
3569
22.4k
            break;
3570
3571
            // Single literal character.  Increase current max length by one or two,
3572
            //       depending on whether the char is in the supplementary range.
3573
203k
        case URX_ONECHAR:
3574
203k
            currentLen = safeIncrement(currentLen, 1);
3575
203k
            if (URX_VAL(op) > 0x10000) {
3576
1.68k
                currentLen = safeIncrement(currentLen, 1);
3577
1.68k
            }
3578
203k
            break;
3579
3580
            // Jumps.
3581
            //
3582
3.03M
        case URX_JMP:
3583
3.03M
        case URX_JMPX:
3584
3.03M
        case URX_JMP_SAV:
3585
3.03M
        case URX_JMP_SAV_X:
3586
3.03M
            {
3587
3.03M
                int32_t  jmpDest = URX_VAL(op);
3588
3.03M
                if (jmpDest < loc) {
3589
                    // Loop of some kind.  Max match length is unbounded.
3590
702
                    currentLen = INT32_MAX;
3591
3.03M
                } else {
3592
                    // Forward jump.  Propagate the current min length to the target loc of the jump.
3593
3.03M
                    if (forwardedLength.elementAti(jmpDest) < currentLen) {
3594
4.06k
                        forwardedLength.setElementAt(currentLen, jmpDest);
3595
4.06k
                    }
3596
3.03M
                    currentLen = 0;
3597
3.03M
                }
3598
3.03M
            }
3599
3.03M
            break;
3600
3601
2.71k
        case URX_BACKTRACK:
3602
            // back-tracks are kind of like a branch, except that the max length was
3603
            //   propagated already, by the state save.
3604
2.71k
            currentLen = forwardedLength.elementAti(loc+1);
3605
2.71k
            break;
3606
3607
3608
3.20M
        case URX_STATE_SAVE:
3609
3.20M
            {
3610
                // State Save, for forward jumps, propagate the current minimum.
3611
                //               of the state save.
3612
                //             For backwards jumps, they create a loop, maximum
3613
                //               match length is unbounded.
3614
3.20M
                int32_t  jmpDest = URX_VAL(op);
3615
3.20M
                if (jmpDest > loc) {
3616
3.20M
                    if (currentLen > forwardedLength.elementAti(jmpDest)) {
3617
1.78M
                        forwardedLength.setElementAt(currentLen, jmpDest);
3618
1.78M
                    }
3619
3.20M
                } else {
3620
78
                    currentLen = INT32_MAX;
3621
78
                }
3622
3.20M
            }
3623
3.20M
            break;
3624
3625
3626
3627
3628
33.2k
        case URX_STRING:
3629
33.2k
            {
3630
33.2k
                loc++;
3631
33.2k
                int32_t stringLenOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3632
33.2k
                currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
3633
33.2k
                break;
3634
3.03M
            }
3635
3636
27.6k
        case URX_STRING_I:
3637
            // TODO:  This code assumes that any user string that matches will be no longer
3638
            //        than our compiled string, with case insensitive matching.
3639
            //        Our compiled string has been case-folded already.
3640
            //
3641
            //        Any matching user string will have no more code points than our
3642
            //        compiled (folded) string.  Folding may add code points, but
3643
            //        not remove them.
3644
            //
3645
            //        There is a potential problem if a supplemental code point
3646
            //        case-folds to a BMP code point.  In this case our compiled string
3647
            //        could be shorter (in code units) than a matching user string.
3648
            //
3649
            //        At this time (Unicode 6.1) there are no such characters, and this case
3650
            //        is not being handled.  A test, intltest regex/Bug9283, will fail if
3651
            //        any problematic characters are added to Unicode.
3652
            //
3653
            //        If this happens, we can make a set of the BMP chars that the
3654
            //        troublesome supplementals fold to, scan our string, and bump the
3655
            //        currentLen one extra for each that is found.
3656
            //
3657
27.6k
            {
3658
27.6k
                loc++;
3659
27.6k
                int32_t stringLenOp = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3660
27.6k
                currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
3661
27.6k
            }
3662
27.6k
            break;
3663
3664
2.56k
        case URX_CTR_INIT:
3665
3.75k
        case URX_CTR_INIT_NG:
3666
            // For Loops, recursively call this function on the pattern for the loop body,
3667
            //   then multiply the result by the maximum loop count.
3668
3.75k
            {
3669
3.75k
                int32_t  loopEndLoc = URX_VAL(fRXPat->fCompiledPat->elementAti(loc+1));
3670
3.75k
                if (loopEndLoc == loc+4) {
3671
                    // Loop has an empty body. No affect on max match length.
3672
                    // Continue processing with code after the loop end.
3673
0
                    loc = loopEndLoc;
3674
0
                    break;
3675
0
                }
3676
3677
3.75k
                int32_t maxLoopCount = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc+3));
3678
3.75k
                if (maxLoopCount == -1) {
3679
                    // Unbounded Loop. No upper bound on match length.
3680
18
                    currentLen = INT32_MAX;
3681
18
                    break;
3682
18
                }
3683
3684
3.73k
                U_ASSERT(loopEndLoc >= loc+4);
3685
3.73k
                int64_t blockLen = maxMatchLength(loc+4, loopEndLoc-1);  // Recursive call.
3686
3.73k
                int64_t updatedLen = static_cast<int64_t>(currentLen) + blockLen * maxLoopCount;
3687
3.73k
                if (updatedLen >= INT32_MAX) {
3688
108
                    currentLen = INT32_MAX;
3689
108
                    break;
3690
108
                }
3691
3.62k
                currentLen = static_cast<int32_t>(updatedLen);
3692
3.62k
                loc = loopEndLoc;
3693
3.62k
                break;
3694
3.73k
            }
3695
3696
0
        case URX_CTR_LOOP:
3697
0
        case URX_CTR_LOOP_NG:
3698
            // These opcodes will be skipped over by code for URX_CTR_INIT.
3699
            // We shouldn't encounter them here.
3700
0
            UPRV_UNREACHABLE_EXIT;
3701
3702
164
        case URX_LOOP_SR_I:
3703
263
        case URX_LOOP_DOT_I:
3704
263
        case URX_LOOP_C:
3705
            // For anything to do with loops, make the match length unbounded.
3706
263
            currentLen = INT32_MAX;
3707
263
            break;
3708
3709
3710
3711
1.49k
        case URX_LA_START:
3712
7.95k
        case URX_LA_END:
3713
            // Look-ahead.  Just ignore, treat the look-ahead block as if
3714
            // it were normal pattern.  Gives a too-long match length,
3715
            //  but good enough for now.
3716
7.95k
            break;
3717
3718
            // End of look-ahead ops should always be consumed by the processing at
3719
            //  the URX_LA_START op.
3720
            // UPRV_UNREACHABLE_EXIT;
3721
3722
2.78k
        case URX_LB_START:
3723
2.78k
            {
3724
                // Look-behind.  Scan forward until the matching look-around end,
3725
                //   without processing the look-behind block.
3726
2.78k
                int32_t dataLoc = URX_VAL(op);
3727
372k
                for (loc = loc + 1; loc <= end; ++loc) {
3728
372k
                    op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3729
372k
                    int32_t opType = URX_TYPE(op);
3730
372k
                    if ((opType == URX_LA_END || opType == URX_LBN_END) && (URX_VAL(op) == dataLoc)) {
3731
2.78k
                        break;
3732
2.78k
                    }
3733
372k
                }
3734
2.78k
                U_ASSERT(loc <= end);
3735
2.78k
            }
3736
2.78k
            break;
3737
3738
0
        default:
3739
0
            UPRV_UNREACHABLE_EXIT;
3740
6.88M
        }
3741
3742
3743
6.88M
        if (currentLen == INT32_MAX) {
3744
            //  The maximum length is unbounded.
3745
            //  Stop further processing of the pattern.
3746
1.88k
            break;
3747
1.88k
        }
3748
3749
6.88M
    }
3750
11.0k
    return currentLen;
3751
3752
11.0k
}
3753
3754
3755
//------------------------------------------------------------------------------
3756
//
3757
//   stripNOPs    Remove any NOP operations from the compiled pattern code.
3758
//                Extra NOPs are inserted for some constructs during the initial
3759
//                code generation to provide locations that may be patched later.
3760
//                Many end up unneeded, and are removed by this function.
3761
//
3762
//                In order to minimize the number of passes through the pattern,
3763
//                back-reference fixup is also performed here (adjusting
3764
//                back-reference operands to point to the correct frame offsets).
3765
//
3766
//------------------------------------------------------------------------------
3767
13.7k
void RegexCompile::stripNOPs() {
3768
3769
13.7k
    if (U_FAILURE(*fStatus)) {
3770
0
        return;
3771
0
    }
3772
3773
13.7k
    int32_t    end = fRXPat->fCompiledPat->size();
3774
13.7k
    UVector32  deltas(end, *fStatus);
3775
3776
    // Make a first pass over the code, computing the amount that things
3777
    //   will be offset at each location in the original code.
3778
13.7k
    int32_t   loc;
3779
13.7k
    int32_t   d = 0;
3780
29.7M
    for (loc=0; loc<end; loc++) {
3781
29.7M
        deltas.addElement(d, *fStatus);
3782
29.7M
        int32_t op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(loc));
3783
29.7M
        if (URX_TYPE(op) == URX_NOP) {
3784
209k
            d++;
3785
209k
        }
3786
29.7M
    }
3787
3788
13.7k
    UnicodeString caseStringBuffer;
3789
3790
    // Make a second pass over the code, removing the NOPs by moving following
3791
    //  code up, and patching operands that refer to code locations that
3792
    //  are being moved.  The array of offsets from the first step is used
3793
    //  to compute the new operand values.
3794
13.7k
    int32_t src;
3795
13.7k
    int32_t dst = 0;
3796
29.7M
    for (src=0; src<end; src++) {
3797
29.7M
        int32_t op = static_cast<int32_t>(fRXPat->fCompiledPat->elementAti(src));
3798
29.7M
        int32_t opType = URX_TYPE(op);
3799
29.7M
        switch (opType) {
3800
209k
        case URX_NOP:
3801
209k
            break;
3802
3803
12.6M
        case URX_STATE_SAVE:
3804
24.4M
        case URX_JMP:
3805
24.4M
        case URX_CTR_LOOP:
3806
24.4M
        case URX_CTR_LOOP_NG:
3807
24.4M
        case URX_RELOC_OPRND:
3808
24.4M
        case URX_JMPX:
3809
24.7M
        case URX_JMP_SAV:
3810
24.7M
        case URX_JMP_SAV_X:
3811
            // These are instructions with operands that refer to code locations.
3812
24.7M
            {
3813
24.7M
                int32_t  operandAddress = URX_VAL(op);
3814
24.7M
                U_ASSERT(operandAddress>=0 && operandAddress<deltas.size());
3815
24.7M
                int32_t fixedOperandAddress = operandAddress - deltas.elementAti(operandAddress);
3816
24.7M
                op = buildOp(opType, fixedOperandAddress);
3817
24.7M
                fRXPat->fCompiledPat->setElementAt(op, dst);
3818
24.7M
                dst++;
3819
24.7M
                break;
3820
24.7M
            }
3821
3822
1.81k
        case URX_BACKREF:
3823
6.67k
        case URX_BACKREF_I:
3824
6.67k
            {
3825
6.67k
                int32_t where = URX_VAL(op);
3826
6.67k
                if (where > fRXPat->fGroupMap->size()) {
3827
845
                    error(U_REGEX_INVALID_BACK_REF);
3828
845
                    break;
3829
845
                }
3830
5.82k
                where = fRXPat->fGroupMap->elementAti(where-1);
3831
5.82k
                op    = buildOp(opType, where);
3832
5.82k
                fRXPat->fCompiledPat->setElementAt(op, dst);
3833
5.82k
                dst++;
3834
3835
5.82k
                fRXPat->fNeedsAltInput = true;
3836
5.82k
                break;
3837
6.67k
            }
3838
15.7k
        case URX_RESERVED_OP:
3839
17.1k
        case URX_RESERVED_OP_N:
3840
22.9k
        case URX_BACKTRACK:
3841
36.7k
        case URX_END:
3842
821k
        case URX_ONECHAR:
3843
904k
        case URX_STRING:
3844
2.20M
        case URX_STRING_LEN:
3845
2.29M
        case URX_START_CAPTURE:
3846
2.38M
        case URX_END_CAPTURE:
3847
2.39M
        case URX_STATIC_SETREF:
3848
2.40M
        case URX_STAT_SETREF_N:
3849
2.58M
        case URX_SETREF:
3850
3.00M
        case URX_DOTANY:
3851
3.02M
        case URX_FAIL:
3852
3.02M
        case URX_BACKSLASH_B:
3853
3.02M
        case URX_BACKSLASH_BU:
3854
3.02M
        case URX_BACKSLASH_G:
3855
3.03M
        case URX_BACKSLASH_X:
3856
3.03M
        case URX_BACKSLASH_Z:
3857
3.04M
        case URX_DOTANY_ALL:
3858
3.04M
        case URX_BACKSLASH_D:
3859
3.05M
        case URX_CARET:
3860
3.11M
        case URX_DOLLAR:
3861
3.12M
        case URX_CTR_INIT:
3862
3.12M
        case URX_CTR_INIT_NG:
3863
3.13M
        case URX_DOTANY_UNIX:
3864
3.18M
        case URX_STO_SP:
3865
3.24M
        case URX_LD_SP:
3866
3.33M
        case URX_STO_INP_LOC:
3867
3.33M
        case URX_LA_START:
3868
3.34M
        case URX_LA_END:
3869
3.39M
        case URX_ONECHAR_I:
3870
4.61M
        case URX_STRING_I:
3871
4.61M
        case URX_DOLLAR_M:
3872
4.61M
        case URX_CARET_M:
3873
4.61M
        case URX_CARET_M_UNIX:
3874
4.62M
        case URX_LB_START:
3875
4.62M
        case URX_LB_CONT:
3876
4.62M
        case URX_LB_END:
3877
4.62M
        case URX_LBN_CONT:
3878
4.62M
        case URX_LBN_END:
3879
4.63M
        case URX_LOOP_SR_I:
3880
4.64M
        case URX_LOOP_DOT_I:
3881
4.66M
        case URX_LOOP_C:
3882
4.69M
        case URX_DOLLAR_D:
3883
4.69M
        case URX_DOLLAR_MD:
3884
4.70M
        case URX_BACKSLASH_H:
3885
4.70M
        case URX_BACKSLASH_R:
3886
4.70M
        case URX_BACKSLASH_V:
3887
            // These instructions are unaltered by the relocation.
3888
4.70M
            fRXPat->fCompiledPat->setElementAt(op, dst);
3889
4.70M
            dst++;
3890
4.70M
            break;
3891
3892
0
        default:
3893
            // Some op is unaccounted for.
3894
0
            UPRV_UNREACHABLE_EXIT;
3895
29.7M
        }
3896
29.7M
    }
3897
3898
13.7k
    fRXPat->fCompiledPat->setSize(dst);
3899
13.7k
}
3900
3901
3902
3903
3904
//------------------------------------------------------------------------------
3905
//
3906
//  Error         Report a rule parse error.
3907
//                Only report it if no previous error has been recorded.
3908
//
3909
//------------------------------------------------------------------------------
3910
8.93k
void RegexCompile::error(UErrorCode e) {
3911
8.93k
    if (U_SUCCESS(*fStatus) || e == U_MEMORY_ALLOCATION_ERROR) {
3912
7.57k
        *fStatus = e;
3913
        // Hmm. fParseErr (UParseError) line & offset fields are int32_t in public
3914
        // API (see common/unicode/parseerr.h), while fLineNum and fCharNum are
3915
        // int64_t. If the values of the latter are out of range for the former,
3916
        // set them to the appropriate "field not supported" values.
3917
7.57k
        if (fLineNum > 0x7FFFFFFF) {
3918
0
            fParseErr->line   = 0;
3919
0
            fParseErr->offset = -1;
3920
7.57k
        } else if (fCharNum > 0x7FFFFFFF) {
3921
0
            fParseErr->line = static_cast<int32_t>(fLineNum);
3922
0
            fParseErr->offset = -1;
3923
7.57k
        } else {
3924
7.57k
            fParseErr->line = static_cast<int32_t>(fLineNum);
3925
7.57k
            fParseErr->offset = static_cast<int32_t>(fCharNum);
3926
7.57k
        }
3927
3928
7.57k
        UErrorCode status = U_ZERO_ERROR; // throwaway status for extracting context
3929
3930
        // Fill in the context.
3931
        //   Note: extractBetween() pins supplied indices to the string bounds.
3932
7.57k
        uprv_memset(fParseErr->preContext,  0, sizeof(fParseErr->preContext));
3933
7.57k
        uprv_memset(fParseErr->postContext, 0, sizeof(fParseErr->postContext));
3934
7.57k
        utext_extract(fRXPat->fPattern, fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex, fParseErr->preContext, U_PARSE_CONTEXT_LEN, &status);
3935
7.57k
        utext_extract(fRXPat->fPattern, fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1, fParseErr->postContext, U_PARSE_CONTEXT_LEN, &status);
3936
7.57k
    }
3937
8.93k
}
3938
3939
3940
//
3941
//  Assorted Unicode character constants.
3942
//     Numeric because there is no portable way to enter them as literals.
3943
//     (Think EBCDIC).
3944
//
3945
static const char16_t   chCR        = 0x0d;      // New lines, for terminating comments.
3946
static const char16_t   chLF        = 0x0a;      // Line Feed
3947
static const char16_t   chPound     = 0x23;      // '#', introduces a comment.
3948
static const char16_t   chDigit0    = 0x30;      // '0'
3949
static const char16_t   chDigit7    = 0x37;      // '9'
3950
static const char16_t   chColon     = 0x3A;      // ':'
3951
static const char16_t   chE         = 0x45;      // 'E'
3952
static const char16_t   chQ         = 0x51;      // 'Q'
3953
//static const char16_t   chN         = 0x4E;      // 'N'
3954
static const char16_t   chP         = 0x50;      // 'P'
3955
static const char16_t   chBackSlash = 0x5c;      // '\'  introduces a char escape
3956
//static const char16_t   chLBracket  = 0x5b;      // '['
3957
static const char16_t   chRBracket  = 0x5d;      // ']'
3958
static const char16_t   chUp        = 0x5e;      // '^'
3959
static const char16_t   chLowerP    = 0x70;
3960
static const char16_t   chLBrace    = 0x7b;      // '{'
3961
static const char16_t   chRBrace    = 0x7d;      // '}'
3962
static const char16_t   chNEL       = 0x85;      //    NEL newline variant
3963
static const char16_t   chLS        = 0x2028;    //    Unicode Line Separator
3964
3965
3966
//------------------------------------------------------------------------------
3967
//
3968
//  nextCharLL    Low Level Next Char from the regex pattern.
3969
//                Get a char from the string, keep track of input position
3970
//                     for error reporting.
3971
//
3972
//------------------------------------------------------------------------------
3973
114M
UChar32  RegexCompile::nextCharLL() {
3974
114M
    UChar32       ch;
3975
3976
114M
    if (fPeekChar != -1) {
3977
448k
        ch = fPeekChar;
3978
448k
        fPeekChar = -1;
3979
448k
        return ch;
3980
448k
    }
3981
3982
    // assume we're already in the right place
3983
113M
    ch = UTEXT_NEXT32(fRXPat->fPattern);
3984
113M
    if (ch == U_SENTINEL) {
3985
25.5k
        return ch;
3986
25.5k
    }
3987
3988
113M
    if (ch == chCR ||
3989
113M
        ch == chNEL ||
3990
113M
        ch == chLS   ||
3991
113M
        (ch == chLF && fLastChar != chCR)) {
3992
        // Character is starting a new line.  Bump up the line number, and
3993
        //  reset the column to 0.
3994
154k
        fLineNum++;
3995
154k
        fCharNum=0;
3996
154k
    }
3997
113M
    else {
3998
        // Character is not starting a new line.  Except in the case of a
3999
        //   LF following a CR, increment the column position.
4000
113M
        if (ch != chLF) {
4001
113M
            fCharNum++;
4002
113M
        }
4003
113M
    }
4004
113M
    fLastChar = ch;
4005
113M
    return ch;
4006
113M
}
4007
4008
//------------------------------------------------------------------------------
4009
//
4010
//   peekCharLL    Low Level Character Scanning, sneak a peek at the next
4011
//                 character without actually getting it.
4012
//
4013
//------------------------------------------------------------------------------
4014
929k
UChar32  RegexCompile::peekCharLL() {
4015
929k
    if (fPeekChar == -1) {
4016
451k
        fPeekChar = nextCharLL();
4017
451k
    }
4018
929k
    return fPeekChar;
4019
929k
}
4020
4021
4022
//------------------------------------------------------------------------------
4023
//
4024
//   nextChar     for pattern scanning.  At this level, we handle stripping
4025
//                out comments and processing some backslash character escapes.
4026
//                The rest of the pattern grammar is handled at the next level up.
4027
//
4028
//------------------------------------------------------------------------------
4029
110M
void RegexCompile::nextChar(RegexPatternChar &c) {
4030
110M
  tailRecursion:
4031
110M
    fScanIndex = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
4032
110M
    c.fChar    = nextCharLL();
4033
110M
    c.fQuoted  = false;
4034
4035
110M
    if (fQuoteMode) {
4036
2.32M
        c.fQuoted = true;
4037
2.32M
        if ((c.fChar == chBackSlash && peekCharLL() == chE && ((fModeFlags & UREGEX_LITERAL) == 0)) ||
4038
2.32M
            c.fChar == static_cast<UChar32>(-1)) {
4039
2.26k
            fQuoteMode = false;  //  Exit quote mode,
4040
2.26k
            nextCharLL();        // discard the E
4041
            // nextChar(c);      // recurse to get the real next char
4042
2.26k
            goto tailRecursion;  // Note: fuzz testing produced testcases that
4043
                                 //       resulted in stack overflow here.
4044
2.26k
        }
4045
2.32M
    }
4046
108M
    else if (fInBackslashQuote) {
4047
        // The current character immediately follows a '\'
4048
        // Don't check for any further escapes, just return it as-is.
4049
        // Don't set c.fQuoted, because that would prevent the state machine from
4050
        //    dispatching on the character.
4051
233k
        fInBackslashQuote = false;
4052
233k
    }
4053
108M
    else
4054
108M
    {
4055
        // We are not in a \Q quoted region \E of the source.
4056
        //
4057
108M
        if (fModeFlags & UREGEX_COMMENTS) {
4058
            //
4059
            // We are in free-spacing and comments mode.
4060
            //  Scan through any white space and comments, until we
4061
            //  reach a significant character or the end of input.
4062
521k
            for (;;) {
4063
521k
                if (c.fChar == static_cast<UChar32>(-1)) {
4064
1.53k
                    break;     // End of Input
4065
1.53k
                }
4066
520k
                if  (c.fChar == chPound && fEOLComments) {
4067
                    // Start of a comment.  Consume the rest of it, until EOF or a new line
4068
2.87M
                    for (;;) {
4069
2.87M
                        c.fChar = nextCharLL();
4070
2.87M
                        if (c.fChar == static_cast<UChar32>(-1) || // EOF
4071
2.87M
                            c.fChar == chCR        ||
4072
2.86M
                            c.fChar == chLF        ||
4073
2.86M
                            c.fChar == chNEL       ||
4074
2.86M
                            c.fChar == chLS)       {
4075
6.11k
                            break;
4076
6.11k
                        }
4077
2.87M
                    }
4078
6.11k
                }
4079
                // TODO:  check what Java & Perl do with non-ASCII white spaces.  Ticket 6061.
4080
520k
                if (PatternProps::isWhiteSpace(c.fChar) == false) {
4081
505k
                    break;
4082
505k
                }
4083
14.6k
                c.fChar = nextCharLL();
4084
14.6k
            }
4085
507k
        }
4086
4087
        //
4088
        //  check for backslash escaped characters.
4089
        //
4090
108M
        if (c.fChar == chBackSlash) {
4091
399k
            int64_t pos = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
4092
399k
            if (RegexStaticSets::gStaticSets->fUnescapeCharSet.contains(peekCharLL())) {
4093
                //
4094
                // A '\' sequence that is handled by ICU's standard unescapeAt function.
4095
                //   Includes \uxxxx, \n, \r, many others.
4096
                //   Return the single equivalent character.
4097
                //
4098
157k
                nextCharLL();                 // get & discard the peeked char.
4099
157k
                c.fQuoted = true;
4100
4101
157k
                if (UTEXT_FULL_TEXT_IN_CHUNK(fRXPat->fPattern, fPatternLength)) {
4102
157k
                    int32_t endIndex = static_cast<int32_t>(pos);
4103
157k
                    c.fChar = u_unescapeAt(uregex_ucstr_unescape_charAt, &endIndex, static_cast<int32_t>(fPatternLength), const_cast<char16_t*>(fRXPat->fPattern->chunkContents));
4104
4105
157k
                    if (endIndex == pos) {
4106
200
                        error(U_REGEX_BAD_ESCAPE_SEQUENCE);
4107
200
                    }
4108
157k
                    fCharNum += endIndex - pos;
4109
157k
                    UTEXT_SETNATIVEINDEX(fRXPat->fPattern, endIndex);
4110
157k
                } else {
4111
0
                    int32_t offset = 0;
4112
0
                    struct URegexUTextUnescapeCharContext context = U_REGEX_UTEXT_UNESCAPE_CONTEXT(fRXPat->fPattern);
4113
4114
0
                    UTEXT_SETNATIVEINDEX(fRXPat->fPattern, pos);
4115
0
                    c.fChar = u_unescapeAt(uregex_utext_unescape_charAt, &offset, INT32_MAX, &context);
4116
4117
0
                    if (offset == 0) {
4118
0
                        error(U_REGEX_BAD_ESCAPE_SEQUENCE);
4119
0
                    } else if (context.lastOffset == offset) {
4120
0
                        UTEXT_PREVIOUS32(fRXPat->fPattern);
4121
0
                    } else if (context.lastOffset != offset-1) {
4122
0
                        utext_moveIndex32(fRXPat->fPattern, offset - context.lastOffset - 1);
4123
0
                    }
4124
0
                    fCharNum += offset;
4125
0
                }
4126
157k
            }
4127
242k
            else if (peekCharLL() == chDigit0) {
4128
                //  Octal Escape, using Java Regexp Conventions
4129
                //    which are \0 followed by 1-3 octal digits.
4130
                //    Different from ICU Unescape handling of Octal, which does not
4131
                //    require the leading 0.
4132
                //  Java also has the convention of only consuming 2 octal digits if
4133
                //    the three digit number would be > 0xff
4134
                //
4135
5.68k
                c.fChar = 0;
4136
5.68k
                nextCharLL();    // Consume the initial 0.
4137
5.68k
                int index;
4138
15.0k
                for (index=0; index<3; index++) {
4139
13.4k
                    int32_t ch = peekCharLL();
4140
13.4k
                    if (ch<chDigit0 || ch>chDigit7) {
4141
4.08k
                        if (index==0) {
4142
                           // \0 is not followed by any octal digits.
4143
292
                           error(U_REGEX_BAD_ESCAPE_SEQUENCE);
4144
292
                        }
4145
4.08k
                        break;
4146
4.08k
                    }
4147
9.33k
                    c.fChar <<= 3;
4148
9.33k
                    c.fChar += ch&7;
4149
9.33k
                    if (c.fChar <= 255) {
4150
8.10k
                        nextCharLL();
4151
8.10k
                    } else {
4152
                        // The last digit made the number too big.  Forget we saw it.
4153
1.22k
                        c.fChar >>= 3;
4154
1.22k
                    }
4155
9.33k
                }
4156
5.68k
                c.fQuoted = true;
4157
5.68k
            }
4158
236k
            else if (peekCharLL() == chQ) {
4159
                //  "\Q"  enter quote mode, which will continue until "\E"
4160
2.55k
                fQuoteMode = true;
4161
2.55k
                nextCharLL();        // discard the 'Q'.
4162
                // nextChar(c);      // recurse to get the real next char.
4163
2.55k
                goto tailRecursion;  // Note: fuzz testing produced test cases that
4164
                //                            resulted in stack overflow here.
4165
2.55k
            }
4166
234k
            else
4167
234k
            {
4168
                // We are in a '\' escape that will be handled by the state table scanner.
4169
                // Just return the backslash, but remember that the following char is to
4170
                //  be taken literally.
4171
234k
                fInBackslashQuote = true;
4172
234k
            }
4173
399k
        }
4174
108M
    }
4175
4176
    // re-enable # to end-of-line comments, in case they were disabled.
4177
    // They are disabled by the parser upon seeing '(?', but this lasts for
4178
    //  the fetching of the next character only.
4179
110M
    fEOLComments = true;
4180
4181
    // putc(c.fChar, stdout);
4182
110M
}
4183
4184
4185
4186
//------------------------------------------------------------------------------
4187
//
4188
//  scanNamedChar
4189
//            Get a UChar32 from a \N{UNICODE CHARACTER NAME} in the pattern.
4190
//
4191
//             The scan position will be at the 'N'.  On return
4192
//             the scan position should be just after the '}'
4193
//
4194
//             Return the UChar32
4195
//
4196
//------------------------------------------------------------------------------
4197
6.49k
UChar32  RegexCompile::scanNamedChar() {
4198
6.49k
    if (U_FAILURE(*fStatus)) {
4199
0
        return 0;
4200
0
    }
4201
4202
6.49k
    nextChar(fC);
4203
6.49k
    if (fC.fChar != chLBrace) {
4204
28
        error(U_REGEX_PROPERTY_SYNTAX);
4205
28
        return 0;
4206
28
    }
4207
4208
6.46k
    UnicodeString  charName;
4209
45.9k
    for (;;) {
4210
45.9k
        nextChar(fC);
4211
45.9k
        if (fC.fChar == chRBrace) {
4212
6.38k
            break;
4213
6.38k
        }
4214
39.5k
        if (fC.fChar == -1) {
4215
78
            error(U_REGEX_PROPERTY_SYNTAX);
4216
78
            return 0;
4217
78
        }
4218
39.4k
        charName.append(fC.fChar);
4219
39.4k
    }
4220
4221
6.38k
    char name[100];
4222
6.38k
    if (!uprv_isInvariantUString(charName.getBuffer(), charName.length()) ||
4223
6.37k
         static_cast<uint32_t>(charName.length()) >= sizeof(name)) {
4224
        // All Unicode character names have only invariant characters.
4225
        // The API to get a character, given a name, accepts only char *, forcing us to convert,
4226
        //   which requires this error check
4227
10
        error(U_REGEX_PROPERTY_SYNTAX);
4228
10
        return 0;
4229
10
    }
4230
6.37k
    charName.extract(0, charName.length(), name, sizeof(name), US_INV);
4231
4232
6.37k
    UChar32  theChar = u_charFromName(U_UNICODE_CHAR_NAME, name, fStatus);
4233
6.37k
    if (U_FAILURE(*fStatus)) {
4234
114
        error(U_REGEX_PROPERTY_SYNTAX);
4235
114
    }
4236
4237
6.37k
    nextChar(fC);      // Continue overall regex pattern processing with char after the '}'
4238
6.37k
    return theChar;
4239
6.38k
}
4240
4241
//------------------------------------------------------------------------------
4242
//
4243
//  scanProp   Construct a UnicodeSet from the text at the current scan
4244
//             position, which will be of the form \p{whaterver}
4245
//
4246
//             The scan position will be at the 'p' or 'P'.  On return
4247
//             the scan position should be just after the '}'
4248
//
4249
//             Return a UnicodeSet, constructed from the \P pattern,
4250
//             or nullptr if the pattern is invalid.
4251
//
4252
//------------------------------------------------------------------------------
4253
3.36k
UnicodeSet *RegexCompile::scanProp() {
4254
3.36k
    UnicodeSet    *uset = nullptr;
4255
4256
3.36k
    if (U_FAILURE(*fStatus)) {
4257
0
        return nullptr;
4258
0
    }
4259
3.36k
    (void)chLowerP;   // Suppress compiler unused variable warning.
4260
3.36k
    U_ASSERT(fC.fChar == chLowerP || fC.fChar == chP);
4261
3.36k
    UBool negated = (fC.fChar == chP);
4262
4263
3.36k
    UnicodeString propertyName;
4264
3.36k
    nextChar(fC);
4265
3.36k
    if (fC.fChar != chLBrace) {
4266
32
        error(U_REGEX_PROPERTY_SYNTAX);
4267
32
        return nullptr;
4268
32
    }
4269
1.72M
    for (;;) {
4270
1.72M
        nextChar(fC);
4271
1.72M
        if (fC.fChar == chRBrace) {
4272
3.28k
            break;
4273
3.28k
        }
4274
1.71M
        if (fC.fChar == -1) {
4275
            // Hit the end of the input string without finding the closing '}'
4276
48
            error(U_REGEX_PROPERTY_SYNTAX);
4277
48
            return nullptr;
4278
48
        }
4279
1.71M
        propertyName.append(fC.fChar);
4280
1.71M
    }
4281
3.28k
    uset = createSetForProperty(propertyName, negated);
4282
3.28k
    nextChar(fC);    // Move input scan to position following the closing '}'
4283
3.28k
    return uset;
4284
3.32k
}
4285
4286
//------------------------------------------------------------------------------
4287
//
4288
//  scanPosixProp   Construct a UnicodeSet from the text at the current scan
4289
//             position, which is expected be of the form [:property expression:]
4290
//
4291
//             The scan position will be at the opening ':'.  On return
4292
//             the scan position must be on the closing ']'
4293
//
4294
//             Return a UnicodeSet constructed from the pattern,
4295
//             or nullptr if this is not a valid POSIX-style set expression.
4296
//             If not a property expression, restore the initial scan position
4297
//                (to the opening ':')
4298
//
4299
//               Note:  the opening '[:' is not sufficient to guarantee that
4300
//                      this is a [:property:] expression.
4301
//                      [:'+=,] is a perfectly good ordinary set expression that
4302
//                              happens to include ':' as one of its characters.
4303
//
4304
//------------------------------------------------------------------------------
4305
109k
UnicodeSet *RegexCompile::scanPosixProp() {
4306
109k
    UnicodeSet    *uset = nullptr;
4307
4308
109k
    if (U_FAILURE(*fStatus)) {
4309
0
        return nullptr;
4310
0
    }
4311
4312
109k
    U_ASSERT(fC.fChar == chColon);
4313
4314
    // Save the scanner state.
4315
    // TODO:  move this into the scanner, with the state encapsulated in some way.  Ticket 6062
4316
109k
    int64_t     savedScanIndex        = fScanIndex;
4317
109k
    int64_t     savedNextIndex        = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
4318
109k
    UBool       savedQuoteMode        = fQuoteMode;
4319
109k
    UBool       savedInBackslashQuote = fInBackslashQuote;
4320
109k
    UBool       savedEOLComments      = fEOLComments;
4321
109k
    int64_t     savedLineNum          = fLineNum;
4322
109k
    int64_t     savedCharNum          = fCharNum;
4323
109k
    UChar32     savedLastChar         = fLastChar;
4324
109k
    UChar32     savedPeekChar         = fPeekChar;
4325
109k
    RegexPatternChar savedfC          = fC;
4326
4327
    // Scan for a closing ].   A little tricky because there are some perverse
4328
    //   edge cases possible.  "[:abc\Qdef:] \E]"  is a valid non-property expression,
4329
    //   ending on the second closing ].
4330
4331
109k
    UnicodeString propName;
4332
109k
    UBool         negated  = false;
4333
4334
    // Check for and consume the '^' in a negated POSIX property, e.g.  [:^Letter:]
4335
109k
    nextChar(fC);
4336
109k
    if (fC.fChar == chUp) {
4337
8.66k
       negated = true;
4338
8.66k
       nextChar(fC);
4339
8.66k
    }
4340
4341
    // Scan for the closing ":]", collecting the property name along the way.
4342
109k
    UBool  sawPropSetTerminator = false;
4343
23.7M
    for (;;) {
4344
23.7M
        propName.append(fC.fChar);
4345
23.7M
        nextChar(fC);
4346
23.7M
        if (fC.fQuoted || fC.fChar == -1) {
4347
            // Escaped characters or end of input - either says this isn't a [:Property:]
4348
8.24k
            break;
4349
8.24k
        }
4350
23.7M
        if (fC.fChar == chColon) {
4351
100k
            nextChar(fC);
4352
100k
            if (fC.fChar == chRBracket) {
4353
77.7k
                sawPropSetTerminator = true;
4354
77.7k
            }
4355
100k
            break;
4356
100k
        }
4357
23.7M
    }
4358
4359
109k
    if (sawPropSetTerminator) {
4360
77.7k
        uset = createSetForProperty(propName, negated);
4361
77.7k
    }
4362
31.4k
    else
4363
31.4k
    {
4364
        // No closing ":]".
4365
        //  Restore the original scan position.
4366
        //  The main scanner will retry the input as a normal set expression,
4367
        //    not a [:Property:] expression.
4368
31.4k
        fScanIndex        = savedScanIndex;
4369
31.4k
        fQuoteMode        = savedQuoteMode;
4370
31.4k
        fInBackslashQuote = savedInBackslashQuote;
4371
31.4k
        fEOLComments      = savedEOLComments;
4372
31.4k
        fLineNum          = savedLineNum;
4373
31.4k
        fCharNum          = savedCharNum;
4374
31.4k
        fLastChar         = savedLastChar;
4375
31.4k
        fPeekChar         = savedPeekChar;
4376
31.4k
        fC                = savedfC;
4377
31.4k
        UTEXT_SETNATIVEINDEX(fRXPat->fPattern, savedNextIndex);
4378
31.4k
    }
4379
109k
    return uset;
4380
109k
}
4381
4382
0
static inline void addIdentifierIgnorable(UnicodeSet *set, UErrorCode& ec) {
4383
0
    set->add(0, 8).add(0x0e, 0x1b).add(0x7f, 0x9f);
4384
0
    addCategory(set, U_GC_CF_MASK, ec);
4385
0
}
4386
4387
//
4388
//  Create a Unicode Set from a Unicode Property expression.
4389
//     This is common code underlying both \p{...} and [:...:] expressions.
4390
//     Includes trying the Java "properties" that aren't supported as
4391
//     normal ICU UnicodeSet properties
4392
//
4393
81.0k
UnicodeSet *RegexCompile::createSetForProperty(const UnicodeString &propName, UBool negated) {
4394
4395
81.0k
    if (U_FAILURE(*fStatus)) {
4396
1
        return nullptr;
4397
1
    }
4398
81.0k
    LocalPointer<UnicodeSet> set;
4399
81.0k
    UErrorCode status = U_ZERO_ERROR;
4400
4401
81.0k
    do {      // non-loop, exists to allow breaks from the block.
4402
        //
4403
        //  First try the property as we received it
4404
        //
4405
81.0k
        UnicodeString   setExpr;
4406
81.0k
        uint32_t        usetFlags = 0;
4407
81.0k
        setExpr.append(u"[\\p{", -1);
4408
81.0k
        setExpr.append(propName);
4409
81.0k
        setExpr.append(u"}]", -1);
4410
81.0k
        if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
4411
40.8k
            usetFlags |= USET_CASE_INSENSITIVE;
4412
40.8k
        }
4413
81.0k
        set.adoptInsteadAndCheckErrorCode(new UnicodeSet(setExpr, usetFlags, nullptr, status), status);
4414
81.0k
        if (U_SUCCESS(status) || status == U_MEMORY_ALLOCATION_ERROR) {
4415
62.4k
            break;
4416
62.4k
        }
4417
4418
        //
4419
        //  The incoming property wasn't directly recognized by ICU.
4420
4421
        //  Check [:word:] and [:all:]. These are not recognized as a properties by ICU UnicodeSet.
4422
        //     Java accepts 'word' with mixed case.
4423
        //     Java accepts 'all' only in all lower case.
4424
4425
18.6k
        status = U_ZERO_ERROR;
4426
18.6k
        if (propName.caseCompare(u"word", -1, 0) == 0) {
4427
765
            set.adoptInsteadAndCheckErrorCode(
4428
765
                RegexStaticSets::gStaticSets->fPropSets[URX_ISWORD_SET].cloneAsThawed(), status);
4429
765
            break;
4430
765
        }
4431
17.8k
        if (propName.compare(u"all", -1) == 0) {
4432
287
            set.adoptInsteadAndCheckErrorCode(new UnicodeSet(0, 0x10ffff), status);
4433
287
            break;
4434
287
        }
4435
4436
4437
        //    Do Java InBlock expressions
4438
        //
4439
17.5k
        UnicodeString mPropName = propName;
4440
17.5k
        if (mPropName.startsWith(u"In", 2) && mPropName.length() >= 3) {
4441
9.27k
            status = U_ZERO_ERROR;
4442
9.27k
            set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
4443
9.27k
            if (U_FAILURE(status)) {
4444
0
                break;
4445
0
            }
4446
9.27k
            UnicodeString blockName(mPropName, 2);  // Property with the leading "In" removed.
4447
9.27k
            set->applyPropertyAlias(UnicodeString(u"Block"), blockName, status);
4448
9.27k
            break;
4449
9.27k
        }
4450
4451
        //  Check for the Java form "IsBooleanPropertyValue", which we will recast
4452
        //  as "BooleanPropertyValue". The property value can be either a
4453
        //  a General Category or a Script Name.
4454
4455
8.32k
        if (propName.startsWith(u"Is", 2) && propName.length()>=3) {
4456
6.45k
            mPropName.remove(0, 2);      // Strip the "Is"
4457
6.45k
            if (mPropName.indexOf(u'=') >= 0) {
4458
                // Reject any "Is..." property expression containing an '=', that is,
4459
                // any non-binary property expression.
4460
32
                status = U_REGEX_PROPERTY_SYNTAX;
4461
32
                break;
4462
32
            }
4463
4464
6.41k
            if (mPropName.caseCompare(u"assigned", -1, 0) == 0) {
4465
0
                mPropName.setTo(u"unassigned", -1);
4466
0
                negated = !negated;
4467
6.41k
            } else if (mPropName.caseCompare(u"TitleCase", -1, 0) == 0) {
4468
0
                mPropName.setTo(u"Titlecase_Letter", -1);
4469
0
            }
4470
4471
6.41k
            mPropName.insert(0, u"[\\p{", -1);
4472
6.41k
            mPropName.append(u"}]", -1);
4473
6.41k
            set.adoptInsteadAndCheckErrorCode(new UnicodeSet(mPropName, *fStatus), status);
4474
4475
6.41k
            if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
4476
2.04k
                set->closeOver(USET_CASE_INSENSITIVE);
4477
2.04k
            }
4478
6.41k
            break;
4479
4480
6.45k
        }
4481
4482
1.87k
        if (propName.startsWith(u"java", -1)) {
4483
0
            status = U_ZERO_ERROR;
4484
0
            set.adoptInsteadAndCheckErrorCode(new UnicodeSet(), status);
4485
0
            if (U_FAILURE(status)) {
4486
0
                break;
4487
0
            }
4488
            //
4489
            //  Try the various Java specific properties.
4490
            //   These all begin with "java"
4491
            //
4492
0
            if (propName.compare(u"javaDefined", -1) == 0) {
4493
0
                addCategory(set.getAlias(), U_GC_CN_MASK, status);
4494
0
                set->complement();
4495
0
            }
4496
0
            else if (propName.compare(u"javaDigit", -1) == 0) {
4497
0
                addCategory(set.getAlias(), U_GC_ND_MASK, status);
4498
0
            }
4499
0
            else if (propName.compare(u"javaIdentifierIgnorable", -1) == 0) {
4500
0
                addIdentifierIgnorable(set.getAlias(), status);
4501
0
            }
4502
0
            else if (propName.compare(u"javaISOControl", -1) == 0) {
4503
0
                set->add(0, 0x1F).add(0x7F, 0x9F);
4504
0
            }
4505
0
            else if (propName.compare(u"javaJavaIdentifierPart", -1) == 0) {
4506
0
                addCategory(set.getAlias(), U_GC_L_MASK, status);
4507
0
                addCategory(set.getAlias(), U_GC_SC_MASK, status);
4508
0
                addCategory(set.getAlias(), U_GC_PC_MASK, status);
4509
0
                addCategory(set.getAlias(), U_GC_ND_MASK, status);
4510
0
                addCategory(set.getAlias(), U_GC_NL_MASK, status);
4511
0
                addCategory(set.getAlias(), U_GC_MC_MASK, status);
4512
0
                addCategory(set.getAlias(), U_GC_MN_MASK, status);
4513
0
                addIdentifierIgnorable(set.getAlias(), status);
4514
0
            }
4515
0
            else if (propName.compare(u"javaJavaIdentifierStart", -1) == 0) {
4516
0
                addCategory(set.getAlias(), U_GC_L_MASK, status);
4517
0
                addCategory(set.getAlias(), U_GC_NL_MASK, status);
4518
0
                addCategory(set.getAlias(), U_GC_SC_MASK, status);
4519
0
                addCategory(set.getAlias(), U_GC_PC_MASK, status);
4520
0
            }
4521
0
            else if (propName.compare(u"javaLetter", -1) == 0) {
4522
0
                addCategory(set.getAlias(), U_GC_L_MASK, status);
4523
0
            }
4524
0
            else if (propName.compare(u"javaLetterOrDigit", -1) == 0) {
4525
0
                addCategory(set.getAlias(), U_GC_L_MASK, status);
4526
0
                addCategory(set.getAlias(), U_GC_ND_MASK, status);
4527
0
            }
4528
0
            else if (propName.compare(u"javaLowerCase", -1) == 0) {
4529
0
                addCategory(set.getAlias(), U_GC_LL_MASK, status);
4530
0
            }
4531
0
            else if (propName.compare(u"javaMirrored", -1) == 0) {
4532
0
                set->applyIntPropertyValue(UCHAR_BIDI_MIRRORED, 1, status);
4533
0
            }
4534
0
            else if (propName.compare(u"javaSpaceChar", -1) == 0) {
4535
0
                addCategory(set.getAlias(), U_GC_Z_MASK, status);
4536
0
            }
4537
0
            else if (propName.compare(u"javaSupplementaryCodePoint", -1) == 0) {
4538
0
                set->add(0x10000, UnicodeSet::MAX_VALUE);
4539
0
            }
4540
0
            else if (propName.compare(u"javaTitleCase", -1) == 0) {
4541
0
                addCategory(set.getAlias(), U_GC_LT_MASK, status);
4542
0
            }
4543
0
            else if (propName.compare(u"javaUnicodeIdentifierStart", -1) == 0) {
4544
0
                addCategory(set.getAlias(), U_GC_L_MASK, status);
4545
0
                addCategory(set.getAlias(), U_GC_NL_MASK, status);
4546
0
            }
4547
0
            else if (propName.compare(u"javaUnicodeIdentifierPart", -1) == 0) {
4548
0
                addCategory(set.getAlias(), U_GC_L_MASK, status);
4549
0
                addCategory(set.getAlias(), U_GC_PC_MASK, status);
4550
0
                addCategory(set.getAlias(), U_GC_ND_MASK, status);
4551
0
                addCategory(set.getAlias(), U_GC_NL_MASK, status);
4552
0
                addCategory(set.getAlias(), U_GC_MC_MASK, status);
4553
0
                addCategory(set.getAlias(), U_GC_MN_MASK, status);
4554
0
                addIdentifierIgnorable(set.getAlias(), status);
4555
0
            }
4556
0
            else if (propName.compare(u"javaUpperCase", -1) == 0) {
4557
0
                addCategory(set.getAlias(), U_GC_LU_MASK, status);
4558
0
            }
4559
0
            else if (propName.compare(u"javaValidCodePoint", -1) == 0) {
4560
0
                set->add(0, UnicodeSet::MAX_VALUE);
4561
0
            }
4562
0
            else if (propName.compare(u"javaWhitespace", -1) == 0) {
4563
0
                addCategory(set.getAlias(), U_GC_Z_MASK, status);
4564
0
                set->removeAll(UnicodeSet().add(0xa0).add(0x2007).add(0x202f));
4565
0
                set->add(9, 0x0d).add(0x1c, 0x1f);
4566
0
            } else {
4567
0
                status = U_REGEX_PROPERTY_SYNTAX;
4568
0
            }
4569
4570
0
            if (U_SUCCESS(status) && !set->isEmpty() && (usetFlags & USET_CASE_INSENSITIVE)) {
4571
0
                set->closeOver(USET_CASE_INSENSITIVE);
4572
0
            }
4573
0
            break;
4574
0
        }
4575
4576
        // Unrecognized property. ICU didn't like it as it was, and none of the Java compatibility
4577
        // extensions matched it.
4578
1.87k
        status = U_REGEX_PROPERTY_SYNTAX;
4579
1.87k
    } while (false);   // End of do loop block. Code above breaks out of the block on success or hard failure.
4580
4581
81.0k
    if (U_SUCCESS(status)) {
4582
        // ICU 70 adds emoji properties of strings, but as long as Java does not say how to
4583
        // deal with properties of strings and character classes with strings, we ignore them.
4584
        // Just in case something downstream might stumble over the strings,
4585
        // we remove them from the set.
4586
        // Note that when we support strings, the complement of a property (as with \P)
4587
        // should be implemented as .complement().removeAllStrings() (code point complement).
4588
79.0k
        set->removeAllStrings();
4589
79.0k
        U_ASSERT(set.isValid());
4590
79.0k
        if (negated) {
4591
2.45k
            set->complement();
4592
2.45k
        }
4593
79.0k
        return set.orphan();
4594
79.0k
    } else {
4595
1.96k
        if (status == U_ILLEGAL_ARGUMENT_ERROR) {
4596
56
            status = U_REGEX_PROPERTY_SYNTAX;
4597
56
        }
4598
1.96k
        error(status);
4599
1.96k
        return nullptr;
4600
1.96k
    }
4601
81.0k
}
4602
4603
4604
//
4605
//  SetEval   Part of the evaluation of [set expressions].
4606
//            Perform any pending (stacked) operations with precedence
4607
//            equal or greater to that of the next operator encountered
4608
//            in the expression.
4609
//
4610
13.4M
void RegexCompile::setEval(int32_t nextOp) {
4611
13.4M
    UnicodeSet *rightOperand = nullptr;
4612
13.4M
    UnicodeSet *leftOperand  = nullptr;
4613
13.8M
    for (;;) {
4614
13.8M
        U_ASSERT(fSetOpStack.empty()==false);
4615
13.8M
        int32_t pendingSetOperation = fSetOpStack.peeki();
4616
13.8M
        if ((pendingSetOperation&0xffff0000) < (nextOp&0xffff0000)) {
4617
13.4M
            break;
4618
13.4M
        }
4619
334k
        fSetOpStack.popi();
4620
334k
        U_ASSERT(fSetStack.empty() == false);
4621
334k
        rightOperand = static_cast<UnicodeSet*>(fSetStack.peek());
4622
        // ICU 70 adds emoji properties of strings, but createSetForProperty() removes all strings
4623
        // (see comments there).
4624
        // We also do not yet support string literals in character classes,
4625
        // so there should not be any strings.
4626
        // Note that when we support strings, the complement of a set (as with ^ or \P)
4627
        // should be implemented as .complement().removeAllStrings() (code point complement).
4628
334k
        U_ASSERT(!rightOperand->hasStrings());
4629
334k
        switch (pendingSetOperation) {
4630
8.47k
            case setNegation:
4631
8.47k
                rightOperand->complement();
4632
8.47k
                break;
4633
257k
            case setCaseClose:
4634
                // TODO: need a simple close function.  Ticket 6065
4635
257k
                rightOperand->closeOver(USET_CASE_INSENSITIVE);
4636
257k
                rightOperand->removeAllStrings();
4637
257k
                break;
4638
1.32k
            case setDifference1:
4639
2.86k
            case setDifference2:
4640
2.86k
                fSetStack.pop();
4641
2.86k
                leftOperand = static_cast<UnicodeSet*>(fSetStack.peek());
4642
2.86k
                leftOperand->removeAll(*rightOperand);
4643
2.86k
                delete rightOperand;
4644
2.86k
                break;
4645
1.12k
            case setIntersection1:
4646
6.78k
            case setIntersection2:
4647
6.78k
                fSetStack.pop();
4648
6.78k
                leftOperand = static_cast<UnicodeSet*>(fSetStack.peek());
4649
6.78k
                leftOperand->retainAll(*rightOperand);
4650
6.78k
                delete rightOperand;
4651
6.78k
                break;
4652
58.8k
            case setUnion:
4653
58.8k
                fSetStack.pop();
4654
58.8k
                leftOperand = static_cast<UnicodeSet*>(fSetStack.peek());
4655
58.8k
                leftOperand->addAll(*rightOperand);
4656
58.8k
                delete rightOperand;
4657
58.8k
                break;
4658
0
            default:
4659
0
                UPRV_UNREACHABLE_EXIT;
4660
334k
            }
4661
334k
        }
4662
13.4M
    }
4663
4664
78.4k
void RegexCompile::setPushOp(int32_t op) {
4665
78.4k
    setEval(op);
4666
78.4k
    fSetOpStack.push(op, *fStatus);
4667
78.4k
    LocalPointer<UnicodeSet> lpSet(new UnicodeSet(), *fStatus);
4668
78.4k
    fSetStack.push(lpSet.orphan(), *fStatus);
4669
78.4k
}
4670
4671
U_NAMESPACE_END
4672
#endif  // !UCONFIG_NO_REGULAR_EXPRESSIONS
4673