Files
OxideJS-New/crates/oxide_emit/src/expr/operator/mod.rs
T

749 lines
38 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 运算符域:二元/一元/条件/逻辑/更新/`in` 表达式 emit 与分发。
//! 逻辑与 `??` 用短路跳转,复合求值利用 `is_side_effect_free` 优化。
//! 函数:`emit_operator` 及各类 `emit_*_expression`。
use crate::{is_side_effect_free, BinaryOperator, CompileCtx, Emitter};
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
use oxide_ir::inst::Inst;
use oxide_ir::operand::Operand;
use oxide_parser::{ChainElement, Expression, LogicalOperator, SimpleAssignmentTarget, UnaryOperator, UpdateOperator};
impl Emitter {
fn emit_private_in_expression(
&self, pin: &oxide_parser::PrivateInExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let obj_reg = self.emit_expression(&pin.right, ctx)?;
let key_reg = self.emit_private_id_reg(pin.left.name.as_str(), ctx)?;
let (brand_reg, brand_id) = self.private_access_brand(obj_reg, pin.left.name.as_str(), ctx)?;
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::private_brand_in(
Operand::Reg(result_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
brand_reg,
brand_id,
));
Ok(result_reg)
}
fn emit_binary_expression(
&self, bin: &oxide_parser::BinaryExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
// Addition 左结合链摊平:≥3 操作数合并为单条 CONCAT_N(单趟预分配拼接,
// 消除 N-2 次中间串分配)。只下钻 left 链、right 括号不拆(a+(b+c) 退化 ADD),
// 保 f64 结合性与源码求值序。
if bin.operator == BinaryOperator::Addition {
let mut operands = Vec::new();
collect_add_operands(&bin.left, &mut operands);
operands.push(&bin.right);
// 上限防寄存器压力:CONCAT_N 单点读全部操作数(须同时存活),超长链回退
// 左结合 ADD(寄存器随链复用,纯表达式寄存器占用有界)。
if operands.len() >= 3 && operands.len() <= MAX_CONCAT_N_OPERANDS {
let mut regs = Vec::with_capacity(operands.len());
for op in &operands {
regs.push(self.emit_expression(op, ctx)?);
}
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::concat_n(Operand::Reg(result_reg), &regs));
return Ok(result_reg);
}
}
let left = self.emit_expression(&bin.left, ctx)?;
let right = self.emit_expression(&bin.right, ctx)?;
let op = match bin.operator {
BinaryOperator::Addition => OpCode::ADD,
BinaryOperator::Subtraction => OpCode::SUB,
BinaryOperator::Multiplication => OpCode::MUL,
BinaryOperator::Division => OpCode::DIV,
BinaryOperator::Remainder => OpCode::MOD,
BinaryOperator::Exponential => OpCode::EXP,
BinaryOperator::BitwiseAnd => OpCode::BIT_AND,
BinaryOperator::BitwiseOR => OpCode::BIT_OR,
BinaryOperator::BitwiseXOR => OpCode::BIT_XOR,
BinaryOperator::ShiftLeft => OpCode::SHL,
BinaryOperator::ShiftRight => OpCode::SHR,
BinaryOperator::ShiftRightZeroFill => OpCode::USHR,
BinaryOperator::Equality => OpCode::EQ,
BinaryOperator::Inequality => OpCode::NEQ,
BinaryOperator::LessThan => OpCode::LT,
BinaryOperator::GreaterThan => OpCode::GT,
BinaryOperator::LessEqualThan => OpCode::LTE,
BinaryOperator::GreaterEqualThan => OpCode::GTE,
BinaryOperator::In => OpCode::IN,
BinaryOperator::Instanceof => OpCode::INSTANCEOF,
BinaryOperator::StrictEquality => OpCode::STRICT_EQ,
BinaryOperator::StrictInequality => OpCode::STRICT_NEQ,
};
ctx.inst(Inst::new(op, Operand::Reg(left), Operand::Reg(left), Operand::Reg(right)));
Ok(left)
}
fn emit_unary_expression(&self, un: &oxide_parser::UnaryExpression, ctx: &mut CompileCtx) -> Result<u32, String> {
if matches!(un.operator, UnaryOperator::Delete) {
// 括号的引用性透传内层操作数:先逐层剥括号,再按内层形态分派。
let mut operand = &un.argument;
while let Expression::ParenthesizedExpression(paren) = operand {
operand = &paren.expression;
}
return self.emit_delete_operand(operand, ctx);
}
let arg = if matches!(un.operator, UnaryOperator::Typeof) {
self.emit_typeof_operand(&un.argument, ctx)?
} else {
self.emit_expression(&un.argument, ctx)?
};
match un.operator {
UnaryOperator::UnaryNegation => {
ctx.inst(Inst::new(OpCode::NEG, Operand::Reg(arg), Operand::Reg(arg), Operand::None));
Ok(arg)
}
UnaryOperator::Typeof => {
ctx.inst(Inst::new(OpCode::TYPEOF, Operand::Reg(arg), Operand::Reg(arg), Operand::None));
Ok(arg)
}
UnaryOperator::Void => {
ctx.inst(Inst::new(OpCode::VOID, Operand::Reg(arg), Operand::Reg(arg), Operand::None));
Ok(arg)
}
UnaryOperator::LogicalNot => {
ctx.inst(Inst::new(OpCode::NOT, Operand::Reg(arg), Operand::Reg(arg), Operand::None));
Ok(arg)
}
UnaryOperator::BitwiseNot => {
ctx.inst(Inst::new(OpCode::BIT_NOT, Operand::Reg(arg), Operand::Reg(arg), Operand::None));
Ok(arg)
}
UnaryOperator::UnaryPlus => {
ctx.inst(Inst::new(OpCode::UNARY_PLUS, Operand::Reg(arg), Operand::Reg(arg), Operand::None));
Ok(arg)
}
UnaryOperator::Delete => Err("invalid delete target".into()),
}
}
/// delete 操作数求值:引用形态(标识符/静态成员/计算成员/链式)按引用语义
/// 删除并返回删除结果;非引用操作数返回 true。
///
/// # 步骤
/// 1. 标识符:with 体动态解析、可删全局内置镜像槽先行;未声明名(含隐式
/// 全局槽,引用不可解析或全局属性可配置)返回 true;其余已声明绑定
/// (var/let/函数名/参数,非可配置或属性引用)返回 false。严格模式的
/// delete 标识符是早期错误,由语义分析阶段拦截,不在此出现。
/// 2. 静态/计算成员与链式成员:从对象真删属性,结果为删除返回值。
/// 3. 其余形态(字面量/调用/new/this/一元形/序列/嵌套 delete 等):先求值
/// 操作数(副作用与操作数求值期错误不被吞),再发常量 true。
fn emit_delete_operand(&self, operand: &Expression, ctx: &mut CompileCtx) -> Result<u32, String> {
match operand {
Expression::Identifier(ident) => {
let name = ident.name.as_str();
// with 体内自由标识符:对象有该属性则删除对象属性(返回删除结果),
// 否则非严格语义返回 true。
if !ctx.with_stack.is_empty() && !ctx.is_with_internal_binding(name) {
let obj_reg = ctx.innermost_with_obj().expect("with stack non-empty");
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
let key_reg = ctx.alloc_reg();
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),
));
let fallback_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
ctx.inst(Inst::jmp_if_false(has_reg, fallback_label));
// 复制 obj 到临时寄存器执行删除:DELETE_PROP_DYNAMIC 把结果写回
// rd 槽,直接用它会把 with 对象寄存器覆盖为布尔值。
let tmp_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(obj_reg), Operand::None));
ctx.inst(Inst::new(
OpCode::DELETE_PROP_DYNAMIC,
Operand::Reg(tmp_reg),
Operand::Reg(tmp_reg),
Operand::Reg(key_reg),
));
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(tmp_reg),
Operand::None,
));
ctx.inst(Inst::jmp(end_label));
ctx.labels.set_label_pos(fallback_label, ctx.insts.len());
let true_idx = ctx.add_constant(Constant::Boolean(true));
ctx.inst(Inst::load_const(Operand::Reg(result_reg), true_idx));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
return Ok(result_reg);
}
// 可删全局内置(可写全局名除宿主名 $262):运行期真删
// 全局对象属性(c:true 数据描述符)并返 true;删除成功时清镜像
// 槽,裸读与 globalThis 反射不失步。
if let Some(slot_reg) = ctx.global_builtin_delete_slot(name) {
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
let reg = ctx.alloc_reg();
ctx.inst(Inst::delete_global_prop_c(Operand::Reg(reg), Operand::Reg(slot_reg), key_idx));
return Ok(reg);
}
// 已声明绑定(upvalue/捕获 cell/局部 var/let/函数名/参数/顶层 var)
// 是非属性引用或全局对象上不可配置绑定,返回 false;未声明名
// (引用不可解析)与隐式全局槽(全局属性可配置)返回 true。
// 严格模式的 delete 标识符由语义分析提前拦截为早期错误。
let declared = ctx.captured_bindings.contains_key(name)
|| ctx.current_upvalue_captures.iter().any(|u| u.name == name)
|| match ctx.lookup(name) {
Err(_) => false,
Ok(reg) => !ctx.is_implicit_global_reg(reg),
};
let idx = ctx.add_constant(Constant::Boolean(!declared));
let reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(reg), idx));
Ok(reg)
}
Expression::StaticMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let prop_name = member.property.name.as_str();
let const_idx = ctx.add_constant(Constant::String(prop_name.to_string()));
ctx.inst(Inst::delete_prop_static(Operand::Reg(obj_reg), const_idx as u32));
Ok(obj_reg)
}
Expression::ComputedMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let key_reg = self.emit_expression(&member.expression, ctx)?;
ctx.inst(Inst::new(
OpCode::DELETE_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
Ok(obj_reg)
}
Expression::ChainExpression(chain) => {
let short_label = ctx.next_label_id();
let result_reg = match &chain.expression {
ChainElement::StaticMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
if member.optional {
let dup_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(dup_reg),
Operand::Reg(obj_reg),
Operand::None,
));
ctx.inst(Inst::jmp_if_nullish(dup_reg, short_label));
}
let prop_name = member.property.name.as_str();
let const_idx = ctx.add_constant(Constant::String(prop_name.to_string()));
ctx.inst(Inst::delete_prop_static(Operand::Reg(obj_reg), const_idx as u32));
obj_reg
}
ChainElement::ComputedMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
if member.optional {
let dup_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(dup_reg),
Operand::Reg(obj_reg),
Operand::None,
));
ctx.inst(Inst::jmp_if_nullish(dup_reg, short_label));
}
let key_reg = self.emit_expression(&member.expression, ctx)?;
ctx.inst(Inst::new(
OpCode::DELETE_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
));
obj_reg
}
_ => return Err("invalid delete target".into()),
};
let end_label = ctx.next_label_id();
ctx.inst(Inst::jmp(end_label));
ctx.labels.set_label_pos(short_label, ctx.insts.len());
let true_idx = ctx.add_constant(Constant::Boolean(true));
ctx.inst(Inst::load_const(Operand::Reg(result_reg), true_idx));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
Ok(result_reg)
}
_ => {
// 非引用操作数恒 true,但操作数本身须先求值:副作用与操作数
// 求值期错误(如未声明基引用)不被吞。
let _ = self.emit_expression(operand, ctx)?;
let idx = ctx.add_constant(Constant::Boolean(true));
let reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(reg), idx));
Ok(reg)
}
}
}
/// typeof 操作数求值:未声明标识符特判为 "undefined"。
///
/// # 步骤
/// 1. 剥括号后若为标识符且不在任何作用域/闭包捕获中、非 with 动态解析,
/// 发射 LOAD_GLOBAL_TYPEOF:运行期查 global object 属性,命中取真实值
/// (含不在 BUILTIN_GLOBALS 名单的真实全局,如 Temporal),缺失求值
/// undefined(IsUnresolvableReference 语义)。
/// 2. 其余(TDZ 绑定、已声明、with 内)走正常求值:TDZ 抛 ReferenceError、
/// with 动态回退未定义、已声明读真实值。
///
/// # 边界与前提
/// - 未声明标识符不能走 LOAD_GLOBAL(读未声明抛 ReferenceError),故必须在此特判;
/// - `typeof x; var x;` / `typeof x; let x;` 分别由 var 预声明(已初始化→undefined)
/// 与 TDZ 占位(未初始化→抛)覆盖,不落本分支。
fn emit_typeof_operand(&self, argument: &Expression, ctx: &mut CompileCtx) -> Result<u32, String> {
let mut arg_expr = argument;
while let Expression::ParenthesizedExpression(p) = arg_expr {
arg_expr = &p.expression;
}
if let Expression::Identifier(ident) = arg_expr {
let name = ident.name.as_str();
let in_with_dynamic = !ctx.with_stack.is_empty() && !ctx.is_with_internal_binding(name);
let captured =
ctx.current_upvalue_captures.iter().any(|u| u.name == name) || ctx.captured_bindings.contains_key(name);
// 顶层已声明 var:typeof 读全局对象属性(A 侧单一真值),缺失 → "undefined"
// (非抛,IsUnresolvableReference 语义)。未声明名同走此路(lookup 未命中)。
let is_tier = self.is_global_tier_name(ctx, name);
if !in_with_dynamic && !captured && (is_tier || ctx.scopes.symbols.lookup_any_binding(name).is_none()) {
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
let r = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_GLOBAL_TYPEOF,
Operand::Reg(r),
Operand::Const(key_idx),
Operand::None,
));
return Ok(r);
}
}
self.emit_expression(argument, ctx)
}
fn emit_conditional_expression(
&self, cond: &oxide_parser::ConditionalExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let else_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
let test_reg = self.emit_expression(&cond.test, ctx)?;
ctx.inst(Inst::jmp_if_false(test_reg, else_label));
let cons_reg = self.emit_expression(&cond.consequent, ctx)?;
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(cons_reg),
Operand::None,
));
ctx.inst(Inst::jmp(end_label));
ctx.labels.set_label_pos(else_label, ctx.insts.len());
let alt_reg = self.emit_expression(&cond.alternate, ctx)?;
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(alt_reg),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
Ok(result_reg)
}
fn emit_logical_expression(
&self, log: &oxide_parser::LogicalExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
let left_reg = self.emit_expression(&log.left, ctx)?;
if is_side_effect_free(&log.left) && is_side_effect_free(&log.right) {
let right_reg = self.emit_expression(&log.right, ctx)?;
let r = ctx.alloc_reg();
let op = match log.operator {
LogicalOperator::And => OpCode::AND,
LogicalOperator::Or => OpCode::OR,
LogicalOperator::Coalesce => OpCode::NULLISH,
};
ctx.inst(Inst::new(op, Operand::Reg(r), Operand::Reg(left_reg), Operand::Reg(right_reg)));
return Ok(r);
}
if matches!(log.operator, LogicalOperator::Coalesce) {
let rhs_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
let dup_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(left_reg), Operand::None));
ctx.inst(Inst::jmp_if_nullish(dup_reg, rhs_label));
ctx.inst(Inst::jmp(end_label));
ctx.labels.set_label_pos(rhs_label, ctx.insts.len());
let right_reg = self.emit_expression(&log.right, ctx)?;
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(right_reg), Operand::None));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
return Ok(dup_reg);
}
let skip_label = match log.operator {
LogicalOperator::And => ctx.next_label_id(),
LogicalOperator::Or => ctx.next_label_id(),
LogicalOperator::Coalesce => return Err("invalid logical operator dispatch".into()),
};
let dup_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(left_reg), Operand::None));
match log.operator {
LogicalOperator::And => ctx.inst(Inst::jmp_if_false(dup_reg, skip_label)),
LogicalOperator::Or => ctx.inst(Inst::jmp_if_true(dup_reg, skip_label)),
LogicalOperator::Coalesce => return Err("invalid logical operator dispatch".into()),
}
let right_reg = self.emit_expression(&log.right, ctx)?;
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(dup_reg), Operand::Reg(right_reg), Operand::None));
ctx.labels.set_label_pos(skip_label, ctx.insts.len());
Ok(dup_reg)
}
fn emit_update_expression(
&self, update: &oxide_parser::UpdateExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
match &update.argument {
SimpleAssignmentTarget::AssignmentTargetIdentifier(id) => {
let name = id.name.as_str();
// with 体内自由标识符的自增/自减:对象有属性则读写对象,否则回退外层。
if !ctx.with_stack.is_empty() && !ctx.is_with_internal_binding(name) {
let obj_reg = ctx.innermost_with_obj().expect("with stack non-empty");
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
let key_reg = ctx.alloc_reg();
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),
));
let fallback_label = ctx.next_label_id();
let end_label = ctx.next_label_id();
ctx.inst(Inst::jmp_if_false(has_reg, fallback_label));
// 对象有该属性:读属性 → 增减 → 写回对象。
let old_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::GET_PROP_DYNAMIC,
Operand::Reg(obj_reg),
Operand::Reg(key_reg),
Operand::Reg(old_reg),
));
let new_reg = ctx.alloc_reg();
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
let op = if update.operator == UpdateOperator::Increment {
OpCode::ADD
} else {
OpCode::SUB
};
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),
Operand::Reg(key_reg),
Operand::Reg(new_reg),
));
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(if update.prefix { new_reg } else { old_reg }),
Operand::None,
));
ctx.inst(Inst::jmp(end_label));
// 对象无该属性:回退静态自增/自减,结果写入同一 result_reg。
ctx.labels.set_label_pos(fallback_label, ctx.insts.len());
let static_result = self.emit_identifier_update_static(name, update, ctx)?;
ctx.inst(Inst::new(
OpCode::LOAD_VAR,
Operand::Reg(result_reg),
Operand::Reg(static_result),
Operand::None,
));
ctx.labels.set_label_pos(end_label, ctx.insts.len());
return Ok(result_reg);
}
// 判断目标是 upvalue 还是被捕获 cell
self.emit_identifier_update_static(name, update, ctx)
}
SimpleAssignmentTarget::StaticMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
let prop_name = member.property.name.as_str();
let key_idx = ctx.add_constant(Constant::String(prop_name.to_string()));
let key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(key_reg), key_idx));
let val_reg = ctx.alloc_reg();
let op = match update.operator {
UpdateOperator::Increment => OpCode::MEMBER_INC,
UpdateOperator::Decrement => OpCode::MEMBER_DEC,
};
match op {
OpCode::MEMBER_INC => {
ctx.inst(Inst::member_inc(Operand::Reg(obj_reg), Operand::Reg(val_reg), Operand::Reg(key_reg)));
}
OpCode::MEMBER_DEC => {
ctx.inst(Inst::member_dec(Operand::Reg(obj_reg), Operand::Reg(val_reg), Operand::Reg(key_reg)));
}
_ => unreachable!(),
}
Ok(val_reg)
}
SimpleAssignmentTarget::ComputedMemberExpression(member) => {
let obj_reg = self.emit_expression(&member.object, ctx)?;
// 常量字符串键折叠为 IC 静态路径:MEMBER_INC/DEC 携带 IC 扩展字。
if let Some(key) = crate::expr::member::computed_const_key(&member.expression) {
let idx = ctx.add_constant(Constant::String(key));
let key_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(key_reg), idx));
let val_reg = ctx.alloc_reg();
let op = match update.operator {
UpdateOperator::Increment => OpCode::MEMBER_INC,
UpdateOperator::Decrement => OpCode::MEMBER_DEC,
};
match op {
OpCode::MEMBER_INC => {
ctx.inst(Inst::member_inc(
Operand::Reg(obj_reg),
Operand::Reg(val_reg),
Operand::Reg(key_reg),
));
}
OpCode::MEMBER_DEC => {
ctx.inst(Inst::member_dec(
Operand::Reg(obj_reg),
Operand::Reg(val_reg),
Operand::Reg(key_reg),
));
}
_ => unreachable!(),
}
return Ok(val_reg);
}
let key_reg = self.emit_expression(&member.expression, ctx)?;
let val_reg = ctx.alloc_reg();
let op = match update.operator {
UpdateOperator::Increment => OpCode::DYN_MEMBER_INC,
UpdateOperator::Decrement => OpCode::DYN_MEMBER_DEC,
};
ctx.inst(Inst::new(op, Operand::Reg(obj_reg), Operand::Reg(key_reg), Operand::Reg(val_reg)));
Ok(val_reg)
}
_ => Err("member update not yet supported".into()),
}
}
/// 标识符自增/自减的静态路径:upvalue / 被捕获 cell 走显式读-增减-写回,
/// 普通槽用 INC_PRE/POST 或 DEC_PRE/POST。返回结果寄存器。
///
/// # 边界与前提
/// - 不可写全局内置槽:值照算(前缀返回新值、后缀返回旧值)但跳过槽写;
/// strict 抛 TypeError。局部遮蔽绑定不受影响。
fn emit_identifier_update_static(
&self, name: &str, update: &oxide_parser::UpdateExpression, ctx: &mut CompileCtx,
) -> Result<u32, String> {
// 自增/自减先解析赋值引用:TDZ 绑定抛 ReferenceError;const 抛 TypeError(编译期拦截)。
// 循环 update 段的 let/const 循环变量是 per-iteration 可变绑定(CreateMutableBinding),
// 规范允许写,故豁免 const 检查(register_update_names 覆盖全部循环头声明名)。
self.emit_identifier_tdz_guard(name, ctx)?;
if !ctx.register_update_names.iter().any(|n| n == name) {
self.emit_const_write_guard(name, ctx)?;
}
let uv_idx = ctx.current_upvalue_captures.iter().position(|u| u.name == name);
let captured_cell = ctx.captured_bindings.get(name).copied();
// 循环 update 段:被捕获绑定走寄存器 INC/DEC(C 风格 for 每迭代 fresh,
// update 写寄存器供下一迭代 fresh 拷贝,不污染本迭代闭包捕获的 cell)。
if ctx.register_update_names.iter().any(|n| n == name) {
if let Some(reg) = ctx.scopes.symbols.lookup_any(name) {
let op = match (update.operator, update.prefix) {
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
(UpdateOperator::Increment, false) => OpCode::INC_POST,
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
(UpdateOperator::Decrement, false) => OpCode::DEC_POST,
};
if ctx.targets_readonly_builtin(name, reg) {
if ctx.is_strict {
return self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx);
}
// 全局不可写内置:值照算(前缀返回新值、后缀返回旧值),跳过槽写。
let tmp_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(reg), Operand::None));
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(op, Operand::Reg(tmp_reg), Operand::Reg(result_reg), Operand::Reg(result_reg)));
return Ok(result_reg);
}
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(op, Operand::Reg(reg), Operand::Reg(result_reg), Operand::Reg(result_reg)));
// 可写内置名:RMW 新值同步落全局对象属性。
if ctx.targets_writable_builtin(name, reg) {
self.emit_global_put_write(name, reg, ctx);
}
return Ok(result_reg);
}
}
if let Some(uv) = uv_idx {
// upvalue:LOAD_UPVALUE + 常量 1 + ADD/SUB + STORE_UPVALUE;
// 后缀形式返回旧值(前缀返回新值)。
let old_reg = ctx.alloc_reg();
ctx.inst(Inst::new(
OpCode::LOAD_UPVALUE,
Operand::Reg(old_reg),
Operand::Imm(uv as u16),
Operand::None,
));
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
let op = if update.operator == UpdateOperator::Increment {
OpCode::ADD
} else {
OpCode::SUB
};
let new_reg = ctx.alloc_reg();
ctx.inst(Inst::new(op, Operand::Reg(new_reg), Operand::Reg(old_reg), Operand::Reg(one_reg)));
let const_flag = if ctx.lookup_const_flag(name) { 1 } else { 0 };
ctx.inst(Inst::new(
OpCode::STORE_UPVALUE,
Operand::Imm(const_flag),
Operand::Reg(new_reg),
Operand::Imm(uv as u16),
));
Ok(if update.prefix { new_reg } else { old_reg })
} else if let Some(cell_idx) = captured_cell {
// 被捕获 cell:CELL_GET 旧值 + 常量 1 + ADD/SUB + CELL_SET。
// 后缀形式须保留旧值(结果寄存器),前缀返回新值。
let old_reg = ctx.alloc_reg();
if let Some((binding, _)) = ctx.scopes.symbols.lookup_any_binding(name) {
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(old_reg),
Operand::Reg(binding.reg),
Operand::Imm(cell_idx as u16),
));
} else {
ctx.inst(Inst::new(
OpCode::CELL_GET,
Operand::Reg(old_reg),
Operand::None,
Operand::Imm(cell_idx as u16),
));
}
let one_idx = ctx.add_constant(Constant::Int(1));
let one_reg = ctx.alloc_reg();
ctx.inst(Inst::load_const(Operand::Reg(one_reg), one_idx));
let op = if update.operator == UpdateOperator::Increment {
OpCode::ADD
} else {
OpCode::SUB
};
let new_reg = ctx.alloc_reg();
ctx.inst(Inst::new(op, Operand::Reg(new_reg), Operand::Reg(old_reg), Operand::Reg(one_reg)));
ctx.inst(Inst::new(
OpCode::CELL_SET,
Operand::None,
Operand::Reg(new_reg),
Operand::Imm(cell_idx as u16),
));
Ok(if update.prefix { new_reg } else { old_reg })
} else {
let var_reg = ctx.lookup_or_global(name);
if ctx.targets_readonly_builtin(name, var_reg) {
// 全局不可写内置槽:strict 抛 TypeError(put 失败);sloppy 值照算
// (前缀返回新值、后缀返回旧值),跳过槽写。
if ctx.is_strict {
return self.emit_throw_error("TypeError", "cannot assign to read-only property", ctx);
}
let tmp_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(tmp_reg), Operand::Reg(var_reg), Operand::None));
let result_reg = ctx.alloc_reg();
let op = match (update.operator, update.prefix) {
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
(UpdateOperator::Increment, false) => OpCode::INC_POST,
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
(UpdateOperator::Decrement, false) => OpCode::DEC_POST,
};
ctx.inst(Inst::new(op, Operand::Reg(tmp_reg), Operand::Reg(result_reg), Operand::Reg(result_reg)));
return Ok(result_reg);
}
let is_tier = self.is_global_tier_name(ctx, name);
let is_implicit = ctx.is_implicit_global_reg(var_reg);
if is_implicit && ctx.is_strict {
// 严格模式未声明更新写:值无关抛 ReferenceError。
return self.emit_strict_undeclared_write(name, ctx);
}
// RMW 前从全局对象属性取旧值:tier 名(顶层已声明 var)与未声明名同,
// 属性缺失按 undefined(update 旧值角落,GetBaseValue 语义,不抛)。
if is_tier || is_implicit {
let key_idx = ctx.add_constant(Constant::String(name.to_string()));
ctx.inst(Inst::new(
OpCode::LOAD_GLOBAL_TYPEOF,
Operand::Reg(var_reg),
Operand::Const(key_idx),
Operand::None,
));
}
let result_reg = ctx.alloc_reg();
let op = match (update.operator, update.prefix) {
(UpdateOperator::Increment, true) => OpCode::INC_PRE,
(UpdateOperator::Increment, false) => OpCode::INC_POST,
(UpdateOperator::Decrement, true) => OpCode::DEC_PRE,
(UpdateOperator::Decrement, false) => OpCode::DEC_POST,
};
ctx.inst(Inst::new(op, Operand::Reg(var_reg), Operand::Reg(result_reg), Operand::Reg(result_reg)));
if is_tier {
// 顶层已声明 var 自增/自减:新值落全局对象属性(A 侧单一真值)。
self.emit_tier_global_write(name, var_reg, ctx);
} else if is_implicit {
self.emit_implicit_global_write(name, var_reg, ctx);
} else if ctx.targets_writable_builtin(name, var_reg) {
// 可写内置名:RMW 新值同步落全局对象属性。
self.emit_global_put_write(name, var_reg, ctx);
}
Ok(result_reg)
}
}
pub(crate) fn emit_operator(&self, expr: &Expression, ctx: &mut CompileCtx) -> Result<u32, String> {
match expr {
Expression::BinaryExpression(bin) => self.emit_binary_expression(bin, ctx),
Expression::PrivateInExpression(pin) => self.emit_private_in_expression(pin, ctx),
Expression::UnaryExpression(un) => self.emit_unary_expression(un, ctx),
Expression::ConditionalExpression(cond) => self.emit_conditional_expression(cond, ctx),
Expression::LogicalExpression(log) => self.emit_logical_expression(log, ctx),
Expression::UpdateExpression(update) => self.emit_update_expression(update, ctx),
_ => self.emit_unsupported_expression(expr, ctx),
}
}
}
/// CONCAT_N 摊平的操作数上限:CONCAT_N 单点读全部操作数(须同时存活),寄存器占用
/// = 操作数 + 结果 ≤ 15;超过上限回退左结合 ADD(超长链保持寄存器随链复用属性)。
const MAX_CONCAT_N_OPERANDS: usize = 14;
/// 收集 Addition 左结合链的操作数(源码求值序):只下钻 left 链,right 恒为单个
/// 操作数(即使自身是 Addition 也不拆——括号右结合保持 f64 结合性不引入偏差)。
fn collect_add_operands<'expr, 'r>(expr: &'r Expression<'expr>, out: &mut Vec<&'r Expression<'expr>>) {
if let Expression::BinaryExpression(bin) = expr {
if bin.operator == BinaryOperator::Addition {
collect_add_operands(&bin.left, out);
out.push(&bin.right);
return;
}
}
out.push(expr);
}