| 450 | return list(dict.fromkeys(items)) |
| 451 | |
| 452 | def _parse_sub(source, state, verbose, nested): |
| 453 | # parse an alternation: a|b|c |
| 454 | |
| 455 | items = [] |
| 456 | itemsappend = items.append |
| 457 | sourcematch = source.match |
| 458 | while True: |
| 459 | itemsappend(_parse(source, state, verbose, nested + 1, |
| 460 | not nested and not items)) |
| 461 | if not sourcematch("|"): |
| 462 | break |
| 463 | if not nested: |
| 464 | verbose = state.flags & SRE_FLAG_VERBOSE |
| 465 | |
| 466 | if len(items) == 1: |
| 467 | return items[0] |
| 468 | |
| 469 | subpattern = SubPattern(state) |
| 470 | |
| 471 | # check if all items share a common prefix |
| 472 | while True: |
| 473 | prefix = None |
| 474 | for item in items: |
| 475 | if not item: |
| 476 | break |
| 477 | if prefix is None: |
| 478 | prefix = item[0] |
| 479 | elif item[0] != prefix: |
| 480 | break |
| 481 | else: |
| 482 | # all subitems start with a common "prefix". |
| 483 | # move it out of the branch |
| 484 | for item in items: |
| 485 | del item[0] |
| 486 | subpattern.append(prefix) |
| 487 | continue # check next one |
| 488 | break |
| 489 | |
| 490 | # check if the branch can be replaced by a character set |
| 491 | set = [] |
| 492 | for item in items: |
| 493 | if len(item) != 1: |
| 494 | break |
| 495 | op, av = item[0] |
| 496 | if op is LITERAL: |
| 497 | set.append((op, av)) |
| 498 | elif op is IN and av[0][0] is not NEGATE: |
| 499 | set.extend(av) |
| 500 | else: |
| 501 | break |
| 502 | else: |
| 503 | # we can store this as a character set instead of a |
| 504 | # branch (the compiler may optimize this even more) |
| 505 | subpattern.append((IN, _uniq(set))) |
| 506 | return subpattern |
| 507 | |
| 508 | subpattern.append((BRANCH, (None, items))) |
| 509 | return subpattern |