feat(parser): pattern parser — NodePattern, RelPattern, PathPattern#656
Conversation
…651) Implements crates/gf-cypher/src/parser/patterns.rs with the full openCypher pattern grammar: - NodePattern: anonymous, variable, label(s), properties - RelPattern: all 6 syntactic forms (-->, <--, --, -[r]->, etc.) with optional variable, type list (pipe-separated), variable-length range (*1..3), and inline properties - PathPattern: chained node+rel elements, optional named path (p = ...) - parse_pattern_list: comma-separated patterns 24 unit tests, all passing. Delegates property parsing to parse_expr. Closes #651 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughImplements a Cypher path pattern parser: new public ChangesPattern Parser Implementation
Sequence Diagram(s)sequenceDiagram
participant TokenStream
participant parse_pattern
participant parse_node_pattern
participant parse_rel_interior
participant parse_expr
TokenStream->>parse_pattern: provide tokens for pattern (maybe "p = (a)-[:K]->(b)")
parse_pattern->>parse_node_pattern: parse initial node `( ... )`
parse_node_pattern->>parse_expr: parse `{...}` property map (if present)
parse_pattern->>parse_rel_interior: parse relationship `-[]->` or `--`
parse_rel_interior->>parse_expr: parse rel property map (if present)
parse_pattern->>parse_node_pattern: parse next node
parse_pattern->>TokenStream: return PathPattern AST (with name/span)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #656 +/- ##
=======================================
Coverage 84.09% 84.09%
=======================================
Files 49 49
Lines 12921 12921
Branches 3628 3628
=======================================
Hits 10866 10866
Misses 1270 1270
Partials 785 785
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/gf-cypher/src/parser/patterns.rs`:
- Around line 109-124: The span for RelPattern currently ends at r_brace which
excludes the trailing direction token; update the span to include the consumed
direction token by advancing the end position to the token you matched when
setting direction (i.e., when ts.eat_if(&Tok::RightArrow) or
ts.eat_if(&Tok::Minus)); locate the block that builds RelPattern (uses vars var,
types, direction, min_hops, max_hops, properties, span: Span::new(start,
r_brace)) and replace the span end with the end position of the consumed
direction token (use the token's span/end returned by the eat/eat_if call or
capture the token node/end and pass that instead of r_brace) so spans for -[r]->
and -[r]- include the final arrow/dash.
- Around line 134-140: After parsing the `]` the code currently treats a
consumed Tok::RightArrow as Direction::Undirected (commenting "<-[r]-> means
both directions"); instead reject the two-headed arrow instead of mapping it to
Direction::Undirected. Replace the branch that returns Direction::Undirected on
ts.eat_if(&Tok::RightArrow) with a return Err(...) from the parser (using ts.err
with a clear message like "`<-[...]->` is not allowed"), keep the Tok::Minus
branch returning Direction::In, and leave the existing fallback error unchanged
so only the allowed `-[...]-`, `-...->`, and `->...-` forms are accepted.
- Around line 244-273: parse_hop_range currently returns (None, None) for a bare
`*`, which collides with the same tuple used for non-variable relationships;
change the default arm so a bare `*` is represented distinctly (e.g., return
(Some(0), None) to mean variable-length any hops) and adjust the function
docstring accordingly so callers can distinguish variable-length (`*`) from
non-variable edges; update parse_hop_range (and any related comments) to use
this new representation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2df7a196-a4de-4983-aa3b-e11e9ce50560
📒 Files selected for processing (2)
crates/gf-cypher/src/parser/mod.rscrates/gf-cypher/src/parser/patterns.rs
…s.rs - RelOpen span now extends past direction token (end at current_pos) - Reject <-[r]-> with a clear error (not a valid Cypher form) - Bare * now encodes as (min=Some(1), max=None) per openCypher semantics instead of (None, None) which is indistinguishable from non-variable-length - Hop count literals use u32::try_from to reject out-of-range values Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`ts.err()` uses `current_pos()` which is past the already-consumed integer literal. Capture the span before advancing and pass it to `ParseError::new` with `ParseErrorKind::InvalidNumericLiteral`. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
crates/gf-cypher/src/parser/patterns.rs(chunk B of rust: implement recursive-descent + Pratt parser for gf-cypher #554)parse_node_pattern: anonymous(), variable, labels, multi-label, inline property mapparse_rel_pattern: all 6 forms (-->,<--,--,-[r]->,<-[r]-,-[r]-), type lists, variable-length ranges, inline propertiesparse_pattern: chained path + named path binding (p = ...)parse_pattern_list: comma-separated pattern listparse_exprfrom chunk ATest plan
cargo test -p gf-cypher— 73 tests passcargo clippy -p gf-cypher -- -D warnings— cleancargo fmt --all -- --check— cleanCloses #651
Part of #554
🤖 Generated with Claude Code
Note
Add pattern parser for NodePattern, RelPattern, and PathPattern in gf-cypher
patternssubmodule to the Cypher parser exposingparse_node_pattern,parse_pattern, andparse_pattern_listin patterns.rs.parse_node_patternhandles(),(n),(:Label), and(n:Label {props})forms, producing aNodePatternwith var, labels, properties, and span.parse_rel_patternsupports all relationship syntaxes (-->,<--,--, bracketed forms) with direction, optional variable, type list, hop ranges, and properties; invalid combinations like<-[r]->produce structured errors.parse_patterncomposes node and relationship elements into aPathPattern, optionally with a named path prefix (var =);parse_pattern_listhandles comma-separated lists of patterns.Macroscope summarized 34b9a3b.
Summary by CodeRabbit
New Features
Tests