#![allow(non_snake_case)]
use core::fmt;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
pub use bun_collections::VecExt as _VecExtReexport;
use bun_collections::{ArrayHashMap, AutoContext, MultiArrayList, StringHashMap};
use bun_core::Output;
use crate::char_freq::CHAR_FREQ_COUNT;
use crate::{Binding, E, Expr, Index, Ref, Scope, Stmt, symbol};
use crate::AstVec;
pub use crate::flags as Flags;
#[repr(transparent)]
pub struct StoreRef<T>(NonNull<T>);
unsafe impl<T: Send> Send for StoreRef<T> {}
unsafe impl<T: Sync> Sync for StoreRef<T> {}
impl<T> StoreRef<T> {
#[inline]
pub const fn from_non_null(p: NonNull<T>) -> Self {
StoreRef(p)
}
#[inline]
pub fn from_raw(p: *mut T) -> Self {
StoreRef(NonNull::new(p).expect("StoreRef::from_raw: null pointer"))
}
#[inline]
pub fn from_bump(r: &mut T) -> Self {
StoreRef(NonNull::from(r))
}
#[inline]
pub fn from_box(b: Box<T>) -> Self {
StoreRef(bun_core::heap::into_raw_nn(b))
}
#[inline]
pub const fn as_ptr(self) -> *mut T {
self.0.as_ptr()
}
#[inline]
pub const fn from_static(r: &'static T) -> Self {
StoreRef(unsafe { NonNull::new_unchecked(core::ptr::from_ref(r).cast_mut()) })
}
#[inline]
pub fn get(&self) -> &T {
self
}
}
impl<T> Clone for StoreRef<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for StoreRef<T> {}
impl<T> Deref for StoreRef<T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
unsafe { self.0.as_ref() }
}
}
impl<T> DerefMut for StoreRef<T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
unsafe { self.0.as_mut() }
}
}
impl<T> From<NonNull<T>> for StoreRef<T> {
#[inline]
fn from(p: NonNull<T>) -> Self {
StoreRef(p)
}
}
impl<T> PartialEq for StoreRef<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Eq for StoreRef<T> {}
pub type ExprNodeIndex = Expr;
pub type StmtNodeIndex = Stmt;
pub type BindingNodeIndex = Binding;
pub(crate) type ArenaStr = StoreStr;
#[inline]
pub(crate) const fn empty_arena_str() -> ArenaStr {
StoreStr::EMPTY
}
#[derive(Copy, Clone)]
#[repr(C)]
pub struct StoreStr {
ptr: core::ptr::NonNull<u8>,
len: usize,
}
unsafe impl Send for StoreStr {}
unsafe impl Sync for StoreStr {}
impl StoreStr {
pub const EMPTY: StoreStr = StoreStr {
ptr: core::ptr::NonNull::<u8>::dangling(),
len: 0,
};
#[inline]
pub const fn new(s: &[u8]) -> Self {
match core::ptr::NonNull::new(s.as_ptr().cast_mut()) {
Some(ptr) => StoreStr { ptr, len: s.len() },
None => StoreStr::EMPTY,
}
}
#[inline]
pub const fn as_ptr(self) -> *const u8 {
self.ptr.as_ptr()
}
#[inline]
pub const fn raw_len(self) -> usize {
self.len
}
#[inline]
pub fn slice<'a>(self) -> &'a [u8] {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len) }
}
#[inline]
pub fn as_raw(self) -> *const [u8] {
core::ptr::slice_from_raw_parts(self.ptr.as_ptr(), self.len)
}
}
impl Default for StoreStr {
#[inline]
fn default() -> Self {
StoreStr::EMPTY
}
}
impl core::ops::Deref for StoreStr {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.slice()
}
}
impl AsRef<[u8]> for StoreStr {
#[inline]
fn as_ref(&self) -> &[u8] {
self.slice()
}
}
impl core::borrow::Borrow<[u8]> for StoreStr {
#[inline]
fn borrow(&self) -> &[u8] {
self.slice()
}
}
impl<const N: usize> From<&[u8; N]> for StoreStr {
#[inline]
fn from(s: &[u8; N]) -> Self {
StoreStr::new(s)
}
}
impl From<&[u8]> for StoreStr {
#[inline]
fn from(s: &[u8]) -> Self {
StoreStr::new(s)
}
}
impl From<&str> for StoreStr {
#[inline]
fn from(s: &str) -> Self {
StoreStr::new(s.as_bytes())
}
}
impl PartialEq for StoreStr {
#[inline]
fn eq(&self, other: &StoreStr) -> bool {
self.slice() == other.slice()
}
}
impl Eq for StoreStr {}
impl PartialEq<[u8]> for StoreStr {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.slice() == other
}
}
impl<const N: usize> PartialEq<&[u8; N]> for StoreStr {
#[inline]
fn eq(&self, other: &&[u8; N]) -> bool {
self.slice() == *other
}
}
impl<const N: usize> PartialEq<[u8; N]> for StoreStr {
#[inline]
fn eq(&self, other: &[u8; N]) -> bool {
self.slice() == other
}
}
impl PartialEq<&[u8]> for StoreStr {
#[inline]
fn eq(&self, other: &&[u8]) -> bool {
self.slice() == *other
}
}
impl core::hash::Hash for StoreStr {
#[inline]
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
self.slice().hash(h)
}
}
impl core::fmt::Debug for StoreStr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
bstr::BStr::new(self.slice()).fmt(f)
}
}
#[repr(C)]
pub struct StoreSlice<T> {
ptr: core::ptr::NonNull<T>,
len: u32,
}
impl<T> Copy for StoreSlice<T> {}
impl<T> Clone for StoreSlice<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
unsafe impl<T: Send> Send for StoreSlice<T> {}
unsafe impl<T: Sync> Sync for StoreSlice<T> {}
impl<T> StoreSlice<T> {
pub const EMPTY: StoreSlice<T> = StoreSlice {
ptr: core::ptr::NonNull::<T>::dangling(),
len: 0,
};
#[inline]
pub const fn new(s: &[T]) -> Self {
debug_assert!(s.len() <= u32::MAX as usize);
match core::ptr::NonNull::new(s.as_ptr().cast_mut()) {
Some(ptr) => StoreSlice {
ptr,
len: s.len() as u32,
},
None => StoreSlice::EMPTY,
}
}
#[inline]
pub fn new_mut(s: &mut [T]) -> Self {
debug_assert!(s.len() <= u32::MAX as usize);
match core::ptr::NonNull::new(s.as_mut_ptr()) {
Some(ptr) => StoreSlice {
ptr,
len: s.len() as u32,
},
None => StoreSlice::EMPTY,
}
}
#[inline]
pub const fn as_ptr(self) -> *const T {
self.ptr.as_ptr()
}
#[inline]
pub const fn raw_len(self) -> u32 {
self.len
}
#[inline]
pub fn slice<'a>(self) -> &'a [T] {
unsafe { core::slice::from_raw_parts(self.ptr.as_ptr(), self.len as usize) }
}
#[inline]
pub fn slice_mut<'a>(self) -> &'a mut [T] {
unsafe { core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len as usize) }
}
#[inline]
pub fn truncate(&mut self, new_len: usize) {
assert!(new_len <= self.len as usize);
self.len = new_len as u32;
}
#[inline]
pub fn from_bump<'b>(v: bun_alloc::ArenaVec<'b, T>) -> Self {
use bun_alloc::ArenaVecExt as _;
StoreSlice::new_mut(v.into_bump_slice_mut())
}
}
impl<'a, T> From<bun_alloc::ArenaVec<'a, T>> for StoreSlice<T> {
#[inline]
fn from(v: bun_alloc::ArenaVec<'a, T>) -> Self {
StoreSlice::from_bump(v)
}
}
impl<T> Default for StoreSlice<T> {
#[inline]
fn default() -> Self {
StoreSlice::EMPTY
}
}
impl<T> core::ops::Deref for StoreSlice<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.slice()
}
}
impl<T> AsRef<[T]> for StoreSlice<T> {
#[inline]
fn as_ref(&self) -> &[T] {
self.slice()
}
}
impl<T> From<&[T]> for StoreSlice<T> {
#[inline]
fn from(s: &[T]) -> Self {
StoreSlice::new(s)
}
}
impl<T> From<&mut [T]> for StoreSlice<T> {
#[inline]
fn from(s: &mut [T]) -> Self {
StoreSlice::new_mut(s)
}
}
impl<T: core::fmt::Debug> core::fmt::Debug for StoreSlice<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.slice().fmt(f)
}
}
pub const NAMESPACE_EXPORT_PART_INDEX: u32 = 0;
pub type ExprNodeList = AstVec<Expr>;
pub type StmtNodeList = StoreSlice<Stmt>;
pub type BindingNodeList = StoreSlice<Binding>;
#[repr(u8)] #[derive(Copy, Clone, PartialEq, Eq, Debug, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum ImportItemStatus {
None,
Generated,
Missing,
}
#[repr(u8)] #[derive(Copy, Clone, PartialEq, Eq, Debug, Default, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum AssignTarget {
#[default]
None = 0,
Replace = 1,
Update = 2,
}
#[derive(Copy, Clone)]
pub struct LocRef {
pub loc: crate::Loc,
pub ref_: Option<Ref>,
}
impl Default for LocRef {
fn default() -> Self {
Self {
loc: crate::Loc::EMPTY,
ref_: None,
}
}
}
pub struct ClauseItem {
pub alias: ArenaStr,
pub alias_loc: crate::Loc,
pub name: LocRef,
pub original_name: ArenaStr,
}
impl ClauseItem {
pub const DEFAULT_ALIAS: &'static [u8] = b"default";
}
impl Default for ClauseItem {
fn default() -> Self {
Self {
alias: empty_arena_str(),
alias_loc: crate::Loc::EMPTY,
name: LocRef::default(),
original_name: empty_arena_str(),
}
}
}
#[derive(Copy, Clone, Default)]
pub struct SlotCounts {
pub slots: symbol::SlotNamespaceCountsArray,
}
impl SlotCounts {
pub fn union_max(&mut self, other: SlotCounts) {
for (a, b) in self.slots.values_mut().zip(other.slots.values()) {
if *a < *b {
*a = *b;
}
}
}
}
pub struct NameMinifier {
pub head: Vec<u8>,
pub tail: Vec<u8>,
}
impl NameMinifier {
pub const DEFAULT_HEAD: &'static [u8] =
b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$";
pub const DEFAULT_TAIL: &'static [u8] =
b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$";
pub fn init() -> NameMinifier {
NameMinifier {
head: Vec::new(),
tail: Vec::new(),
}
}
pub fn number_to_minified_name(
&self,
name: &mut Vec<u8>,
i_: isize,
) -> core::result::Result<(), bun_alloc::AllocError> {
name.clear();
let mut i = i_;
let mut j = usize::try_from(i.rem_euclid(54)).expect("int cast");
name.extend_from_slice(&self.head[j..j + 1]);
i = i.div_euclid(54);
while i > 0 {
i -= 1;
j = usize::try_from(i.rem_euclid(CHAR_FREQ_COUNT as isize)).expect("int cast");
name.extend_from_slice(&self.tail[j..j + 1]);
i = i.div_euclid(CHAR_FREQ_COUNT as isize);
}
Ok(())
}
pub fn default_number_to_minified_name(
i_: isize,
) -> core::result::Result<Vec<u8>, bun_alloc::AllocError> {
let mut i = i_;
let mut j = usize::try_from(i.rem_euclid(54)).expect("int cast");
let mut name: Vec<u8> = Vec::new();
name.extend_from_slice(&Self::DEFAULT_HEAD[j..j + 1]);
i = i.div_euclid(54);
while i > 0 {
i -= 1;
j = usize::try_from(i.rem_euclid(CHAR_FREQ_COUNT as isize)).expect("int cast");
name.extend_from_slice(&Self::DEFAULT_TAIL[j..j + 1]);
i = i.div_euclid(CHAR_FREQ_COUNT as isize);
}
Ok(name)
}
}
#[repr(u8)] #[derive(Copy, Clone, PartialEq, Eq, Debug, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum OptionalChain {
Start,
Continuation,
}
pub struct EnumValue {
pub loc: crate::Loc,
pub ref_: Ref,
pub name: ArenaStr,
pub value: Option<ExprNodeIndex>,
}
impl EnumValue {
pub fn name_as_e_string(&self, bump: &bun_alloc::Arena) -> E::String {
E::String::init_re_encode_utf8(self.name.slice(), bump)
}
}
pub struct Catch {
pub loc: crate::Loc,
pub binding: Option<BindingNodeIndex>,
pub body: StmtNodeList,
pub body_loc: crate::Loc,
}
pub struct Finally {
pub loc: crate::Loc,
pub stmts: StmtNodeList,
}
pub struct Case {
pub loc: crate::Loc,
pub value: Option<ExprNodeIndex>,
pub body: StmtNodeList,
}
pub struct ArrayBinding {
pub binding: BindingNodeIndex,
pub default_value: Option<ExprNodeIndex>,
}
#[derive(Copy, Clone)]
pub struct TlaCheck {
pub depth: u32,
pub parent: crate::base::IndexInt,
pub import_record_index: crate::base::IndexInt,
}
impl Default for TlaCheck {
fn default() -> Self {
Self {
depth: 0,
parent: Index::INVALID.get(),
import_record_index: Index::INVALID.get(),
}
}
}
#[derive(Copy, Clone)]
pub struct Span {
pub text: ArenaStr,
pub range: crate::Range,
}
impl Default for Span {
fn default() -> Self {
Self {
text: empty_arena_str(),
range: crate::Range::default(),
}
}
}
#[derive(Copy, Clone)]
pub struct InlinedEnumValue {
pub raw_data: u64,
}
#[derive(Copy, Clone)]
pub enum InlinedEnumValueDecoded {
String(*const E::String),
Number(f64),
}
impl InlinedEnumValue {
const DOUBLE_ENCODE_OFFSET: u64 = 1 << 49;
const PURE_NAN: f64 = f64::from_bits(0x7ff8000000000000);
fn purify_nan(value: f64) -> f64 {
if value.is_nan() {
Self::PURE_NAN
} else {
value
}
}
pub fn encode(decoded: InlinedEnumValueDecoded) -> InlinedEnumValue {
let encoded = InlinedEnumValue {
raw_data: match decoded {
InlinedEnumValueDecoded::String(ptr) => {
(ptr as usize as u64) & 0x0000_FFFF_FFFF_FFFF
} InlinedEnumValueDecoded::Number(num) => {
Self::purify_nan(num).to_bits() + Self::DOUBLE_ENCODE_OFFSET
}
},
};
if cfg!(debug_assertions) {
debug_assert!(match encoded.decode() {
InlinedEnumValueDecoded::String(str_) => match decoded {
InlinedEnumValueDecoded::String(orig) => core::ptr::eq(str_, orig),
_ => false,
},
InlinedEnumValueDecoded::Number(num) => match decoded {
InlinedEnumValueDecoded::Number(orig) =>
num.to_bits() == Self::purify_nan(orig).to_bits(),
_ => false,
},
});
}
encoded
}
pub fn decode(self) -> InlinedEnumValueDecoded {
if self.raw_data > 0x0000_FFFF_FFFF_FFFF {
InlinedEnumValueDecoded::Number(f64::from_bits(
self.raw_data - Self::DOUBLE_ENCODE_OFFSET,
))
} else {
InlinedEnumValueDecoded::String(self.raw_data as usize as *const E::String)
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum ExportsKind {
None,
Cjs,
Esm,
EsmWithDynamicFallback,
EsmWithDynamicFallbackFromCjs,
}
impl ExportsKind {
pub fn is_dynamic(self) -> bool {
matches!(
self,
Self::Cjs | Self::EsmWithDynamicFallback | Self::EsmWithDynamicFallbackFromCjs
)
}
pub fn is_esm_with_dynamic_fallback(self) -> bool {
matches!(
self,
Self::EsmWithDynamicFallback | Self::EsmWithDynamicFallbackFromCjs
)
}
}
#[derive(bun_collections::SoaRowDerive, Copy, Clone)]
pub struct DeclaredSymbol {
pub ref_: Ref,
pub is_top_level: bool,
}
pub struct DeclaredSymbolList {
pub entries: MultiArrayList<DeclaredSymbol, bun_alloc::AstAlloc>,
}
impl Default for DeclaredSymbolList {
fn default() -> Self {
Self {
entries: MultiArrayList::new_in(bun_alloc::AstAlloc),
}
}
}
impl DeclaredSymbolList {
pub fn refs(&self) -> &[Ref] {
self.entries.items_named::<Ref>("ref_")
}
pub fn to_owned_slice(&mut self) -> DeclaredSymbolList {
core::mem::take(self)
}
pub fn clone(&self) -> core::result::Result<DeclaredSymbolList, bun_alloc::AllocError> {
Ok(DeclaredSymbolList {
entries: self.entries.clone()?,
})
}
#[inline]
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn append(
&mut self,
entry: DeclaredSymbol,
) -> core::result::Result<(), bun_alloc::AllocError> {
self.ensure_unused_capacity(1)?;
self.append_assume_capacity(entry);
Ok(())
}
pub fn append_list(
&mut self,
other: &DeclaredSymbolList,
) -> core::result::Result<(), bun_alloc::AllocError> {
self.ensure_unused_capacity(other.len())?;
self.append_list_assume_capacity(other);
Ok(())
}
pub fn append_list_assume_capacity(&mut self, other: &DeclaredSymbolList) {
self.entries.append_list_assume_capacity(&other.entries);
}
pub fn append_assume_capacity(&mut self, entry: DeclaredSymbol) {
self.entries.append_assume_capacity(entry);
}
pub fn ensure_total_capacity(
&mut self,
count: usize,
) -> core::result::Result<(), bun_alloc::AllocError> {
self.entries.ensure_total_capacity(count)
}
pub fn ensure_unused_capacity(
&mut self,
count: usize,
) -> core::result::Result<(), bun_alloc::AllocError> {
self.entries.ensure_unused_capacity(count)
}
pub fn clear_retaining_capacity(&mut self) {
self.entries.clear_retaining_capacity();
}
pub fn init_capacity(
capacity: usize,
) -> core::result::Result<DeclaredSymbolList, bun_alloc::AllocError> {
let mut entries = MultiArrayList::new_in(bun_alloc::AstAlloc);
entries.ensure_unused_capacity(capacity)?;
Ok(DeclaredSymbolList { entries })
}
pub fn from_slice(
entries: &[DeclaredSymbol],
) -> core::result::Result<DeclaredSymbolList, bun_alloc::AllocError> {
let mut this = Self::init_capacity(entries.len())?;
for entry in entries {
this.append_assume_capacity(*entry);
}
Ok(this)
}
}
impl DeclaredSymbol {
fn for_each_top_level_symbol_with_type<C>(
decls: &DeclaredSymbolList,
ctx: &mut C,
f: impl Fn(&mut C, Ref),
) {
let entries = decls.entries.slice();
let is_top_level: &[bool] = entries.items_named::<bool>("is_top_level");
let refs: &[Ref] = entries.items_named::<Ref>("ref_");
debug_assert_eq!(is_top_level.len(), refs.len());
for (top, ref_) in is_top_level.iter().zip(refs.iter()) {
if *top {
f(ctx, *ref_);
}
}
}
pub fn for_each_top_level_symbol<C>(
decls: &DeclaredSymbolList,
ctx: &mut C,
f: impl Fn(&mut C, Ref),
) {
Self::for_each_top_level_symbol_with_type(decls, ctx, f);
}
}
#[derive(Copy, Clone)]
pub struct Dependency {
pub source_index: Index,
pub part_index: u32, }
pub type DependencyList = AstVec<Dependency>;
pub type ExprList = Vec<Expr>;
pub type StmtList = Vec<Stmt>;
pub type BindingList = Vec<Binding>;
pub struct Part {
pub stmts: StoreSlice<Stmt>,
pub scopes: StoreSlice<*mut Scope>,
pub import_record_indices: PartImportRecordIndices,
pub declared_symbols: DeclaredSymbolList,
pub symbol_uses: PartSymbolUseMap,
pub import_symbol_property_uses: PartSymbolPropertyUseMap,
pub dependencies: DependencyList,
pub can_be_removed_if_unused: bool,
pub force_tree_shaking: bool,
pub tag: PartTag,
}
pub type PartImportRecordIndices = AstVec<u32>;
pub type PartList<'a> = bun_alloc::ArenaVec<'a, Part>;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PartTag {
None,
JsxImport,
Runtime,
CjsImports,
ReactFastRefresh,
DirnameFilename,
BunTest,
DeadDueToInlining,
CommonjsNamedExport,
ImportToConvertFromRequire,
}
pub type PartSymbolUseMap = ArrayHashMap<Ref, symbol::Use, AutoContext, bun_alloc::AstAlloc>;
pub type PartSymbolPropertyUseMap = ArrayHashMap<
Ref,
StringHashMap<symbol::Use, bun_alloc::AstAlloc>,
AutoContext,
bun_alloc::AstAlloc,
>;
impl Default for Part {
fn default() -> Self {
Self {
stmts: StoreSlice::EMPTY,
scopes: StoreSlice::EMPTY,
import_record_indices: PartImportRecordIndices::new_in(bun_alloc::AstAlloc),
declared_symbols: DeclaredSymbolList::default(),
symbol_uses: PartSymbolUseMap::default(),
import_symbol_property_uses: PartSymbolPropertyUseMap::default(),
dependencies: AstVec::new_in(bun_alloc::AstAlloc),
can_be_removed_if_unused: false,
force_tree_shaking: false,
tag: PartTag::None,
}
}
}
#[derive(Clone, Copy)]
pub enum StmtOrExpr {
Stmt(Stmt),
Expr(Expr),
}
impl Default for StmtOrExpr {
fn default() -> Self {
StmtOrExpr::Expr(Expr::default())
}
}
impl StmtOrExpr {
pub fn to_expr(self) -> Expr {
match self {
StmtOrExpr::Expr(expr) => expr,
StmtOrExpr::Stmt(stmt) => match stmt.data {
crate::stmt::Data::SFunction(mut s) => {
let func = core::mem::take(&mut s.func);
Expr::init(E::Function { func }, stmt.loc)
}
crate::stmt::Data::SClass(mut s) => {
let class = core::mem::take(&mut s.class);
Expr::init::<E::Class>(class, stmt.loc)
}
other => Output::panic(format_args!(
"Unexpected statement type in default export: .{}",
<&'static str>::from(other.tag())
)),
},
}
}
}
pub struct NamedImport {
pub local_parts_with_uses: bun_alloc::AstVec<u32>,
pub alias: Option<ArenaStr>,
pub alias_loc: Option<crate::Loc>,
pub namespace_ref: Option<Ref>,
pub import_record_index: u32,
pub alias_is_star: bool,
pub is_exported: bool,
}
#[derive(Copy, Clone)]
pub struct NamedExport {
pub ref_: Ref,
pub alias_loc: crate::Loc,
}
#[repr(u8)] #[derive(Copy, Clone, PartialEq, Eq, Debug, strum::IntoStaticStr)]
#[strum(serialize_all = "snake_case")]
pub enum StrictModeKind {
SloppyMode,
ExplicitStrictMode,
ImplicitStrictModeImport,
ImplicitStrictModeExport,
ImplicitStrictModeTopLevelAwait,
ImplicitStrictModeClass,
}
pub fn printmem(args: fmt::Arguments<'_>) {
Output::init_test();
Output::print(args);
Output::flush();
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::IntoStaticStr)]
pub enum ToJSError {
#[strum(serialize = "Cannot convert argument type to JS")]
CannotConvertArgumentTypeToJS,
#[strum(serialize = "Cannot convert identifier to JS. Try a statically-known value")]
CannotConvertIdentifierToJS,
MacroError,
OutOfMemory,
JSError,
JSTerminated,
}
bun_core::impl_tag_error!(ToJSError);
bun_core::named_error_set!(ToJSError);
pub struct Batcher<T> {
pub head: StoreSlice<T>,
}
impl<T> Batcher<T> {
pub fn init(
bump: &bun_alloc::Arena,
count: usize,
) -> core::result::Result<Self, bun_alloc::AllocError>
where
T: Default,
{
let all = bump.alloc_slice_fill_default(count);
Ok(Self {
head: StoreSlice::new_mut(all),
})
}
pub fn done(&mut self) {
debug_assert!(self.head.is_empty()); }
pub fn eat(&mut self, value: T) -> *mut T {
self.eat1(value).as_ptr().cast_mut()
}
pub fn eat1(&mut self, value: T) -> StoreSlice<T> {
let head = self.head.slice_mut();
let (prev, rest) = head.split_at_mut(1);
prev[0] = value;
self.head = StoreSlice::new_mut(rest);
StoreSlice::new_mut(prev)
}
pub fn next<const N: usize>(&mut self, values: [T; N]) -> StoreSlice<T> {
let head = self.head.slice_mut();
let (prev, rest) = head.split_at_mut(N);
for (dst, src) in prev.iter_mut().zip(values) {
*dst = src;
}
self.head = StoreSlice::new_mut(rest);
StoreSlice::new_mut(prev)
}
}
pub type NewBatcher<T> = Batcher<T>;
pub mod math {
pub const MAX_SAFE_INTEGER: f64 = 9007199254740991.0;
pub const MIN_SAFE_INTEGER: f64 = -9007199254740991.0;
const MAX_EXPONENT_FOR_INTEGER_MATH_POW: i32 = 1000;
pub fn pow(x: f64, y: f64) -> f64 {
if y.is_nan() {
return f64::NAN;
}
let absolute_base = x.abs();
if absolute_base == 1.0 && y.is_infinite() {
return f64::NAN;
}
if y == 0.5 {
if absolute_base == 0.0 {
return 0.0;
}
if absolute_base == f64::INFINITY {
return f64::INFINITY;
}
return x.sqrt();
}
if y == -0.5 {
if absolute_base == 0.0 {
return f64::INFINITY;
}
if absolute_base == f64::INFINITY {
return 0.0;
}
return 1.0 / x.sqrt();
}
let mut y_as_int = y as i32;
if f64::from(y_as_int) == y
&& (0..=MAX_EXPONENT_FOR_INTEGER_MATH_POW).contains(&y_as_int)
{
let mut result = 1.0;
let mut xd = x;
while y_as_int != 0 {
if y_as_int & 1 != 0 {
result *= xd;
}
xd *= xd;
y_as_int >>= 1;
}
return result;
}
x.powf(y)
}
#[cfg(test)]
mod pow_tests {
use super::*;
#[test]
fn exponent_zero_and_zero_base() {
assert_eq!(pow(0.0, 0.0), 1.0);
assert_eq!(pow(-0.0, 0.0), 1.0);
assert_eq!(pow(0.0, -0.0), 1.0);
assert_eq!(pow(-0.0, -0.0), 1.0);
assert_eq!(pow(f64::NAN, 0.0), 1.0);
}
#[test]
fn integer_exponentiation_by_squaring() {
assert_eq!(pow(2.0, 10.0), 1024.0);
assert_eq!(pow(-2.0, 3.0), -8.0);
assert_eq!(pow(-2.0, 2.0), 4.0);
assert_eq!(pow(-8.0, 3.0), -512.0);
assert_eq!(pow(1.5, 4.0), 5.0625);
assert_eq!(pow(-1.5, 3.0), -3.375);
assert_eq!(pow(7.0, 5.0), 16807.0);
assert_eq!(pow(2.0, 1000.0), 2f64.powi(1000));
assert_eq!(pow(2.0, 1001.0), 2f64.powi(1001));
assert_eq!(pow(2.0, -2.0), 0.25);
}
#[test]
fn nan_and_infinity_propagation() {
assert!(pow(f64::NAN, 1.0).is_nan());
assert!(pow(1.0, f64::NAN).is_nan());
assert!(pow(1.0, f64::INFINITY).is_nan());
assert!(pow(-1.0, f64::INFINITY).is_nan());
assert!(pow(1.0, f64::NEG_INFINITY).is_nan());
assert_eq!(pow(f64::INFINITY, 2.0), f64::INFINITY);
assert_eq!(pow(2.0, f64::INFINITY), f64::INFINITY);
}
#[test]
fn half_exponent_sqrt_paths() {
assert_eq!(pow(4.0, 0.5), 2.0);
assert_eq!(pow(2.0, 0.5), 2f64.sqrt());
assert_eq!(pow(0.0, 0.5), 0.0);
assert_eq!(pow(f64::INFINITY, 0.5), f64::INFINITY);
assert_eq!(pow(4.0, -0.5), 0.5);
assert_eq!(pow(0.0, -0.5), f64::INFINITY);
assert_eq!(pow(f64::INFINITY, -0.5), 0.0);
assert!(pow(-4.0, 0.5).is_nan());
}
}
}
pub type MangledProps = ArrayHashMap<Ref, StoreStr>;