Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ecmascript): more builtins #43

Merged
merged 4 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ pub(crate) fn is_less_than<const LEFT_FIRST: bool>(
agent: &mut Agent,
x: impl Into<Value> + Copy,
y: impl Into<Value> + Copy,
) -> JsResult<Value> {
) -> JsResult<Option<bool>> {
// 1. If LeftFirst is true, then
let (px, py) = if LEFT_FIRST {
// a. Let px be ? ToPrimitive(x, NUMBER).
Expand Down Expand Up @@ -239,7 +239,7 @@ pub(crate) fn is_less_than<const LEFT_FIRST: bool>(
// 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 {
Expand All @@ -249,7 +249,7 @@ pub(crate) fn is_less_than<const LEFT_FIRST: bool>(
// 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)));
}
}

Expand All @@ -258,22 +258,22 @@ pub(crate) fn is_less_than<const LEFT_FIRST: bool>(

// 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));
}
}
30 changes: 16 additions & 14 deletions nova_vm/src/ecmascript/types/language/number.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down Expand Up @@ -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();
}

Expand All @@ -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<bool> {
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,
Expand Down
9 changes: 6 additions & 3 deletions nova_vm/src/ecmascript/types/language/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,12 @@ impl From<bool> for Value {
}
}

impl From<Option<Value>> for Value {
fn from(value: Option<Value>) -> Self {
value.unwrap_or(Value::Undefined)
impl<T> From<Option<T>> for Value
where
T: Into<Value>,
{
fn from(value: Option<T>) -> Self {
value.map_or(Value::Undefined, |v| v.into())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: I wonder if this is a good idea. There might be some places where we want to "default" into Null instead of Undefined.

That being said, we can just make a helper for it at that time.

}
}

Expand Down