Lexer: reduce code duplication in Rule mapping

produce_token renamed to map_rule
- Skips leading whitespace before any Rule evaluations
- Handles creation and destruction of Rule
This commit is contained in:
John 2023-09-27 22:51:51 -05:00
parent d4245844ce
commit 0661789d42

View File

@ -83,10 +83,12 @@ pub mod lexer {
self.cursor += len self.cursor += len
} }
} }
/// Advances the cursor and produces a token /// Advances the cursor and produces a token from a provided [Rule] function
fn produce_token(&mut self, ty: Type, len: usize) -> Option<Token> { fn map_rule<F>(&mut self, rule: F, ty: Type) -> Option<Token>
where F: Fn(Rule) -> Rule {
self.skip_whitespace();
let start = self.cursor; let start = self.cursor;
self.cursor += len; self.cursor += Rule::new(self.text()).and(rule).end()?;
Some(Token::new(ty, start, self.cursor)) Some(Token::new(ty, start, self.cursor))
} }
/// Gets a slice of text beginning at the cursor /// Gets a slice of text beginning at the cursor
@ -126,85 +128,66 @@ pub mod lexer {
} }
// functions for lexing individual tokens // functions for lexing individual tokens
pub fn invalid(&mut self) -> Option<Token> { pub fn invalid(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.invalid(), Type::Invalid)
self.produce_token(Type::Invalid, Rule::new(self.text()).invalid().end()?)
} }
// comments // comments
pub fn comment(&mut self) -> Option<Token> { pub fn comment(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.comment(), Type::Comment)
self.produce_token(Type::Comment, Rule::new(self.text()).comment().end()?)
} }
// keywords // keywords
pub fn kw_else(&mut self) -> Option<Token> { pub fn kw_else(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("else"), Type::KwElse)
self.produce_token(Type::KwElse, Rule::new(self.text()).str("else").end()?)
} }
pub fn kw_for(&mut self) -> Option<Token> { pub fn kw_for(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("for"), Type::KwFor)
self.produce_token(Type::KwFor, Rule::new(self.text()).str("for").end()?)
} }
pub fn kw_fn(&mut self) -> Option<Token> { pub fn kw_fn(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("fn"), Type::KwFn)
self.produce_token(Type::KwFn, Rule::new(self.text()).str("fn").end()?)
} }
pub fn kw_if(&mut self) -> Option<Token> { pub fn kw_if(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("if"), Type::KwIf)
self.produce_token(Type::KwIf, Rule::new(self.text()).str("if").end()?)
} }
pub fn kw_in(&mut self) -> Option<Token> { pub fn kw_in(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("in"), Type::KwIn)
self.produce_token(Type::KwIn, Rule::new(self.text()).str("in").end()?)
} }
pub fn kw_let(&mut self) -> Option<Token> { pub fn kw_let(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("let"), Type::KwLet)
self.produce_token(Type::KwLet, Rule::new(self.text()).str("let").end()?)
} }
pub fn kw_while(&mut self) -> Option<Token> { pub fn kw_while(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.str("while"), Type::KwWhile)
self.produce_token(Type::KwWhile, Rule::new(self.text()).str("while").end()?)
} }
// identifiers // identifiers
pub fn identifier(&mut self) -> Option<Token> { pub fn identifier(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.identifier(), Type::Identifier)
self.produce_token(Type::Identifier, Rule::new(self.text()).identifier().end()?)
} }
// literals // literals
pub fn lit_integer(&mut self) -> Option<Token> { pub fn lit_integer(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.integer(), Type::LitInteger)
self.produce_token(Type::LitInteger, Rule::new(self.text()).integer().end()?)
} }
pub fn lit_float(&mut self) -> Option<Token> { pub fn lit_float(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.float(), Type::LitFloat)
self.produce_token(Type::LitFloat, Rule::new(self.text()).float().end()?)
} }
pub fn lit_string(&mut self) -> Option<Token> { pub fn lit_string(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.string(), Type::LitString)
self.produce_token(Type::LitString, Rule::new(self.text()).string().end()?)
} }
// delimiters // delimiters
pub fn l_brack(&mut self) -> Option<Token> { pub fn l_brack(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.char('['), Type::LBrack)
self.produce_token(Type::LBrack, Rule::new(self.text()).char('[').end()?)
} }
pub fn r_brack(&mut self) -> Option<Token> { pub fn r_brack(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.char(']'), Type::RBrack)
self.produce_token(Type::RBrack, Rule::new(self.text()).char(']').end()?)
} }
pub fn l_curly(&mut self) -> Option<Token> { pub fn l_curly(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.char('{'), Type::LCurly)
self.produce_token(Type::LCurly, Rule::new(self.text()).char('{').end()?)
} }
pub fn r_curly(&mut self) -> Option<Token> { pub fn r_curly(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.char('}'), Type::RCurly)
self.produce_token(Type::RCurly, Rule::new(self.text()).char('}').end()?)
} }
pub fn l_paren(&mut self) -> Option<Token> { pub fn l_paren(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.char('('), Type::LParen)
self.produce_token(Type::LParen, Rule::new(self.text()).char('(').end()?)
} }
pub fn r_paren(&mut self) -> Option<Token> { pub fn r_paren(&mut self) -> Option<Token> {
self.skip_whitespace(); self.map_rule(|r| r.char(')'), Type::RParen)
self.produce_token(Type::RParen, Rule::new(self.text()).char(')').end()?)
} }
} }