diff --git a/crates/oxc_minifier/src/compressor/fold.rs b/crates/oxc_minifier/src/compressor/fold.rs index e69de29bb..198c8e5f9 100644 --- a/crates/oxc_minifier/src/compressor/fold.rs +++ b/crates/oxc_minifier/src/compressor/fold.rs @@ -0,0 +1,139 @@ +//! Constant Folding +//! +//! + +#[allow(clippy::wildcard_imports)] +use oxc_hir::hir::*; +use oxc_span::Span; +use oxc_syntax::operator::BinaryOperator; + +use super::Compressor; + +/// Tri state +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Tri { + True, + False, + Unknown, +} + +/// JavaScript Language Type +/// +/// +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Ty { + BigInt, + Boolean, + Null, + Number, + Object, + Str, + Void, + Undetermined, +} + +impl<'a> From<&Expression<'a>> for Ty { + fn from(expr: &Expression<'a>) -> Self { + // TODO: complete this + match expr { + Expression::BigintLiteral(_) => Self::BigInt, + Expression::BooleanLiteral(_) => Self::Boolean, + Expression::NullLiteral(_) => Self::Null, + Expression::NumberLiteral(_) => Self::Number, + Expression::ObjectExpression(_) => Self::Object, + Expression::StringLiteral(_) => Self::Str, + Expression::Identifier(ident) => match ident.name.as_str() { + "undefined" => Self::Void, + _ => Self::Undetermined, + }, + _ => Self::Undetermined, + } + } +} + +impl<'a> Compressor<'a> { + pub(crate) fn fold_expression<'b>(&mut self, expr: &'b mut Expression<'a>) { + let folded_expr = match expr { + Expression::BinaryExpression(binary_expr) => match binary_expr.operator { + BinaryOperator::Equality => self.try_fold_comparison( + binary_expr.span, + binary_expr.operator, + &binary_expr.left, + &binary_expr.right, + ), + _ => None, + }, + _ => None, + }; + if let Some(folded_expr) = folded_expr { + *expr = folded_expr; + } + } + + fn try_fold_comparison<'b>( + &mut self, + span: Span, + op: BinaryOperator, + left: &'b Expression<'a>, + right: &'b Expression<'a>, + ) -> Option> { + let value = match self.evaluate_comparison(op, left, right) { + Tri::True => true, + Tri::False => false, + Tri::Unknown => return None, + }; + let boolean_literal = self.hir.boolean_literal(span, value); + Some(self.hir.literal_boolean_expression(boolean_literal)) + } + + fn evaluate_comparison<'b>( + &self, + op: BinaryOperator, + left: &'b Expression<'a>, + right: &'b Expression<'a>, + ) -> Tri { + match op { + BinaryOperator::Equality => self.try_abstract_equality_comparison(left, right), + _ => Tri::Unknown, + } + } + + /// + fn try_abstract_equality_comparison<'b>( + &self, + left_expr: &'b Expression<'a>, + right_expr: &'b Expression<'a>, + ) -> Tri { + let left = Ty::from(left_expr); + let right = Ty::from(right_expr); + if left != Ty::Undetermined && right != Ty::Undetermined { + if left == right { + return self.try_strict_equality_comparison(left_expr, right_expr); + } + if matches!((left, right), (Ty::Null, Ty::Void) | (Ty::Void, Ty::Null)) { + return Tri::True; + } + } + Tri::Unknown + } + + /// + fn try_strict_equality_comparison<'b>( + &self, + left_expr: &'b Expression<'a>, + right_expr: &'b Expression<'a>, + ) -> Tri { + let left = Ty::from(left_expr); + let right = Ty::from(right_expr); + if left != Ty::Undetermined && right != Ty::Undetermined { + if left != right { + return Tri::False; + } + return match left { + Ty::Void | Ty::Null => Tri::True, + _ => Tri::Unknown, + }; + } + Tri::Unknown + } +} diff --git a/crates/oxc_minifier/src/compressor/mod.rs b/crates/oxc_minifier/src/compressor/mod.rs index 16b5ce71d..3d349ec6d 100644 --- a/crates/oxc_minifier/src/compressor/mod.rs +++ b/crates/oxc_minifier/src/compressor/mod.rs @@ -1,5 +1,7 @@ #![allow(clippy::unused_self)] +mod fold; + use oxc_allocator::{Allocator, Vec}; #[allow(clippy::wildcard_imports)] use oxc_hir::{hir::*, HirBuilder, VisitMut}; @@ -275,6 +277,7 @@ impl<'a, 'b> VisitMut<'a, 'b> for Compressor<'a> { } fn visit_expression(&mut self, expr: &'b mut Expression<'a>) { + self.fold_expression(expr); if self.compress_undefined(expr) || self.compress_boolean(expr) || self.compress_infinity(expr) diff --git a/crates/oxc_minifier/tests/closure/fold_constants.rs b/crates/oxc_minifier/tests/closure/fold_constants.rs index 2b6f10e67..b55c795d1 100644 --- a/crates/oxc_minifier/tests/closure/fold_constants.rs +++ b/crates/oxc_minifier/tests/closure/fold_constants.rs @@ -1,4 +1,8 @@ //! +use crate::test; + #[test] -fn undefined_comparison1() {} +fn undefined_comparison1() { + test("undefined == undefined", "!0"); +}