From 719bb68ef2597f77f34775f7dc4a9d21416a9954 Mon Sep 17 00:00:00 2001 From: Haled Odat <8566042+HalidOdat@users.noreply.github.com> Date: Thu, 2 Apr 2026 20:23:50 +0200 Subject: [PATCH] feat(compiler): Generate single emit opcode for negative numbers. --- core/ast/src/expression/literal/mod.rs | 21 +++++++++++++++++++ .../src/bytecompiler/expression/unary.rs | 16 ++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/core/ast/src/expression/literal/mod.rs b/core/ast/src/expression/literal/mod.rs index 76110d070ce..49e78e29b57 100644 --- a/core/ast/src/expression/literal/mod.rs +++ b/core/ast/src/expression/literal/mod.rs @@ -250,6 +250,27 @@ pub enum LiteralKind { Undefined, } +/// Represents a numeric value. +#[derive(Debug, Clone, Copy)] +pub enum Number { + /// An integer. + Int(i32), + /// A floating point number. + Num(f64), +} + +impl LiteralKind { + /// Returns [`Number::Int`] for [`LiteralKind::Int`], [`Number::Num`] for [`LiteralKind::Num`], and [`None`] otherwise. + #[must_use] + pub fn as_number(&self) -> Option { + Some(match self { + Self::Int(int) => Number::Int(*int), + Self::Num(num) => Number::Num(*num), + _ => return None, + }) + } +} + /// Manual implementation, because `Undefined` is never constructed during parsing. #[cfg(feature = "arbitrary")] impl<'a> arbitrary::Arbitrary<'a> for LiteralKind { diff --git a/core/engine/src/bytecompiler/expression/unary.rs b/core/engine/src/bytecompiler/expression/unary.rs index c5d4a402cd9..8226d234cc5 100644 --- a/core/engine/src/bytecompiler/expression/unary.rs +++ b/core/engine/src/bytecompiler/expression/unary.rs @@ -1,5 +1,6 @@ use crate::bytecompiler::{Access, BindingAccessOpcode, ByteCompiler, Register, ToJsString}; use boa_ast::Expression; +use boa_ast::expression::literal::Number; use boa_ast::expression::operator::{Unary, unary::UnaryOp}; impl ByteCompiler<'_> { @@ -18,8 +19,19 @@ impl ByteCompiler<'_> { } } UnaryOp::Minus => { - self.compile_expr(unary.target(), dst); - self.bytecode.emit_neg(dst.variable()); + if let Expression::Literal(literal) = unary.target().flatten() + && let Some(number) = literal.kind().as_number() + { + match number { + // Handles special case -0 + Number::Int(0) => self.emit_store_rational(-0.0, dst), + Number::Int(value) => self.emit_store_integer(-value, dst), + Number::Num(value) => self.emit_store_rational(-value, dst), + } + } else { + self.compile_expr(unary.target(), dst); + self.bytecode.emit_neg(dst.variable()); + } } UnaryOp::Plus => { self.compile_expr(unary.target(), dst);