From 2007768e8a1418f4e3876679ced6821cdac35308 Mon Sep 17 00:00:00 2001 From: Samyak Bambole Date: Sun, 26 Jul 2026 20:06:37 +0530 Subject: [PATCH] add support for arbitrary strings inside text commands --- src/parser.rs | 39 +++++++++++++++++++++++++++++++++- src/token.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ tests/smoke.rs | 2 +- 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 2074d15..2ea06f4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -120,6 +120,19 @@ impl<'a> Parser<'a> { self.advance(); } Some(Token::RBrace) => break, + Some(tok) if tok.text_char().is_some() => { + let span = self.current_span().ok_or(ParseError::UnexpectedEof)?; + + if let Some(prev_end) = last_end + && prev_end != span.start + { + name.push(' '); + } + + name.push(tok.text_char().unwrap()); + last_end = Some(span.end); + self.advance(); + } _ => { return Err(ParseError::ExpectedString.at( self.current_span() @@ -193,6 +206,14 @@ impl<'a> Parser<'a> { | Some(Token::Semicolon) | Some(Token::Less) | Some(Token::Greater) + | Some(Token::Question) + | Some(Token::At) + | Some(Token::Hash) + | Some(Token::Dollar) + | Some(Token::Percent) + | Some(Token::Tilde) + | Some(Token::Quote) + | Some(Token::Backtick) ) } @@ -221,7 +242,15 @@ impl<'a> Parser<'a> { | Some(Token::Colon) | Some(Token::Semicolon) | Some(Token::Less) - | Some(Token::Greater) = self.peek() + | Some(Token::Greater) + | Some(Token::Question) + | Some(Token::At) + | Some(Token::Hash) + | Some(Token::Dollar) + | Some(Token::Percent) + | Some(Token::Tilde) + | Some(Token::Quote) + | Some(Token::Backtick) = self.peek() { exprs.push(self.parse_scripted()?); } @@ -373,6 +402,14 @@ impl<'a> Parser<'a> { Token::Semicolon => Ok(Expr::Ident(";".into())), Token::Less => Ok(Expr::Ident("<".into())), Token::Greater => Ok(Expr::Ident(">".into())), + Token::Question => Ok(Expr::Ident("?".into())), + Token::At => Ok(Expr::Ident("@".into())), + Token::Hash => Ok(Expr::Ident("#".into())), + Token::Dollar => Ok(Expr::Ident("$".into())), + Token::Percent => Ok(Expr::Ident("%".into())), + Token::Tilde => Ok(Expr::Ident("~".into())), + Token::Quote => Ok(Expr::Ident("\"".into())), + Token::Backtick => Ok(Expr::Ident("`".into())), other => Err(ParseError::UnexpectedToken { position: self.pos - 1, token: format!("{other:?}"), diff --git a/src/token.rs b/src/token.rs index 904ec79..b91b213 100644 --- a/src/token.rs +++ b/src/token.rs @@ -56,6 +56,23 @@ pub enum Token<'a> { #[token("&")] Ampersand, + #[token("?")] + Question, + #[token("@")] + At, + #[token("#")] + Hash, + #[token("$")] + Dollar, + #[token("%")] + Percent, + #[token("~")] + Tilde, + #[token("\"")] + Quote, + #[token("`")] + Backtick, + #[regex(r"\\[a-zA-Z]+", |lex| &lex.slice()[1..])] Command(&'a str), @@ -74,6 +91,46 @@ pub enum Token<'a> { } impl<'a> Token<'a> { + pub fn text_char(&self) -> Option { + match self { + Token::Bang => Some('!'), + Token::Question => Some('?'), + Token::Comma => Some(','), + Token::Dot => Some('.'), + Token::Colon => Some(':'), + Token::Semicolon => Some(';'), + Token::Slash => Some('/'), + Token::Less => Some('<'), + Token::Greater => Some('>'), + Token::Plus => Some('+'), + Token::Minus => Some('-'), + Token::Equals => Some('='), + Token::Star => Some('*'), + Token::Pipe => Some('|'), + Token::Ampersand => Some('&'), + Token::LParen => Some('('), + Token::RParen => Some(')'), + Token::LBracket => Some('['), + Token::RBracket => Some(']'), + Token::LBrace => Some('{'), + Token::RBrace => Some('}'), + Token::Prime => Some('\''), + Token::Caret => Some('^'), + Token::Underscore => Some('_'), + Token::At => Some('@'), + Token::Hash => Some('#'), + Token::Dollar => Some('$'), + Token::Percent => Some('%'), + Token::Tilde => Some('~'), + Token::Quote => Some('"'), + Token::Backtick => Some('`'), + Token::Ident(s) => s.chars().next(), + Token::Number(s) if s.len() == 1 => s.chars().next(), + Token::Escape(s) => s.chars().next(), + _ => None, + } + } + pub fn as_char(&self) -> Option { match self { Token::LParen | Token::Escape("(") => Some('('), diff --git a/tests/smoke.rs b/tests/smoke.rs index b3c05c4..8a90b6a 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -83,7 +83,7 @@ fn braces_group_invisibly() { #[test] fn render_returns_error_for_invalid_lexer_input() { - assert!(txm::render("@").is_err()); + assert!(txm::render("\\").is_err()); } #[test]