feat: 更新错误处理机制,增强词法分析器和解析器的错误报告功能

This commit is contained in:
0264408
2026-06-16 14:24:49 +08:00
parent e052226cdb
commit c7e4e0dce0
4 changed files with 240 additions and 155 deletions
+27 -12
View File
@@ -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 {