1use super::*;
4
5pub(crate) fn math_log2(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
7 Ok(Value::Number(libm::log2(arg(a, 0).to_number())))
8}
9pub(crate) fn math_log10(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
10 Ok(Value::Number(libm::log10(arg(a, 0).to_number())))
11}
12pub(crate) fn math_cbrt(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
13 Ok(Value::Number(libm::cbrt(arg(a, 0).to_number())))
14}
15pub(crate) fn math_tan(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
16 Ok(Value::Number(libm::tan(arg(a, 0).to_number())))
17}
18pub(crate) fn math_atan(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
19 Ok(Value::Number(libm::atan(arg(a, 0).to_number())))
20}
21pub(crate) fn math_asin(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
22 Ok(Value::Number(libm::asin(arg(a, 0).to_number())))
23}
24pub(crate) fn math_acos(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
25 Ok(Value::Number(libm::acos(arg(a, 0).to_number())))
26}
27pub(crate) fn math_atan2(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
28 Ok(Value::Number(libm::atan2(
29 arg(a, 0).to_number(),
30 arg(a, 1).to_number(),
31 )))
32}
33pub(crate) fn math_hypot(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
34 let sum: f64 = a
35 .iter()
36 .map(|v| {
37 let x = v.to_number();
38 x * x
39 })
40 .sum();
41 Ok(Value::Number(libm::sqrt(sum)))
42}
43pub(crate) fn math_fround(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
48 Ok(Value::Number(arg(a, 0).to_number() as f32 as f64))
49}
50pub(crate) fn math_f16round(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
53 let n = arg(a, 0).to_number();
54 let bits = super::typed_array::f64_to_f16_bits(n);
55 Ok(Value::Number(super::typed_array::f16_bits_to_f64(bits)))
56}
57pub(crate) fn math_clamp(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
60 let val = arg(a, 0).to_number();
61 let min = arg(a, 1).to_number();
62 let max = arg(a, 2).to_number();
63 if val.is_nan() || min.is_nan() || max.is_nan() || min > max {
64 Ok(Value::Number(f64::NAN))
65 } else {
66 Ok(Value::Number(val.max(min).min(max)))
67 }
68}
69pub(crate) fn math_clz32(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
72 let n = arg(a, 0).to_number();
73 let u = if n.is_finite() { n as i64 as u32 } else { 0 };
74 Ok(Value::Number(u.leading_zeros() as f64))
75}
76pub(crate) fn math_imul(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
81 let x = arg(a, 0).to_number() as i64 as i32;
82 let y = arg(a, 1).to_number() as i64 as i32;
83 Ok(Value::Number(x.wrapping_mul(y) as f64))
84}
85pub(crate) fn math_sinh(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
86 Ok(Value::Number(libm::sinh(arg(a, 0).to_number())))
87}
88pub(crate) fn math_cosh(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
89 Ok(Value::Number(libm::cosh(arg(a, 0).to_number())))
90}
91pub(crate) fn math_tanh(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
92 Ok(Value::Number(libm::tanh(arg(a, 0).to_number())))
93}
94pub(crate) fn math_asinh(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
95 Ok(Value::Number(libm::asinh(arg(a, 0).to_number())))
96}
97pub(crate) fn math_acosh(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
98 Ok(Value::Number(libm::acosh(arg(a, 0).to_number())))
99}
100pub(crate) fn math_atanh(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
101 Ok(Value::Number(libm::atanh(arg(a, 0).to_number())))
102}
103pub(crate) fn math_expm1(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
104 Ok(Value::Number(libm::expm1(arg(a, 0).to_number())))
105}
106pub(crate) fn math_log1p(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
107 Ok(Value::Number(libm::log1p(arg(a, 0).to_number())))
108}
109pub(crate) fn math_sum_precise(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
113 let source = arg(a, 0);
114 let items = it.iter_to_vec(&source);
115
116 let mut has_nan = false;
117 let mut has_pos_inf = false;
118 let mut has_neg_inf = false;
119
120 let mut numbers = alloc::vec::Vec::with_capacity(items.len());
121 for item in items {
122 let n = item.to_number();
123 if n.is_nan() {
124 has_nan = true;
125 } else if n == f64::INFINITY {
126 has_pos_inf = true;
127 } else if n == f64::NEG_INFINITY {
128 has_neg_inf = true;
129 } else {
130 numbers.push(n);
131 }
132 }
133
134 if has_nan || (has_pos_inf && has_neg_inf) {
135 return Ok(Value::Number(f64::NAN));
136 }
137 if has_pos_inf {
138 return Ok(Value::Number(f64::INFINITY));
139 }
140 if has_neg_inf {
141 return Ok(Value::Number(f64::NEG_INFINITY));
142 }
143
144 let mut sum = 0.0f64;
146 let mut c = 0.0f64;
147 for x in numbers {
148 let t = sum + x;
149 if libm::fabs(sum) >= libm::fabs(x) {
150 c += (sum - t) + x;
151 } else {
152 c += (x - t) + sum;
153 }
154 sum = t;
155 }
156 Ok(Value::Number(sum + c))
157}
158
159pub(crate) fn object_get_prototype_of(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
163 if let Value::Object(o) = arg(a, 0) {
164 return Ok(effective_proto(it, &o));
165 }
166 Ok(Value::Null)
167}
168
169pub(crate) fn effective_proto(it: &Interp, o: &Rc<RefCell<Obj>>) -> Value {
177 match implicit_proto(it, o) {
178 Some(p) => Value::Object(p),
179 None => Value::Null,
180 }
181}
182
183pub(crate) fn global_ctor_proto(it: &Interp, name: &str) -> Option<Rc<RefCell<Obj>>> {
185 match it.global.borrow().vars.get(name) {
186 Some(Value::Object(c)) => match c.borrow().props.get("prototype") {
187 Some(Value::Object(p)) => Some(p.clone()),
188 _ => None,
189 },
190 _ => None,
191 }
192}
193
194pub(crate) fn implicit_proto(it: &Interp, o: &Rc<RefCell<Obj>>) -> Option<Rc<RefCell<Obj>>> {
200 let (explicit, null_proto, ctor_name) = {
201 let b = o.borrow();
202 let name = match &b.kind {
203 ObjKind::Array(_) => Some("Array"),
204 ObjKind::PromiseObj(_) => Some("Promise"),
205 ObjKind::MapObj(_) => Some("Map"),
206 ObjKind::SetObj(_) => Some("Set"),
207 ObjKind::RegExpObj(_) => Some("RegExp"),
208 ObjKind::DateObj(_) => Some("Date"),
209 _ if b.is_callable() => Some("Function"),
210 _ => None,
211 };
212 (b.proto.clone(), b.null_proto, name)
213 };
214 if explicit.is_some() {
215 return explicit;
216 }
217 if null_proto {
218 return None;
219 }
220 let dom_idx = match o.borrow().kind {
222 ObjKind::DomElement(i) => Some(i),
223 _ => None,
224 };
225 if let Some(i) = dom_idx {
226 if let Some(p) = it.get_dom_node_proto(i) {
227 return Some(p);
228 }
229 }
230 let object_proto = global_ctor_proto(it, "Object")?;
231 if Rc::ptr_eq(&object_proto, o) {
232 return None;
233 }
234 match ctor_name.and_then(|n| global_ctor_proto(it, n)) {
235 Some(p) if !Rc::ptr_eq(&p, o) => Some(p),
236 _ => Some(object_proto),
237 }
238}
239pub(crate) fn object_set_prototype_of(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
241 let target = arg(a, 0);
242 if let Value::Object(o) = &target {
243 let dom_idx = match o.borrow().kind {
245 ObjKind::DomElement(i) => Some(i),
246 _ => None,
247 };
248 if let (Some(i), Value::Object(p)) = (dom_idx, arg(a, 1)) {
249 it.dom.borrow_mut().node_protos.insert(i, p);
250 return Ok(target);
251 }
252 match arg(a, 1) {
253 Value::Object(p) => {
254 let mut b = o.borrow_mut();
255 b.proto = Some(p);
256 b.null_proto = false;
257 }
258 Value::Null => {
259 let mut b = o.borrow_mut();
260 b.proto = None;
261 b.null_proto = true;
264 }
265 _ => {}
266 }
267 }
268 Ok(target)
269}
270pub(crate) fn object_from_entries(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
271 let o = Obj::plain();
272 for pair in it.iter_to_vec(&arg(a, 0)) {
273 let k = key_at(&pair, 0).to_js_string();
274 let v = key_at(&pair, 1);
275 o.borrow_mut().props.insert(k, v);
276 }
277 Ok(Value::Object(o))
278}
279pub(crate) fn object_freeze(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
283 let v = arg(a, 0);
284 if let Value::Object(o) = &v {
285 o.borrow_mut().frozen = true;
286 }
287 Ok(v)
288}
289pub(crate) fn object_is_frozen(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
291 Ok(Value::Bool(match arg(a, 0) {
292 Value::Object(o) => o.borrow().frozen,
293 _ => true,
294 }))
295}
296pub(crate) fn object_seal(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
299 let v = arg(a, 0);
300 if let Value::Object(o) = &v {
301 o.borrow_mut().sealed = true;
302 }
303 Ok(v)
304}
305pub(crate) fn object_is_sealed(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
306 Ok(Value::Bool(match arg(a, 0) {
307 Value::Object(o) => {
308 let b = o.borrow();
309 b.frozen || b.sealed
310 }
311 _ => true,
312 }))
313}
314pub(crate) fn object_prevent_extensions(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
316 let v = arg(a, 0);
317 if let Value::Object(o) = &v {
318 o.borrow_mut().non_extensible = true;
319 }
320 Ok(v)
321}
322pub(crate) fn object_is_extensible(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
323 Ok(Value::Bool(match arg(a, 0) {
324 Value::Object(o) => {
325 let b = o.borrow();
326 !(b.frozen || b.sealed || b.non_extensible)
327 }
328 _ => false,
329 }))
330}
331pub(crate) fn object_is(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
335 let x = arg(a, 0);
336 let y = arg(a, 1);
337 let result = match (&x, &y) {
338 (Value::Number(nx), Value::Number(ny)) => {
339 if nx.is_nan() && ny.is_nan() {
340 true
341 } else if *nx == 0.0 && *ny == 0.0 {
342 nx.is_sign_positive() == ny.is_sign_positive()
343 } else {
344 nx == ny
345 }
346 }
347 _ => x.strict_eq(&y),
348 };
349 Ok(Value::Bool(result))
350}
351pub(crate) fn object_create(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
352 let obj = Obj::plain();
354 match arg(a, 0) {
358 Value::Object(p) => obj.borrow_mut().proto = Some(p),
359 Value::Null => obj.borrow_mut().null_proto = true,
360 _ => {}
361 }
362 let props = arg(a, 1);
366 if let Value::Object(d) = &props {
367 let keys: alloc::vec::Vec<String> = d.borrow().props.keys().map(Clone::clone).collect();
368 for key in keys {
369 let desc = obj_prop(&props, &key).unwrap_or(Value::Undefined);
370 apply_define_property(it, &Value::Object(obj.clone()), &key, &desc);
371 }
372 }
373 Ok(Value::Object(obj))
374}
375
376pub(crate) fn apply_define_property(it: &mut Interp, obj: &Value, key: &str, desc: &Value) {
379 let Value::Object(o) = obj else { return };
380 let o = unwrap_proxy_target(o);
381
382 let writable = obj_prop(desc, "writable").map(|v| v.truthy());
383 let configurable = obj_prop(desc, "configurable").map(|v| v.truthy());
384 let enumerable = obj_prop(desc, "enumerable").map(|v| v.truthy());
385
386 let is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
387 if is_array {
388 if key == "length" {
389 if let Some(v) = obj_prop(desc, "value") {
390 let new_len = v.to_number().max(0.0) as usize;
391 if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
392 items.resize(new_len, Value::Undefined);
393 }
394 }
395 return;
396 }
397 if let Ok(idx) = key.parse::<usize>() {
398 if let Some(v) = obj_prop(desc, "value") {
399 if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
400 if idx >= items.len() {
401 items.resize(idx + 1, Value::Undefined);
402 }
403 items[idx] = v;
404 }
405 }
406 return;
407 }
408 }
409 let get = obj_prop(desc, "get");
410 let set = obj_prop(desc, "set");
411 let has_value = obj_prop(desc, "value").is_some();
412
413 let is_new = !o.borrow().props.contains_key(key) && !o.borrow().accessors.contains_key(key);
414 let attr = if is_new {
415 super::super::value::PropertyAttributes {
416 writable: writable.unwrap_or(false),
417 configurable: configurable.unwrap_or(false),
418 enumerable: enumerable.unwrap_or(false),
419 }
420 } else {
421 let prev = o.borrow().attrs.get(key).copied().unwrap_or_default();
422 super::super::value::PropertyAttributes {
423 writable: writable.unwrap_or(prev.writable),
424 configurable: configurable.unwrap_or(prev.configurable),
425 enumerable: enumerable.unwrap_or(prev.enumerable),
426 }
427 };
428
429 if get.is_some() || set.is_some() {
430 use super::super::value::Accessor;
432 let getter = get.filter(|v| matches!(v, Value::Object(f) if f.borrow().is_callable()));
433 let setter = set.filter(|v| matches!(v, Value::Object(f) if f.borrow().is_callable()));
434 o.borrow_mut().accessors.insert(
435 alloc::string::String::from(key),
436 Accessor { get: getter, set: setter },
437 );
438 o.borrow_mut().props.shift_remove(key);
439 } else if has_value {
440 let val = obj_prop(desc, "value").unwrap_or(Value::Undefined);
442 o.borrow_mut().props.insert(alloc::string::String::from(key), val);
443 o.borrow_mut().accessors.shift_remove(key);
444 }
445
446 o.borrow_mut().attrs.insert(alloc::string::String::from(key), attr);
447 let _ = it;
448}
449
450pub(crate) fn object_define_property(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
451 let obj = arg(a, 0);
452 let key = arg(a, 1).to_js_string();
453 let desc = arg(a, 2);
454 apply_define_property(it, &obj, &key, &desc);
455 Ok(obj)
456}
457
458pub(crate) fn object_define_properties(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
459 let obj = arg(a, 0);
460 let descs = arg(a, 1);
461 if let Value::Object(d) = &descs {
462 let keys: alloc::vec::Vec<String> = d.borrow().props.keys().map(Clone::clone).collect();
463 for key in keys {
464 let desc = obj_prop(&descs, &key).unwrap_or(Value::Undefined);
465 apply_define_property(it, &obj, &key, &desc);
466 }
467 }
468 Ok(obj)
469}
470
471pub(crate) fn make_property_descriptor(obj: &super::super::value::ObjRef, key: &str) -> Value {
472 let obj = unwrap_proxy_target(obj);
473 let b = obj.borrow();
474 let attr = b.attrs.get(key).copied().unwrap_or_default();
475
476 if let ObjKind::Array(items) = &b.kind {
477 if key == "length" {
478 let desc = Obj::plain();
479 desc.borrow_mut().props.insert("value".into(), Value::Number(items.len() as f64));
480 desc.borrow_mut().props.insert("writable".into(), Value::Bool(true));
481 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(false));
482 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(false));
483 return Value::Object(desc);
484 }
485 if let Ok(idx) = key.parse::<usize>() {
486 if let Some(v) = items.get(idx) {
487 let desc = Obj::plain();
488 desc.borrow_mut().props.insert("value".into(), v.clone());
489 desc.borrow_mut().props.insert("writable".into(), Value::Bool(true));
490 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(true));
491 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(true));
492 return Value::Object(desc);
493 }
494 return Value::Undefined;
495 }
496 }
497 if let Some(acc) = b.accessors.get(key) {
498 let desc = Obj::plain();
499 if let Some(g) = &acc.get {
500 desc.borrow_mut().props.insert("get".into(), g.clone());
501 } else {
502 desc.borrow_mut().props.insert("get".into(), Value::Undefined);
503 }
504 if let Some(s) = &acc.set {
505 desc.borrow_mut().props.insert("set".into(), s.clone());
506 } else {
507 desc.borrow_mut().props.insert("set".into(), Value::Undefined);
508 }
509 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(attr.enumerable));
510 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(attr.configurable));
511 Value::Object(desc)
512 } else if let Some(v) = b.props.get(key) {
513 let desc = Obj::plain();
514 desc.borrow_mut().props.insert("value".into(), v.clone());
515 desc.borrow_mut().props.insert("writable".into(), Value::Bool(attr.writable));
516 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(attr.enumerable));
517 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(attr.configurable));
518 Value::Object(desc)
519 } else {
520 Value::Undefined
521 }
522}
523
524pub(crate) fn object_get_own_property_descriptor(
525 _it: &mut Interp,
526 _t: Value,
527 a: &[Value],
528) -> Result<Value, Value> {
529 let Value::Object(o) = arg(a, 0) else { return Ok(Value::Undefined) };
530 let key = arg(a, 1).to_js_string();
531 Ok(make_property_descriptor(&o, &key))
532}
533
534pub(crate) fn object_get_own_property_descriptors(
535 _it: &mut Interp,
536 _t: Value,
537 a: &[Value],
538) -> Result<Value, Value> {
539 let Value::Object(o) = arg(a, 0) else { return Ok(Value::Object(Obj::plain())) };
540 let result = Obj::plain();
541 let keys: alloc::vec::Vec<String> = {
542 let b = o.borrow();
543 if let ObjKind::Array(items) = &b.kind {
544 let mut ks: alloc::vec::Vec<String> = (0..items.len()).map(|i| i.to_string()).collect();
545 ks.push(String::from("length"));
546 ks
547 } else {
548 let mut ks: alloc::vec::Vec<String> = b.props.keys().map(Clone::clone).collect();
549 for k in b.accessors.keys() {
550 if !ks.contains(k) {
551 ks.push(k.clone());
552 }
553 }
554 ks
555 }
556 };
557 for key in keys {
558 let desc = make_property_descriptor(&o, &key);
559 result.borrow_mut().props.insert(key, desc);
560 }
561 Ok(Value::Object(result))
562}
563
564pub(crate) fn number_is_integer(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
566 Ok(Value::Bool(match arg(a, 0) {
567 Value::Number(x) => x.is_finite() && libm::floor(x) == x,
568 _ => false,
569 }))
570}
571pub(crate) fn number_is_safe_integer(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
572 Ok(Value::Bool(match arg(a, 0) {
573 Value::Number(x) => {
574 x.is_finite() && libm::floor(x) == x && libm::fabs(x) <= 9007199254740991.0
575 }
576 _ => false,
577 }))
578}
579pub(crate) fn number_is_finite_static(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
580 Ok(Value::Bool(
581 matches!(arg(a, 0), Value::Number(x) if x.is_finite()),
582 ))
583}
584pub(crate) fn number_is_nan_static(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
585 Ok(Value::Bool(
586 matches!(arg(a, 0), Value::Number(x) if x.is_nan()),
587 ))
588}
589