feat: class 私有成员语义(字段/方法/访问器 + brand 检查 + 契约修复)

This commit is contained in:
爱特每羊队
2026-08-09 11:08:36 +08:00
parent e1f0d578fa
commit 915dedb151
41 changed files with 573 additions and 216 deletions
+6 -3
View File
@@ -207,12 +207,15 @@ impl Emitter {
}
let obj_reg = self.emit_expression(&member.object, ctx)?;
let val_reg = self.emit_expression(&assign.right, ctx)?;
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
ctx.inst(Inst::new(
OpCode::SET_PRIVATE,
let name = member.field.name.as_str();
let (brand_reg, brand_id) = self.private_access_brand(obj_reg, name, ctx)?;
let key_reg = self.emit_private_id_reg(name, ctx)?;
ctx.inst(Inst::set_private(
Operand::Reg(obj_reg),
Operand::Reg(val_reg),
Operand::Reg(key_reg),
brand_reg,
brand_id,
));
Ok(val_reg)
} else if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(id_ref) = &assign.left {
+6 -3
View File
@@ -39,13 +39,16 @@ impl Emitter {
let (callee_reg, this_reg) = match &call.callee {
Expression::PrivateFieldExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let name = member.field.name.as_str();
let (brand_reg, brand_id) = self.private_access_brand(obj_reg, name, ctx)?;
let key_reg = self.emit_private_id_reg(name, ctx)?;
let callee_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
ctx.inst(Inst::get_private(
Operand::Reg(callee_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
brand_reg,
brand_id,
));
(callee_reg, obj_reg)
}
+3 -18
View File
@@ -54,12 +54,7 @@ impl Emitter {
ctx.inst(Inst::load_const(Operand::Reg(key_reg), key_idx));
let has_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::IN,
Operand::Reg(has_reg),
Operand::Reg(key_reg),
Operand::Reg(obj_reg),
));
ctx.inst(Inst::new(OpCode::IN, Operand::Reg(has_reg), Operand::Reg(key_reg), Operand::Reg(obj_reg)));
let fallback_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
@@ -101,12 +96,7 @@ impl Emitter {
));
}
} else if let Some(reg) = ctx.scopes.symbols.lookup_any(name) {
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(reg),
Operand::None,
));
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::Reg(reg), Operand::None));
} else {
let undef_idx = ctx.add_constant(Constant::Undefined);
ctx.inst(Inst::load_const(Operand::Reg(result_reg), undef_idx));
@@ -164,12 +154,7 @@ impl Emitter {
ctx.inst(Inst::load_const(Operand::Reg(key_reg), key_idx));
let has_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::IN,
Operand::Reg(has_reg),
Operand::Reg(key_reg),
Operand::Reg(obj_reg),
));
ctx.inst(Inst::new(OpCode::IN, Operand::Reg(has_reg), Operand::Reg(key_reg), Operand::Reg(obj_reg)));
let fallback_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
+1 -5
View File
@@ -70,9 +70,7 @@ impl Emitter {
// 非法正则字面量须在编译期报 SyntaxError(负面测试期望编译失败)。
// 用 regress(ECMAScript 语法)校验,避免误报 backreference/lookaround 等合法模式。
if regress::Regex::with_flags(&pattern, flags.as_str()).is_err() {
return Err(format!(
"SyntaxError: Invalid regular expression: /{pattern}/{flags}"
));
return Err(format!("SyntaxError: Invalid regular expression: /{pattern}/{flags}"));
}
let pat_ci = ctx.add_constant(Constant::String(pattern));
let pat_reg = ctx.alloc_reg();
@@ -96,5 +94,3 @@ impl Emitter {
}
}
}
+6 -3
View File
@@ -60,13 +60,16 @@ impl Emitter {
&self, member: &oxide_parser::PrivateFieldExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_private_id_reg(member.field.name.as_str(), ctx)?;
let name = member.field.name.as_str();
let (brand_reg, brand_id) = self.private_access_brand(obj_reg, name, ctx)?;
let key_reg = self.emit_private_id_reg(name, ctx)?;
let r = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::GET_PRIVATE,
ctx.inst(Inst::get_private(
Operand::Reg(r),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
brand_reg,
brand_id,
));
Ok(r)
}
+1 -6
View File
@@ -343,12 +343,7 @@ impl Emitter {
} else {
OpCode::SUB
};
ctx.inst(Inst::new(
op,
Operand::Reg(new_reg),
Operand::Reg(old_reg),
Operand::Reg(one_reg),
));
ctx.inst(Inst::new(op, Operand::Reg(new_reg), Operand::Reg(old_reg), Operand::Reg(one_reg)));
ctx.inst(Inst::new(
OpCode::SET_PROP_DYNAMIC,
Operand::Reg(obj_reg),