error tokens instead of result

This commit is contained in:
nora 2021-12-30 16:21:18 +01:00
parent 5ae747d513
commit 11b735d728
3 changed files with 49 additions and 36 deletions

View file

@ -62,7 +62,7 @@ mod span {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq)]
pub struct CompilerError { pub struct CompilerError {
pub span: Span, pub span: Span,
pub message: String, pub message: String,

View file

@ -95,6 +95,9 @@ pub enum TokenType<'code> {
GreaterEqual, GreaterEqual,
/// <= /// <=
LessEqual, LessEqual,
/// An error occurred
Error(CompilerError),
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -141,7 +144,7 @@ impl<'code> Lexer<'code> {
} }
impl<'code> Iterator for Lexer<'code> { impl<'code> Iterator for Lexer<'code> {
type Item = Result<Token<'code>, CompilerError>; type Item = Token<'code>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
let token = loop { let token = loop {
@ -190,18 +193,18 @@ impl<'code> Iterator for Lexer<'code> {
); );
} }
'!' => { '!' => {
if self.expect('=') { break if self.expect('=') {
let _ = self.code.next(); // consume =; let _ = self.code.next(); // consume =;
break Token { Token::new(Span::start_len(start, start + 2), TokenType::BangEqual)
span: Span::start_len(start, start + 2),
kind: TokenType::BangEqual,
};
} else { } else {
return Some(Err(CompilerError::with_note( Token::new(
Span::single(start), Span::single(start),
"Expected '=' after '!'".to_string(), TokenType::Error(CompilerError::with_note(
"If you meant to use it for negation, use `not`".to_string(), Span::single(start),
))); "Expected '=' after '!'".to_string(),
"If you meant to use it for negation, use `not`".to_string(),
)),
)
}; };
} }
'>' => { '>' => {
@ -227,11 +230,14 @@ impl<'code> Iterator for Lexer<'code> {
buffer.push(char); buffer.push(char);
} }
None => { None => {
return Some(Err(CompilerError::with_note( return Some(Token::new(
Span::single(start), // no not show the whole literal, this does not make sense Span::single(start),
"String literal not closed".to_string(), TokenType::Error(CompilerError::with_note(
"Close the literal using '\"'".to_string(), Span::single(start), // no not show the whole literal, this does not make sense
))); "String literal not closed".to_string(),
"Close the literal using '\"'".to_string(),
)),
));
} }
} }
}; };
@ -256,25 +262,23 @@ impl<'code> Iterator for Lexer<'code> {
}; };
let number_str = &self.src[start..end]; let number_str = &self.src[start..end];
let span = Span::start_end(start, end); let span = Span::start_end(start, end);
let number = number_str.parse::<f64>().map_err(|err| { let number = number_str.parse::<f64>();
CompilerError::with_note( break match number {
span,
"Invalid number".to_string(),
err.to_string(),
)
});
match number {
Ok(number) if number.is_infinite() => { Ok(number) if number.is_infinite() => {
return Some(Err(CompilerError::with_note( Token::new(span, TokenType::Error(CompilerError::with_note(
span, span,
"Number literal too long".to_string(), "Number literal too long".to_string(),
"A number literal cannot be larger than a 64 bit float can represent" "A number literal cannot be larger than a 64 bit float can represent"
.to_string(), .to_string(),
))) )))
} }
Ok(number) => break Token::new(span, TokenType::Number(number)), Ok(number) => Token::new(span, TokenType::Number(number)),
Err(err) => return Some(Err(err)), Err(err) => Token::new(span, TokenType::Error(CompilerError::with_note(
} span,
"Invalid number".to_string(),
err.to_string(),
))),
};
} else if is_valid_ident_start(char) { } else if is_valid_ident_start(char) {
// it must be an identifier // it must be an identifier
let end = loop { let end = loop {
@ -291,18 +295,21 @@ impl<'code> Iterator for Lexer<'code> {
keyword_or_ident(&self.src[start..end]), keyword_or_ident(&self.src[start..end]),
); );
} else { } else {
return Some(Err(CompilerError::with_note( break Token::new(
Span::single(start), Span::single(start),
format!("Unexpected character: '{}'", char), TokenType::Error(CompilerError::with_note(
"Character is not allowed outside of string literals and comments" Span::single(start),
.to_string(), format!("Unexpected character: '{}'", char),
))); "Character is not allowed outside of string literals and comments"
.to_string(),
)),
);
} }
} }
} }
}; };
Some(Ok(token)) Some(token)
} }
} }
@ -345,7 +352,7 @@ mod test {
fn lex_types(str: &str) -> Vec<TokenType> { fn lex_types(str: &str) -> Vec<TokenType> {
let lexer = Lexer::new(str); let lexer = Lexer::new(str);
lexer.map(|token| token.unwrap().kind).collect::<Vec<_>>() lexer.map(|token| token.kind).collect::<Vec<_>>()
} }
fn lex_test(code: &str, expected: Vec<TokenType>) { fn lex_test(code: &str, expected: Vec<TokenType>) {

View file

@ -18,7 +18,13 @@ pub fn run_program(program: &str) {
let ast_alloc = Bump::new(); let ast_alloc = Bump::new();
let lexer = lex::Lexer::new(program); let lexer = lex::Lexer::new(program);
let ast = parse::parse(lexer, &ast_alloc); let ast = parse::parse(
lexer.map(|token| match &token.kind {
TokenType::Error(err) => Err(err.clone()),
_ => Ok(token),
}),
&ast_alloc,
);
match ast { match ast {
Ok(ast) => process_ast(program, ast), Ok(ast) => process_ast(program, ast),