ADR-0024 Phase E: replay end-to-end
Migrate `replay <path>` to the walker. Shape is Choice(StringLit, BarePath); the StringLit branch handles the quoted form (with the existing `''` escape), and BarePath handles the unquoted form. Per ADR-0024's path-bearing UX change (already shipped for import / export in Phase A), bare `replay` paths terminate at the first whitespace byte. Paths with spaces require the quoted form. The legacy `try_parse_replay_with_bare_path` source-slice helper in dsl/parser.rs is removed; the chumsky-side replay branch in command_parser stays declared but unreachable until Phase F sweeps the chumsky path. Tests: - 7 new walker-specific tests for replay: bare relative path, bare absolute path, quoted with whitespace, quoted with escaped quote, case-insensitive keyword, missing-path error, empty-quoted-path parses to empty (runtime layer rejects). - Total: 844 passed, 0 failed, 1 ignored (was 838 / 1). - cargo clippy --all-targets -- -D warnings clean.
This commit is contained in:
+5
-45
@@ -120,9 +120,6 @@ pub fn parse_tokens(tokens: &[Token], source: &str) -> Result<Command, ParseErro
|
||||
if let Some(result) = try_walker_route(source) {
|
||||
return result;
|
||||
}
|
||||
if let Some(result) = try_parse_replay_with_bare_path(tokens, source) {
|
||||
return result;
|
||||
}
|
||||
match command_parser().parse(tokens).into_result() {
|
||||
Ok(cmd) => Ok(cmd),
|
||||
Err(errs) => Err(into_parse_error(&errs, tokens, source)),
|
||||
@@ -272,48 +269,11 @@ fn oxford_join(items: &[String]) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// `replay` source-slice special case (ADR-0020 §6).
|
||||
///
|
||||
/// `replay <bare-path>` lets the user write paths containing
|
||||
/// `/`, `.`, `~`, etc. — characters that the lexer would either
|
||||
/// classify as `Punct` or as `Error(UnknownChar)`. To keep the
|
||||
/// existing UX working, we detect `replay` followed by anything
|
||||
/// other than a `StringLiteral` and source-slice the rest of
|
||||
/// the input as the path. The quoted form (`replay '<path>'`)
|
||||
/// goes through the regular chumsky path.
|
||||
fn try_parse_replay_with_bare_path(
|
||||
tokens: &[Token],
|
||||
source: &str,
|
||||
) -> Option<Result<Command, ParseError>> {
|
||||
let first = tokens.first()?;
|
||||
if !matches!(first.kind, TokenKind::Keyword(Keyword::Replay)) {
|
||||
return None;
|
||||
}
|
||||
if matches!(
|
||||
tokens.get(1).map(|t| &t.kind),
|
||||
Some(TokenKind::StringLiteral(_))
|
||||
) {
|
||||
// Quoted form — chumsky handles it (and rejects any
|
||||
// trailing garbage).
|
||||
return None;
|
||||
}
|
||||
let after_replay = first.span.1;
|
||||
let rest = source[after_replay..].trim();
|
||||
if rest.is_empty() {
|
||||
// `replay` with nothing after — produce the same shape
|
||||
// of error chumsky would (positioned where the path
|
||||
// should have started).
|
||||
return Some(Err(ParseError::Invalid {
|
||||
message: crate::t!("parse.custom.replay_path_expected"),
|
||||
position: after_replay,
|
||||
at_eof: true,
|
||||
expected: vec!["path".to_string()],
|
||||
}));
|
||||
}
|
||||
Some(Ok(Command::Replay {
|
||||
path: rest.to_string(),
|
||||
}))
|
||||
}
|
||||
// ADR-0024 Phase E removed `try_parse_replay_with_bare_path`:
|
||||
// the walker now owns `replay` end-to-end via
|
||||
// `Choice(StringLit, BarePath)`. The chumsky-side replay
|
||||
// branch in `command_parser` is unreachable until Phase F
|
||||
// sweeps the chumsky path.
|
||||
|
||||
// ADR-0024 Phase A removed `try_parse_app_path_command`: the
|
||||
// walker (`crate::dsl::walker`) now owns export / import end-to-
|
||||
|
||||
Reference in New Issue
Block a user