feat: new.target MetaProperty emit 支持(LOAD_VAR NewTarget)
This commit is contained in:
@@ -1440,6 +1440,7 @@ impl Emitter {
|
|||||||
Expression::ThisExpression(_) => self.emit_this_expression(ctx),
|
Expression::ThisExpression(_) => self.emit_this_expression(ctx),
|
||||||
Expression::SequenceExpression(seq) => self.emit_sequence_expression(seq, ctx),
|
Expression::SequenceExpression(seq) => self.emit_sequence_expression(seq, ctx),
|
||||||
Expression::ParenthesizedExpression(p) => self.emit_parenthesized_expression(p, ctx),
|
Expression::ParenthesizedExpression(p) => self.emit_parenthesized_expression(p, ctx),
|
||||||
|
Expression::MetaProperty(mp) => self.emit_meta_property_expression(mp, ctx),
|
||||||
_ => self.emit_unsupported_expression(expr, ctx),
|
_ => self.emit_unsupported_expression(expr, ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
//! `new.target` / `import.meta` 元属性表达式 emit。
|
||||||
|
//!
|
||||||
|
//! - `new.target` → `LOAD_VAR` 读物理寄存器 255(VM 帧 `saved_new_target`,构造时传
|
||||||
|
//! constructor、普通调用传 undefined)。
|
||||||
|
//! - `import.meta` 需模块命名空间对象,当前未支持:显式报错分类 Skip,不留静默错误。
|
||||||
|
|
||||||
|
use crate::{CompileCtx, Emitter};
|
||||||
|
use oxide_bytecode::opcode::OpCode;
|
||||||
|
use oxide_ir::inst::Inst;
|
||||||
|
use oxide_ir::operand::Operand;
|
||||||
|
use oxide_parser::MetaProperty;
|
||||||
|
|
||||||
|
impl Emitter {
|
||||||
|
/// 元属性表达式 emit:`new.target` 读当前构造目标寄存器,`import.meta` 显式报错。
|
||||||
|
///
|
||||||
|
/// # 边界与前提
|
||||||
|
/// - `new.target` 语法上仅出现在函数体内,顶层用法由 oxc 早期错误拦截。
|
||||||
|
/// - 非 `new.target` 的元属性(`import.meta`)返回编译错误,错误文本含
|
||||||
|
/// "not supported" 供 test262 分类为 Skip。
|
||||||
|
///
|
||||||
|
/// # 副作用
|
||||||
|
/// - 分配一个结果寄存器(`ctx.alloc_reg`)。
|
||||||
|
pub(crate) fn emit_meta_property_expression(&self, mp: &MetaProperty, ctx: &mut CompileCtx) -> Result<u32, String> {
|
||||||
|
if mp.meta.name == "new" && mp.property.name == "target" {
|
||||||
|
let r = ctx.alloc_reg();
|
||||||
|
ctx.inst(Inst::new(OpCode::LOAD_VAR, Operand::Reg(r), Operand::NewTarget, Operand::None));
|
||||||
|
return Ok(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// import.meta 需要模块命名空间对象,未支持:显式报错避免静默错误结果。
|
||||||
|
Err("import.meta not yet supported".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ pub mod function;
|
|||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod literal;
|
pub mod literal;
|
||||||
pub mod member;
|
pub mod member;
|
||||||
|
pub mod meta_property;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
pub mod operator;
|
pub mod operator;
|
||||||
pub mod parenthesized;
|
pub mod parenthesized;
|
||||||
|
|||||||
@@ -0,0 +1,104 @@
|
|||||||
|
use oxide_compiler::compiler::Compiler;
|
||||||
|
use oxide_types::value::JsValue;
|
||||||
|
use oxide_vm::vm::Vm;
|
||||||
|
|
||||||
|
fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||||
|
let allocator = oxide_parser::Allocator::default();
|
||||||
|
let program = oxide_parser::parse(&allocator, source).map_err(|e| format!("Parse error: {:?}", e))?;
|
||||||
|
let module = Compiler::new().compile(&program).map_err(|e| format!("Compile error: {}", e))?;
|
||||||
|
vm.run(&module)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_bool(value: JsValue, expected: bool) {
|
||||||
|
assert!(value.is_bool(), "expected boolean, got {value:?}");
|
||||||
|
assert_eq!(value.as_bool(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_call_new_target_is_undefined() {
|
||||||
|
// 普通调用不传构造目标:`new.target` 应为 undefined。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "function f(){ return new.target === undefined; } f()").unwrap();
|
||||||
|
assert_bool(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn construct_new_target_is_constructor() {
|
||||||
|
// `new f()` 以 f 为构造目标:`new.target` 应为 f 本身。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "function f(){ this.t = new.target === f; } new f().t").unwrap();
|
||||||
|
assert_bool(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn class_constructor_new_target_is_class() {
|
||||||
|
// 类构造器内 `new.target` 应为被 new 的类自身。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "class A { constructor(){ this.t = new.target; } } new A().t === A").unwrap();
|
||||||
|
assert_bool(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn derived_class_new_target_is_derived_constructor() {
|
||||||
|
// 子类构造经 super() 链路:基类构造器内 `new.target` 仍是派生类(new 表达式目标)。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"class A { constructor(){ this.t = new.target; } } class B extends A {} new B().t === B",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_bool(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_function_new_target_is_undefined() {
|
||||||
|
// 内层普通函数是独立调用帧,不继承外层构造目标的 `new.target`。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(
|
||||||
|
&mut vm,
|
||||||
|
"(function(){ var f = function(){ return new.target; }; return f() === undefined; })()",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_bool(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn typeof_and_void_new_target() {
|
||||||
|
// unary 表达式组合:构造调用下 `typeof new.target` 为 "function",普通调用下为 "undefined"。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "function f(){ return typeof new.target; } f()").unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(result).expect("typeof should be string"), "undefined");
|
||||||
|
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "function f(){ this.t = typeof new.target; } new f().t").unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(result).expect("typeof should be string"), "function");
|
||||||
|
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "function f(){ this.u = void new.target; } new f().u").unwrap();
|
||||||
|
assert!(result.is_undefined());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore = "已知规范缺口:箭头函数 new.target 词法继承未实现(VM 对 arrow 帧写 undefined),修复(闭包捕获)后移除"]
|
||||||
|
fn arrow_function_inherits_outer_new_target() {
|
||||||
|
// 规范要求箭头函数词法继承外层 `new.target`;当前 VM 对 arrow 帧直接写
|
||||||
|
// undefined(普通 CALL 路径传 undefined 为 new.target),无词法捕获——
|
||||||
|
// 已知规范缺口,登记不修;修复(闭包捕获)后移除 #[ignore]。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
let result = eval(&mut vm, "function f(){ return (() => new.target)(); } new f() === f").unwrap();
|
||||||
|
assert_bool(result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn import_meta_is_explicit_error() {
|
||||||
|
// `import.meta` 需模块命名空间对象:显式编译报错(含 "not supported" 供
|
||||||
|
// test262 分类 Skip),不留静默错误结果。
|
||||||
|
let allocator = oxide_parser::Allocator::default();
|
||||||
|
let program = oxide_parser::parse_module(&allocator, "import.meta").map_err(|e| format!("Parse error: {:?}", e));
|
||||||
|
let program = program.expect("import.meta should parse in module context");
|
||||||
|
let err = match Compiler::new().compile(&program) {
|
||||||
|
Ok(_) => panic!("import.meta must not compile"),
|
||||||
|
Err(e) => e,
|
||||||
|
};
|
||||||
|
assert!(err.contains("import.meta not yet supported"), "unexpected compile error: {err}");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user