1use super::*;
2use crate::builtins::number::{f64_to_int32, f64_to_uint32, Number};
3
4impl JsValue {
5 #[inline]
6 pub fn add(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
7 Ok(match (self, other) {
8 (Self::Integer(x), Self::Integer(y)) => Self::new(f64::from(*x) + f64::from(*y)),
10 (Self::Rational(x), Self::Rational(y)) => Self::new(x + y),
11 (Self::Integer(x), Self::Rational(y)) => Self::new(f64::from(*x) + y),
12 (Self::Rational(x), Self::Integer(y)) => Self::new(x + f64::from(*y)),
13
14 (Self::String(ref x), Self::String(ref y)) => Self::from(JsString::concat(x, y)),
15 (Self::String(ref x), y) => Self::from(JsString::concat(x, y.to_string(context)?)),
16 (x, Self::String(ref y)) => Self::from(JsString::concat(x.to_string(context)?, y)),
17 (Self::BigInt(ref x), Self::BigInt(ref y)) => Self::new(JsBigInt::add(x, y)),
18
19 (_, _) => match (
21 self.to_primitive(context, PreferredType::Default)?,
22 other.to_primitive(context, PreferredType::Default)?,
23 ) {
24 (Self::String(ref x), ref y) => {
25 Self::from(JsString::concat(x, y.to_string(context)?))
26 }
27 (ref x, Self::String(ref y)) => {
28 Self::from(JsString::concat(x.to_string(context)?, y))
29 }
30 (x, y) => match (x.to_numeric(context)?, y.to_numeric(context)?) {
31 (Numeric::Number(x), Numeric::Number(y)) => Self::new(x + y),
32 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
33 Self::new(JsBigInt::add(x, y))
34 }
35 (_, _) => {
36 return context.throw_type_error(
37 "cannot mix BigInt and other types, use explicit conversions",
38 )
39 }
40 },
41 },
42 })
43 }
44
45 #[inline]
46 pub fn sub(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
47 Ok(match (self, other) {
48 (Self::Integer(x), Self::Integer(y)) => Self::new(f64::from(*x) - f64::from(*y)),
50 (Self::Rational(x), Self::Rational(y)) => Self::new(x - y),
51 (Self::Integer(x), Self::Rational(y)) => Self::new(f64::from(*x) - y),
52 (Self::Rational(x), Self::Integer(y)) => Self::new(x - f64::from(*y)),
53
54 (Self::BigInt(ref x), Self::BigInt(ref y)) => Self::new(JsBigInt::sub(x, y)),
55
56 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
58 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a - b),
59 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => Self::new(JsBigInt::sub(x, y)),
60 (_, _) => {
61 return context.throw_type_error(
62 "cannot mix BigInt and other types, use explicit conversions",
63 );
64 }
65 },
66 })
67 }
68
69 #[inline]
70 pub fn mul(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
71 Ok(match (self, other) {
72 (Self::Integer(x), Self::Integer(y)) => Self::new(f64::from(*x) * f64::from(*y)),
74 (Self::Rational(x), Self::Rational(y)) => Self::new(x * y),
75 (Self::Integer(x), Self::Rational(y)) => Self::new(f64::from(*x) * y),
76 (Self::Rational(x), Self::Integer(y)) => Self::new(x * f64::from(*y)),
77
78 (Self::BigInt(ref x), Self::BigInt(ref y)) => Self::new(JsBigInt::mul(x, y)),
79
80 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
82 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a * b),
83 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => Self::new(JsBigInt::mul(x, y)),
84 (_, _) => {
85 return context.throw_type_error(
86 "cannot mix BigInt and other types, use explicit conversions",
87 );
88 }
89 },
90 })
91 }
92
93 #[inline]
94 pub fn div(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
95 Ok(match (self, other) {
96 (Self::Integer(x), Self::Integer(y)) => Self::new(f64::from(*x) / f64::from(*y)),
98 (Self::Rational(x), Self::Rational(y)) => Self::new(x / y),
99 (Self::Integer(x), Self::Rational(y)) => Self::new(f64::from(*x) / y),
100 (Self::Rational(x), Self::Integer(y)) => Self::new(x / f64::from(*y)),
101
102 (Self::BigInt(ref x), Self::BigInt(ref y)) => {
103 if y.is_zero() {
104 return context.throw_range_error("BigInt division by zero");
105 }
106 Self::new(JsBigInt::div(x, y))
107 }
108
109 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
111 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a / b),
112 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
113 if y.is_zero() {
114 return context.throw_range_error("BigInt division by zero");
115 }
116 Self::new(JsBigInt::div(x, y))
117 }
118 (_, _) => {
119 return context.throw_type_error(
120 "cannot mix BigInt and other types, use explicit conversions",
121 );
122 }
123 },
124 })
125 }
126
127 #[inline]
128 pub fn rem(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
129 Ok(match (self, other) {
130 (Self::Integer(x), Self::Integer(y)) => {
132 if *y == 0 {
133 Self::nan()
134 } else {
135 match x % *y {
136 rem if rem == 0 && *x < 0 => Self::new(-0.0),
137 rem => Self::new(rem),
138 }
139 }
140 }
141 (Self::Rational(x), Self::Rational(y)) => Self::new((x % y).copysign(*x)),
142 (Self::Integer(x), Self::Rational(y)) => {
143 let x = f64::from(*x);
144 Self::new((x % y).copysign(x))
145 }
146
147 (Self::Rational(x), Self::Integer(y)) => Self::new((x % f64::from(*y)).copysign(*x)),
148
149 (Self::BigInt(ref x), Self::BigInt(ref y)) => {
150 if y.is_zero() {
151 return context.throw_range_error("BigInt division by zero");
152 }
153 Self::new(JsBigInt::rem(x, y))
154 }
155
156 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
158 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a % b),
159 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
160 if y.is_zero() {
161 return context.throw_range_error("BigInt division by zero");
162 }
163 Self::new(JsBigInt::rem(x, y))
164 }
165 (_, _) => {
166 return context.throw_type_error(
167 "cannot mix BigInt and other types, use explicit conversions",
168 );
169 }
170 },
171 })
172 }
173
174 #[inline]
175 pub fn pow(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
176 Ok(match (self, other) {
177 (Self::Integer(x), Self::Integer(y)) => Self::new(f64::from(*x).powi(*y)),
179 (Self::Rational(x), Self::Rational(y)) => Self::new(x.powf(*y)),
180 (Self::Integer(x), Self::Rational(y)) => Self::new(f64::from(*x).powf(*y)),
181 (Self::Rational(x), Self::Integer(y)) => Self::new(x.powi(*y)),
182
183 (Self::BigInt(ref a), Self::BigInt(ref b)) => Self::new(JsBigInt::pow(a, b, context)?),
184
185 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
187 (Numeric::Number(a), Numeric::Number(b)) => Self::new(a.powf(b)),
188 (Numeric::BigInt(ref a), Numeric::BigInt(ref b)) => {
189 Self::new(JsBigInt::pow(a, b, context)?)
190 }
191 (_, _) => {
192 return context.throw_type_error(
193 "cannot mix BigInt and other types, use explicit conversions",
194 );
195 }
196 },
197 })
198 }
199
200 #[inline]
201 pub fn bitand(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
202 Ok(match (self, other) {
203 (Self::Integer(x), Self::Integer(y)) => Self::new(x & y),
205 (Self::Rational(x), Self::Rational(y)) => {
206 Self::new(f64_to_int32(*x) & f64_to_int32(*y))
207 }
208 (Self::Integer(x), Self::Rational(y)) => Self::new(x & f64_to_int32(*y)),
209 (Self::Rational(x), Self::Integer(y)) => Self::new(f64_to_int32(*x) & y),
210
211 (Self::BigInt(ref x), Self::BigInt(ref y)) => Self::new(JsBigInt::bitand(x, y)),
212
213 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
215 (Numeric::Number(a), Numeric::Number(b)) => {
216 Self::new(f64_to_int32(a) & f64_to_int32(b))
217 }
218 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
219 Self::new(JsBigInt::bitand(x, y))
220 }
221 (_, _) => {
222 return context.throw_type_error(
223 "cannot mix BigInt and other types, use explicit conversions",
224 );
225 }
226 },
227 })
228 }
229
230 #[inline]
231 pub fn bitor(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
232 Ok(match (self, other) {
233 (Self::Integer(x), Self::Integer(y)) => Self::new(x | y),
235 (Self::Rational(x), Self::Rational(y)) => {
236 Self::new(f64_to_int32(*x) | f64_to_int32(*y))
237 }
238 (Self::Integer(x), Self::Rational(y)) => Self::new(x | f64_to_int32(*y)),
239 (Self::Rational(x), Self::Integer(y)) => Self::new(f64_to_int32(*x) | y),
240
241 (Self::BigInt(ref x), Self::BigInt(ref y)) => Self::new(JsBigInt::bitor(x, y)),
242
243 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
245 (Numeric::Number(a), Numeric::Number(b)) => {
246 Self::new(f64_to_int32(a) | f64_to_int32(b))
247 }
248 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
249 Self::new(JsBigInt::bitor(x, y))
250 }
251 (_, _) => {
252 return context.throw_type_error(
253 "cannot mix BigInt and other types, use explicit conversions",
254 );
255 }
256 },
257 })
258 }
259
260 #[inline]
261 pub fn bitxor(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
262 Ok(match (self, other) {
263 (Self::Integer(x), Self::Integer(y)) => Self::new(x ^ y),
265 (Self::Rational(x), Self::Rational(y)) => {
266 Self::new(f64_to_int32(*x) ^ f64_to_int32(*y))
267 }
268 (Self::Integer(x), Self::Rational(y)) => Self::new(x ^ f64_to_int32(*y)),
269 (Self::Rational(x), Self::Integer(y)) => Self::new(f64_to_int32(*x) ^ y),
270
271 (Self::BigInt(ref x), Self::BigInt(ref y)) => Self::new(JsBigInt::bitxor(x, y)),
272
273 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
275 (Numeric::Number(a), Numeric::Number(b)) => {
276 Self::new(f64_to_int32(a) ^ f64_to_int32(b))
277 }
278 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
279 Self::new(JsBigInt::bitxor(x, y))
280 }
281 (_, _) => {
282 return context.throw_type_error(
283 "cannot mix BigInt and other types, use explicit conversions",
284 );
285 }
286 },
287 })
288 }
289
290 #[inline]
291 pub fn shl(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
292 Ok(match (self, other) {
293 (Self::Integer(x), Self::Integer(y)) => Self::new(x.wrapping_shl(*y as u32)),
295 (Self::Rational(x), Self::Rational(y)) => {
296 Self::new(f64_to_int32(*x).wrapping_shl(f64_to_uint32(*y)))
297 }
298 (Self::Integer(x), Self::Rational(y)) => Self::new(x.wrapping_shl(f64_to_uint32(*y))),
299 (Self::Rational(x), Self::Integer(y)) => {
300 Self::new(f64_to_int32(*x).wrapping_shl(*y as u32))
301 }
302
303 (Self::BigInt(ref a), Self::BigInt(ref b)) => {
304 Self::new(JsBigInt::shift_left(a, b, context)?)
305 }
306
307 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
309 (Numeric::Number(x), Numeric::Number(y)) => {
310 Self::new(f64_to_int32(x).wrapping_shl(f64_to_uint32(y)))
311 }
312 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
313 Self::new(JsBigInt::shift_left(x, y, context)?)
314 }
315 (_, _) => {
316 return context.throw_type_error(
317 "cannot mix BigInt and other types, use explicit conversions",
318 );
319 }
320 },
321 })
322 }
323
324 #[inline]
325 pub fn shr(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
326 Ok(match (self, other) {
327 (Self::Integer(x), Self::Integer(y)) => Self::new(x.wrapping_shr(*y as u32)),
329 (Self::Rational(x), Self::Rational(y)) => {
330 Self::new(f64_to_int32(*x).wrapping_shr(f64_to_uint32(*y)))
331 }
332 (Self::Integer(x), Self::Rational(y)) => Self::new(x.wrapping_shr(f64_to_uint32(*y))),
333 (Self::Rational(x), Self::Integer(y)) => {
334 Self::new(f64_to_int32(*x).wrapping_shr(*y as u32))
335 }
336
337 (Self::BigInt(ref a), Self::BigInt(ref b)) => {
338 Self::new(JsBigInt::shift_right(a, b, context)?)
339 }
340
341 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
343 (Numeric::Number(x), Numeric::Number(y)) => {
344 Self::new(f64_to_int32(x).wrapping_shr(f64_to_uint32(y)))
345 }
346 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => {
347 Self::new(JsBigInt::shift_right(x, y, context)?)
348 }
349 (_, _) => {
350 return context.throw_type_error(
351 "cannot mix BigInt and other types, use explicit conversions",
352 );
353 }
354 },
355 })
356 }
357
358 #[inline]
359 pub fn ushr(&self, other: &Self, context: &mut Context) -> JsResult<JsValue> {
360 Ok(match (self, other) {
361 (Self::Integer(x), Self::Integer(y)) => Self::new((*x as u32).wrapping_shr(*y as u32)),
363 (Self::Rational(x), Self::Rational(y)) => {
364 Self::new(f64_to_uint32(*x).wrapping_shr(f64_to_uint32(*y)))
365 }
366 (Self::Integer(x), Self::Rational(y)) => {
367 Self::new((*x as u32).wrapping_shr(f64_to_uint32(*y)))
368 }
369 (Self::Rational(x), Self::Integer(y)) => {
370 Self::new(f64_to_uint32(*x).wrapping_shr(*y as u32))
371 }
372
373 (_, _) => match (self.to_numeric(context)?, other.to_numeric(context)?) {
375 (Numeric::Number(x), Numeric::Number(y)) => {
376 Self::new(f64_to_uint32(x).wrapping_shr(f64_to_uint32(y)))
377 }
378 (Numeric::BigInt(_), Numeric::BigInt(_)) => {
379 return context
380 .throw_type_error("BigInts have no unsigned right shift, use >> instead");
381 }
382 (_, _) => {
383 return context.throw_type_error(
384 "cannot mix BigInt and other types, use explicit conversions",
385 );
386 }
387 },
388 })
389 }
390
391 #[inline]
392 pub fn neg(&self, context: &mut Context) -> JsResult<JsValue> {
393 Ok(match *self {
394 Self::Symbol(_) | Self::Undefined => Self::new(f64::NAN),
395 Self::Object(_) => Self::new(match self.to_numeric_number(context) {
396 Ok(num) => -num,
397 Err(_) => f64::NAN,
398 }),
399 Self::String(ref str) => Self::new(match f64::from_str(str) {
400 Ok(num) => -num,
401 Err(_) => f64::NAN,
402 }),
403 Self::Rational(num) => Self::new(-num),
404 Self::Integer(num) if num == 0 => Self::new(-f64::from(0)),
405 Self::Integer(num) => Self::new(-num),
406 Self::Boolean(true) => Self::new(1),
407 Self::Boolean(false) | Self::Null => Self::new(0),
408 Self::BigInt(ref x) => Self::new(JsBigInt::neg(x)),
409 })
410 }
411
412 #[inline]
413 pub fn not(&self, _: &mut Context) -> JsResult<bool> {
414 Ok(!self.to_boolean())
415 }
416
417 pub fn abstract_relation(
435 &self,
436 other: &Self,
437 left_first: bool,
438 context: &mut Context,
439 ) -> JsResult<AbstractRelation> {
440 Ok(match (self, other) {
441 (Self::Integer(x), Self::Integer(y)) => (x < y).into(),
443 (Self::Integer(x), Self::Rational(y)) => Number::less_than(f64::from(*x), *y),
444 (Self::Rational(x), Self::Integer(y)) => Number::less_than(*x, f64::from(*y)),
445 (Self::Rational(x), Self::Rational(y)) => Number::less_than(*x, *y),
446 (Self::BigInt(ref x), Self::BigInt(ref y)) => (x < y).into(),
447
448 (_, _) => {
450 let (px, py) = if left_first {
451 let px = self.to_primitive(context, PreferredType::Number)?;
452 let py = other.to_primitive(context, PreferredType::Number)?;
453 (px, py)
454 } else {
455 let py = other.to_primitive(context, PreferredType::Number)?;
457 let px = self.to_primitive(context, PreferredType::Number)?;
458 (px, py)
459 };
460
461 match (px, py) {
462 (Self::String(ref x), Self::String(ref y)) => {
463 if x.starts_with(y.as_str()) {
464 return Ok(AbstractRelation::False);
465 }
466 if y.starts_with(x.as_str()) {
467 return Ok(AbstractRelation::True);
468 }
469 for (x, y) in x.chars().zip(y.chars()) {
470 if x != y {
471 return Ok((x < y).into());
472 }
473 }
474 unreachable!()
475 }
476 (Self::BigInt(ref x), Self::String(ref y)) => {
477 if let Some(y) = JsBigInt::from_string(y) {
478 (*x < y).into()
479 } else {
480 AbstractRelation::Undefined
481 }
482 }
483 (Self::String(ref x), Self::BigInt(ref y)) => {
484 if let Some(x) = JsBigInt::from_string(x) {
485 (x < *y).into()
486 } else {
487 AbstractRelation::Undefined
488 }
489 }
490 (px, py) => match (px.to_numeric(context)?, py.to_numeric(context)?) {
491 (Numeric::Number(x), Numeric::Number(y)) => Number::less_than(x, y),
492 (Numeric::BigInt(ref x), Numeric::BigInt(ref y)) => (x < y).into(),
493 (Numeric::BigInt(ref x), Numeric::Number(y)) => {
494 if y.is_nan() {
495 return Ok(AbstractRelation::Undefined);
496 }
497 if y.is_infinite() {
498 return Ok(y.is_sign_positive().into());
499 }
500 let n = if y.is_sign_negative() {
501 y.floor()
502 } else {
503 y.ceil()
504 };
505 (*x < JsBigInt::try_from(n).unwrap()).into()
506 }
507 (Numeric::Number(x), Numeric::BigInt(ref y)) => {
508 if x.is_nan() {
509 return Ok(AbstractRelation::Undefined);
510 }
511 if x.is_infinite() {
512 return Ok(x.is_sign_negative().into());
513 }
514 let n = if x.is_sign_negative() {
515 x.floor()
516 } else {
517 x.ceil()
518 };
519 (JsBigInt::try_from(n).unwrap() < *y).into()
520 }
521 },
522 }
523 }
524 })
525 }
526
527 #[inline]
537 pub fn lt(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
538 match self.abstract_relation(other, true, context)? {
539 AbstractRelation::True => Ok(true),
540 AbstractRelation::False | AbstractRelation::Undefined => Ok(false),
541 }
542 }
543
544 #[inline]
554 pub fn le(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
555 match other.abstract_relation(self, false, context)? {
556 AbstractRelation::False => Ok(true),
557 AbstractRelation::True | AbstractRelation::Undefined => Ok(false),
558 }
559 }
560
561 #[inline]
571 pub fn gt(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
572 match other.abstract_relation(self, false, context)? {
573 AbstractRelation::True => Ok(true),
574 AbstractRelation::False | AbstractRelation::Undefined => Ok(false),
575 }
576 }
577
578 #[inline]
588 pub fn ge(&self, other: &Self, context: &mut Context) -> JsResult<bool> {
589 match self.abstract_relation(other, true, context)? {
590 AbstractRelation::False => Ok(true),
591 AbstractRelation::True | AbstractRelation::Undefined => Ok(false),
592 }
593 }
594}
595
596#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
604pub enum AbstractRelation {
605 True,
607 False,
609 Undefined,
611}
612
613impl From<bool> for AbstractRelation {
614 #[inline]
615 fn from(value: bool) -> Self {
616 if value {
617 AbstractRelation::True
618 } else {
619 AbstractRelation::False
620 }
621 }
622}