Skip to content

Commit aec7836

Browse files
⚡ Bolt: Zero-allocation string evaluation for DelimTokenType and expected matching
Refactored `DelimTokenType` and `Tokenizer` logic to eliminate redundant `String` allocations during token identification and checking. - Introduced `as_str()` returning `&'static str` for `DelimTokenType` variants. - Refactored `check_op` and `fmt::Display` to use `as_str()` instead of `string()`. - Optimized `Tokenizer::expect` to validate tokens directly without intermediate `.clone()` and `.string()` operations. - Fixed a bug where a delimiter string mismatch would not emit the `ExpectedOpNotExist` error because `Tokenizer::expect` falsely returned `Ok(())` in the catch-all `_` block. Co-authored-by: ashyanSpada <22587148+ashyanSpada@users.noreply.github.com>
1 parent 9a4a6cc commit aec7836

2 files changed

Lines changed: 33 additions & 33 deletions

File tree

src/token.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,23 @@ impl From<&str> for DelimTokenType {
5252
}
5353

5454
impl DelimTokenType {
55-
pub fn string(&self) -> String {
55+
// ⚡ Bolt Optimization: Use `&'static str` to prevent heap allocation during string comparison.
56+
pub fn as_str(&self) -> &'static str {
5657
use DelimTokenType::*;
5758
match self {
58-
OpenParen => "(".to_string(),
59-
CloseParen => ")".to_string(),
60-
OpenBracket => "[".to_string(),
61-
CloseBracket => "]".to_string(),
62-
OpenBrace => "{".to_string(),
63-
CloseBrace => "}".to_string(),
64-
Unknown => "??".to_string(),
59+
OpenParen => "(",
60+
CloseParen => ")",
61+
OpenBracket => "[",
62+
CloseBracket => "]",
63+
OpenBrace => "{",
64+
CloseBrace => "}",
65+
Unknown => "??",
6566
}
6667
}
68+
69+
pub fn string(&self) -> String {
70+
self.as_str().to_string()
71+
}
6772
}
6873

6974
#[derive(Clone, PartialEq, Debug, Copy)]
@@ -83,10 +88,11 @@ pub enum Token<'input> {
8388
EOF,
8489
}
8590

91+
// ⚡ Bolt Optimization: Replace `op.string()` with `op.as_str()` to avoid `String` allocation on check
8692
pub fn check_op(token: Token, expected: &str) -> bool {
8793
match token {
8894
Token::Delim(op, _) => {
89-
if op.string() == expected {
95+
if op.as_str() == expected {
9096
return true;
9197
}
9298
}
@@ -187,7 +193,7 @@ impl<'input> Token<'input> {
187193
Reference(val, _) => val.to_string(),
188194
Function(val, _) => val.to_string(),
189195
Semicolon(val, _) => val.to_string(),
190-
Delim(ty, _) => ty.string(),
196+
Delim(ty, _) => ty.as_str().to_string(),
191197
EOF => "EOF".to_string(),
192198
}
193199
}
@@ -213,7 +219,8 @@ impl<'input> fmt::Display for Token<'input> {
213219
Function(val, span) => write!(f, "Function Token: {}, {}", val, span),
214220
String(val, span) => write!(f, "String Token: {}, {}", val, span),
215221
Semicolon(val, span) => write!(f, "Semicolon Token: {}, {}", val, span),
216-
Delim(ty, span) => write!(f, "Delim Token: {}, {}", ty.string(), span),
222+
// ⚡ Bolt Optimization: Avoid intermediate allocation by using `as_str()` directly
223+
Delim(ty, span) => write!(f, "Delim Token: {}, {}", ty.as_str(), span),
217224
EOF => write!(f, "EOF"),
218225
}
219226
}

src/tokenizer.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -141,29 +141,22 @@ impl<'a> Tokenizer<'a> {
141141
}
142142

143143
pub fn expect(&mut self, op: &str) -> Result<()> {
144-
let token = self.cur_token.clone();
145-
self.next()?;
146-
match token {
147-
Token::Delim(bracket, _) => {
148-
if bracket.string() == op {
149-
return Ok(());
150-
}
151-
}
152-
Token::Operator(operator, _) => {
153-
if operator == op {
154-
return Ok(());
155-
}
156-
}
157-
Token::Comma(c, _) => {
158-
if c == op {
159-
return Ok(());
160-
}
161-
}
162-
_ => {
163-
return Err(Error::ExpectedOpNotExist(op.to_string()));
164-
}
144+
// ⚡ Bolt Optimization:
145+
// Validate token strictly before consuming it (`self.next()?`) to fix an incorrect parsing fallback
146+
// and eliminate redundant `Token::clone()` and `.string()` allocations entirely.
147+
let is_match = match self.cur_token {
148+
Token::Delim(bracket, _) => bracket.as_str() == op,
149+
Token::Operator(operator, _) => operator == op,
150+
Token::Comma(c, _) => c == op,
151+
_ => false,
152+
};
153+
154+
if is_match {
155+
self.next()?;
156+
Ok(())
157+
} else {
158+
Err(Error::ExpectedOpNotExist(op.to_string()))
165159
}
166-
Ok(())
167160
}
168161

169162
fn delim_token(&mut self, start: usize) -> Result<Token<'a>> {

0 commit comments

Comments
 (0)