feat: 完整实现 typeof/void/in 操作符逻辑
This commit is contained in:
@@ -340,6 +340,7 @@ impl Compiler {
|
|||||||
BinaryOperator::GreaterThan => OpCode::GT,
|
BinaryOperator::GreaterThan => OpCode::GT,
|
||||||
BinaryOperator::LessEqualThan => OpCode::LTE,
|
BinaryOperator::LessEqualThan => OpCode::LTE,
|
||||||
BinaryOperator::GreaterEqualThan => OpCode::GTE,
|
BinaryOperator::GreaterEqualThan => OpCode::GTE,
|
||||||
|
BinaryOperator::In => OpCode::IN,
|
||||||
_ => return Err(format!("unsupported binary operator: {:?}", bin.operator)),
|
_ => return Err(format!("unsupported binary operator: {:?}", bin.operator)),
|
||||||
};
|
};
|
||||||
let r = ctx.alloc_reg();
|
let r = ctx.alloc_reg();
|
||||||
@@ -348,12 +349,23 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
Expression::UnaryExpression(un) => {
|
Expression::UnaryExpression(un) => {
|
||||||
let arg = self.emit_expression(&un.argument, ctx)?;
|
let arg = self.emit_expression(&un.argument, ctx)?;
|
||||||
if matches!(un.operator, UnaryOperator::UnaryNegation) {
|
match un.operator {
|
||||||
let r = ctx.alloc_reg();
|
UnaryOperator::UnaryNegation => {
|
||||||
ctx.emit(opcode::encode(OpCode::NEG, r, arg, 0));
|
let r = ctx.alloc_reg();
|
||||||
Ok(r)
|
ctx.emit(opcode::encode(OpCode::NEG, r, arg, 0));
|
||||||
} else {
|
Ok(r)
|
||||||
Err(format!("unsupported unary operator: {:?}", un.operator))
|
}
|
||||||
|
UnaryOperator::Typeof => {
|
||||||
|
let r = ctx.alloc_reg();
|
||||||
|
ctx.emit(opcode::encode(OpCode::TYPEOF, r, arg, 0));
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
UnaryOperator::Void => {
|
||||||
|
let r = ctx.alloc_reg();
|
||||||
|
ctx.emit(opcode::encode(OpCode::VOID, r, arg, 0));
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
_ => Err(format!("unsupported unary operator: {:?}", un.operator)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::StaticMemberExpression(member) => {
|
Expression::StaticMemberExpression(member) => {
|
||||||
|
|||||||
@@ -426,6 +426,51 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpCode::TYPEOF => {
|
||||||
|
let val = self.regs[a];
|
||||||
|
let result = if val.is_undefined() {
|
||||||
|
"undefined"
|
||||||
|
} else if val.is_null() {
|
||||||
|
"object"
|
||||||
|
} else if val.is_bool() {
|
||||||
|
"boolean"
|
||||||
|
} else if val.is_int() || val.is_double() {
|
||||||
|
"number"
|
||||||
|
} else if val.is_string() {
|
||||||
|
"string"
|
||||||
|
} else if val.is_object() {
|
||||||
|
let obj = unsafe { &*val.as_js_object_ptr() };
|
||||||
|
if obj.is_function() {
|
||||||
|
"function"
|
||||||
|
} else {
|
||||||
|
"object"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
"undefined"
|
||||||
|
};
|
||||||
|
self.regs[rd] = self.intern(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
OpCode::VOID => {
|
||||||
|
self.regs[rd] = JsValue::undefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpCode::IN => {
|
||||||
|
let key_val = self.regs[a];
|
||||||
|
let obj_ptr = self.regs[b].as_object_ptr() as *mut JsObject;
|
||||||
|
if obj_ptr.is_null() {
|
||||||
|
return Err("IN right-hand side is not an object".into());
|
||||||
|
}
|
||||||
|
let obj = unsafe { &*obj_ptr };
|
||||||
|
let prop_name_si = if key_val.is_string() {
|
||||||
|
key_val.as_string_index()
|
||||||
|
} else {
|
||||||
|
return Err("IN key must be a string".into());
|
||||||
|
};
|
||||||
|
let found = self.resolve_property(obj, prop_name_si).is_some();
|
||||||
|
self.regs[rd] = JsValue::bool(found);
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
if !op.is_implemented() {
|
if !op.is_implemented() {
|
||||||
return Ok(JsValue::undefined());
|
return Ok(JsValue::undefined());
|
||||||
|
|||||||
Reference in New Issue
Block a user