Refactor regex quantifiers into base and mode [reduced-it] [databricks] - #15899
Conversation
Closes NVIDIA#15831 Contributes to NVIDIA#14733 Validation: - Tests: succeeded 183, failed 0, canceled 6, ignored 0, pending 0 - 7 passed, 89 deselected, 2 warnings in 13.61s Signed-off-by: Allen Xu <allxu@nvidia.com>
|
There was a problem hiding this comment.
🔵 Needs a closer look
It is a broad refactor in a core parsing/transpilation path where subtle semantic or diagnostic-position regressions are possible despite unit coverage.
Pull request overview
Refactors the regex quantifier AST model to a single RegexQuantifier(base, mode) representation, separating repetition shape (base) from matching behavior (mode), while keeping diagnostics positions and the cuDF 999-count boundary behavior intact.
Changes:
- Replaces the former quantifier subtype hierarchy with
RegexQuantifier.Base+RegexQuantifier.Mode, constructed directly by the parser. - Updates cuDF transpiler quantifier pattern matches to use the new
base/modedecomposition. - Updates Scala test suites and fuzz generation to build quantifiers via the new model and adds an independence/equality regression test.
File summaries
| File | Description |
|---|---|
| tests/src/test/scala/com/nvidia/spark/rapids/RegularExpressionTranspilerSuite.scala | Updates fuzz regex generation to construct RegexQuantifier(base, mode) rather than subtype + mode-copy helpers. |
| tests/src/test/scala/com/nvidia/spark/rapids/RegularExpressionParserSuite.scala | Updates expected ASTs to the new quantifier model and adds a test asserting base/mode independence plus equality ignoring diagnostic position. |
| sql-plugin/src/main/scala/com/nvidia/spark/rapids/RegexParser.scala | Refactors parsing and transpilation logic to use RegexQuantifier(base, mode); introduces Base ADT and ports quantifier-related matching/serialization accordingly. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
build |
Apply the requested parser, AST, and test cleanups while preserving the production parse validation boundary. Performance: these changes run only while parsing and transpiling regex plans; they add no per-row or GPU-kernel work, and the consolidated matches reduce dispatch branches. Signed-off-by: Allen Xu <allxu@nvidia.com>
|
build |
2 similar comments
|
build |
|
build |
igorpeshansky
left a comment
There was a problem hiding this comment.
Would like to resolve the "closer to Java semantics" discussion eventually, but it doesn't have to be addressed in this PR. The rest are minor cleanups.
| Some(QuantifierVariableLength(minLength, maxLength)) | ||
| Some(Variable(minLength, maxLength)) | ||
| } else { | ||
| None |
There was a problem hiding this comment.
FWIW, I think sticking closer to Java semantics helps maintain cleaner code and avoids questions about consistency… Since these edge cases are only reachable from tests, it would be easiest to match Java to decide on the expected behavior.
Signed-off-by: Allen Xu <allxu@nvidia.com>
|
build |
Signed-off-by: Allen Xu <allxu@nvidia.com>
|
build |
igorpeshansky
left a comment
There was a problem hiding this comment.
One bad suggestion to undo (#15899 (comment)), otherwise LGTM
. Approving to unblock.
|
|
||
| import com.nvidia.spark.rapids.GpuOverrides.regexMetaChars | ||
| import com.nvidia.spark.rapids.RegexParser.toReadableString | ||
| import com.nvidia.spark.rapids.RegexQuantifier.{Base, Mode} |
There was a problem hiding this comment.
Apologies for the churn, see #15899 (comment).
There was a problem hiding this comment.
Updated. (actually, it's not a bad suggestion at all, by this chance I updated my local review skill like "always check unnecessary call chain if caller is already/can be imported" and "try best to reuse existing objests/functions". It's what review rounds for :)
| } else { | ||
| None | ||
| if (!peek().contains('}')) { | ||
| throw new PatternSyntaxException("Unclosed counted closure", pattern, pos) |
There was a problem hiding this comment.
Hmm, the parser didn't use to throw PatternSyntaxExceptions — only RegexUnsupportedExceptions (the former were thrown by Java's Pattern.compile). Many pattern errors (as opposed to unsupported patterns) also currently throw the latter. I like matching the Java ones, but it might make sense to do a sweep and convert the existing pattern errors into those as well… Let's open an issue to track?
There was a problem hiding this comment.
Thanks, filed #15963 to track the syntax-error sweep.
|
|
||
| // The caller restores its position when this is a literal brace rather than a quantifier. | ||
| consumeExpected('{') | ||
| consumeInt.flatMap { minLength => |
There was a problem hiding this comment.
[Really optional] Almost certainly a follow-up change, but just noting here that we still try to parse the quantifier and fall back on treating invalid strings as literals. At some point we might want to match Java's behavior, which commits to the quantifier given the { prefix and errors out for invalid ones (like a{, a{}, or a{x}).
Signed-off-by: Allen Xu <allxu@nvidia.com>
|
build |
1 similar comment
|
build |
JaCoCo production line coverage: +64 lines (
sql-plugin +64; shim 330, fix-line measurement against basee313d91fd)Closes #15831
Contributes to #14733
Follow-up to #15478 and the review suggestion.
Description
This refactor gives regex quantifiers one representation for repetition bounds and matching mode. Parser, transpiler, rewrite, serializer, and fuzz-generator code now use that shared representation, reducing duplicated handling while preserving supported public regex behavior, GPU fallback boundaries, and the 999 repetition limit.
The package-private unchecked parser also matches Java's error descriptions and positions for malformed counted closures and descending repetition ranges. A broader syntax-error classification sweep remains follow-up work; public parsing continues to validate through
Pattern.compilefirst.Base/Modeimport.AI assistance: AI tools assisted with the code and PR description.
Validation
Validated the source committed in
e76806599on Spark 3.3.0, Scala 2.12, Python 3.10.18, and an RTX 5880 Ada:RegularExpressionParserSuite,RegularExpressionTranspilerSuite,RegularExpressionRewriteSuite, andRegExpUtilsSuite: 184 succeeded, 0 failed, 6 canceled, 0 ignored, 0 pending; MavenBUILD SUCCESSin 5:53. The six cancellations retain the existing Unicode line-separator exclusions tracked by [BUG] [Regexp] Line anchor '$' incorrect matching of unicode line terminators #7585. These suites include CPU/GPU comparisons and fuzz coverage.dist,integration_tests: MavenBUILD SUCCESSin 1:24. Verified 21 parser, quantifier, transpiler, and rewrite class files match the distribution JAR.regexp_test.pyselection: 7 passed, 32692 deselected, 14 warnings in 18.29 seconds. It covers negative-limit split, unsupported split fallback, repetition replacement, possessive fallback, extract/extract-all fallback, and lazy quantifiers with CPU/GPU result comparisons.BUILD SUCCESS. Resource-nesting lint and its 20 unit tests also passed.sql-pluginclasses analyzed and no class-ID mismatch. All added JVM production source is insql-plugin; the diff adds no production lines in the API, Delta Lake, Iceberg, shuffle, or UDF modules. This is a measurement of the complete PR diff.Maven commands used
package, the worktree-local Maven repository, and GPU allocation fractions0.3/0.3/0. The Python run used the rebuilt distribution and explicitly selected Python 3.10 for driver and workers. Local runtime validation covers shim 330; the remaining runtime matrix is delegated to CI.Performance impact
Regex parsing remains O(pattern length) and runs during expression translation rather than per input row. This representation change adds no JNI calls or GPU work. The constructor qualification follow-up changes only name resolution: its rebuilt JVM instructions and method descriptors match the pre-edit artifact. No runtime benchmark was run for this cold-path refactor.
Checklists
Documentation
Testing
(Please provide the names of the existing tests in the PR description.)
Performance