fix: 逐个按顺序处理 field 与 block 以符合 JS 类元素源码顺序语义

This commit is contained in:
2026-08-05 15:04:44 +08:00
parent 94576d60c5
commit dce335e766
4 changed files with 26 additions and 36 deletions
+1 -2
View File
@@ -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_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_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_elements(&class.body.body, ctor_reg, ctx)?;
self.emit_class_static_blocks(&class.body.body, ctor_reg, ctx)?;
ctx.scopes.private_name_map = saved_private_names; ctx.scopes.private_name_map = saved_private_names;
Ok(ctor_reg) Ok(ctor_reg)
+25 -11
View File
@@ -2,24 +2,38 @@ use crate::compiler::{CompileCtx, Compiler};
use oxide_parser::{ClassElement, PropertyKey}; use oxide_parser::{ClassElement, PropertyKey};
impl Compiler { 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, &self, elements: &[ClassElement], ctor_reg: u8, ctx: &mut CompileCtx,
) -> Result<(), String> { ) -> Result<(), String> {
let saved_static_this = ctx.static_block_this_reg;
ctx.static_block_this_reg = Some(ctor_reg);
for element in elements { for element in elements {
if let ClassElement::PropertyDefinition(prop) = element { match element {
let prop = prop.as_ref(); ClassElement::PropertyDefinition(prop) => {
if prop.r#static { let prop = prop.as_ref();
let saved_static_this = ctx.static_block_this_reg; if prop.r#static {
ctx.static_block_this_reg = Some(ctor_reg); if let PropertyKey::PrivateIdentifier(private) = &prop.key {
if let PropertyKey::PrivateIdentifier(private) = &prop.key { self.emit_private_field_init(ctor_reg, private.name.as_str(), prop.value.as_ref(), ctx)?;
self.emit_private_field_init(ctor_reg, private.name.as_str(), prop.value.as_ref(), ctx)?; } else {
} else { self.emit_public_field_init(ctor_reg, &prop.key, prop.computed, prop.value.as_ref(), ctx)?;
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(()) Ok(())
} }
} }
-1
View File
@@ -4,4 +4,3 @@ pub mod field;
pub mod header; pub mod header;
pub mod method; pub mod method;
pub mod prototype; pub mod prototype;
pub mod static_block;
@@ -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(())
}
}