feat: 实现 ECMAScript 类型强制转换
This commit is contained in:
Generated
+8
@@ -293,6 +293,12 @@ version = "3.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
|
checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fast-float"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95765f67b4b18863968b4a1bd5bb576f732b29a4a28c7cd84c09fa3e2875f33c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
@@ -795,10 +801,12 @@ name = "oxide_vm"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
|
"fast-float",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown 0.14.5",
|
||||||
"oxide_compiler",
|
"oxide_compiler",
|
||||||
"oxide_kernel",
|
"oxide_kernel",
|
||||||
"proptest",
|
"proptest",
|
||||||
|
"ryu",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ bumpalo = "3"
|
|||||||
hashbrown = "0.14"
|
hashbrown = "0.14"
|
||||||
proptest = "1"
|
proptest = "1"
|
||||||
rustc-hash = "2"
|
rustc-hash = "2"
|
||||||
|
fast-float = "0.2"
|
||||||
|
ryu = "1"
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
all = { level = "deny", priority = -1 }
|
all = { level = "deny", priority = -1 }
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ oxide_compiler = { path = "../oxide_compiler" }
|
|||||||
oxide_kernel = { path = "../oxide_kernel" }
|
oxide_kernel = { path = "../oxide_kernel" }
|
||||||
bumpalo.workspace = true
|
bumpalo.workspace = true
|
||||||
hashbrown.workspace = true
|
hashbrown.workspace = true
|
||||||
|
fast-float.workspace = true
|
||||||
|
ryu.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest.workspace = true
|
proptest.workspace = true
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
use crate::value::JsValue;
|
||||||
|
|
||||||
|
pub fn to_primitive(val: JsValue) -> JsValue {
|
||||||
|
if val.is_object() {
|
||||||
|
panic_to_object();
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_number(val: JsValue) -> f64 {
|
||||||
|
if val.is_int() {
|
||||||
|
return val.as_int() as f64;
|
||||||
|
}
|
||||||
|
if val.is_double() {
|
||||||
|
return val.as_double();
|
||||||
|
}
|
||||||
|
if val.is_bool() {
|
||||||
|
return if val.as_bool() { 1.0 } else { 0.0 };
|
||||||
|
}
|
||||||
|
if val.is_null() {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
if val.is_undefined() {
|
||||||
|
return f64::NAN;
|
||||||
|
}
|
||||||
|
if val.is_object() {
|
||||||
|
panic_to_object();
|
||||||
|
}
|
||||||
|
f64::NAN
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_string(val: JsValue) -> String {
|
||||||
|
if val.is_int() {
|
||||||
|
return val.as_int().to_string();
|
||||||
|
}
|
||||||
|
if val.is_double() {
|
||||||
|
let d = val.as_double();
|
||||||
|
if d.is_nan() {
|
||||||
|
return "NaN".to_string();
|
||||||
|
}
|
||||||
|
if d.is_infinite() {
|
||||||
|
return if d.is_sign_positive() {
|
||||||
|
"Infinity".to_string()
|
||||||
|
} else {
|
||||||
|
"-Infinity".to_string()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let mut buf = ryu::Buffer::new();
|
||||||
|
return buf.format(d).to_string();
|
||||||
|
}
|
||||||
|
if val.is_bool() {
|
||||||
|
return val.as_bool().to_string();
|
||||||
|
}
|
||||||
|
if val.is_null() {
|
||||||
|
return "null".to_string();
|
||||||
|
}
|
||||||
|
if val.is_undefined() {
|
||||||
|
return "undefined".to_string();
|
||||||
|
}
|
||||||
|
if val.is_object() {
|
||||||
|
panic_to_object();
|
||||||
|
}
|
||||||
|
String::new()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_boolean(val: JsValue) -> bool {
|
||||||
|
if val.is_undefined() || val.is_null() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if val.is_bool() {
|
||||||
|
return val.as_bool();
|
||||||
|
}
|
||||||
|
if val.is_int() {
|
||||||
|
return val.as_int() != 0;
|
||||||
|
}
|
||||||
|
if val.is_double() {
|
||||||
|
let d = val.as_double();
|
||||||
|
return !(d == 0.0 || d == -0.0 || d.is_nan());
|
||||||
|
}
|
||||||
|
if val.is_object() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn abstract_eq(lhs: JsValue, rhs: JsValue) -> bool {
|
||||||
|
if lhs.is_null() && rhs.is_undefined() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if lhs.is_undefined() && rhs.is_null() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if lhs.is_int() && rhs.is_int() {
|
||||||
|
return lhs.as_int() == rhs.as_int();
|
||||||
|
}
|
||||||
|
if lhs.is_double() && rhs.is_double() {
|
||||||
|
return strict_double_eq(lhs.as_double(), rhs.as_double());
|
||||||
|
}
|
||||||
|
if lhs.is_bool() && rhs.is_bool() {
|
||||||
|
return lhs.as_bool() == rhs.as_bool();
|
||||||
|
}
|
||||||
|
if lhs.is_null() && rhs.is_null() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if lhs.is_undefined() && rhs.is_undefined() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (lhs.is_int() || lhs.is_double()) && (rhs.is_int() || rhs.is_double()) {
|
||||||
|
return strict_double_eq(to_number(lhs), to_number(rhs));
|
||||||
|
}
|
||||||
|
if (lhs.is_int() || lhs.is_double()) && rhs.is_bool() {
|
||||||
|
return to_number(lhs) == to_number(rhs);
|
||||||
|
}
|
||||||
|
if lhs.is_bool() && (rhs.is_int() || rhs.is_double()) {
|
||||||
|
return to_number(lhs) == to_number(rhs);
|
||||||
|
}
|
||||||
|
if lhs.is_bool() || rhs.is_bool() {
|
||||||
|
return to_number(lhs) == to_number(rhs);
|
||||||
|
}
|
||||||
|
if lhs.is_null() || rhs.is_null() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if lhs.is_object() || rhs.is_object() {
|
||||||
|
panic_to_object();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn strict_eq(lhs: JsValue, rhs: JsValue) -> bool {
|
||||||
|
if lhs.is_int() && rhs.is_int() {
|
||||||
|
return lhs.as_int() == rhs.as_int();
|
||||||
|
}
|
||||||
|
if lhs.is_double() && rhs.is_double() {
|
||||||
|
return strict_double_eq(lhs.as_double(), rhs.as_double());
|
||||||
|
}
|
||||||
|
if lhs.is_bool() && rhs.is_bool() {
|
||||||
|
return lhs.as_bool() == rhs.as_bool();
|
||||||
|
}
|
||||||
|
if lhs.is_null() && rhs.is_null() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if lhs.is_undefined() && rhs.is_undefined() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if lhs.is_object() && rhs.is_object() {
|
||||||
|
return lhs.as_ptr() == rhs.as_ptr();
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn strict_double_eq(a: f64, b: f64) -> bool {
|
||||||
|
if a.is_nan() || b.is_nan() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
a == b
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn relational_compare(lhs: JsValue, rhs: JsValue) -> Option<bool> {
|
||||||
|
let l = to_number(lhs);
|
||||||
|
let r = to_number(rhs);
|
||||||
|
if l.is_nan() || r.is_nan() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
l.partial_cmp(&r).map(|o| o.is_lt())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn string_concat(lhs: &str, rhs: &str) -> String {
|
||||||
|
let mut s = String::with_capacity(lhs.len() + rhs.len());
|
||||||
|
s.push_str(lhs);
|
||||||
|
s.push_str(rhs);
|
||||||
|
s
|
||||||
|
}
|
||||||
|
|
||||||
|
fn panic_to_object() {
|
||||||
|
panic!("ToObject not yet implemented (Phase 6)")
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#![doc = "OxideJS - Register-based VM with epoch arena memory"]
|
#![doc = "OxideJS - Register-based VM with epoch arena memory"]
|
||||||
|
|
||||||
|
pub mod coercion;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod value;
|
pub mod value;
|
||||||
pub use value::JsValue;
|
pub use value::JsValue;
|
||||||
|
|||||||
Reference in New Issue
Block a user