diff --git a/crates/oxide_compiler/src/counter.rs b/crates/oxide_compiler/src/counter.rs index 863229cd..13e0533e 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 43345955..f27a1f0e 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 96e7909d..1ccd93b1 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 {