()
| 428 | // ----- Group parsing (alternations, lookaheads, etc.) ----- |
| 429 | // 分组解析(交替 |、前瞻等) |
| 430 | function parseGroup(): Unit | null { |
| 431 | const parts: string[] = []; |
| 432 | let depth = 1, |
| 433 | buf = "", |
| 434 | isAlt = false; |
| 435 | |
| 436 | // 处理 (?:...), (?=...), (?!...), (?<=...), (?<!...) |
| 437 | if (peek() === "?") { |
| 438 | next(); |
| 439 | const kind: string = next(); |
| 440 | if (kind === ":") { |
| 441 | // Non-capturing |
| 442 | // 非捕获 |
| 443 | } else if (kind === "=" || kind === "!") { |
| 444 | // 前瞻(零宽) |
| 445 | let laDepth = 1; |
| 446 | while (i < n && laDepth > 0) { |
| 447 | const ch2 = next(); |
| 448 | if (ch2 === "\\") { |
| 449 | if (!next()) return null; |
| 450 | } else if (ch2 === "(") laDepth++; |
| 451 | else if (ch2 === ")") laDepth--; |
| 452 | } |
| 453 | if (laDepth !== 0) return null; |
| 454 | return { glob: "", baseGlob: "", canRepeat: false, min: 0, isLiteral: false, varLen: false }; |
| 455 | } else if (kind === "<") { |
| 456 | const lb = next(); |
| 457 | if (lb === "=" || lb === "!") { |
| 458 | let lbDepth = 1; |
| 459 | while (i < n && lbDepth > 0) { |
| 460 | const ch2 = next(); |
| 461 | if (ch2 === "\\") { |
| 462 | if (!next()) return null; |
| 463 | } else if (ch2 === "(") lbDepth++; |
| 464 | else if (ch2 === ")") lbDepth--; |
| 465 | } |
| 466 | if (lbDepth !== 0) return null; |
| 467 | return { glob: "", baseGlob: "", canRepeat: false, min: 0, isLiteral: false, varLen: false }; |
| 468 | } else { |
| 469 | buf += "<?" + lb; |
| 470 | } |
| 471 | } else { |
| 472 | buf += "?" + kind; |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | // 解析内容并在最外层分割 '|' |
| 477 | while (i < n && depth > 0) { |
| 478 | const ch: string = next(); |
| 479 | if (ch === "\\") { |
| 480 | const esc = next(); |
| 481 | if (!esc) return null; |
| 482 | // preserve escape while scanning |
| 483 | // 保留转义 |
| 484 | buf += "\\" + esc; |
| 485 | } else if (ch === "(") { |
| 486 | depth++; |
| 487 | buf += ch; |
no test coverage detected