Add Result + Err to lexer
This commit is contained in:
parent
264d8f92f4
commit
bc68d9fa49
@ -4,3 +4,5 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
anyhow = "1.0.53"
|
||||||
|
thiserror = "1.0.30"
|
||||||
|
|||||||
@ -21,7 +21,7 @@ impl Interpreter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_str(&mut self, code: &str, print_tokens: bool, print_ast: bool) {
|
pub fn run_str(&mut self, code: &str, print_tokens: bool, print_ast: bool) {
|
||||||
let tokens = lex(code);
|
let tokens = lex(code).unwrap();
|
||||||
if print_tokens {
|
if print_tokens {
|
||||||
println!("Tokens: {:?}", tokens);
|
println!("Tokens: {:?}", tokens);
|
||||||
}
|
}
|
||||||
|
|||||||
36
src/lexer.rs
36
src/lexer.rs
@ -1,7 +1,23 @@
|
|||||||
use std::{iter::Peekable, str::Chars};
|
use std::{iter::Peekable, str::Chars};
|
||||||
|
use anyhow::Result;
|
||||||
|
use thiserror::Error;
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LexErr {
|
||||||
|
#[error("Failed to parse '{0}' as i64")]
|
||||||
|
NumericParse(String),
|
||||||
|
|
||||||
|
#[error("Invalid escape character '\\{0}'")]
|
||||||
|
InvalidStrEscape(char),
|
||||||
|
|
||||||
|
#[error("Lexer encountered unexpected char: '{0}'")]
|
||||||
|
UnexpectedChar(char),
|
||||||
|
|
||||||
|
#[error("Missing closing string quote '\"'")]
|
||||||
|
MissingClosingString
|
||||||
|
}
|
||||||
|
|
||||||
struct Lexer<'a> {
|
struct Lexer<'a> {
|
||||||
code: Peekable<Chars<'a>>,
|
code: Peekable<Chars<'a>>,
|
||||||
}
|
}
|
||||||
@ -12,7 +28,7 @@ impl<'a> Lexer<'a> {
|
|||||||
Self { code }
|
Self { code }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lex(&mut self) -> Vec<Token> {
|
fn lex(&mut self) -> Result<Vec<Token>, LexErr> {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -103,9 +119,11 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We only added numeric chars to the string, but the conversion could still fail
|
// TODO: We only added numeric chars to the string, but the conversion could still fail
|
||||||
tokens.push(Token::I64(sval.parse().unwrap()));
|
let i64val = sval.parse().map_err(|_| LexErr::NumericParse(sval))?;
|
||||||
|
tokens.push(Token::I64(i64val));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lex a string
|
||||||
'"' => {
|
'"' => {
|
||||||
// Opening " was consumed in match
|
// Opening " was consumed in match
|
||||||
|
|
||||||
@ -114,7 +132,7 @@ impl<'a> Lexer<'a> {
|
|||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
'"' => break,
|
'"' => break,
|
||||||
'\0' => panic!("Encountered EoF while lexing string. Missing closing '\"'"),
|
'\0' => Err(LexErr::MissingClosingString)?,
|
||||||
_ => {
|
_ => {
|
||||||
|
|
||||||
match self.next() {
|
match self.next() {
|
||||||
@ -125,7 +143,7 @@ impl<'a> Lexer<'a> {
|
|||||||
't' => text.push('\t'),
|
't' => text.push('\t'),
|
||||||
'\\' => text.push('\\'),
|
'\\' => text.push('\\'),
|
||||||
'"' => text.push('"'),
|
'"' => text.push('"'),
|
||||||
ch => panic!("Invalid backslash escape: '{}'", ch),
|
ch => Err(LexErr::InvalidStrEscape(ch))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ch => text.push(ch),
|
ch => text.push(ch),
|
||||||
@ -168,11 +186,11 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Don't panic, keep calm
|
//TODO: Don't panic, keep calm
|
||||||
ch => panic!("Lexer encountered unexpected char: '{}'", ch),
|
ch => Err(LexErr::UnexpectedChar(ch))?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens
|
Ok(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Advance to next character and return the removed char
|
/// Advance to next character and return the removed char
|
||||||
@ -189,7 +207,7 @@ impl<'a> Lexer<'a> {
|
|||||||
/// Lex the provided code into a Token Buffer
|
/// Lex the provided code into a Token Buffer
|
||||||
///
|
///
|
||||||
/// TODO: Don't panic and implement error handling using Result
|
/// TODO: Don't panic and implement error handling using Result
|
||||||
pub fn lex(code: &str) -> Vec<Token> {
|
pub fn lex(code: &str) -> Result<Vec<Token>, LexErr> {
|
||||||
let mut lexer = Lexer::new(code);
|
let mut lexer = Lexer::new(code);
|
||||||
lexer.lex()
|
lexer.lex()
|
||||||
}
|
}
|
||||||
@ -223,7 +241,7 @@ mod tests {
|
|||||||
Token::Shr,
|
Token::Shr,
|
||||||
];
|
];
|
||||||
|
|
||||||
let actual = lex(code);
|
let actual = lex(code).unwrap();
|
||||||
assert_eq!(expected, actual);
|
assert_eq!(expected, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user