Skip to content

Commit 0e0430f

Browse files
committed
ISLE: use string references in Token::Symbol
Replace `String` with `&str` in `Token::Symbol`, so we don't need to heap allocate a new string for every symbol that is lexed. Copyright (c) 2024, Arm Limited. Signed-off-by: Karl Meakin <karl.meakin@arm.com>
1 parent f3933a0 commit 0e0430f

2 files changed

Lines changed: 30 additions & 33 deletions

File tree

cranelift/isle/isle/src/lexer.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type Result<T> = std::result::Result<T, Error>;
1414
pub struct Lexer<'src> {
1515
src: &'src str,
1616
pos: Pos,
17-
lookahead: Option<(Pos, Token)>,
17+
lookahead: Option<(Pos, Token<'src>)>,
1818
}
1919

2020
/// A source position.
@@ -46,14 +46,14 @@ impl Pos {
4646
}
4747

4848
/// A token of ISLE source.
49-
#[derive(Clone, Debug, PartialEq, Eq)]
50-
pub enum Token {
49+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
50+
pub enum Token<'src> {
5151
/// Left paren.
5252
LParen,
5353
/// Right paren.
5454
RParen,
5555
/// A symbol, e.g. `Foo`.
56-
Symbol(String),
56+
Symbol(&'src str),
5757
/// An integer.
5858
Int(i128),
5959
/// `@`
@@ -88,7 +88,7 @@ impl<'src> Lexer<'src> {
8888
}
8989
}
9090

91-
fn next_token(&mut self) -> Result<Option<(Pos, Token)>> {
91+
fn next_token(&mut self) -> Result<Option<(Pos, Token<'src>)>> {
9292
fn is_sym_first_char(c: u8) -> bool {
9393
match c {
9494
b'-' | b'0'..=b'9' | b'(' | b')' | b';' => false,
@@ -149,7 +149,7 @@ impl<'src> Lexer<'src> {
149149
let end = self.pos.offset;
150150
let s = &self.src[start..end];
151151
debug_assert!(!s.is_empty());
152-
Ok(Some((start_pos, Token::Symbol(s.to_string()))))
152+
Ok(Some((start_pos, Token::Symbol(s))))
153153
}
154154
c @ (b'0'..=b'9' | b'-') => {
155155
let start_pos = self.pos();
@@ -225,7 +225,7 @@ impl<'src> Lexer<'src> {
225225
}
226226

227227
/// Get the next token from this lexer's token stream, if any.
228-
pub fn next(&mut self) -> Result<Option<(Pos, Token)>> {
228+
pub fn next(&mut self) -> Result<Option<(Pos, Token<'src>)>> {
229229
let tok = self.lookahead.take();
230230
self.reload()?;
231231
Ok(tok)
@@ -239,7 +239,7 @@ impl<'src> Lexer<'src> {
239239
}
240240

241241
/// Peek ahead at the next token.
242-
pub fn peek(&self) -> Option<&(Pos, Token)> {
242+
pub fn peek(&self) -> Option<&(Pos, Token<'src>)> {
243243
self.lookahead.as_ref()
244244
}
245245

@@ -253,7 +253,7 @@ impl<'src> Lexer<'src> {
253253
}
254254
}
255255

256-
impl Token {
256+
impl<'src> Token<'src> {
257257
/// Is this an `Int` token?
258258
pub fn is_int(&self) -> bool {
259259
matches!(self, Token::Int(_))
@@ -285,9 +285,9 @@ mod test {
285285
lex(";; comment\n; another\r\n \t(one two three 23 -568 )\n"),
286286
[
287287
Token::LParen,
288-
Token::Symbol("one".to_string()),
289-
Token::Symbol("two".to_string()),
290-
Token::Symbol("three".to_string()),
288+
Token::Symbol("one"),
289+
Token::Symbol("two"),
290+
Token::Symbol("three"),
291291
Token::Int(23),
292292
Token::Int(-568),
293293
Token::RParen
@@ -297,7 +297,7 @@ mod test {
297297

298298
#[test]
299299
fn ends_with_sym() {
300-
assert_eq!(lex("asdf"), [Token::Symbol("asdf".to_string())]);
300+
assert_eq!(lex("asdf"), [Token::Symbol("asdf")]);
301301
}
302302

303303
#[test]
@@ -311,11 +311,11 @@ mod test {
311311
lex("(+ [] => !! _test!;comment\n)"),
312312
[
313313
Token::LParen,
314-
Token::Symbol("+".to_string()),
315-
Token::Symbol("[]".to_string()),
316-
Token::Symbol("=>".to_string()),
317-
Token::Symbol("!!".to_string()),
318-
Token::Symbol("_test!".to_string()),
314+
Token::Symbol("+"),
315+
Token::Symbol("[]"),
316+
Token::Symbol("=>"),
317+
Token::Symbol("!!"),
318+
Token::Symbol("_test!"),
319319
Token::RParen,
320320
]
321321
);

cranelift/isle/isle/src/parser.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ pub fn parse(lexer: Lexer) -> Result<Vec<Def>> {
1616
///
1717
/// Takes in a lexer and creates an AST.
1818
#[derive(Clone, Debug)]
19-
struct Parser<'a> {
20-
lexer: Lexer<'a>,
19+
struct Parser<'src> {
20+
lexer: Lexer<'src>,
2121
}
2222

2323
/// Used during parsing a `(rule ...)` to encapsulate some form that
@@ -28,9 +28,9 @@ enum IfLetOrExpr {
2828
Expr(Expr),
2929
}
3030

31-
impl<'a> Parser<'a> {
31+
impl<'src> Parser<'src> {
3232
/// Construct a new parser from the given lexer.
33-
pub fn new(lexer: Lexer<'a>) -> Parser<'a> {
33+
pub fn new(lexer: Lexer<'src>) -> Parser<'src> {
3434
Parser { lexer }
3535
}
3636

@@ -41,7 +41,7 @@ impl<'a> Parser<'a> {
4141
}
4242
}
4343

44-
fn expect<F: Fn(&Token) -> bool>(&mut self, f: F) -> Result<Token> {
44+
fn expect<F: Fn(&Token<'src>) -> bool>(&mut self, f: F) -> Result<Token<'src>> {
4545
if let Some(&(pos, ref peek)) = self.lexer.peek() {
4646
if !f(peek) {
4747
return Err(self.error(pos, format!("Unexpected token {peek:?}")));
@@ -52,7 +52,7 @@ impl<'a> Parser<'a> {
5252
}
5353
}
5454

55-
fn eat<F: Fn(&Token) -> bool>(&mut self, f: F) -> Result<Option<Token>> {
55+
fn eat<F: Fn(&Token<'src>) -> bool>(&mut self, f: F) -> Result<Option<Token<'src>>> {
5656
if let Some(&(_pos, ref peek)) = self.lexer.peek() {
5757
if !f(peek) {
5858
return Ok(None);
@@ -63,7 +63,7 @@ impl<'a> Parser<'a> {
6363
}
6464
}
6565

66-
fn is<F: Fn(&Token) -> bool>(&self, f: F) -> bool {
66+
fn is<F: Fn(&Token<'src>) -> bool>(&self, f: F) -> bool {
6767
if let Some((_, peek)) = self.lexer.peek() {
6868
f(peek)
6969
} else {
@@ -108,10 +108,7 @@ impl<'a> Parser<'a> {
108108
}
109109

110110
fn is_spec_bool(&self) -> bool {
111-
self.is(|tok| match tok {
112-
Token::Symbol(tok_s) if tok_s == "$true" || tok_s == "$false" => true,
113-
_ => false,
114-
})
111+
self.is(|tok| matches!(tok, Token::Symbol("$true" | "$false")))
115112
}
116113

117114
fn expect_lparen(&mut self) -> Result<()> {
@@ -124,7 +121,7 @@ impl<'a> Parser<'a> {
124121
self.expect(|tok| *tok == Token::At).map(|_| ())
125122
}
126123

127-
fn expect_symbol(&mut self) -> Result<String> {
124+
fn expect_symbol(&mut self) -> Result<&'src str> {
128125
match self.expect(Token::is_sym)? {
129126
Token::Symbol(s) => Ok(s),
130127
_ => unreachable!(),
@@ -133,7 +130,7 @@ impl<'a> Parser<'a> {
133130

134131
fn eat_sym_str(&mut self, s: &str) -> Result<bool> {
135132
self.eat(|tok| match tok {
136-
Token::Symbol(ref tok_s) if tok_s == s => true,
133+
Token::Symbol(ref tok_s) if *tok_s == s => true,
137134
_ => false,
138135
})
139136
.map(|token| token.is_some())
@@ -424,7 +421,7 @@ impl<'a> Parser<'a> {
424421
}
425422
if self.is_sym() && !self.is_spec_bit_vector() {
426423
let sym = self.expect_symbol()?;
427-
if let Ok(op) = self.parse_spec_op(sym.as_str()) {
424+
if let Ok(op) = self.parse_spec_op(sym) {
428425
let mut args: Vec<SpecExpr> = vec![];
429426
while !self.is_rparen() {
430427
args.push(self.parse_spec_expr()?);
@@ -531,7 +528,7 @@ impl<'a> Parser<'a> {
531528
fn parse_spec_bool(&mut self) -> Result<i8> {
532529
let pos = self.pos();
533530
let s = self.expect_symbol()?;
534-
match s.as_str() {
531+
match s {
535532
"$true" => Ok(1),
536533
"$false" => Ok(0),
537534
x => Err(self.error(pos, format!("Not a valid spec boolean: {x}"))),

0 commit comments

Comments
 (0)