metrale_grammar/grammar/
lexer.rs1#[path = "lexer_scan.rs"]
16mod scan;
17#[cfg(test)]
18#[path = "lexer_tests.rs"]
19mod tests;
20#[path = "lexer_token.rs"]
21mod token;
22
23pub use token::{LexError, Token, TokenType, TokenValue};
24
25pub(super) const MAX_INTEGER_IN_GRAMMAR: i64 = 1_000_000_000_000_000;
27
28pub struct EbnfLexer {
30 pub(super) input: Vec<u8>,
31 pub(super) pos: usize,
32 pub(super) line: i32,
33 pub(super) column: i32,
34}
35
36impl EbnfLexer {
37 pub fn tokenize(input: &str) -> Result<Vec<Token>, LexError> {
39 let mut lexer = EbnfLexer {
40 input: input.as_bytes().to_vec(),
41 pos: 0,
42 line: 1,
43 column: 1,
44 };
45 let mut tokens: Vec<Token> = Vec::new();
46 loop {
47 let mut produced = lexer.next_token()?;
48 let stop = produced
49 .last()
50 .is_some_and(|t| t.ty == TokenType::EndOfFile);
51 tokens.append(&mut produced);
52 if stop {
53 break;
54 }
55 }
56 Self::convert_identifier_to_rule_name(&mut tokens)?;
57 Ok(tokens)
58 }
59
60 pub(super) fn peek(&self, delta: usize) -> u8 {
63 self.input.get(self.pos + delta).copied().unwrap_or(0)
64 }
65
66 fn peek_back(&self) -> u8 {
68 if self.pos == 0 {
69 0
70 } else {
71 self.input[self.pos - 1]
72 }
73 }
74
75 pub(super) fn consume(&mut self, cnt: usize) {
77 for _ in 0..cnt {
78 let c = self.peek(0);
79 if c == b'\n' || (c == b'\r' && self.peek(1) != b'\n') {
80 self.line += 1;
81 self.column = 1;
82 } else {
83 self.column += 1;
84 }
85 self.pos += 1;
86 }
87 }
88
89 pub(super) fn consume_space(&mut self) {
91 while matches!(self.peek(0), b' ' | b'\t' | b'#' | b'\n' | b'\r') {
92 self.consume(1);
93 if self.peek_back() == b'#' {
94 while self.peek(0) != 0 && self.peek(0) != b'\n' && self.peek(0) != b'\r' {
95 self.consume(1);
96 }
97 if self.peek(0) == 0 {
98 return;
99 }
100 self.consume(1);
101 if self.peek_back() == b'\r' && self.peek(0) == b'\n' {
102 self.consume(1);
103 }
104 }
105 }
106 }
107
108 pub(super) fn err(&self, msg: impl Into<String>) -> LexError {
110 LexError {
111 line: self.line,
112 column: self.column,
113 msg: msg.into(),
114 }
115 }
116
117 pub(super) fn is_name_char(c: u8, is_first: bool) -> bool {
119 c == b'_'
120 || c == b'-'
121 || c == b'.'
122 || c.is_ascii_lowercase()
123 || c.is_ascii_uppercase()
124 || (!is_first && c.is_ascii_digit())
125 }
126
127 fn parse_identifier_str(&mut self) -> Result<String, LexError> {
129 let start = self.pos;
130 let mut first = true;
131 while self.peek(0) != 0 && Self::is_name_char(self.peek(0), first) {
132 self.consume(1);
133 first = false;
134 }
135 if start == self.pos {
136 return Err(self.err("Expect identifier"));
137 }
138 Ok(String::from_utf8_lossy(&self.input[start..self.pos]).into_owned())
139 }
140
141 pub(super) fn parse_identifier_or_boolean(&mut self) -> Result<Token, LexError> {
143 let (line, column) = (self.line, self.column);
144 let ident = self.parse_identifier_str()?;
145 if ident == "true" || ident == "false" {
146 return Ok(Token {
147 ty: TokenType::BooleanLiteral,
148 value: TokenValue::Bool(ident == "true"),
149 lexeme: ident,
150 line,
151 column,
152 });
153 }
154 Ok(Token {
155 ty: TokenType::Identifier,
156 value: TokenValue::Str(ident.clone()),
157 lexeme: ident,
158 line,
159 column,
160 })
161 }
162
163 pub(super) fn simple_token(
165 &self,
166 ty: TokenType,
167 lexeme: &str,
168 line: i32,
169 column: i32,
170 ) -> Token {
171 Token {
172 ty,
173 lexeme: lexeme.to_string(),
174 value: TokenValue::None,
175 line,
176 column,
177 }
178 }
179}