diff --git a/crates/oxide_compiler/src/class/emit.rs b/crates/oxide_compiler/src/class/emit.rs index 1958812a..5b918f6d 100644 --- a/crates/oxide_compiler/src/class/emit.rs +++ b/crates/oxide_compiler/src/class/emit.rs @@ -156,8 +156,7 @@ impl Compiler { self.emit_class_prototype(ctor_reg, proto_reg, super_reg, ctx.sub_modules.len() as u32, ctx)?; self.emit_class_methods(&class.body.body, ctor_reg, proto_reg, &self_binding, ctx)?; - self.emit_class_static_fields(&class.body.body, ctor_reg, ctx)?; - self.emit_class_static_blocks(&class.body.body, ctor_reg, ctx)?; + self.emit_class_static_elements(&class.body.body, ctor_reg, ctx)?; ctx.scopes.private_name_map = saved_private_names; Ok(ctor_reg) diff --git a/crates/oxide_compiler/src/class/field.rs b/crates/oxide_compiler/src/class/field.rs index 26e30978..ad0715b3 100644 --- a/crates/oxide_compiler/src/class/field.rs +++ b/crates/oxide_compiler/src/class/field.rs @@ -2,24 +2,38 @@ use crate::compiler::{CompileCtx, Compiler}; use oxide_parser::{ClassElement, PropertyKey}; impl Compiler { - pub(crate) fn emit_class_static_fields( + /// Emit static field initializers and static blocks in source order. + /// JS class semantics interleave them (e.g. `static x = 1; static { + /// this.y = 1 } static z = this.y + 1` must run in that order). Emitting + /// all fields before all blocks would make `z` read `y` before it is set. + pub(crate) fn emit_class_static_elements( &self, elements: &[ClassElement], ctor_reg: u8, ctx: &mut CompileCtx, ) -> Result<(), String> { + let saved_static_this = ctx.static_block_this_reg; + ctx.static_block_this_reg = Some(ctor_reg); for element in elements { - if let ClassElement::PropertyDefinition(prop) = element { - let prop = prop.as_ref(); - if prop.r#static { - let saved_static_this = ctx.static_block_this_reg; - ctx.static_block_this_reg = Some(ctor_reg); - if let PropertyKey::PrivateIdentifier(private) = &prop.key { - self.emit_private_field_init(ctor_reg, private.name.as_str(), prop.value.as_ref(), ctx)?; - } else { - self.emit_public_field_init(ctor_reg, &prop.key, prop.computed, prop.value.as_ref(), ctx)?; + match element { + ClassElement::PropertyDefinition(prop) => { + let prop = prop.as_ref(); + if prop.r#static { + if let PropertyKey::PrivateIdentifier(private) = &prop.key { + self.emit_private_field_init(ctor_reg, private.name.as_str(), prop.value.as_ref(), ctx)?; + } else { + self.emit_public_field_init(ctor_reg, &prop.key, prop.computed, prop.value.as_ref(), ctx)?; + } } - ctx.static_block_this_reg = saved_static_this; } + ClassElement::StaticBlock(block) => { + ctx.push_scope(); + for stmt in &block.body { + self.emit_statement(stmt, ctx)?; + } + ctx.pop_scope(); + } + _ => {} } } + ctx.static_block_this_reg = saved_static_this; Ok(()) } } diff --git a/crates/oxide_compiler/src/class/mod.rs b/crates/oxide_compiler/src/class/mod.rs index e418e299..51027cee 100644 --- a/crates/oxide_compiler/src/class/mod.rs +++ b/crates/oxide_compiler/src/class/mod.rs @@ -4,4 +4,3 @@ pub mod field; pub mod header; pub mod method; pub mod prototype; -pub mod static_block; diff --git a/crates/oxide_compiler/src/class/static_block.rs b/crates/oxide_compiler/src/class/static_block.rs deleted file mode 100644 index ffe79f79..00000000 --- a/crates/oxide_compiler/src/class/static_block.rs +++ /dev/null @@ -1,22 +0,0 @@ -use crate::compiler::{CompileCtx, Compiler}; -use oxide_parser::ClassElement; - -impl Compiler { - pub(crate) fn emit_class_static_blocks( - &self, elements: &[ClassElement], ctor_reg: u8, ctx: &mut CompileCtx, - ) -> Result<(), String> { - for element in elements { - if let ClassElement::StaticBlock(block) = element { - let saved_static_this = ctx.static_block_this_reg; - ctx.static_block_this_reg = Some(ctor_reg); - ctx.push_scope(); - for stmt in &block.body { - self.emit_statement(stmt, ctx)?; - } - ctx.pop_scope(); - ctx.static_block_this_reg = saved_static_this; - } - } - Ok(()) - } -}