From d49ab9e405a4c925ad284a3dcc697e54ae852904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Sat, 6 Jun 2026 14:45:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20for-var=20?= =?UTF-8?q?=E8=AF=AD=E6=B3=95=E6=94=AF=E6=8C=81=E5=B9=B6=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=A3=B0=E6=98=8E=E8=AF=AD=E5=8F=A5=E8=AE=A1?= =?UTF-8?q?=E6=95=B0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_compiler/src/counter.rs | 16 ++++++++++++++-- crates/oxide_compiler/src/emitter.rs | 22 +++++++++++++++++----- crates/oxide_compiler/src/hash.rs | 11 ++++++++--- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/crates/oxide_compiler/src/counter.rs b/crates/oxide_compiler/src/counter.rs index 863229c..13e0533 100644 --- a/crates/oxide_compiler/src/counter.rs +++ b/crates/oxide_compiler/src/counter.rs @@ -1,4 +1,4 @@ -use oxide_parser::{Expression, Statement}; +use oxide_parser::{Expression, ForStatementInit, Statement}; use crate::compiler::{is_side_effect_free, CompileCtx, Compiler, Label}; @@ -13,8 +13,10 @@ impl Compiler { ctx.alloc_reg(); if let Some(init) = &d.init { self.count_expression(init, ctx); + ctx.projected_pc += 1; // STORE_VAR + } else { + ctx.projected_pc += 2; // LOAD_CONST(undefined) + STORE_VAR } - ctx.projected_pc += 1; // STORE_VAR } } Statement::ReturnStatement(ret) => { @@ -64,6 +66,16 @@ impl Compiler { if let Some(init) = &fr.init { if let Some(expr) = init.as_expression() { self.count_expression(expr, ctx); + } else if let ForStatementInit::VariableDeclaration(decl) = init { + for d in &decl.declarations { + ctx.alloc_reg(); + if let Some(init_expr) = &d.init { + self.count_expression(init_expr, ctx); + ctx.projected_pc += 1; // STORE_VAR + } else { + ctx.projected_pc += 2; // LOAD_CONST(undefined) + STORE_VAR + } + } } } ctx.label_map.insert(start_label, ctx.projected_pc); diff --git a/crates/oxide_compiler/src/emitter.rs b/crates/oxide_compiler/src/emitter.rs index 4334595..f27a1f0 100644 --- a/crates/oxide_compiler/src/emitter.rs +++ b/crates/oxide_compiler/src/emitter.rs @@ -1,6 +1,6 @@ use crate::compiler::Label; use crate::opcode::{self, OpCode}; -use oxide_parser::{AssignmentOperator, Expression, Statement, UnaryOperator}; +use oxide_parser::{AssignmentOperator, Expression, ForStatementInit, Statement, UnaryOperator}; use crate::compiler::{is_int_literal, is_side_effect_free, BinaryOperator, CompileCtx, Compiler}; use crate::module::Constant; @@ -150,10 +150,22 @@ impl Compiler { if let Some(init) = &fr.init { if let Some(expr) = init.as_expression() { self.emit_expression(expr, ctx)?; - } else if init.is_var_declaration() { - return Err( - "for-loop `let` init not yet supported; use expression init".into() - ); + } else if let ForStatementInit::VariableDeclaration(decl) = init { + for d in &decl.declarations { + let name = match &d.id { + oxide_parser::BindingPattern::BindingIdentifier(bi) => { + bi.name.as_str() + } + _ => return Err("destructuring not supported".into()), + }; + let var_reg = ctx.alloc_reg(); + ctx.declare(name, var_reg)?; + if let Some(init_expr) = &d.init { + let val_reg = self.emit_expression(init_expr, ctx)?; + ctx.emit(opcode::encode(OpCode::STORE_VAR, var_reg, val_reg, 0)); + ctx.init_var(name); + } + } } } diff --git a/crates/oxide_compiler/src/hash.rs b/crates/oxide_compiler/src/hash.rs index 96e7909..1ccd93b 100644 --- a/crates/oxide_compiler/src/hash.rs +++ b/crates/oxide_compiler/src/hash.rs @@ -1,4 +1,4 @@ -use oxide_parser::{Expression, Statement}; +use oxide_parser::{Expression, ForStatementInit, Statement}; pub fn structural_hash(program: &oxide_parser::Program) -> u64 { use std::hash::Hasher; @@ -53,8 +53,13 @@ fn hash_statement(stmt: &Statement, h: &mut rustc_hash::FxHasher) { if let Some(init) = &fr.init { if let Some(expr) = init.as_expression() { hash_expression(expr, h); - } else if init.is_var_declaration() { - 0u8.hash(h); + } else if let ForStatementInit::VariableDeclaration(decl) = init { + (decl.declarations.len() as u32).hash(h); + for d in &decl.declarations { + if let Some(init_expr) = &d.init { + hash_expression(init_expr, h); + } + } } } if let Some(test) = &fr.test {