feat: 更新错误处理机制,增强词法分析器和解析器的错误报告功能
This commit is contained in:
+27
-12
@@ -1,6 +1,7 @@
|
||||
// src/lexer/lexer.rs
|
||||
|
||||
use super::{Token, TokenKind};
|
||||
use crate::error::RuntimeError;
|
||||
|
||||
pub struct Lexer {
|
||||
src: Vec<char>,
|
||||
@@ -19,11 +20,12 @@ impl Lexer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tokenize(mut self) -> Vec<Token> {
|
||||
pub fn tokenize(mut self) -> (Vec<Token>, Vec<RuntimeError>) {
|
||||
let mut tokens = Vec::new();
|
||||
let mut errors = Vec::new();
|
||||
|
||||
while !self.is_at_end() {
|
||||
if let Some(token) = self.next_token() {
|
||||
if let Some(token) = self.next_token(&mut errors) {
|
||||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
@@ -34,10 +36,10 @@ impl Lexer {
|
||||
column: self.column,
|
||||
});
|
||||
|
||||
tokens
|
||||
(tokens, errors)
|
||||
}
|
||||
|
||||
fn next_token(&mut self) -> Option<Token> {
|
||||
fn next_token(&mut self, errors: &mut Vec<RuntimeError>) -> Option<Token> {
|
||||
self.skip_whitespace();
|
||||
|
||||
if self.is_at_end() {
|
||||
@@ -140,7 +142,8 @@ impl Lexer {
|
||||
if self.match_char('&') {
|
||||
TokenKind::AndAnd
|
||||
} else {
|
||||
panic!("Unexpected '&' at {}:{}", line, column);
|
||||
errors.push(RuntimeError::lex("Unexpected '&'. Did you mean '&&'?", line, column));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,11 +151,12 @@ impl Lexer {
|
||||
if self.match_char('|') {
|
||||
TokenKind::OrOr
|
||||
} else {
|
||||
panic!("Unexpected '|' at {}:{}", line, column);
|
||||
errors.push(RuntimeError::lex("Unexpected '|'. Did you mean '||'?", line, column));
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
'"' => return Some(self.string_literal(line, column)),
|
||||
'"' => return self.string_literal(line, column, errors),
|
||||
|
||||
c if c.is_ascii_digit() => {
|
||||
return Some(self.number_literal(c, line, column));
|
||||
@@ -163,7 +167,12 @@ impl Lexer {
|
||||
}
|
||||
|
||||
_ => {
|
||||
panic!("Unexpected character '{}' at {}:{}", c, line, column);
|
||||
errors.push(RuntimeError::lex(
|
||||
format!("Unexpected character '{}'", c),
|
||||
line,
|
||||
column,
|
||||
));
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -215,7 +224,12 @@ impl Lexer {
|
||||
self.current >= self.src.len()
|
||||
}
|
||||
|
||||
fn string_literal(&mut self, line: usize, column: usize) -> Token {
|
||||
fn string_literal(
|
||||
&mut self,
|
||||
line: usize,
|
||||
column: usize,
|
||||
errors: &mut Vec<RuntimeError>,
|
||||
) -> Option<Token> {
|
||||
let mut value = String::new();
|
||||
|
||||
while !self.is_at_end() && self.peek() != '"' {
|
||||
@@ -223,16 +237,17 @@ impl Lexer {
|
||||
}
|
||||
|
||||
if self.is_at_end() {
|
||||
panic!("Unterminated string at {}:{}", line, column);
|
||||
errors.push(RuntimeError::lex("Unterminated string literal", line, column));
|
||||
return None;
|
||||
}
|
||||
|
||||
self.advance(); // consume closing "
|
||||
|
||||
Token {
|
||||
Some(Token {
|
||||
kind: TokenKind::String(value),
|
||||
line,
|
||||
column,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn number_literal(&mut self, first: char, line: usize, column: usize) -> Token {
|
||||
|
||||
Reference in New Issue
Block a user