feat: 添加for-in循环支持,更新解析器、解释器和相关测试用例
This commit is contained in:
@@ -134,6 +134,20 @@ impl Parser {
|
||||
|
||||
fn for_statement(&mut self) -> Result<Stmt, RuntimeError> {
|
||||
self.consume(TokenKind::LeftParen, "Expected '(' after 'for'.")?;
|
||||
|
||||
// Detect for-in: for (Identifier in expr) body
|
||||
if let TokenKind::Identifier(var_name) = &self.peek().kind {
|
||||
let var_name = var_name.clone();
|
||||
if matches!(self.peek_next().kind, TokenKind::In) {
|
||||
self.advance(); // consume identifier
|
||||
self.advance(); // consume 'in'
|
||||
let iterable = self.expression()?;
|
||||
self.consume(TokenKind::RightParen, "Expected ')' after for-in expression.")?;
|
||||
let body = Box::new(self.statement()?);
|
||||
return Ok(Stmt::ForIn { var_name, iterable, body });
|
||||
}
|
||||
}
|
||||
|
||||
let initializer = if self.match_kind(&[TokenKind::Semicolon]) {
|
||||
None
|
||||
} else if self.match_kind(&[TokenKind::Let]) {
|
||||
@@ -534,6 +548,10 @@ impl Parser {
|
||||
&self.tokens[self.current]
|
||||
}
|
||||
|
||||
fn peek_next(&self) -> &Token {
|
||||
&self.tokens[self.current + 1]
|
||||
}
|
||||
|
||||
fn previous(&self) -> &Token {
|
||||
&self.tokens[self.current - 1]
|
||||
}
|
||||
@@ -1257,6 +1275,48 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_in_array() {
|
||||
match parse_stmt("for (x in arr) { print(x); }") {
|
||||
Stmt::ForIn { var_name, iterable, body } => {
|
||||
assert_eq!(var_name, "x");
|
||||
assert!(matches!(iterable, Expr::Variable(_)));
|
||||
assert!(matches!(*body, Stmt::Block(_)));
|
||||
}
|
||||
e => panic!("Expected ForIn, got {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_in_with_object_literal() {
|
||||
match parse_stmt("for (k in {a:1,b:2}) { print(k); }") {
|
||||
Stmt::ForIn { var_name, iterable, .. } => {
|
||||
assert_eq!(var_name, "k");
|
||||
assert!(matches!(iterable, Expr::ObjectLiteral { .. }));
|
||||
}
|
||||
e => panic!("Expected ForIn, got {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_in_with_expression() {
|
||||
match parse_stmt("for (v in get_list()) { }") {
|
||||
Stmt::ForIn { var_name, .. } => {
|
||||
assert_eq!(var_name, "v");
|
||||
}
|
||||
e => panic!("Expected ForIn, got {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_for_in_distinct_from_c_style() {
|
||||
// "for (x = 0; ...)" is C-style for, not for-in
|
||||
match parse_stmt("for (x = 0; x < 10; x = x + 1) { }") {
|
||||
Stmt::For { .. } => {}
|
||||
e => panic!("Expected C-style For, got {:?}", e),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_block() {
|
||||
match parse_stmt("{ let x = 1; x; }") {
|
||||
|
||||
Reference in New Issue
Block a user