feat: 调用实参 spread(f(...args) / new F(...args) / super(...args))

This commit is contained in:
爱特每羊队
2026-08-08 10:33:16 +08:00
parent ea86a2c0ac
commit 2777b00c82
14 changed files with 811 additions and 140 deletions
+29 -28
View File
@@ -1,6 +1,7 @@
//! 可选链(`?.`)emit:短路守卫、链式成员访问/调用与逻辑赋值短路测试。
//! 函数:`emit_chainable_expression`、`emit_optional_guard`、`emit_chain_call` 等。
use crate::expr::call::pack_arg_regs;
use crate::{CompileCtx, Emitter};
use oxide_bytecode::module::Constant;
use oxide_bytecode::opcode::OpCode;
@@ -106,36 +107,36 @@ impl Emitter {
self.emit_optional_guard(callee_reg, label, ctx)?;
}
}
let mut arg_regs = Vec::new();
for arg in &call.arguments {
if let Some(expr) = arg.as_expression() {
arg_regs.push(self.emit_expression(expr, ctx)?);
let words = self.emit_call_args(&call.arguments, ctx)?;
if words.iter().any(|w| w >> 31 == 1) {
ctx.inst(Inst::call_spread(Operand::Reg(callee_reg), Operand::Reg(this_reg), &words));
} else {
let mut static_regs = words;
let first_arg_reg = if static_regs.is_empty() { 0u32 } else { pack_arg_regs(&mut static_regs, ctx) };
let op = match &call.callee {
Expression::Identifier(ident) if ctx.is_builtin(ident.name.as_str()) => OpCode::CALL_NATIVE,
_ => OpCode::CALL,
};
match op {
OpCode::CALL => {
ctx.inst(Inst::call(
Operand::Reg(callee_reg),
Operand::Reg(this_reg),
Operand::Reg(first_arg_reg),
static_regs.len() as u8,
));
}
OpCode::CALL_NATIVE => {
ctx.inst(Inst::call_native(
Operand::Reg(callee_reg),
Operand::Reg(this_reg),
Operand::Reg(first_arg_reg),
static_regs.len() as u8,
));
}
_ => unreachable!(),
}
}
let first_arg_reg = if arg_regs.is_empty() { 0u32 } else { arg_regs[0] };
let op = match &call.callee {
Expression::Identifier(ident) if ctx.is_builtin(ident.name.as_str()) => OpCode::CALL_NATIVE,
_ => OpCode::CALL,
};
match op {
OpCode::CALL => {
ctx.inst(Inst::call(
Operand::Reg(callee_reg),
Operand::Reg(this_reg),
Operand::Reg(first_arg_reg),
arg_regs.len() as u8,
));
}
OpCode::CALL_NATIVE => {
ctx.inst(Inst::call_native(
Operand::Reg(callee_reg),
Operand::Reg(this_reg),
Operand::Reg(first_arg_reg),
arg_regs.len() as u8,
));
}
_ => unreachable!(),
}
let result_reg = ctx.alloc_reg();
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(result_reg), Operand::None, Operand::None));
Ok(result_reg)