1use super::*;
5
6impl Interp {
7 pub(crate) fn eval_unary(
8 &mut self,
9 op: &UnaryOp,
10 expr: &Expression,
11 scope: &Rc<RefCell<Scope>>,
12 this: &Value,
13 ) -> EvalResult {
14 if let UnaryOp::TypeOf = op {
16 if let Expression::Identifier(name) = expr {
17 let on_window = || match scope_get(scope, "window") {
21 Some(Value::Object(w)) => w.borrow().props.contains_key(name.as_str()),
22 _ => false,
23 };
24 if scope_get(scope, name).is_none() && !on_window() {
25 return Ok(Value::str("undefined"));
26 }
27 }
28 }
29 if let UnaryOp::Delete = op {
32 return self.eval_delete(expr, scope, this);
33 }
34 let v = self.eval(expr, scope, this)?;
35 Ok(match op {
36 UnaryOp::Neg => match &v {
37 Value::BigInt(b) => Value::bigint(b.neg()),
38 _ => Value::Number(-v.to_number()),
39 },
40 UnaryOp::Pos => {
41 if matches!(v, Value::BigInt(_)) {
43 return Err(self.throw("Cannot convert a BigInt to a number"));
44 }
45 Value::Number(v.to_number())
46 }
47 UnaryOp::Not => Value::Bool(!v.truthy()),
48 UnaryOp::BitNot => match &v {
49 Value::BigInt(b) => Value::bigint(b.bitnot()),
50 _ => Value::Number(!(to_i32(v.to_number())) as f64),
51 },
52 UnaryOp::TypeOf => Value::str(v.type_of()),
53 UnaryOp::Void => Value::Undefined,
54 UnaryOp::Delete => Value::Bool(true),
56 })
57 }
58
59 pub(crate) fn eval_delete(
64 &mut self,
65 expr: &Expression,
66 scope: &Rc<RefCell<Scope>>,
67 this: &Value,
68 ) -> EvalResult {
69 match expr {
70 Expression::Member {
71 object, property, ..
72 } => {
73 let obj = self.eval(object, scope, this)?;
74 self.delete_property(&obj, property)
75 }
76 Expression::Index { object, index, .. } => {
77 let obj = self.eval(object, scope, this)?;
78 let key = self.eval(index, scope, this)?;
79 let k = to_property_key(&key);
80 self.delete_property(&obj, &k)
81 }
82 _ => Ok(Value::Bool(true)),
83 }
84 }
85
86 pub(crate) fn delete_property(&mut self, obj: &Value, property: &str) -> EvalResult {
91 if let Value::Object(o) = obj {
92 let proxy = match &o.borrow().kind {
98 ObjKind::Proxy { target, handler } => Some((target.clone(), handler.clone())),
99 _ => None,
100 };
101 if let Some((target, handler)) = proxy {
102 let trap = handler.borrow().props.get("deleteProperty").cloned();
103 if let Some(trap) =
104 trap.filter(|t| matches!(t, Value::Object(f) if f.borrow().is_callable()))
105 {
106 let args = [Value::Object(target), Value::str(property)];
107 let res = self.call_value(&trap, Value::Object(handler), &args)?;
108 return Ok(Value::Bool(res.truthy()));
109 }
110 return self.delete_property(&Value::Object(target), property);
111 }
112 let dataset_idx = match &o.borrow().kind {
116 ObjKind::Host(t) if t.starts_with("dataset:") => {
117 t.strip_prefix("dataset:").and_then(|s| s.parse::<usize>().ok())
118 }
119 _ => None,
120 };
121 if let Some(idx) = dataset_idx {
122 let attr = camel_to_data_attr(property);
123 self.dom.borrow_mut().remove_attr(idx, &attr);
124 return Ok(Value::Bool(true));
125 }
126 let style_idx = match &o.borrow().kind {
130 ObjKind::Host(t) if t.starts_with("style:") => {
131 t.strip_prefix("style:").and_then(|s| s.parse::<usize>().ok())
132 }
133 _ => None,
134 };
135 if let Some(idx) = style_idx {
136 self.dom.borrow_mut().set_style(idx, property, "");
137 return Ok(Value::Bool(true));
138 }
139 let storage_tag = match &o.borrow().kind {
142 ObjKind::Host(t) if t.starts_with("storage:") => Some(t.clone()),
143 _ => None,
144 };
145 if let Some(tag) = storage_tag {
146 super::super::builtins::storage_remove_prop(&tag, property);
147 return Ok(Value::Bool(true));
148 }
149 if let Some(attr) = o.borrow().attrs.get(property) {
151 if !attr.configurable {
152 return Ok(Value::Bool(false));
153 }
154 }
155 if o.borrow().frozen || o.borrow().sealed {
157 return Ok(Value::Bool(false));
158 }
159 let is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
160 if is_array {
161 if let Ok(idx) = property.parse::<usize>() {
165 if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
166 if idx < items.len() {
167 items[idx] = Value::Undefined;
168 }
169 }
170 }
171 } else {
172 let mut b = o.borrow_mut();
173 if let Some(attr) = b.attrs.get(property) {
174 if !attr.configurable {
175 return Ok(Value::Bool(false));
176 }
177 }
178 b.props.shift_remove(property);
179 b.accessors.shift_remove(property);
180 b.attrs.shift_remove(property);
181 }
182 }
183 Ok(Value::Bool(true))
184 }
185
186 pub(crate) fn eval_update(
187 &mut self,
188 op: &str,
189 prefix: bool,
190 target: &Expression,
191 scope: &Rc<RefCell<Scope>>,
192 this: &Value,
193 ) -> EvalResult {
194 let lref: Option<(Value, String)> = match target {
196 Expression::Member { object, property, .. } if !matches!(**object, Expression::Super) => {
197 Some((self.eval(object, scope, this)?, property.clone()))
198 }
199 Expression::Index { object, index, .. } if !matches!(**object, Expression::Super) => {
200 let o = self.eval(object, scope, this)?;
201 let k = self.eval(index, scope, this)?;
202 Some((o, to_property_key(&k)))
203 }
204 _ => None,
205 };
206 let old = match &lref {
207 Some((o, k)) => self.get_property(o, k)?,
208 None => self.eval(target, scope, this)?,
209 }
210 .to_number();
211 let new = if op == "++" { old + 1.0 } else { old - 1.0 };
212 match &lref {
213 Some((o, k)) => {
214 self.set_property(o, k, Value::Number(new));
215 }
216 None => self.assign_to(target, Value::Number(new), scope, this)?,
217 }
218 Ok(Value::Number(if prefix { new } else { old }))
219 }
220
221 pub(crate) fn eval_assign(
222 &mut self,
223 op: &str,
224 target: &Expression,
225 value: &Expression,
226 scope: &Rc<RefCell<Scope>>,
227 this: &Value,
228 ) -> EvalResult {
229 let lref: Option<(Value, String)> = match target {
241 Expression::Member { object, property, .. } if !matches!(**object, Expression::Super) => {
242 Some((self.eval(object, scope, this)?, property.clone()))
243 }
244 Expression::Index { object, index, .. } if !matches!(**object, Expression::Super) => {
245 let o = self.eval(object, scope, this)?;
246 let k = self.eval(index, scope, this)?;
247 Some((o, to_property_key(&k)))
248 }
249 _ => None,
250 };
251 match op {
252 "&&=" | "||=" | "??=" => {
253 let cur = match &lref {
254 Some((o, k)) => self.get_property(o, k)?,
255 None => self.eval(target, scope, this)?,
256 };
257 let assign = match op {
258 "&&=" => cur.truthy(),
259 "||=" => !cur.truthy(),
260 _ => matches!(cur, Value::Undefined | Value::Null),
261 };
262 return if assign {
263 let v = self.eval(value, scope, this)?;
264 match &lref {
265 Some((o, k)) => {
266 self.set_property(o, k, v.clone());
267 }
268 None => self.assign_to(target, v.clone(), scope, this)?,
269 }
270 Ok(v)
271 } else {
272 Ok(cur)
273 };
274 }
275 _ => {}
276 }
277 let cur = if op == "=" {
279 None
280 } else {
281 Some(match &lref {
282 Some((o, k)) => self.get_property(o, k)?,
283 None => self.eval(target, scope, this)?,
284 })
285 };
286 let rhs = self.eval(value, scope, this)?;
287 if op == "=" {
288 match target {
289 Expression::Identifier(n) => super::infer_function_name(&rhs, n),
291 Expression::Member { property, .. } => {
294 if let Value::Object(o) = &rhs {
295 let anon = matches!(&o.borrow().kind, ObjKind::Function(fd) if fd.name.is_empty());
296 if anon {
297 o.borrow_mut().props.insert("_diag_name".into(), Value::str(property.as_str()));
298 }
299 }
300 }
301 _ => {}
302 }
303 }
304 let final_val = if let Some(cur) = cur {
305 let bop = match op {
306 "+=" => BinaryOp::Add,
307 "-=" => BinaryOp::Sub,
308 "*=" => BinaryOp::Mul,
309 "/=" => BinaryOp::Div,
310 "%=" => BinaryOp::Mod,
311 "**=" => BinaryOp::Pow,
312 "&=" => BinaryOp::BitAnd,
313 "|=" => BinaryOp::BitOr,
314 "^=" => BinaryOp::BitXor,
315 "<<=" => BinaryOp::Shl,
316 ">>=" => BinaryOp::Shr,
317 ">>>=" => BinaryOp::UShr,
318 _ => BinaryOp::Add,
319 };
320 self.eval_binary(&bop, cur, rhs)?
321 } else {
322 rhs
323 };
324 match &lref {
325 Some((o, k)) => {
326 self.set_property(o, k, final_val.clone());
327 }
328 None => self.assign_to(target, final_val.clone(), scope, this)?,
329 }
330 Ok(final_val)
331 }
332
333 pub(crate) fn assign_to(
335 &mut self,
336 target: &Expression,
337 val: Value,
338 scope: &Rc<RefCell<Scope>>,
339 this: &Value,
340 ) -> Result<(), Value> {
341 match target {
342 Expression::Identifier(name) => {
343 if !scope_assign(scope, name, val.clone()) {
344 let mut s = scope.clone();
346 loop {
347 let p = s.borrow().parent.clone();
348 match p {
349 Some(pp) => s = pp,
350 None => break,
351 }
352 }
353 scope_declare(&s, name, val);
354 }
355 Ok(())
356 }
357 Expression::Member {
358 object, property, ..
359 } => {
360 let obj = self.eval(object, scope, this)?;
361 self.set_property(&obj, property, val);
362 Ok(())
363 }
364 Expression::Index { object, index, .. } => {
365 let obj = self.eval(object, scope, this)?;
366 let key = self.eval(index, scope, this)?;
367 self.set_property(&obj, &to_property_key(&key), val);
368 Ok(())
369 }
370 _ => Ok(()),
371 }
372 }
373
374 pub(crate) fn to_primitive(&mut self, v: Value, hint: &str) -> EvalResult {
381 let Value::Object(o) = &v else { return Ok(v) };
382 if !matches!(o.borrow().kind, ObjKind::Plain | ObjKind::Function(_)) {
383 return Ok(v);
384 }
385 let mut has = [false; 3];
387 let names = ["Symbol(Symbol.toPrimitive)", "toString", "valueOf"];
388 let mut cur = Some(o.clone());
389 let mut guard = 0;
390 while let Some(c) = cur {
391 {
392 let b = c.borrow();
393 for (i, n) in names.iter().enumerate() {
394 if b.props.contains_key(*n) || b.accessors.contains_key(*n) {
395 has[i] = true;
396 }
397 }
398 }
399 guard += 1;
400 if guard > 64 {
401 break;
402 }
403 cur = c.borrow().proto.clone();
404 }
405 if !has.iter().any(|&h| h) {
406 return Ok(v);
407 }
408 let is_callable = |f: &Value| matches!(f, Value::Object(x) if x.borrow().is_callable());
409 if has[0] {
410 let f = self.get_property(&v, names[0])?;
411 if is_callable(&f) {
412 let r = self.call_value(&f, v.clone(), &[Value::str(hint)])?;
413 if !matches!(r, Value::Object(_)) {
414 return Ok(r);
415 }
416 return Err(self.type_error("Cannot convert object to primitive value"));
417 }
418 }
419 let order: [&str; 2] = if hint == "string" { ["toString", "valueOf"] } else { ["valueOf", "toString"] };
420 for name in order {
421 let f = self.get_property(&v, name)?;
422 if is_callable(&f) {
423 let r = self.call_value(&f, v.clone(), &[])?;
424 if !matches!(r, Value::Object(_)) {
425 return Ok(r);
426 }
427 }
428 }
429 Ok(v)
430 }
431
432 pub(crate) fn to_string_value(&mut self, v: Value) -> Result<String, Value> {
434 Ok(self.to_primitive(v, "string")?.to_js_string())
435 }
436
437 pub fn eval_binary(&mut self, op: &BinaryOp, l: Value, r: Value) -> EvalResult {
438 let (l, r) = if matches!(op, BinaryOp::Add) && (matches!(l, Value::Object(_)) || matches!(r, Value::Object(_))) {
440 (self.to_primitive(l, "default")?, self.to_primitive(r, "default")?)
441 } else {
442 (l, r)
443 };
444 if matches!(l, Value::BigInt(_)) || matches!(r, Value::BigInt(_)) {
446 return self.eval_binary_bigint(op, l, r);
447 }
448 Ok(match op {
449 BinaryOp::Add => {
450 let l_str = matches!(l, Value::Str(_) | Value::Object(_));
452 let r_str = matches!(r, Value::Str(_) | Value::Object(_));
453 if l_str || r_str {
454 Value::str(format!("{}{}", l.to_js_string(), r.to_js_string()))
455 } else {
456 Value::Number(l.to_number() + r.to_number())
457 }
458 }
459 BinaryOp::Sub => Value::Number(l.to_number() - r.to_number()),
460 BinaryOp::Mul => Value::Number(l.to_number() * r.to_number()),
461 BinaryOp::Div => Value::Number(l.to_number() / r.to_number()),
462 BinaryOp::Mod => {
463 let a = l.to_number();
464 let b = r.to_number();
465 Value::Number(if b == 0.0 { f64::NAN } else { a % b })
466 }
467 BinaryOp::Pow => Value::Number(powf(l.to_number(), r.to_number())),
468 BinaryOp::Eq => Value::Bool(loose_eq(&l, &r)),
469 BinaryOp::NotEq => Value::Bool(!loose_eq(&l, &r)),
470 BinaryOp::StrictEq => Value::Bool(l.strict_eq(&r)),
471 BinaryOp::StrictNotEq => Value::Bool(!l.strict_eq(&r)),
472 BinaryOp::Lt => cmp(&l, &r, |o| o == core::cmp::Ordering::Less),
473 BinaryOp::Gt => cmp(&l, &r, |o| o == core::cmp::Ordering::Greater),
474 BinaryOp::LtEq => cmp(&l, &r, |o| o != core::cmp::Ordering::Greater),
475 BinaryOp::GtEq => cmp(&l, &r, |o| o != core::cmp::Ordering::Less),
476 BinaryOp::BitAnd => {
477 Value::Number((to_i32(l.to_number()) & to_i32(r.to_number())) as f64)
478 }
479 BinaryOp::BitOr => {
480 Value::Number((to_i32(l.to_number()) | to_i32(r.to_number())) as f64)
481 }
482 BinaryOp::BitXor => {
483 Value::Number((to_i32(l.to_number()) ^ to_i32(r.to_number())) as f64)
484 }
485 BinaryOp::Shl => Value::Number(
486 (to_i32(l.to_number()).wrapping_shl(to_u32(r.to_number()) & 31)) as f64,
487 ),
488 BinaryOp::Shr => Value::Number(
489 (to_i32(l.to_number()).wrapping_shr(to_u32(r.to_number()) & 31)) as f64,
490 ),
491 BinaryOp::UShr => Value::Number(
492 ((to_u32(l.to_number())).wrapping_shr(to_u32(r.to_number()) & 31)) as f64,
493 ),
494 BinaryOp::In => {
495 let key = l.to_js_string();
496 match &r {
497 Value::Object(o) => {
498 let proxy = match &o.borrow().kind {
500 ObjKind::Proxy { target, handler } => {
501 Some((target.clone(), handler.clone()))
502 }
503 _ => None,
504 };
505 if let Some((target, handler)) = proxy {
506 let trap = handler.borrow().props.get("has").cloned();
507 if let Some(trap) = trap.filter(
508 |t| matches!(t, Value::Object(f) if f.borrow().is_callable()),
509 ) {
510 let args = [Value::Object(target), Value::str(&key)];
511 let res = self.call_value(&trap, Value::Object(handler), &args)?;
512 return Ok(Value::Bool(res.truthy()));
513 }
514 return self.eval_binary(&BinaryOp::In, l, Value::Object(target));
515 }
516 if self.has_property_chain(o, &key) {
517 return Ok(Value::Bool(true));
518 }
519 let is_dom = matches!(o.borrow().kind, ObjKind::DomElement(_));
523 if is_dom {
524 let v = self.get_property(&r, &key)?;
525 return Ok(Value::Bool(!matches!(v, Value::Undefined)));
526 }
527 Value::Bool(false)
528 }
529 _ => Value::Bool(false),
530 }
531 }
532 BinaryOp::InstanceOf => self.instance_of(&l, &r)?,
533 })
534 }
535
536 pub(crate) fn get_dom_node_proto(&self, node_idx: usize) -> Option<ObjRef> {
539 if let Some(p) = self.dom.borrow().node_protos.get(&node_idx) {
541 return Some(p.clone());
542 }
543 let tag_or_text = {
544 let dom = self.dom.borrow();
545 dom.nodes.get(node_idx).map(|n| (n.tag.to_lowercase(), n.is_text))
546 }?;
547
548 let (tag, is_text) = tag_or_text;
549 let cls_name = if is_text {
553 "Text"
554 } else {
555 match tag.as_str() {
556 "#comment" => "Comment",
557 "#fragment" | "#document-fragment" => "DocumentFragment",
558 "video" => "HTMLVideoElement",
559 "audio" => "HTMLAudioElement",
560 "input" => "HTMLInputElement",
561 "form" => "HTMLFormElement",
562 "a" => "HTMLAnchorElement",
563 "img" => "HTMLImageElement",
564 "button" => "HTMLButtonElement",
565 "select" => "HTMLSelectElement",
566 "option" => "HTMLOptionElement",
567 "textarea" => "HTMLTextAreaElement",
568 "div" => "HTMLDivElement",
569 "span" => "HTMLSpanElement",
570 "script" => "HTMLScriptElement",
571 "style" => "HTMLStyleElement",
572 "iframe" => "HTMLIFrameElement",
573 "canvas" => "HTMLCanvasElement",
574 "p" => "HTMLParagraphElement",
575 "h1" | "h2" | "h3" | "h4" | "h5" | "h6" => "HTMLHeadingElement",
576 "table" => "HTMLTableElement",
577 "tr" => "HTMLTableRowElement",
578 "td" | "th" => "HTMLTableCellElement",
579 "ul" | "ol" => "HTMLUListElement",
580 "li" => "HTMLLIElement",
581 "template" => "HTMLTemplateElement",
582 _ => "HTMLUnknownElement",
583 }
584 };
585
586 let ctor_val = super::scope_get(&self.global, cls_name)?;
587 if let Value::Object(ctor_obj) = ctor_val {
588 if let Some(Value::Object(proto)) = ctor_obj.borrow().props.get("prototype") {
589 return Some(proto.clone());
590 }
591 }
592 None
593 }
594
595 pub(crate) fn instance_of(&mut self, l: &Value, r: &Value) -> EvalResult {
598 let ctor = match r {
599 Value::Object(o) if o.borrow().is_callable() => o.clone(),
600 _ => return Err(self.throw("Right-hand side of 'instanceof' is not callable")),
601 };
602 let has_instance = ctor.borrow().props.get("Symbol(Symbol.hasInstance)").cloned();
607 if let Some(f) = has_instance {
608 if matches!(&f, Value::Object(fo) if fo.borrow().is_callable()) {
609 let result = self.call_value(&f, Value::Object(ctor), core::slice::from_ref(l))?;
610 return Ok(Value::Bool(result.truthy()));
611 }
612 }
613 let proto = match ctor.borrow().props.get("prototype") {
614 Some(Value::Object(p)) => p.clone(),
615 _ => return Ok(Value::Bool(false)),
616 };
617 let mut cur = match l {
618 Value::Object(o) => {
619 let dom_idx = match o.borrow().kind {
620 ObjKind::DomElement(idx) if o.borrow().proto.is_none() => Some(idx),
621 _ => None,
622 };
623 match dom_idx {
624 Some(idx) => self.get_dom_node_proto(idx),
625 None => super::super::builtins::implicit_proto(self, o),
626 }
627 }
628 _ => None,
629 };
630 let mut guard = 0;
631 while let Some(p) = cur {
632 if Rc::ptr_eq(&p, &proto) {
633 return Ok(Value::Bool(true));
634 }
635 cur = super::super::builtins::implicit_proto(self, &p);
637 guard += 1;
638 if guard > 1000 {
639 break;
640 }
641 }
642 Ok(Value::Bool(false))
643 }
644
645 pub(crate) fn eval_binary_bigint(&mut self, op: &BinaryOp, l: Value, r: Value) -> EvalResult {
648 use super::super::bigint::BigInt;
649 if matches!(op, BinaryOp::Add) && (matches!(l, Value::Str(_)) || matches!(r, Value::Str(_)))
651 {
652 return Ok(Value::str(format!(
653 "{}{}",
654 l.to_js_string(),
655 r.to_js_string()
656 )));
657 }
658
659 match op {
661 BinaryOp::StrictEq => return Ok(Value::Bool(l.strict_eq(&r))),
662 BinaryOp::StrictNotEq => return Ok(Value::Bool(!l.strict_eq(&r))),
663 BinaryOp::Eq => return Ok(Value::Bool(self.bigint_loose_eq(&l, &r))),
664 BinaryOp::NotEq => return Ok(Value::Bool(!self.bigint_loose_eq(&l, &r))),
665 BinaryOp::Lt | BinaryOp::Gt | BinaryOp::LtEq | BinaryOp::GtEq => {
666 return Ok(self.bigint_compare(op, &l, &r));
667 }
668 BinaryOp::In | BinaryOp::InstanceOf => {
669 return Ok(Value::Bool(false));
670 }
671 _ => {}
672 }
673
674 let (a, b) = match (&l, &r) {
676 (Value::BigInt(a), Value::BigInt(b)) => (a.clone(), b.clone()),
677 _ => {
678 return Err(
679 self.throw("Cannot mix BigInt and other types, use explicit conversions")
680 );
681 }
682 };
683 let result: BigInt = match op {
684 BinaryOp::Add => a.add(&b),
685 BinaryOp::Sub => a.sub(&b),
686 BinaryOp::Mul => a.mul(&b),
687 BinaryOp::Div => match a.div(&b) {
688 Some(v) => v,
689 None => return Err(self.throw("Division by zero")),
690 },
691 BinaryOp::Mod => match a.rem(&b) {
692 Some(v) => v,
693 None => return Err(self.throw("Division by zero")),
694 },
695 BinaryOp::Pow => match a.pow(&b) {
696 Some(v) => v,
697 None => return Err(self.throw("Exponent must be non-negative")),
698 },
699 BinaryOp::BitAnd => a.bitand(&b),
700 BinaryOp::BitOr => a.bitor(&b),
701 BinaryOp::BitXor => a.bitxor(&b),
702 BinaryOp::Shl => {
703 match shift_amount(&b) {
705 Some(n) => a.shl(n),
706 None => return Err(self.throw("BigInt shift amount out of range")),
707 }
708 }
709 BinaryOp::Shr => match shift_amount(&b) {
710 Some(n) => a.shr(n),
711 None => return Err(self.throw("BigInt shift amount out of range")),
712 },
713 BinaryOp::UShr => {
714 return Err(self.throw("BigInts have no unsigned right shift, use >> instead"));
716 }
717 _ => return Err(self.throw("Unsupported BigInt operation")),
718 };
719 Ok(Value::bigint(result))
720 }
721
722 pub(crate) fn bigint_loose_eq(&self, l: &Value, r: &Value) -> bool {
724 use core::cmp::Ordering;
725 match (l, r) {
726 (Value::BigInt(a), Value::BigInt(b)) => a.cmp(b) == Ordering::Equal,
727 (Value::BigInt(a), Value::Number(n)) | (Value::Number(n), Value::BigInt(a)) => {
728 n.is_finite() && a.to_f64() == *n
729 }
730 (Value::BigInt(a), Value::Str(s)) | (Value::Str(s), Value::BigInt(a)) => {
731 match super::super::bigint::BigInt::parse_str(s) {
732 Some(bi) => a.cmp(&bi) == Ordering::Equal,
733 None => false,
734 }
735 }
736 (Value::BigInt(a), Value::Bool(bb)) | (Value::Bool(bb), Value::BigInt(a)) => {
737 a.to_f64() == if *bb { 1.0 } else { 0.0 }
738 }
739 _ => false,
740 }
741 }
742
743 pub(crate) fn bigint_compare(&self, op: &BinaryOp, l: &Value, r: &Value) -> Value {
745 use core::cmp::Ordering;
746 let ord: Option<Ordering> = match (l, r) {
747 (Value::BigInt(a), Value::BigInt(b)) => Some(a.cmp(b)),
748 (Value::BigInt(a), _) => {
749 let x = a.to_f64();
750 let y = r.to_number();
751 cmp_f64(x, y)
752 }
753 (_, Value::BigInt(b)) => {
754 let x = l.to_number();
755 let y = b.to_f64();
756 cmp_f64(x, y)
757 }
758 _ => None,
759 };
760 let ord = match ord {
761 Some(o) => o,
762 None => return Value::Bool(false),
763 };
764 let res = match op {
765 BinaryOp::Lt => ord == Ordering::Less,
766 BinaryOp::Gt => ord == Ordering::Greater,
767 BinaryOp::LtEq => ord != Ordering::Greater,
768 BinaryOp::GtEq => ord != Ordering::Less,
769 _ => false,
770 };
771 Value::Bool(res)
772 }
773
774}