diff --git a/hel/src/parser.rs b/hel/src/parser.rs index 2ce8f0a..014c1a0 100644 --- a/hel/src/parser.rs +++ b/hel/src/parser.rs @@ -85,7 +85,10 @@ peg::parser! { _ => Err("unknown mode"), } } - rule mode() -> Mode = m:(umode() / rmode()) { m } + // A mode is a whole token: it must not be followed by another letter/digit, or + // a single letter would be stolen from a longer word (e.g. the `n` of `now`, + // making `name r now` mis-parse as name=`r`, mode=`n` instead of date=`now`). + rule mode() -> Mode = m:(umode() / rmode()) !['0'..='9' | 'a'..='z' | 'A'..='Z'] { m } rule noop_cmd() -> Command<'input> = ("#" [' '..='~']*)? { Command::Noop } rule help_cmd() -> Command<'input> = "help" { Command::Help } @@ -269,6 +272,24 @@ add t3 C 99 2022-12-14 assert_eq!(p3.comment, None); } + #[test] + fn parse_mode_word_boundary_test() { + // `now` must be the date, not mode `n` + leftover `ow`: name=testG mode=Regular. + let g = command_parser::name("testG r now").unwrap(); + assert_eq!(g.name, "testG"); + assert_eq!(g.prefix, None); + assert_eq!(g.mode, Mode::Regular); + // the whole gen command parses with no trailing-input error (so `now` was + // consumed as the date, not as a mode that left `ow` dangling) + assert!(command_parser::cmd("gen testG r now").is_ok()); + assert!(command_parser::cmd("gen testG R now").is_ok()); + // a length+mode token still works right up to a word boundary + let h = command_parser::name("github 20R").unwrap(); + assert_eq!(h.name, "github"); + assert_eq!(h.length, Some(20)); + assert_eq!(h.mode, Mode::Regular); + } + #[test] fn parse_password_test() { assert_eq!( diff --git a/helwasm/pkg/helwasm_bg.wasm b/helwasm/pkg/helwasm_bg.wasm index c268558..5fe3518 100644 Binary files a/helwasm/pkg/helwasm_bg.wasm and b/helwasm/pkg/helwasm_bg.wasm differ