feat: try-catch-finally 异常处理
语法: try { ... } catch (e) { ... } finally { ... }
catch 和 finally 都是可选的,但至少需要一个。throw expr 抛出任意值。
- Lexer: 新增 try, catch, finally, throw 关键字
- AST: Stmt::Try { body, catch_var, catch_body, finally_body } + Stmt::Throw(Expr)
- Parser: try/catch/finally/throw 语句解析,更新 synchronize()
- Opcode: Throw = 46,FunctionProto 新增 exception_handlers 表
- ExceptionHandler: { try_start, try_end, catch_ip, catch_slot, finally_ip }
- Compiler: compile_try 将 finally 在成功/异常两条路径各内联一次
- VM: unwind() 栈展开 + find_handler() 处理器搜索
- RuntimeError(除零、未定义变量等)在 try 块内自动转为可捕获异常
- LSP: 补全关键字列表追加
已知限制: return/break/continue 在 try-finally 内部不会先执行 finally
16 个新测试,全部 343 个测试通过。
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -54,6 +54,10 @@ impl Parser {
|
||||
self.continue_statement()
|
||||
} else if self.match_kind(&[TokenKind::Return]) {
|
||||
self.return_statement()
|
||||
} else if self.match_kind(&[TokenKind::Try]) {
|
||||
self.try_statement()
|
||||
} else if self.match_kind(&[TokenKind::Throw]) {
|
||||
self.throw_statement()
|
||||
} else if self.match_kind(&[TokenKind::LeftBrace]) {
|
||||
Ok(Stmt::Block(self.block()?))
|
||||
} else {
|
||||
@@ -201,6 +205,39 @@ impl Parser {
|
||||
Ok(Stmt::Return(value))
|
||||
}
|
||||
|
||||
fn try_statement(&mut self) -> Result<Stmt, RuntimeError> {
|
||||
self.consume(TokenKind::LeftBrace, "Expected '{' after 'try'.")?;
|
||||
let body = self.block()?;
|
||||
|
||||
let mut catch_var = None;
|
||||
let mut catch_body = None;
|
||||
if self.match_kind(&[TokenKind::Catch]) {
|
||||
self.consume(TokenKind::LeftParen, "Expected '(' after 'catch'.")?;
|
||||
catch_var = Some(self.consume_ident("Expected exception variable.")?);
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after catch variable.")?;
|
||||
self.consume(TokenKind::LeftBrace, "Expected '{' before catch body.")?;
|
||||
catch_body = Some(self.block()?);
|
||||
}
|
||||
|
||||
let mut finally_body = None;
|
||||
if self.match_kind(&[TokenKind::Finally]) {
|
||||
self.consume(TokenKind::LeftBrace, "Expected '{' after 'finally'.")?;
|
||||
finally_body = Some(self.block()?);
|
||||
}
|
||||
|
||||
if catch_var.is_none() && finally_body.is_none() {
|
||||
return Err(RuntimeError::parse("Expected 'catch' or 'finally' after 'try'.", self.peek().clone()));
|
||||
}
|
||||
|
||||
Ok(Stmt::Try { body, catch_var, catch_body, finally_body })
|
||||
}
|
||||
|
||||
fn throw_statement(&mut self) -> Result<Stmt, RuntimeError> {
|
||||
let expr = self.expression()?;
|
||||
self.match_kind(&[TokenKind::Semicolon]); // 分号可选
|
||||
Ok(Stmt::Throw(expr))
|
||||
}
|
||||
|
||||
fn block(&mut self) -> Result<Vec<Stmt>, RuntimeError> {
|
||||
let mut statements = Vec::new();
|
||||
|
||||
@@ -616,7 +653,9 @@ impl Parser {
|
||||
| TokenKind::For
|
||||
| TokenKind::Return
|
||||
| TokenKind::Break
|
||||
| TokenKind::Continue => return,
|
||||
| TokenKind::Continue
|
||||
| TokenKind::Try
|
||||
| TokenKind::Throw => return,
|
||||
_ => {
|
||||
self.advance();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user