Skip to content
  •  
  •  
  •  
9 changes: 2 additions & 7 deletions src/ast/ast_memory_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ use crate::stmt;
// stack-fallback would still avoid the heap entirely for small modules — left
// for a follow-up.)

// TODO(port): `Expr.Data.Store.memory_allocator` / `Stmt.Data.Store.memory_allocator` are
// `threadlocal var ?*ASTMemoryAllocator` in Zig, read/written directly. Phase B must expose
// `memory_allocator() -> *mut ASTMemoryAllocator`, `set_memory_allocator(*mut ASTMemoryAllocator)`,
// and `begin()` on the Rust `expr::data::Store` / `stmt::data::Store` (thread_local! + Cell).

// ── Thread-local arena pool ──────────────────────────────────────────────
//
// Zig's `ASTMemoryAllocator` was a `StackFallbackAllocator(8192, fallback)`:
Expand Down Expand Up @@ -114,7 +109,7 @@ impl ASTMemoryAllocator {
/// `a.enter(arena)` (passing the fallback `std.mem.Allocator`). In the
/// Rust port the SFA + fallback collapse to a single internal `Arena`, so
/// the passed arena is currently unused — kept for call-site shape compat.
// TODO(port): if Phase B routes the parser bump arena through here instead
// TODO(port): if the parser bump arena is ever routed through here instead
// of allocating a fresh one, thread `_fallback` into `self.arena`.
pub fn new(_fallback: &Arena) -> Self {
// PERF(port): was stack-fallback — profile
Expand Down Expand Up @@ -221,7 +216,7 @@ impl ASTMemoryAllocator {
}

/// Zig: `this.stack_allocator.get()` — the `std.mem.Allocator` vtable into
/// the stack-fallback buffer. In Phase A both `stack_allocator` and
/// the stack-fallback buffer. In the Rust port both `stack_allocator` and
/// `bump_allocator` collapse to the single `Arena`, so this returns it.
#[inline]
pub fn stack_allocator(&self) -> &Arena {
Expand Down
4 changes: 2 additions & 2 deletions src/ast/b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ pub use crate::ArrayBinding;
/// ----------------
/// B.Object
// Zig: `union(Binding.Tag)` — tag enum lives on `Binding::Tag`.
// PORT NOTE: arena ptrs are raw `*mut` in Phase A (LIFETIMES.tsv: ARENA → raw);
// 'bump threaded crate-wide (`&'bump mut T`).
// PORT NOTE: arena values are referenced via `StoreRef<T>` (LIFETIMES.tsv: ARENA)
// rather than a threaded `&'bump mut T`.
#[derive(Copy, Clone, bun_core::EnumTag)]
#[enum_tag(existing = super::binding::Tag)]
pub enum B {
Expand Down
25 changes: 12 additions & 13 deletions src/ast/e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ impl Array {
};

/// Zig: `pub fn push(this: *Array, arena, item) !void`.
/// Phase A `Vec::append` uses the global arena; `_bump` is kept
/// `Vec::append` uses the global arena; `_bump` is kept
/// for call-site shape parity and the eventual bump-arena Vec.
pub fn push(&mut self, _bump: &Bump, item: Expr) -> Result<(), AllocError> {
VecExt::append(&mut self.items, item);
Expand All @@ -98,7 +98,7 @@ impl Array {
estimated_count: usize,
) -> Result<ExprNodeList, AllocError> {
// This over-allocates a little but it's fine
// PERF(port): Zig allocated in arena; Phase-A Vec uses global arena.
// PERF(port): Zig allocated in arena; this Vec uses the global arena.
// `Expr.data` is an enum (validity invariant), so the Zig
// `expandToCapacity` + index-walk pattern would form `&mut [Expr]`
// over invalid bit patterns. Push into reserved capacity instead —
Expand Down Expand Up @@ -685,13 +685,12 @@ pub enum JSXSpecialProp {
}
impl JSXSpecialProp {
// PERF(port): Zig used `ComptimeStringMap` (length-prefix lookup, all
// resolved at comptime). Phase A reached for `phf::Map`, which on every
// JSX prop name computes a full SipHash + index + slice compare even
// though the overwhelming majority of inputs (`className`, `onClick`,
// `style`, ...) miss. With only 4 keys at 3 distinct lengths, a
// length-gated `match` rejects almost every miss on a single `usize`
// compare and never hashes. See clap::find_param (12577e958d71) for the
// same pattern.
// resolved at comptime). A `phf::Map` here would compute a full SipHash +
// index + slice compare on every JSX prop name even though the
// overwhelming majority of inputs (`className`, `onClick`, `style`, ...)
// miss. With only 4 keys at 3 distinct lengths, a length-gated `match`
// rejects almost every miss on a single `usize` compare and never hashes.
// See clap::find_param (12577e958d71) for the same pattern.
#[inline]
pub fn from_bytes(s: &[u8]) -> Option<Self> {
match s.len() {
Expand All @@ -709,7 +708,7 @@ impl JSXSpecialProp {

// `Missing` re-exported from `crate::E` above.
// TODO(port): `Missing::json_stringify` — Zig std.json protocol; orphan rules
// prevent an inherent impl here now that the type lives at T2. Phase B picks a
// prevent an inherent impl here now that the type lives at T2. Pick a
// serde strategy (extension trait or move the method down).

#[derive(Clone, Copy)]
Expand Down Expand Up @@ -895,7 +894,7 @@ impl Default for Object {

/// used in TOML parser to merge properties.
///
/// Phase A keeps node types lifetime-free, so `next` is a raw `*mut Rope`
/// Node types are lifetime-free, so `next` is a raw `*mut Rope`
/// into the bump arena (Zig: `next: ?*Rope`). Segments are bulk-freed at
/// arena reset.
pub struct Rope {
Expand Down Expand Up @@ -1575,7 +1574,7 @@ impl EString {
}

/// Zig `string(arena)` — return UTF-8 bytes, transcoding if UTF-16.
/// Phase A: transcode allocates via global arena then copies into
/// The transcode allocates via the global arena then copies into
/// `bump` (Zig used the passed arena directly).
pub fn string<'b>(&self, bump: &'b Bump) -> Result<&'b [u8], AllocError> {
if self.is_utf8() {
Expand Down Expand Up @@ -1816,7 +1815,7 @@ impl EString {
}
}

// TODO(port): jsonStringify — Zig std.json protocol; Phase B picks a serde strategy.
// TODO(port): jsonStringify — Zig std.json protocol; pick a serde strategy.
pub fn json_stringify<W>(&self, writer: &mut W) -> Result<(), bun_core::Error> {
let _ = writer;
let mut buf = [0u8; 4096];
Expand Down
15 changes: 7 additions & 8 deletions src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use core::fmt;
use crate::Loc;
use bun_alloc::{AllocError, Arena as Bump};
use bun_collections::{ArrayHashMap, VecExt};
use bun_core::ZStr;
use bun_core::{self};
use bun_core::{ZStr, strings};

use crate::{DebugOnlyDisabler, E, G, Op, Ref, S, Stmt};
use bun_alloc::ArenaVecExt as _;
Expand Down Expand Up @@ -708,12 +708,11 @@ impl ArrayIterator {
}
}

// TODO(b2-ast-round-C): same as above (string/array accessors).
// PORT NOTE: the Phase-A draft of `as_array`/`is_string`/`as_utf8_string_literal`/
// PORT NOTE: earlier drafts of `as_array`/`is_string`/`as_utf8_string_literal`/
// `as_string`/`as_string_cloned`/`as_bool`/`as_number` duplicated the live `&self`
// implementations above (lines ~231-315) with worse signatures (`expr: &Expr`,
// raw-ptr returns). Those drafts were dropped during un-gating; only the methods
// without a live counterpart remain.
// raw-ptr returns). Those drafts were dropped; only the methods without a live
// counterpart remain.
impl Expr {
#[inline]
pub fn as_string_literal<'b>(&self, bump: &'b Bump) -> Option<&'b [u8]> {
Expand Down Expand Up @@ -960,8 +959,8 @@ impl Expr {
}
}

// TODO(port): jsonStringify protocol — replace with serde or custom trait in
// Phase B. Kept gated; `Serializable` is its payload shape.
// TODO(refactor): jsonStringify protocol — replace with serde or a custom trait.
// `Serializable` is its payload shape.

impl Expr {
// PORT NOTE: Zig's `jsonStringify` fed `Serializable` to `std.json.stringify`.
Expand Down Expand Up @@ -3387,7 +3386,7 @@ pub mod data {
crate::thread_local_ast_store!(expr_store::Store, "Expr");
}

/// Compatibility shim: Phase-A draft callers in this file used `Store::method()`
/// Compatibility shim: callers in this file use `Store::method()`
/// (impl-on-struct namespace). Forward to the real `data::Store` module.
pub use data::Store;

Expand Down
2 changes: 1 addition & 1 deletion src/ast/g.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ pub enum PropertyKind {

impl PropertyKind {
// TODO(port): Zig `jsonStringify(self, writer: anytype) !void` — maps to a serde-like
// protocol writing @tagName(self). Phase B: decide on the json writer trait.
// protocol writing @tagName(self). Decide on a shared json writer trait.
pub fn json_stringify(self, writer: &mut impl core::fmt::Write) -> core::fmt::Result {
// Zig: `writer.write(@tagName(self))` on a std.json WriteStream — emits a
// *quoted* JSON string. Tag names are [a-z_] so no escaping needed.
Expand Down
4 changes: 2 additions & 2 deletions src/ast/import_record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use crate::{ImportKind, Index, Loader};
pub struct ImportRecord {
pub range: Range,
// TODO(port): lifetime — `bun_paths::fs::Path<'a>` borrows resolver-owned
// strings. Phase A uses 'static (PORTING.md: no struct lifetime params).
// strings. Uses 'static (PORTING.md: no struct lifetime params).
pub path: Path<'static>,
pub kind: ImportKind,
pub tag: Tag,
Expand All @@ -35,7 +35,7 @@ pub struct ImportRecord {
/// This is preserved before resolution overwrites `path` with the resolved path.
/// Used for metafile generation.
// TODO(port): lifetime — Zig `[]const u8` defaulting to "", never freed in this file.
// Likely a borrow into parser-owned source text; using &'static [u8] as Phase-A placeholder.
// Likely a borrow into parser-owned source text; using &'static [u8] as a placeholder.
pub original_path: &'static [u8],

/// Pack all boolean flags into 2 bytes to reduce padding overhead.
Expand Down
4 changes: 2 additions & 2 deletions src/ast/known_global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub enum KnownGlobal {
// `pub const map = bun.ComptimeEnumMap(KnownGlobal);`
//
// PERF(port): Zig's `ComptimeEnumMap` lowers to a comptime-generated switch.
// Phase A used `phf::Map<&[u8], _>`, which on every probe computes a 128-bit
// An earlier port used `phf::Map<&[u8], _>`, which on every probe computes a 128-bit
// SipHash of the name, two modular reductions, a bounds check, and a final
// slice compare. `minify_global_constructor` calls this for every `new Ident`
// expression in the input, and the overwhelming majority of probes are
Expand Down Expand Up @@ -113,7 +113,7 @@ impl KnownGlobal {
}

// PORT NOTE: `_bump` is kept for call-site shape parity with the Zig
// `std.mem.Allocator` arg. Phase-A `Vec` uses the global arena.
// `std.mem.Allocator` arg. The `Vec` uses the global arena.
#[inline(never)]
pub fn minify_global_constructor(
_bump: &Bump,
Expand Down
6 changes: 3 additions & 3 deletions src/ast/lexer_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,9 @@ pub fn is_type_script_accessibility_modifier(s: &[u8]) -> bool {
}
}

/// `.rodata` `[&[u8]; T::COUNT]` indexed by [`T`] discriminant. Replaces the
/// `LazyLock<EnumMap<T, _>>` Phase-A scaffolding so lookup is a plain array
/// index with zero init code (matches Zig `std.EnumArray`).
/// `.rodata` `[&[u8]; T::COUNT]` indexed by [`T`] discriminant. Replaces an
/// earlier `LazyLock<EnumMap<T, _>>` so lookup is a plain array index with
/// zero init code (matches Zig `std.EnumArray`).
#[repr(transparent)]
pub struct TokenEnumType(pub [&'static [u8]; <T as Enum>::LENGTH]);

Expand Down
24 changes: 12 additions & 12 deletions src/ast/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
//! mixed/ambiguous ownership in the Zig original (see the comment on
//! `Location::deinit`: "don't really know what's safe to deinit here!"). Strings
//! are sometimes literals, sometimes `allocator.dupe` results, sometimes slices
//! into `Source.contents` or a `StringBuilder` arena. Phase A keeps them as
//! into `Source.contents` or a `StringBuilder` arena. They are kept as
//! `&'static [u8]` to mirror the Zig `[]const u8` shape without lifetime params;
//! Phase B must decide on a real ownership story (likely `bun_core::String` or a
//! `'source` lifetime threaded through `Location`/`Data`/`Msg`).
//! a real ownership story (likely `bun_core::String` or a `'source` lifetime
//! threaded through `Location`/`Data`/`Msg`) is still needed.

#![warn(unreachable_pub)]
use core::fmt;
Expand Down Expand Up @@ -510,17 +510,17 @@ pub mod api {
}
}

/// Phase-A `[]const u8` parameter shim — accepts `&str` / `&[u8]` (any lifetime)
/// `[]const u8` parameter shim — accepts `&str` / `&[u8]` (any lifetime)
/// and erases to the crate-wide `Str` (`&'static [u8]`) lie so callers in either
/// string flavour compile against the same Zig-shaped signatures.
/// TODO(port): lifetime — remove with `Str` once Phase B threads `'source`.
/// TODO(port): lifetime — remove with `Str` once `'source` is threaded through.
pub trait IntoStr {
fn into_str(self) -> Str;
}
impl IntoStr for &[u8] {
#[inline]
fn into_str(self) -> Str {
// SAFETY: Phase-A lifetime erasure; see module-level OWNERSHIP note.
// SAFETY: lifetime erasure; see module-level OWNERSHIP note.
unsafe { bun_collections::detach_lifetime(self) }
}
}
Expand Down Expand Up @@ -1572,7 +1572,7 @@ impl Log {
/// Port of Zig's `log.msgs.allocator.dupe(u8, s)` pattern: copy `s` into
/// storage owned by this `Log` and return a `&'static [u8]` view. The
/// returned slice is valid for as long as `self` lives (the box is never
/// moved out of `owned_strings`); `'static` is a Phase-A erasure matching
/// moved out of `owned_strings`); `'static` is a lifetime erasure matching
/// the `Str` alias used by `Location`/`Msg`. NOT a leak — the bytes free
/// when the `Log` drops.
pub fn dupe(&mut self, s: &[u8]) -> &'static [u8] {
Expand Down Expand Up @@ -2150,8 +2150,8 @@ impl Log {
let data = Data {
text: alloc_print(args),
location: Some(Location {
// TODO(port): lifetime — Phase A keeps `Location.file` borrowing
// `Str`; Phase B threads real ownership (see module doc).
// TODO(port): lifetime — `Location.file` borrows `Str`; thread
// real ownership through (see module doc).
file: Cow::Borrowed(filepath),
line: i32::try_from(line).expect("int cast"),
column: i32::try_from(col).expect("int cast"),
Expand Down Expand Up @@ -2500,7 +2500,7 @@ pub struct AddErrorOptions<'a> {
pub redact_sensitive_information: bool,
}

/// Downstream-compat alias: B-1 callers (`bunfig.rs`, `PnpmMatcher.rs`) spell
/// Downstream-compat alias: some callers (`bunfig.rs`, `PnpmMatcher.rs`) spell
/// the option-struct as `bun_ast::ErrorOpts { .. }` (Zig: `Log.addError*` opts
/// param). Same layout as `AddErrorOptions`; the canonical name is kept while
/// the Zig side still calls it `addErrorOpts`.
Expand Down Expand Up @@ -2982,7 +2982,7 @@ pub struct ToSourceOptions {
pub convert_bom: bool,
}

/// Downstream-compat alias: B-1 callers (`ini::load_npmrc_config`) spell the
/// Downstream-compat alias: some callers (`ini::load_npmrc_config`) spell the
/// option-struct as `bun_ast::ToSourceOpts { convert_bom: true }`.
pub type ToSourceOpts = ToSourceOptions;

Expand Down Expand Up @@ -3012,7 +3012,7 @@ pub fn source_from_file_at(
bytes = bom.remove_and_convert_to_utf8_and_free(bytes);
}
}
// `path` is caller-owned; goes through the Phase-A `IntoStr` borrow shim
// `path` is caller-owned; goes through the `IntoStr` borrow shim
// (same as every other `Source` constructor). `bytes` is owned by the
// returned `Source` via `Cow::Owned` — no leaking.
Ok(Source::init_path_string_owned(path.as_bytes(), bytes))
Expand Down
3 changes: 1 addition & 2 deletions src/ast/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,7 @@ impl Loader {
slice_
};
// Zig: names.getWithEql(slice, strings.eqlCaseInsensitiveASCIIICheckLength)
// TODO(port): phf is case-sensitive; Phase B may need a lowercase pass or
// bun_core::eql_case_insensitive_ascii lookup over NAMES.entries().
// phf is case-sensitive, so fall back to a case-insensitive scan over NAMES.entries().
Self::NAMES.get(slice).copied().or_else(|| {
Self::NAMES
.entries()
Expand Down
2 changes: 1 addition & 1 deletion src/ast/new_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ macro_rules! new_store {
/// Zig: `pub const Block = struct { ... }`
// PORT NOTE: `buffer` needs `align(LARGEST_ALIGN)` but `#[repr(align(N))]`
// requires a literal. Over-approximate with align(16) — every AST payload
// type is `<= 16` aligned (asserted below). Phase B can switch to a
// type is `<= 16` aligned (asserted below). Switch to a
// `#[repr(C)] union AlignUnion { $($T),+ }` element type if a >16-aligned
// payload is ever introduced.
const _: () = assert!(LARGEST_ALIGN <= 16, "NewStore payload type with align>16; bump Block repr(align)");
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1036,7 +1036,7 @@ impl DeclaredSymbolList {
}
// TODO(port): arena threading — Zig passes `std.mem.Allocator` to every
// MultiArrayList op. bun_collections::MultiArrayList owns its arena (global
// mimalloc); if Phase B needs arena-backed SoA storage, add a `&'bump Bump`
// mimalloc); if arena-backed SoA storage is ever needed, add a `&'bump Bump`
// param here.

impl DeclaredSymbol {
Expand Down
2 changes: 1 addition & 1 deletion src/ast/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ macro_rules! impl_statement_data {
}
#[inline]
fn arena_alloc(self, bump: &bun_alloc::Arena) -> Data {
// TODO(port): StoreRef vs &'bump — Phase B unify arena ref type
// TODO(port): StoreRef vs &'bump — unify the arena ref type.
Data::$variant(StoreRef::from_bump(bump.alloc(self)))
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/ast/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ pub struct Symbol {
}

// TODO(port): Zig asserts @sizeOf(Symbol) == 88 and @alignOf(Symbol) == @alignOf([]const u8).
// Rust default repr reorders fields and Option<NamespaceAlias> niche may differ; verify in
// Phase B (likely needs #[repr(C)] or manual packing if the size is load-bearing).
// Rust default repr reorders fields and Option<NamespaceAlias> niche may differ
// (likely needs #[repr(C)] or manual packing if the size is load-bearing).
// const _: () = assert!(core::mem::size_of::<Symbol>() == 88);
// const _: () = assert!(core::mem::align_of::<Symbol>() == core::mem::align_of::<crate::StoreStr>());

Expand Down
4 changes: 2 additions & 2 deletions src/ast/ts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ use crate::e::String as EString;
/// hierarchical scope-based identifier lookup in JavaScript. Lookup now needs
/// to search sibling scopes in addition to parent scopes. This is accomplished
/// by sharing the map of exported members between all matching sibling scopes.
// PORT NOTE: 'arena lifetime dropped — `EnumString` payload uses *const EString
// (LIFETIMES.tsv ARENA → raw ptr in Phase A; Phase B threads 'bump crate-wide).
// PORT NOTE: 'arena lifetime dropped — `EnumString` payload is a `StoreRef<EString>`
// rather than an arena-borrowed reference (see the TODO on that variant).
pub struct TSNamespaceScope {
/// This is specific to this namespace block. It's the argument of the
/// immediately-invoked function expression that the namespace block is
Expand Down
Loading
Loading