Skip to content

refactor(parser): extract helpers from three oversize parsers#69

Merged
mpecan merged 1 commit into
mainfrom
feat/58-parser-helpers
Apr 17, 2026
Merged

refactor(parser): extract helpers from three oversize parsers#69
mpecan merged 1 commit into
mainfrom
feat/58-parser-helpers

Conversation

@mpecan
Copy link
Copy Markdown
Owner

@mpecan mpecan commented Apr 17, 2026

Summary

Extracts helpers from three parser functions that each carried #[allow(clippy::too_many_lines)]:

Function Before After File
parse_simple_command 88 lines 55 lines src/parser/simple_command.rs
parse_cond_primary 79 lines 13 lines src/parser/conditionals.rs
parse_coproc 114 lines 27 lines src/parser/functions.rs

All three #[allow] attributes dropped.

Shared

  • src/parser/helpers.rs: new pub(super) const fn is_redirect_op_kind(TokenType) -> bool collapses the 12-variant redirect-operator matches! used in 3 places (simple_command.rs, functions.rs, and redirects.rs::is_redirect_operator).

simple_command.rs

  • try_parse_fd_redirect(&mut self, tok) -> Result<Option<Node>> — encapsulates the adjacent-fd / varfd redirect lookahead.
  • build_word_node(Token) -> Node — span-preserving Word node builder, documented distinct from helpers::word_node_from_token (which uses Node::empty).

conditionals.rs

  • try_parse_cond_negation, try_parse_cond_group, parse_cond_operand methods extract the !, (...), and operand-dispatch branches. Dispatcher extracts TokenType (Copy) to avoid borrow-vs-mut conflicts with the peeked &Token.

functions.rs

  • coproc_starts_command(TokenType) -> bool (free const fn) unifies the two starts_command() && !matches!(Coproc|Time|Bang) checks.
  • build_coproc_with_command, parse_coproc_redirect_only, parse_coproc_word_loop, build_coproc_synthetic_command methods split the 4 dispatch paths (A/B/C/D) of parse_coproc.

Test plan

  • cargo fmt
  • cargo clippy --all-targets -- -D warnings — no warnings
  • cargo test — 252 passed
  • Oracle suite — 12 oracle_* tests pass (cargo test --test integration oracle_)
  • AST is byte-identical (constitutional: compatibility is correctness)

Stack

Part of the v0.2.0 refactoring cycle (#61). This is PR 8 of 10.

Closes #58

🤖 Generated with Claude Code

Three parser functions carried #[allow(clippy::too_many_lines)]:

- parse_simple_command (simple_command.rs): 88 -> 55 lines
- parse_cond_primary (conditionals.rs): 79 -> 13 lines
- parse_coproc (functions.rs): 114 -> 27 lines

Shared extraction:

- helpers.rs: add pub(super) const fn is_redirect_op_kind(TokenType)
  that returns true for the 12 redirect operator kinds. Reused by
  simple_command.rs, functions.rs, and redirects.rs (the third call
  site previously had the same 12-variant matches! inlined).

simple_command.rs:
- try_parse_fd_redirect(&mut self, tok) -> Result<Option<Node>>
  encapsulates the adjacent-fd / varfd redirect lookahead.
- build_word_node(Token) -> Node builds a Word node preserving the
  token's position as the node span. Documented to distinguish it
  from helpers::word_node_from_token (which uses Node::empty).

conditionals.rs:
- try_parse_cond_negation(&mut self, start, kind) -> Result<Option<Node>>
- try_parse_cond_group(&mut self, start, kind) -> Result<Option<Node>>
- parse_cond_operand(&mut self, start, first) -> Result<Node>
Extract TokenType via Copy before downstream lexer calls to avoid
borrow conflicts with the peeked &Token.

functions.rs:
- coproc_starts_command(TokenType) -> bool (free const fn) unifies the
  two "starts_command && !coproc|time|bang" checks.
- build_coproc_with_command(start, name) for paths A and C.
- parse_coproc_redirect_only(start, first_tok) for path B.
- parse_coproc_word_loop(first_tok) -> (Vec<Node>, Vec<Node>) for path D.
- build_coproc_synthetic_command(&self, start, name, words, redirects)
  assembles the synthetic Command inside a Coproc (used by B and D).

Drops all three too_many_lines attributes. AST remains byte-identical:
all 252 unit/integration + 12 oracle tests pass. Part of #61 (v0.2.0).

Closes #58

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mpecan mpecan merged commit 25d0762 into main Apr 17, 2026
5 checks passed
@mpecan mpecan deleted the feat/58-parser-helpers branch April 17, 2026 14:55
mpecan pushed a commit that referenced this pull request Apr 19, 2026
🤖 I have created a release *beep* *boop*
---


##
[0.2.0](rable-v0.1.15...rable-v0.2.0)
(2026-04-18)


### ⚠ BREAKING CHANGES

* tighten lexer API surface and relocate WordSpan to ast
([#70](#70))

### Bug Fixes

* **format:** align cmdsub reformatter with bash canonical form
([#49](#49))
([c7a4411](c7a4411))
* **lexer:** accept sloppy heredoc terminator in cmdsub mode
([#50](#50))
([40f394f](40f394f))
* **lexer:** backticks opaque when content is invalid
([#71](#71))
([e72166f](e72166f)),
closes [#38](#38)
* **lexer:** disable reserved-word recognition after assignment words
([#44](#44))
([42e1fc0](42e1fc0))
* **lexer:** stop treating ]] and unbalanced [...] as special outside
conditionals ([#45](#45))
([4bf5a5c](4bf5a5c))
* **parser:** fall back from (( … )) arith to nested subshells
([#48](#48))
([1437f00](1437f00))


### Code Refactoring

* **format:** introduce Formatter struct
([#65](#65))
([d965a8f](d965a8f))
* **lexer:** drop Result&lt;Token&gt; wrapper from operator readers
([#62](#62))
([d52a841](d52a841))
* **lexer:** split read_word_token into classify + advance + dispatch
helpers ([#63](#63))
([3ba09f5](3ba09f5))
* **parser:** extract fill_heredoc_contents visitor helpers
([#68](#68))
([40e6165](40e6165))
* **parser:** extract helpers from three oversize parsers
([#69](#69))
([25d0762](25d0762))
* **sexp:** dispatch NodeKind Display to per-category helpers
([#66](#66))
([44b0330](44b0330))
* **sexp:** table-drive ANSI-C escape dispatch
([#67](#67))
([91a5267](91a5267))
* tighten lexer API surface and relocate WordSpan to ast
([#70](#70))
([5171d01](5171d01))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: repository-butler[bot] <166800726+repository-butler[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PR 8: parser/{simple_command,conditionals,functions}.rs — extract parsing helpers

1 participant