feat: 添加break和continue语句的支持,更新解析器、解释器和词法分析器以处理相关语法

This commit is contained in:
0264408
2026-06-10 17:37:12 +08:00
parent dd3f18da6f
commit ae3060708d
7 changed files with 109 additions and 21 deletions
+27
View File
@@ -0,0 +1,27 @@
// test break
let i = 0
while (i < 10) {
if (i == 5) { break }
i = i + 1
}
print("break (expect 5):", i)
// test continue
let sum = 0
let j = 0
while (j < 10) {
j = j + 1
if (j == 5) { continue }
sum = sum + j
}
print("continue (expect 50):", sum)
// test for + break
let found = -1
for (let k = 0; k < 100; k = k + 1) {
if (k * k > 50) {
found = k
break
}
}
print("for break (expect 8):", found)
+6
View File
@@ -44,4 +44,10 @@ pub enum Stmt {
/// return expr?; /// return expr?;
Return(Option<Expr>), Return(Option<Expr>),
/// break
Break,
/// continue
Continue,
} }
+51 -21
View File
@@ -1,5 +1,6 @@
use crate::ast::*; use crate::ast::*;
use crate::error::RuntimeError; use crate::error::RuntimeError;
use crate::interpreter::Signal;
use super::{Value, Env, Function}; use super::{Value, Env, Function};
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
@@ -23,26 +24,30 @@ impl Interpreter {
Ok(()) Ok(())
} }
fn execute(&mut self, stmt: Stmt) -> Result<Option<Value>, RuntimeError> { fn execute(&mut self, stmt: Stmt) -> Result<Signal, RuntimeError> {
match stmt { match stmt {
Stmt::Let { name, initializer } => { Stmt::Let { name, initializer } => {
let val = self.evaluate(initializer)?; let val = self.evaluate(initializer)?;
self.env.borrow_mut().define(name, val); self.env.borrow_mut().define(name, val);
Ok(None) Ok(Signal::None)
} }
Stmt::ExprStmt(expr) => { Stmt::ExprStmt(expr) => {
Ok(Some(self.evaluate(expr)?)) self.evaluate(expr)?;
Ok(Signal::None)
} }
Stmt::Block(stmts) => { Stmt::Block(stmts) => {
let previous = Rc::clone(&self.env); let previous = Rc::clone(&self.env);
self.env = Rc::new(RefCell::new(Env::new(Some(previous)))); self.env = Rc::new(RefCell::new(Env::new(Some(previous))));
let mut result = None; let mut signal = Signal::None;
for s in stmts { for s in stmts {
result = self.execute(s)?; signal = self.execute(s)?;
if !matches!(signal, Signal::None) {
break;
}
} }
let parent = self.env.borrow().parent.as_ref().unwrap().clone(); let parent = self.env.borrow().parent.as_ref().unwrap().clone();
self.env = parent; self.env = parent;
Ok(result) Ok(signal)
} }
Stmt::If { condition, then_branch, else_branch } => { Stmt::If { condition, then_branch, else_branch } => {
let cond_val = self.evaluate(condition)?; let cond_val = self.evaluate(condition)?;
@@ -51,7 +56,7 @@ impl Interpreter {
} else if let Some(else_branch) = else_branch { } else if let Some(else_branch) = else_branch {
self.execute(*else_branch) self.execute(*else_branch)
} else { } else {
Ok(None) Ok(Signal::None)
} }
} }
Stmt::While { condition, body } => { Stmt::While { condition, body } => {
@@ -60,25 +65,42 @@ impl Interpreter {
if !self.is_truthy(&cond_val) { if !self.is_truthy(&cond_val) {
break; break;
} }
self.execute(*body.clone())?; match self.execute(*body.clone())? {
Signal::Break => break,
Signal::Continue => continue,
sig @ Signal::Return(_) => return Ok(sig),
Signal::None => {}
}
} }
Ok(None) Ok(Signal::None)
} }
Stmt::For { initializer, condition, step, body } => { Stmt::For { initializer, condition, step, body } => {
if let Some(init) = initializer { if let Some(init) = initializer {
self.execute(*init)?; self.execute(*init)?;
} }
while let Some(cond) = &condition { loop {
let cond_val = self.evaluate(cond.clone())?; if let Some(cond) = &condition {
if !self.is_truthy(&cond_val) { let cond_val = self.evaluate(cond.clone())?;
break; if !self.is_truthy(&cond_val) {
break;
}
}
match self.execute(*body.clone())? {
Signal::Break => break,
Signal::Continue => {
if let Some(step) = &step {
self.evaluate(step.clone())?;
}
continue;
}
sig @ Signal::Return(_) => return Ok(sig),
Signal::None => {}
} }
self.execute(*body.clone())?;
if let Some(step) = &step { if let Some(step) = &step {
self.evaluate(step.clone())?; self.evaluate(step.clone())?;
} }
} }
Ok(None) Ok(Signal::None)
} }
Stmt::Function { name, params, body } => { Stmt::Function { name, params, body } => {
let func = Value::Function(Rc::new(Function { let func = Value::Function(Rc::new(Function {
@@ -88,15 +110,17 @@ impl Interpreter {
name: Some(name.clone()), name: Some(name.clone()),
})); }));
self.env.borrow_mut().define(name, func); self.env.borrow_mut().define(name, func);
Ok(None) Ok(Signal::None)
} }
Stmt::Return(expr_opt) => { Stmt::Return(expr_opt) => {
if let Some(expr) = expr_opt { if let Some(expr) = expr_opt {
Ok(Some(self.evaluate(expr)?)) Ok(Signal::Return(self.evaluate(expr)?))
} else { } else {
Ok(Some(Value::Nil)) Ok(Signal::Return(Value::Nil))
} }
} }
Stmt::Break => Ok(Signal::Break),
Stmt::Continue => Ok(Signal::Continue),
} }
} }
@@ -327,9 +351,15 @@ impl Interpreter {
self.env = env; self.env = env;
let mut ret = Value::Nil; let mut ret = Value::Nil;
for stmt in &f.body { for stmt in &f.body {
if let Some(val) = self.execute(stmt.clone())? { match self.execute(stmt.clone())? {
ret = val; Signal::Return(val) => { ret = val; break; }
break; Signal::None => {}
Signal::Break | Signal::Continue => {
return Err(RuntimeError::RuntimeError {
message: "break/continue outside of loop".to_string(),
token: None,
});
}
} }
} }
self.env = previous; self.env = previous;
+7
View File
@@ -24,6 +24,13 @@ pub enum Value {
NativeFunction(NativeFn), NativeFunction(NativeFn),
} }
pub enum Signal {
None, // 正常执行
Return(Value), // return 语句携带的返回值
Break, // break 信号
Continue, // continue 信号
}
impl std::fmt::Debug for Value { impl std::fmt::Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self { match self {
+2
View File
@@ -246,6 +246,8 @@ impl Lexer {
"else" => TokenKind::Else, "else" => TokenKind::Else,
"while" => TokenKind::While, "while" => TokenKind::While,
"for" => TokenKind::For, "for" => TokenKind::For,
"break" => TokenKind::Break,
"continue" => TokenKind::Continue,
"return" => TokenKind::Return, "return" => TokenKind::Return,
"true" => TokenKind::True, "true" => TokenKind::True,
"false" => TokenKind::False, "false" => TokenKind::False,
+2
View File
@@ -29,6 +29,8 @@ pub enum TokenKind {
Else, Else,
While, While,
For, For,
Break,
Continue,
Return, Return,
True, True,
False, False,
+14
View File
@@ -39,6 +39,10 @@ impl Parser {
self.while_statement() self.while_statement()
} else if self.match_kind(&[TokenKind::For]) { } else if self.match_kind(&[TokenKind::For]) {
self.for_statement() self.for_statement()
} else if self.match_kind(&[TokenKind::Break]) {
self.break_statement()
} else if self.match_kind(&[TokenKind::Continue]) {
self.continue_statement()
} else if self.match_kind(&[TokenKind::Return]) { } else if self.match_kind(&[TokenKind::Return]) {
self.return_statement() self.return_statement()
} else if self.match_kind(&[TokenKind::LeftBrace]) { } else if self.match_kind(&[TokenKind::LeftBrace]) {
@@ -153,6 +157,16 @@ impl Parser {
} }
} }
fn break_statement(&mut self) -> Stmt {
self.match_kind(&[TokenKind::Semicolon]); // 分号可选
Stmt::Break
}
fn continue_statement(&mut self) -> Stmt {
self.match_kind(&[TokenKind::Semicolon]); // 分号可选
Stmt::Continue
}
fn return_statement(&mut self) -> Stmt { fn return_statement(&mut self) -> Stmt {
let value = if !self.check(&TokenKind::Semicolon) && !self.check(&TokenKind::RightBrace) { let value = if !self.check(&TokenKind::Semicolon) && !self.check(&TokenKind::RightBrace) {
Some(self.expression()) Some(self.expression())