diff options
Diffstat (limited to 'src/lexer.rs')
| -rw-r--r-- | src/lexer.rs | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/lexer.rs b/src/lexer.rs new file mode 100644 index 0000000..49d2d04 --- /dev/null +++ b/src/lexer.rs @@ -0,0 +1,74 @@ +pub struct Lexer<'a> { + pub buf: &'a str, +} + +impl<'a> Lexer<'a> { + fn skip_whitespace(&mut self) { + while let Some(b' ') = self.buf.as_bytes().first() { + self.buf = &self.buf[1..] + } + } + + fn parse_num(&mut self) -> Option<&'a str> { + let mut i = 0; + while matches!(self.buf.as_bytes().get(i), Some(&b) if b.is_ascii_digit()) { + i += 1; + } + if let Some(b'.') = self.buf.as_bytes().get(i) { + i += 1; + } + while matches!(self.buf.as_bytes().get(i), Some(&b) if b.is_ascii_digit()) { + i += 1; + } + let (Some(b'e') | Some(b'E')) = self.buf.as_bytes().get(i) else { + let t = &self.buf[..i]; + self.buf = &self.buf[i..]; + return Some(t); + }; + i += 1; + if let Some(b'-') = self.buf.as_bytes().get(i) { + i += 1; + } + while matches!(self.buf.as_bytes().get(i), Some(&b) if b.is_ascii_digit()) { + i += 1; + } + let t = &self.buf[..i]; + self.buf = &self.buf[i..]; + Some(t) + } +} + +impl<'a> Iterator for Lexer<'a> { + type Item = &'a str; + + fn next(&mut self) -> Option<&'a str> { + self.skip_whitespace(); + let &first_byte = self.buf.as_bytes().first()?; + if first_byte.is_ascii_digit() || first_byte == b'.' { + return self.parse_num(); + } + match first_byte { + b'/' => { + if let Some(b'/') = self.buf.as_bytes().get(1) { + self.buf = &self.buf[2..]; + return Some("//"); + } + self.buf = &self.buf[1..]; + return Some("/"); + } + b'+' | b'-' | b'*' | b'^' | b'(' | b')' => { + let t = &self.buf[..1]; + self.buf = &self.buf[1..]; + return Some(t); + } + _ => (), + } + let mut i = 0; + while let Some(b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9') = self.buf.as_bytes().get(i) { + i += 1; + } + let t = &self.buf[..i]; + self.buf = &self.buf[i..]; + Some(t) + } +} |
