From c2ad1835441937c188537d635631fc2806379536 Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Mon, 30 Oct 2023 10:16:55 -0500 Subject: [PATCH 1/4] feat(ecmascript): implement `SameValueZero` --- .../testing_and_comparison.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs index ff3216ab5..4a10a3a59 100644 --- a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs +++ b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs @@ -83,6 +83,37 @@ pub(crate) fn same_value, V2: Copy + Into>( same_value_non_number(agent, x, y) } +/// ### [7.2.11 SameValueZero ( x, y )](https://tc39.es/ecma262/#sec-samevaluezero) +/// +/// The abstract operation SameValueZero takes arguments x (an ECMAScript +/// language value) and y (an ECMAScript language value) and returns a Boolean. +/// It determines whether or not the two arguments are the same value (ignoring +/// the difference between +0𝔽 and -0𝔽). It performs the following steps when +/// called: +pub(crate) fn same_value_zero( + agent: &mut Agent, + x: impl Copy + Into, + y: impl Copy + Into, +) -> bool { + let (x, y) = (x.into(), y.into()); + + // 1. If Type(x) is not Type(y), return false. + if !is_same_type(x, y) { + return false; + } + + // 2. If x is a Number, then + // NOTE: We need to convert both to a number because we use number + // type-safety. + if let (Ok(x), Ok(y)) = (x.to_number(agent), y.to_number(agent)) { + // a. Return Number::sameValueZero(x, y). + return x.same_value_zero(agent, y); + } + + // 3. Return SameValueNonNumber(x, y). + return same_value_non_number(agent, x, y); +} + /// 7.2.12 SameValueNonNumber ( x, y ) /// https://tc39.es/ecma262/#sec-samevaluenonnumber pub(crate) fn same_value_non_number>(_agent: &mut Agent, x: T, y: T) -> bool { From 4f7afec8e6f901f0b62ba627e9422da0870b7c9d Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Mon, 30 Oct 2023 10:47:12 -0500 Subject: [PATCH 2/4] feat(ecmascript): implement `IsLessThan` --- .../testing_and_comparison.rs | 127 ++++++++++++++++++ .../src/ecmascript/types/language/bigint.rs | 26 +++- .../ecmascript/types/language/bigint/data.rs | 2 +- .../src/ecmascript/types/language/value.rs | 42 +++++- nova_vm/src/heap.rs | 1 + 5 files changed, 191 insertions(+), 7 deletions(-) diff --git a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs index 4a10a3a59..1ee57bd38 100644 --- a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs +++ b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs @@ -5,6 +5,8 @@ use crate::ecmascript::{ types::{Number, Value}, }; +use super::type_conversion::{to_primitive, PreferredType}; + /// ### [7.2.1 RequireObjectCoercible ( argument )](https://tc39.es/ecma262/#sec-requireobjectcoercible) /// /// The abstract operation RequireObjectCoercible takes argument argument (an @@ -150,3 +152,128 @@ pub(crate) fn same_value_non_number>(_agent: &mut Agent, x // 7. If x is y, return true; otherwise, return false. todo!() } + +/// [7.2.13 IsLessThan ( x, y, LeftFirst )](https://tc39.es/ecma262/#sec-islessthan) +/// +/// The abstract operation IsLessThan takes arguments x (an ECMAScript language +/// value), y (an ECMAScript language value), and LeftFirst (a Boolean) and +/// returns either a normal completion containing either a Boolean or undefined, +/// or a throw completion. It provides the semantics for the comparison x < y, +/// returning true, false, or undefined (which indicates that at least one +/// operand is NaN). The LeftFirst flag is used to control the order in which +/// operations with potentially visible side-effects are performed upon x and y. +/// It is necessary because ECMAScript specifies left to right evaluation of +/// expressions. If LeftFirst is true, the x parameter corresponds to an +/// expression that occurs to the left of the y parameter's corresponding +/// expression. If LeftFirst is false, the reverse is the case and operations +/// must be performed upon y before x. It performs the following steps when +/// called: +pub(crate) fn is_less_than( + agent: &mut Agent, + x: impl Into + Copy, + y: impl Into + Copy, +) -> JsResult { + // 1. If LeftFirst is true, then + let (px, py) = if LEFT_FIRST { + // a. Let px be ? ToPrimitive(x, NUMBER). + let px = to_primitive(agent, x.into(), Some(PreferredType::Number))?; + + // b. Let py be ? ToPrimitive(y, NUMBER). + let py = to_primitive(agent, y.into(), Some(PreferredType::Number))?; + + (px, py) + } + // 2. Else, + else { + // a. NOTE: The order of evaluation needs to be reversed to preserve left to right evaluation. + // b. Let py be ? ToPrimitive(y, NUMBER). + let py = to_primitive(agent, y.into(), Some(PreferredType::Number))?; + + // c. Let px be ? ToPrimitive(x, NUMBER). + let px = to_primitive(agent, x.into(), Some(PreferredType::Number))?; + + (px, py) + }; + + // 3. If px is a String and py is a String, then + if px.is_string() && py.is_string() { + todo!("Finish this") + // a. Let lx be the length of px. + // b. Let ly be the length of py. + // c. For each integer i such that 0 ≤ i < min(lx, ly), in ascending order, do + // i. Let cx be the numeric value of the code unit at index i within px. + // ii. Let cy be the numeric value of the code unit at index i within py. + // iii. If cx < cy, return true. + // iv. If cx > cy, return false. + // d. If lx < ly, return true. Otherwise, return false. + } + // 4. Else, + else { + // a. If px is a BigInt and py is a String, then + if px.is_bigint() && py.is_string() { + todo!("Finish this") + // i. Let ny be StringToBigInt(py). + // ii. If ny is undefined, return undefined. + // iii. Return BigInt::lessThan(px, ny). + } + + // b. If px is a String and py is a BigInt, then + if px.is_string() && py.is_bigint() { + todo!("Finish this") + // i. Let nx be StringToBigInt(px). + // ii. If nx is undefined, return undefined. + // iii. Return BigInt::lessThan(nx, py). + } + + // c. NOTE: Because px and py are primitive values, evaluation order is not important. + // d. Let nx be ? ToNumeric(px). + let nx = px.to_numeric(agent)?; + + // e. Let ny be ? ToNumeric(py). + let ny = py.to_numeric(agent)?; + + // f. If Type(nx) is Type(ny), then + if is_same_type(nx, ny) { + // i. If nx is a Number, then + if nx.is_number() { + // 1. Return Number::lessThan(nx, ny). + let nx = nx.to_number(agent)?; + let ny = ny.to_number(agent)?; + return Ok(nx.less_than(agent, ny).into()); + } + // ii. Else, + else { + // 1. Assert: nx is a BigInt. + assert!(nx.is_bigint()); + + // 2. Return BigInt::lessThan(nx, ny). + let nx = nx.to_bigint(agent)?; + let ny = ny.to_bigint(agent)?; + return Ok(nx.less_than(agent, ny).into()); + } + } + + // g. Assert: nx is a BigInt and ny is a Number, or nx is a Number and ny is a BigInt. + assert!(nx.is_bigint() && ny.is_number() || nx.is_number() && ny.is_bigint()); + + // h. If nx or ny is NaN, return undefined. + if nx.is_nan(agent) || ny.is_nan(agent) { + return Ok(Value::Undefined); + } + + // i. If nx is -∞𝔽 or ny is +∞𝔽, return true. + if nx.is_neg_infinity(agent) || ny.is_pos_infinity(agent) { + return Ok(Value::from(true)); + } + + // j. If nx is +∞𝔽 or ny is -∞𝔽, return false. + if nx.is_pos_infinity(agent) || ny.is_neg_infinity(agent) { + return Ok(Value::from(false)); + } + + // k. If ℝ(nx) < ℝ(ny), return true; otherwise return false. + let rnx = nx.to_real(agent)?; + let rny = nx.to_real(agent)?; + return Ok(Value::from(rnx < rny)); + } +} diff --git a/nova_vm/src/ecmascript/types/language/bigint.rs b/nova_vm/src/ecmascript/types/language/bigint.rs index db9841726..3bbf02cb0 100644 --- a/nova_vm/src/ecmascript/types/language/bigint.rs +++ b/nova_vm/src/ecmascript/types/language/bigint.rs @@ -1,7 +1,11 @@ mod data; use super::value::{BIGINT_DISCRIMINANT, SMALL_BIGINT_DISCRIMINANT}; -use crate::{heap::indexes::BigIntIndex, SmallInteger}; +use crate::{ + ecmascript::execution::Agent, + heap::{indexes::BigIntIndex, GetHeapData}, + SmallInteger, +}; pub use data::BigIntHeapData; @@ -11,3 +15,23 @@ pub enum BigInt { BigInt(BigIntIndex) = BIGINT_DISCRIMINANT, SmallBigInt(SmallInteger) = SMALL_BIGINT_DISCRIMINANT, } + +impl BigInt { + /// ### [6.1.6.2.12 BigInt::lessThan ( x, y )](https://tc39.es/ecma262/#sec-numeric-types-bigint-lessThan) + /// + /// The abstract operation BigInt::lessThan takes arguments x (a BigInt) and + /// y (a BigInt) and returns a Boolean. It performs the following steps when + /// called: + pub(crate) fn less_than(self, agent: &mut Agent, y: BigInt) -> bool { + // 1. If ℝ(x) < ℝ(y), return true; otherwise return false. + match (self, y) { + (BigInt::BigInt(_), BigInt::SmallBigInt(_)) => false, + (BigInt::SmallBigInt(_), BigInt::BigInt(_)) => true, + (BigInt::BigInt(b1), BigInt::BigInt(b2)) => { + let (b1, b2) = (agent.heap.get(b1), agent.heap.get(b2)); + b1.data < b2.data + } + (BigInt::SmallBigInt(b1), BigInt::SmallBigInt(b2)) => b1.into_i64() < b2.into_i64(), + } + } +} diff --git a/nova_vm/src/ecmascript/types/language/bigint/data.rs b/nova_vm/src/ecmascript/types/language/bigint/data.rs index 2eaeec913..7507b3c97 100644 --- a/nova_vm/src/ecmascript/types/language/bigint/data.rs +++ b/nova_vm/src/ecmascript/types/language/bigint/data.rs @@ -4,7 +4,7 @@ use num_bigint_dig::BigInt; #[derive(Debug, Clone)] pub struct BigIntHeapData { - pub(super) data: BigInt, + pub(crate) data: BigInt, } impl TryInto for BigIntHeapData { diff --git a/nova_vm/src/ecmascript/types/language/value.rs b/nova_vm/src/ecmascript/types/language/value.rs index 8016cde9a..6635c00fa 100644 --- a/nova_vm/src/ecmascript/types/language/value.rs +++ b/nova_vm/src/ecmascript/types/language/value.rs @@ -2,17 +2,22 @@ use std::mem::size_of; use crate::{ ecmascript::{ - abstract_operations::type_conversion::{to_int32, to_number, to_numeric, to_uint32}, + abstract_operations::type_conversion::{ + to_big_int, to_int32, to_number, to_numeric, to_uint32, + }, execution::{Agent, JsResult}, }, - heap::indexes::{ - ArrayBufferIndex, ArrayIndex, BigIntIndex, DateIndex, ErrorIndex, FunctionIndex, - NumberIndex, ObjectIndex, RegExpIndex, StringIndex, SymbolIndex, + heap::{ + indexes::{ + ArrayBufferIndex, ArrayIndex, BigIntIndex, DateIndex, ErrorIndex, FunctionIndex, + NumberIndex, ObjectIndex, RegExpIndex, StringIndex, SymbolIndex, + }, + GetHeapData, }, Heap, SmallInteger, SmallString, }; -use super::Number; +use super::{BigInt, Number}; /// 6.1 ECMAScript Language Types /// https://tc39.es/ecma262/#sec-ecmascript-language-types @@ -208,6 +213,18 @@ impl Value { .unwrap_or(false) } + pub fn is_pos_infinity(self, agent: &mut Agent) -> bool { + Number::try_from(self) + .map(|n| n.is_pos_infinity(agent)) + .unwrap_or(false) + } + + pub fn is_neg_infinity(self, agent: &mut Agent) -> bool { + Number::try_from(self) + .map(|n| n.is_neg_infinity(agent)) + .unwrap_or(false) + } + pub fn is_nan(self, agent: &mut Agent) -> bool { Number::try_from(self) .map(|n| n.is_nan(agent)) @@ -239,6 +256,10 @@ impl Value { to_number(agent, self) } + pub fn to_bigint(self, agent: &mut Agent) -> JsResult { + to_big_int(agent, self) + } + pub fn to_numeric(self, agent: &mut Agent) -> JsResult { to_numeric(agent, self) } @@ -250,6 +271,17 @@ impl Value { pub fn to_uint32(self, agent: &mut Agent) -> JsResult { to_uint32(agent, self) } + + /// ### [ℝ](https://tc39.es/ecma262/#%E2%84%9D) + pub fn to_real(self, agent: &mut Agent) -> JsResult { + Ok(match self { + Value::Number(n) => *agent.heap.get(n), + Value::Integer(i) => i.into_i64() as f64, + Value::Float(f) => f as f64, + // NOTE: Converting to a number should give us a nice error message. + _ => to_number(agent, self)?.into_f64(agent), + }) + } } impl From for Value { diff --git a/nova_vm/src/heap.rs b/nova_vm/src/heap.rs index 4e9f57741..f583e5915 100644 --- a/nova_vm/src/heap.rs +++ b/nova_vm/src/heap.rs @@ -146,6 +146,7 @@ impl_heap_data!(functions, FunctionHeapData, FunctionHeapData); impl_heap_data!(numbers, NumberHeapData, f64, data); impl_heap_data!(objects, ObjectHeapData, ObjectHeapData); impl_heap_data!(strings, StringHeapData, Wtf8Buf, data); +impl_heap_data!(bigints, BigIntHeapData, BigIntHeapData); impl CreateHeapData<&str, String> for Heap<'_, '_> { fn create(&mut self, data: &str) -> String { From 31ed6624e1bd1eb335fb68b1da4f24cfd31bdc88 Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Mon, 30 Oct 2023 12:00:57 -0500 Subject: [PATCH 3/4] port the Undefined | Value::Number to Option --- .../testing_and_comparison.rs | 14 ++++----- .../src/ecmascript/types/language/number.rs | 30 ++++++++++--------- .../src/ecmascript/types/language/value.rs | 9 ++++-- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs index 1ee57bd38..0f3f90e18 100644 --- a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs +++ b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs @@ -172,7 +172,7 @@ pub(crate) fn is_less_than( agent: &mut Agent, x: impl Into + Copy, y: impl Into + Copy, -) -> JsResult { +) -> JsResult> { // 1. If LeftFirst is true, then let (px, py) = if LEFT_FIRST { // a. Let px be ? ToPrimitive(x, NUMBER). @@ -239,7 +239,7 @@ pub(crate) fn is_less_than( // 1. Return Number::lessThan(nx, ny). let nx = nx.to_number(agent)?; let ny = ny.to_number(agent)?; - return Ok(nx.less_than(agent, ny).into()); + return Ok(nx.less_than(agent, ny)); } // ii. Else, else { @@ -249,7 +249,7 @@ pub(crate) fn is_less_than( // 2. Return BigInt::lessThan(nx, ny). let nx = nx.to_bigint(agent)?; let ny = ny.to_bigint(agent)?; - return Ok(nx.less_than(agent, ny).into()); + return Ok(Some(nx.less_than(agent, ny))); } } @@ -258,22 +258,22 @@ pub(crate) fn is_less_than( // h. If nx or ny is NaN, return undefined. if nx.is_nan(agent) || ny.is_nan(agent) { - return Ok(Value::Undefined); + return Ok(None); } // i. If nx is -∞𝔽 or ny is +∞𝔽, return true. if nx.is_neg_infinity(agent) || ny.is_pos_infinity(agent) { - return Ok(Value::from(true)); + return Ok(Some(true)); } // j. If nx is +∞𝔽 or ny is -∞𝔽, return false. if nx.is_pos_infinity(agent) || ny.is_neg_infinity(agent) { - return Ok(Value::from(false)); + return Ok(Some(false)); } // k. If ℝ(nx) < ℝ(ny), return true; otherwise return false. let rnx = nx.to_real(agent)?; let rny = nx.to_real(agent)?; - return Ok(Value::from(rnx < rny)); + return Ok(Some(rnx < rny)); } } diff --git a/nova_vm/src/ecmascript/types/language/number.rs b/nova_vm/src/ecmascript/types/language/number.rs index e5a1b75d4..c3167ac86 100644 --- a/nova_vm/src/ecmascript/types/language/number.rs +++ b/nova_vm/src/ecmascript/types/language/number.rs @@ -281,7 +281,7 @@ impl Number { pub fn greater_than(self, agent: &mut Agent, y: Self) -> Value { let x = self; - y.less_than(agent, x) + y.less_than(agent, x).into() } /// 6.1.6.1.1 Number::unaryMinus ( x ) @@ -443,7 +443,9 @@ impl Number { debug_assert!(exponent.is_finite(agent) && exponent.is_nonzero(agent)); // 12. If base < -0𝔽 and exponent is not an integral Number, return NaN. - if base.less_than(agent, Number::neg_zero()).is_true() && !exponent.is_odd_integer(agent) { + if base.less_than(agent, Number::neg_zero()) == Some(true) + && !exponent.is_odd_integer(agent) + { return Number::nan(); } @@ -457,61 +459,61 @@ impl Number { /// 6.1.6.1.12 Number::lessThan ( x, y ) /// https://tc39.es/ecma262/#sec-numeric-types-number-lessThan - pub fn less_than(self, agent: &mut Agent, y: Self) -> Value { + pub fn less_than(self, agent: &mut Agent, y: Self) -> Option { let x = self; // 1. If x is NaN, return undefined. if x.is_nan(agent) { - return Value::Undefined; + return None; } // 2. If y is NaN, return undefined. if y.is_nan(agent) { - return Value::Undefined; + return None; } // 3. If x is y, return false. if x.is(agent, y) { - return false.into(); + return Some(false); } // 4. If x is +0𝔽 and y is -0𝔽, return false. if x.is_pos_zero(agent) && y.is_neg_zero(agent) { - return false.into(); + return Some(false); } // 5. If x is -0𝔽 and y is +0𝔽, return false. if x.is_neg_zero(agent) && y.is_pos_zero(agent) { - return false.into(); + return Some(false); } // 6. If x is +∞𝔽, return false. if x.is_pos_infinity(agent) { - return false.into(); + return Some(false); } // 7. If y is +∞𝔽, return true. if y.is_pos_infinity(agent) { - return true.into(); + return Some(true); } // 8. If y is -∞𝔽, return false. if y.is_neg_infinity(agent) { - return false.into(); + return Some(false); } // 9. If x is -∞𝔽, return true. if x.is_neg_infinity(agent) { - return true.into(); + return Some(true); } // 10. Assert: x and y are finite and non-zero. - debug_assert!( + assert!( x.is_finite(agent) && x.is_nonzero(agent) && y.is_finite(agent) && y.is_nonzero(agent) ); // 11. If ℝ(x) < ℝ(y), return true. Otherwise, return false. - Value::Boolean(match (x.into_value(), y.into_value()) { + Some(match (x.into_value(), y.into_value()) { (Value::Number(x), Value::Number(y)) => agent.heap.get(x) < agent.heap.get(y), (Value::Number(x), Value::Integer(y)) => *agent.heap.get(x) < y.into_i64() as f64, (Value::Number(x), Value::Float(y)) => *agent.heap.get(x) < y as f64, diff --git a/nova_vm/src/ecmascript/types/language/value.rs b/nova_vm/src/ecmascript/types/language/value.rs index 6635c00fa..df024a1fa 100644 --- a/nova_vm/src/ecmascript/types/language/value.rs +++ b/nova_vm/src/ecmascript/types/language/value.rs @@ -290,9 +290,12 @@ impl From for Value { } } -impl From> for Value { - fn from(value: Option) -> Self { - value.unwrap_or(Value::Undefined) +impl From> for Value +where + T: Into, +{ + fn from(value: Option) -> Self { + value.map_or(Value::Undefined, |v| v.into()) } } From abb9e053fdb612c84a8c33f7bec220a543e85dfa Mon Sep 17 00:00:00 2001 From: Carter Snook Date: Mon, 30 Oct 2023 14:06:44 -0500 Subject: [PATCH 4/4] create abstract_operations module for `BigInt` --- nova_vm/src/ecmascript/abstract_operations.rs | 1 + .../ecmascript/abstract_operations/bigint.rs | 22 ++++++++++++++++ .../testing_and_comparison.rs | 3 ++- .../src/ecmascript/types/language/bigint.rs | 26 +------------------ 4 files changed, 26 insertions(+), 26 deletions(-) create mode 100644 nova_vm/src/ecmascript/abstract_operations/bigint.rs diff --git a/nova_vm/src/ecmascript/abstract_operations.rs b/nova_vm/src/ecmascript/abstract_operations.rs index 6eb2da6e8..e96365c1f 100644 --- a/nova_vm/src/ecmascript/abstract_operations.rs +++ b/nova_vm/src/ecmascript/abstract_operations.rs @@ -1,3 +1,4 @@ +pub(crate) mod bigint; pub(crate) mod operations_on_objects; pub(crate) mod testing_and_comparison; pub(crate) mod type_conversion; diff --git a/nova_vm/src/ecmascript/abstract_operations/bigint.rs b/nova_vm/src/ecmascript/abstract_operations/bigint.rs new file mode 100644 index 000000000..9c7fbb2bc --- /dev/null +++ b/nova_vm/src/ecmascript/abstract_operations/bigint.rs @@ -0,0 +1,22 @@ +use crate::{ + ecmascript::{execution::Agent, types::BigInt}, + heap::GetHeapData, +}; + +/// ### [6.1.6.2.12 BigInt::lessThan ( x, y )](https://tc39.es/ecma262/#sec-numeric-types-bigint-lessThan) +/// +/// The abstract operation BigInt::lessThan takes arguments x (a BigInt) and +/// y (a BigInt) and returns a Boolean. It performs the following steps when +/// called: +pub(crate) fn less_than(agent: &mut Agent, x: BigInt, y: BigInt) -> bool { + // 1. If ℝ(x) < ℝ(y), return true; otherwise return false. + match (x, y) { + (BigInt::BigInt(_), BigInt::SmallBigInt(_)) => false, + (BigInt::SmallBigInt(_), BigInt::BigInt(_)) => true, + (BigInt::BigInt(b1), BigInt::BigInt(b2)) => { + let (b1, b2) = (agent.heap.get(b1), agent.heap.get(b2)); + b1.data < b2.data + } + (BigInt::SmallBigInt(b1), BigInt::SmallBigInt(b2)) => b1.into_i64() < b2.into_i64(), + } +} diff --git a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs index 0f3f90e18..bef1d36d7 100644 --- a/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs +++ b/nova_vm/src/ecmascript/abstract_operations/testing_and_comparison.rs @@ -1,6 +1,7 @@ //! ## [7.2 Testing and Comparison Operations](https://tc39.es/ecma262/#sec-testing-and-comparison-operations) use crate::ecmascript::{ + abstract_operations::bigint, execution::{agent::JsError, Agent, JsResult}, types::{Number, Value}, }; @@ -249,7 +250,7 @@ pub(crate) fn is_less_than( // 2. Return BigInt::lessThan(nx, ny). let nx = nx.to_bigint(agent)?; let ny = ny.to_bigint(agent)?; - return Ok(Some(nx.less_than(agent, ny))); + return Ok(Some(bigint::less_than(agent, nx, ny))); } } diff --git a/nova_vm/src/ecmascript/types/language/bigint.rs b/nova_vm/src/ecmascript/types/language/bigint.rs index 3bbf02cb0..db9841726 100644 --- a/nova_vm/src/ecmascript/types/language/bigint.rs +++ b/nova_vm/src/ecmascript/types/language/bigint.rs @@ -1,11 +1,7 @@ mod data; use super::value::{BIGINT_DISCRIMINANT, SMALL_BIGINT_DISCRIMINANT}; -use crate::{ - ecmascript::execution::Agent, - heap::{indexes::BigIntIndex, GetHeapData}, - SmallInteger, -}; +use crate::{heap::indexes::BigIntIndex, SmallInteger}; pub use data::BigIntHeapData; @@ -15,23 +11,3 @@ pub enum BigInt { BigInt(BigIntIndex) = BIGINT_DISCRIMINANT, SmallBigInt(SmallInteger) = SMALL_BIGINT_DISCRIMINANT, } - -impl BigInt { - /// ### [6.1.6.2.12 BigInt::lessThan ( x, y )](https://tc39.es/ecma262/#sec-numeric-types-bigint-lessThan) - /// - /// The abstract operation BigInt::lessThan takes arguments x (a BigInt) and - /// y (a BigInt) and returns a Boolean. It performs the following steps when - /// called: - pub(crate) fn less_than(self, agent: &mut Agent, y: BigInt) -> bool { - // 1. If ℝ(x) < ℝ(y), return true; otherwise return false. - match (self, y) { - (BigInt::BigInt(_), BigInt::SmallBigInt(_)) => false, - (BigInt::SmallBigInt(_), BigInt::BigInt(_)) => true, - (BigInt::BigInt(b1), BigInt::BigInt(b2)) => { - let (b1, b2) = (agent.heap.get(b1), agent.heap.get(b2)); - b1.data < b2.data - } - (BigInt::SmallBigInt(b1), BigInt::SmallBigInt(b2)) => b1.into_i64() < b2.into_i64(), - } - } -}