Skip to content
Merged
Changes from all commits
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
166 changes: 87 additions & 79 deletions crates/oxc_ecmascript/src/constant_evaluation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,51 +233,60 @@ fn binary_operation_evaluate_value_to<'a>(
}
None
}
BinaryOperator::Subtraction
| BinaryOperator::Division
| BinaryOperator::Remainder
| BinaryOperator::Multiplication
| BinaryOperator::Exponential => {
BinaryOperator::Subtraction => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
let val = match operator {
BinaryOperator::Subtraction => lval - rval,
BinaryOperator::Division => lval / rval,
BinaryOperator::Remainder => {
if rval.is_zero() {
f64::NAN
} else {
lval % rval
}
}
BinaryOperator::Multiplication => lval * rval,
BinaryOperator::Exponential => {
let result = lval.powf(rval);
// For now, ignore the result if it large or has a decimal part
// so that the output does not become bigger than the input.
if result.is_finite() && (result.fract() != 0.0 || result.log10() > 4.0) {
return None;
}
result
}
_ => unreachable!(),
};
Some(ConstantValue::Number(val))
Some(ConstantValue::Number(lval - rval))
}
BinaryOperator::Division => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
Some(ConstantValue::Number(lval / rval))
}
BinaryOperator::Remainder => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
Some(ConstantValue::Number(if rval.is_zero() { f64::NAN } else { lval % rval }))
}
BinaryOperator::Multiplication => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
Some(ConstantValue::Number(lval * rval))
}
BinaryOperator::Exponential => {
let lval = left.evaluate_value_to_number(ctx)?;
let rval = right.evaluate_value_to_number(ctx)?;
let result = lval.powf(rval);
// For now, ignore the result if it large or has a decimal part
// so that the output does not become bigger than the input.
if result.is_finite() && (result.fract() != 0.0 || result.log10() > 4.0) {
return None;
}
Some(ConstantValue::Number(result))
}
#[expect(clippy::cast_sign_loss)]
BinaryOperator::ShiftLeft
| BinaryOperator::ShiftRight
| BinaryOperator::ShiftRightZeroFill => {
BinaryOperator::ShiftLeft => {
let left = left.evaluate_value_to_number(ctx)?;
let right = right.evaluate_value_to_number(ctx)?;
let left = left.to_int_32();
let right = (right.to_int_32() as u32) & 31;
Some(ConstantValue::Number(match operator {
BinaryOperator::ShiftLeft => f64::from(left << right),
BinaryOperator::ShiftRight => f64::from(left >> right),
BinaryOperator::ShiftRightZeroFill => f64::from((left as u32) >> right),
_ => unreachable!(),
}))
Some(ConstantValue::Number(f64::from(left << right)))
}
#[expect(clippy::cast_sign_loss)]
BinaryOperator::ShiftRight => {
let left = left.evaluate_value_to_number(ctx)?;
let right = right.evaluate_value_to_number(ctx)?;
let left = left.to_int_32();
let right = (right.to_int_32() as u32) & 31;
Some(ConstantValue::Number(f64::from(left >> right)))
}
#[expect(clippy::cast_sign_loss)]
BinaryOperator::ShiftRightZeroFill => {
let left = left.evaluate_value_to_number(ctx)?;
let right = right.evaluate_value_to_number(ctx)?;
let left = left.to_int_32();
let right = (right.to_int_32() as u32) & 31;
Some(ConstantValue::Number(f64::from((left as u32) >> right)))
}
BinaryOperator::LessThan => is_less_than(ctx, left, right).map(|value| match value {
ConstantValue::Undefined => ConstantValue::Boolean(false),
Expand All @@ -303,33 +312,35 @@ fn binary_operation_evaluate_value_to<'a>(
_ => unreachable!(),
})
}
BinaryOperator::BitwiseAnd | BinaryOperator::BitwiseOR | BinaryOperator::BitwiseXOR => {
BinaryOperator::BitwiseAnd => {
if left.value_type(ctx).is_bigint() && right.value_type(ctx).is_bigint() {
let left_val = left.evaluate_value_to_bigint(ctx)?;
let right_val = right.evaluate_value_to_bigint(ctx)?;
let result_val: BigInt = match operator {
BinaryOperator::BitwiseAnd => left_val & right_val,
BinaryOperator::BitwiseOR => left_val | right_val,
BinaryOperator::BitwiseXOR => left_val ^ right_val,
_ => unreachable!(),
};
return Some(ConstantValue::BigInt(result_val));
let left_biginit = left.evaluate_value_to_bigint(ctx)?;
let right_bigint = right.evaluate_value_to_bigint(ctx)?;
return Some(ConstantValue::BigInt(left_biginit & right_bigint));
}
let left_num = left.evaluate_value_to_number(ctx);
let right_num = right.evaluate_value_to_number(ctx);
if let (Some(left_val), Some(right_val)) = (left_num, right_num) {
let left_val_int = left_val.to_int_32();
let right_val_int = right_val.to_int_32();

let result_val: f64 = match operator {
BinaryOperator::BitwiseAnd => f64::from(left_val_int & right_val_int),
BinaryOperator::BitwiseOR => f64::from(left_val_int | right_val_int),
BinaryOperator::BitwiseXOR => f64::from(left_val_int ^ right_val_int),
_ => unreachable!(),
};
return Some(ConstantValue::Number(result_val));
let left_int = left.evaluate_value_to_number(ctx)?.to_int_32();
let right_int = right.evaluate_value_to_number(ctx)?.to_int_32();
Some(ConstantValue::Number(f64::from(left_int & right_int)))
}
BinaryOperator::BitwiseOR => {
if left.value_type(ctx).is_bigint() && right.value_type(ctx).is_bigint() {
let left_biginit = left.evaluate_value_to_bigint(ctx)?;
let right_bigint = right.evaluate_value_to_bigint(ctx)?;
return Some(ConstantValue::BigInt(left_biginit | right_bigint));
}
None
let left_int = left.evaluate_value_to_number(ctx)?.to_int_32();
let right_int = right.evaluate_value_to_number(ctx)?.to_int_32();
Some(ConstantValue::Number(f64::from(left_int | right_int)))
}
BinaryOperator::BitwiseXOR => {
if left.value_type(ctx).is_bigint() && right.value_type(ctx).is_bigint() {
let left_biginit = left.evaluate_value_to_bigint(ctx)?;
let right_bigint = right.evaluate_value_to_bigint(ctx)?;
return Some(ConstantValue::BigInt(left_biginit ^ right_bigint));
}
let left_int = left.evaluate_value_to_number(ctx)?.to_int_32();
let right_int = right.evaluate_value_to_number(ctx)?.to_int_32();
Some(ConstantValue::Number(f64::from(left_int ^ right_int)))
}
BinaryOperator::Instanceof => {
if let Expression::Identifier(right_ident) = right {
Expand All @@ -348,24 +359,21 @@ fn binary_operation_evaluate_value_to<'a>(
}
None
}
BinaryOperator::StrictEquality
| BinaryOperator::StrictInequality
| BinaryOperator::Equality
| BinaryOperator::Inequality => {
let value = match operator {
BinaryOperator::StrictEquality | BinaryOperator::StrictInequality => {
strict_equality_comparison(ctx, left, right)?
}
BinaryOperator::Equality | BinaryOperator::Inequality => {
abstract_equality_comparison(ctx, left, right)?
}
_ => unreachable!(),
};
Some(ConstantValue::Boolean(match operator {
BinaryOperator::StrictEquality | BinaryOperator::Equality => value,
BinaryOperator::StrictInequality | BinaryOperator::Inequality => !value,
_ => unreachable!(),
}))
BinaryOperator::StrictEquality => {
let value = strict_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(value))
}
BinaryOperator::StrictInequality => {
let value = strict_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(!value))
}
BinaryOperator::Equality => {
let value = abstract_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(value))
}
BinaryOperator::Inequality => {
let value = abstract_equality_comparison(ctx, left, right)?;
Some(ConstantValue::Boolean(!value))
}
BinaryOperator::In => None,
}
Expand Down
Loading