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(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
163 if let Value::Object(o) = arg(a, 0) {
164 return Ok(match o.borrow().proto.clone() {
165 Some(p) => Value::Object(p),
166 None => Value::Null,
167 });
168 }
169 Ok(Value::Null)
170}
171pub(crate) fn object_set_prototype_of(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
173 let target = arg(a, 0);
174 if let Value::Object(o) = &target {
175 match arg(a, 1) {
176 Value::Object(p) => {
177 let mut b = o.borrow_mut();
178 b.proto = Some(p);
179 b.null_proto = false;
180 }
181 Value::Null => {
182 let mut b = o.borrow_mut();
183 b.proto = None;
184 b.null_proto = true;
187 }
188 _ => {}
189 }
190 }
191 Ok(target)
192}
193pub(crate) fn object_from_entries(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
194 let o = Obj::plain();
195 for pair in it.iter_to_vec(&arg(a, 0)) {
196 let k = key_at(&pair, 0).to_js_string();
197 let v = key_at(&pair, 1);
198 o.borrow_mut().props.insert(k, v);
199 }
200 Ok(Value::Object(o))
201}
202pub(crate) fn object_freeze(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
206 let v = arg(a, 0);
207 if let Value::Object(o) = &v {
208 o.borrow_mut().frozen = true;
209 }
210 Ok(v)
211}
212pub(crate) fn object_is_frozen(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
214 Ok(Value::Bool(match arg(a, 0) {
215 Value::Object(o) => o.borrow().frozen,
216 _ => true,
217 }))
218}
219pub(crate) fn object_seal(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
222 let v = arg(a, 0);
223 if let Value::Object(o) = &v {
224 o.borrow_mut().sealed = true;
225 }
226 Ok(v)
227}
228pub(crate) fn object_is_sealed(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
229 Ok(Value::Bool(match arg(a, 0) {
230 Value::Object(o) => {
231 let b = o.borrow();
232 b.frozen || b.sealed
233 }
234 _ => true,
235 }))
236}
237pub(crate) fn object_prevent_extensions(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
239 let v = arg(a, 0);
240 if let Value::Object(o) = &v {
241 o.borrow_mut().non_extensible = true;
242 }
243 Ok(v)
244}
245pub(crate) fn object_is_extensible(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
246 Ok(Value::Bool(match arg(a, 0) {
247 Value::Object(o) => {
248 let b = o.borrow();
249 !(b.frozen || b.sealed || b.non_extensible)
250 }
251 _ => false,
252 }))
253}
254pub(crate) fn object_is(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
258 let x = arg(a, 0);
259 let y = arg(a, 1);
260 let result = match (&x, &y) {
261 (Value::Number(nx), Value::Number(ny)) => {
262 if nx.is_nan() && ny.is_nan() {
263 true
264 } else if *nx == 0.0 && *ny == 0.0 {
265 nx.is_sign_positive() == ny.is_sign_positive()
266 } else {
267 nx == ny
268 }
269 }
270 _ => x.strict_eq(&y),
271 };
272 Ok(Value::Bool(result))
273}
274pub(crate) fn object_create(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
275 let obj = Obj::plain();
277 match arg(a, 0) {
281 Value::Object(p) => obj.borrow_mut().proto = Some(p),
282 Value::Null => obj.borrow_mut().null_proto = true,
283 _ => {}
284 }
285 let props = arg(a, 1);
289 if let Value::Object(d) = &props {
290 let keys: alloc::vec::Vec<String> = d.borrow().props.keys().map(Clone::clone).collect();
291 for key in keys {
292 let desc = obj_prop(&props, &key).unwrap_or(Value::Undefined);
293 apply_define_property(it, &Value::Object(obj.clone()), &key, &desc);
294 }
295 }
296 Ok(Value::Object(obj))
297}
298
299pub(crate) fn apply_define_property(it: &mut Interp, obj: &Value, key: &str, desc: &Value) {
302 let Value::Object(o) = obj else { return };
303 let o = unwrap_proxy_target(o);
304
305 let writable = obj_prop(desc, "writable").map(|v| v.truthy());
306 let configurable = obj_prop(desc, "configurable").map(|v| v.truthy());
307 let enumerable = obj_prop(desc, "enumerable").map(|v| v.truthy());
308
309 let is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
310 if is_array {
311 if key == "length" {
312 if let Some(v) = obj_prop(desc, "value") {
313 let new_len = v.to_number().max(0.0) as usize;
314 if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
315 items.resize(new_len, Value::Undefined);
316 }
317 }
318 return;
319 }
320 if let Ok(idx) = key.parse::<usize>() {
321 if let Some(v) = obj_prop(desc, "value") {
322 if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
323 if idx >= items.len() {
324 items.resize(idx + 1, Value::Undefined);
325 }
326 items[idx] = v;
327 }
328 }
329 return;
330 }
331 }
332 let get = obj_prop(desc, "get");
333 let set = obj_prop(desc, "set");
334 let has_value = obj_prop(desc, "value").is_some();
335
336 let is_new = !o.borrow().props.contains_key(key) && !o.borrow().accessors.contains_key(key);
337 let attr = if is_new {
338 super::super::value::PropertyAttributes {
339 writable: writable.unwrap_or(false),
340 configurable: configurable.unwrap_or(false),
341 enumerable: enumerable.unwrap_or(false),
342 }
343 } else {
344 let prev = o.borrow().attrs.get(key).copied().unwrap_or_default();
345 super::super::value::PropertyAttributes {
346 writable: writable.unwrap_or(prev.writable),
347 configurable: configurable.unwrap_or(prev.configurable),
348 enumerable: enumerable.unwrap_or(prev.enumerable),
349 }
350 };
351
352 if get.is_some() || set.is_some() {
353 use super::super::value::Accessor;
355 let getter = get.filter(|v| matches!(v, Value::Object(f) if f.borrow().is_callable()));
356 let setter = set.filter(|v| matches!(v, Value::Object(f) if f.borrow().is_callable()));
357 o.borrow_mut().accessors.insert(
358 alloc::string::String::from(key),
359 Accessor { get: getter, set: setter },
360 );
361 o.borrow_mut().props.shift_remove(key);
362 } else if has_value {
363 let val = obj_prop(desc, "value").unwrap_or(Value::Undefined);
365 o.borrow_mut().props.insert(alloc::string::String::from(key), val);
366 o.borrow_mut().accessors.shift_remove(key);
367 }
368
369 o.borrow_mut().attrs.insert(alloc::string::String::from(key), attr);
370 let _ = it;
371}
372
373pub(crate) fn object_define_property(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
374 let obj = arg(a, 0);
375 let key = arg(a, 1).to_js_string();
376 let desc = arg(a, 2);
377 apply_define_property(it, &obj, &key, &desc);
378 Ok(obj)
379}
380
381pub(crate) fn object_define_properties(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
382 let obj = arg(a, 0);
383 let descs = arg(a, 1);
384 if let Value::Object(d) = &descs {
385 let keys: alloc::vec::Vec<String> = d.borrow().props.keys().map(Clone::clone).collect();
386 for key in keys {
387 let desc = obj_prop(&descs, &key).unwrap_or(Value::Undefined);
388 apply_define_property(it, &obj, &key, &desc);
389 }
390 }
391 Ok(obj)
392}
393
394pub(crate) fn make_property_descriptor(obj: &super::super::value::ObjRef, key: &str) -> Value {
395 let obj = unwrap_proxy_target(obj);
396 let b = obj.borrow();
397 let attr = b.attrs.get(key).copied().unwrap_or_default();
398
399 if let ObjKind::Array(items) = &b.kind {
400 if key == "length" {
401 let desc = Obj::plain();
402 desc.borrow_mut().props.insert("value".into(), Value::Number(items.len() as f64));
403 desc.borrow_mut().props.insert("writable".into(), Value::Bool(true));
404 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(false));
405 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(false));
406 return Value::Object(desc);
407 }
408 if let Ok(idx) = key.parse::<usize>() {
409 if let Some(v) = items.get(idx) {
410 let desc = Obj::plain();
411 desc.borrow_mut().props.insert("value".into(), v.clone());
412 desc.borrow_mut().props.insert("writable".into(), Value::Bool(true));
413 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(true));
414 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(true));
415 return Value::Object(desc);
416 }
417 return Value::Undefined;
418 }
419 }
420 if let Some(acc) = b.accessors.get(key) {
421 let desc = Obj::plain();
422 if let Some(g) = &acc.get {
423 desc.borrow_mut().props.insert("get".into(), g.clone());
424 } else {
425 desc.borrow_mut().props.insert("get".into(), Value::Undefined);
426 }
427 if let Some(s) = &acc.set {
428 desc.borrow_mut().props.insert("set".into(), s.clone());
429 } else {
430 desc.borrow_mut().props.insert("set".into(), Value::Undefined);
431 }
432 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(attr.enumerable));
433 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(attr.configurable));
434 Value::Object(desc)
435 } else if let Some(v) = b.props.get(key) {
436 let desc = Obj::plain();
437 desc.borrow_mut().props.insert("value".into(), v.clone());
438 desc.borrow_mut().props.insert("writable".into(), Value::Bool(attr.writable));
439 desc.borrow_mut().props.insert("enumerable".into(), Value::Bool(attr.enumerable));
440 desc.borrow_mut().props.insert("configurable".into(), Value::Bool(attr.configurable));
441 Value::Object(desc)
442 } else {
443 Value::Undefined
444 }
445}
446
447pub(crate) fn object_get_own_property_descriptor(
448 _it: &mut Interp,
449 _t: Value,
450 a: &[Value],
451) -> Result<Value, Value> {
452 let Value::Object(o) = arg(a, 0) else { return Ok(Value::Undefined) };
453 let key = arg(a, 1).to_js_string();
454 Ok(make_property_descriptor(&o, &key))
455}
456
457pub(crate) fn object_get_own_property_descriptors(
458 _it: &mut Interp,
459 _t: Value,
460 a: &[Value],
461) -> Result<Value, Value> {
462 let Value::Object(o) = arg(a, 0) else { return Ok(Value::Object(Obj::plain())) };
463 let result = Obj::plain();
464 let keys: alloc::vec::Vec<String> = {
465 let b = o.borrow();
466 if let ObjKind::Array(items) = &b.kind {
467 let mut ks: alloc::vec::Vec<String> = (0..items.len()).map(|i| i.to_string()).collect();
468 ks.push(String::from("length"));
469 ks
470 } else {
471 let mut ks: alloc::vec::Vec<String> = b.props.keys().map(Clone::clone).collect();
472 for k in b.accessors.keys() {
473 if !ks.contains(k) {
474 ks.push(k.clone());
475 }
476 }
477 ks
478 }
479 };
480 for key in keys {
481 let desc = make_property_descriptor(&o, &key);
482 result.borrow_mut().props.insert(key, desc);
483 }
484 Ok(Value::Object(result))
485}
486
487pub(crate) fn number_is_integer(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
489 Ok(Value::Bool(match arg(a, 0) {
490 Value::Number(x) => x.is_finite() && libm::floor(x) == x,
491 _ => false,
492 }))
493}
494pub(crate) fn number_is_safe_integer(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
495 Ok(Value::Bool(match arg(a, 0) {
496 Value::Number(x) => {
497 x.is_finite() && libm::floor(x) == x && libm::fabs(x) <= 9007199254740991.0
498 }
499 _ => false,
500 }))
501}
502pub(crate) fn number_is_finite_static(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
503 Ok(Value::Bool(
504 matches!(arg(a, 0), Value::Number(x) if x.is_finite()),
505 ))
506}
507pub(crate) fn number_is_nan_static(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
508 Ok(Value::Bool(
509 matches!(arg(a, 0), Value::Number(x) if x.is_nan()),
510 ))
511}
512