diff --git a/.github/.generated_ast_watch_list.yml b/.github/.generated_ast_watch_list.yml index 3e455247fdf84..c3e880c417a89 100644 --- a/.github/.generated_ast_watch_list.yml +++ b/.github/.generated_ast_watch_list.yml @@ -39,10 +39,16 @@ src: - 'crates/oxc_syntax/src/generated/derive_content_eq.rs' - 'crates/oxc_syntax/src/generated/derive_estree.rs' - 'crates/oxc_syntax/src/lib.rs' + - 'crates/oxc_syntax/src/module_record.rs' - 'crates/oxc_syntax/src/number.rs' - 'crates/oxc_syntax/src/operator.rs' - 'crates/oxc_syntax/src/reference.rs' - 'crates/oxc_syntax/src/scope.rs' + - 'crates/oxc_syntax/src/serialize.rs' - 'crates/oxc_syntax/src/symbol.rs' + - 'napi/parser/deserialize.js' + - 'napi/parser/src/generated/assert_layouts.rs' + - 'napi/parser/src/generated/derive_estree.rs' + - 'napi/parser/src/raw_transfer_types.rs' - 'npm/oxc-types/types.d.ts' - 'tasks/ast_tools/src/**' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 027fcc1419f57..688a3836f1b95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -303,6 +303,8 @@ jobs: filters: | src: - '!crates/oxc_linter/**' + - uses: ./.github/actions/clone-submodules + if: steps.filter.outputs.src == 'true' - uses: oxc-project/setup-rust@cd82e1efec7fef815e2c23d296756f31c7cdc03d # v1.0.0 if: steps.filter.outputs.src == 'true' with: @@ -311,7 +313,7 @@ jobs: if: steps.filter.outputs.src == 'true' - if: steps.filter.outputs.src == 'true' run: | - pnpm run build-dev + pnpm run build pnpm run test pnpm --filter e2e run test git diff --exit-code # Must commit everything diff --git a/Cargo.lock b/Cargo.lock index ec1a6426b32ff..f6bd8a9931797 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1994,6 +1994,8 @@ dependencies = [ "napi-build", "napi-derive", "oxc", + "oxc_ast_macros", + "oxc_estree", "oxc_napi", "rustc-hash", ] diff --git a/Cargo.toml b/Cargo.toml index b0328989d9f7f..f45df27c260bf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,7 +160,11 @@ assert-unchecked = "0.1.2" base64 = "0.22.1" bitflags = "2.8.0" bpaf = "0.9.16" -bumpalo = "3.17.0" +# `bumpalo` must be pinned to exactly this version. +# `Allocator::from_raw_parts` (used in raw transfer) depends on internal implementation details +# of `bumpalo` which may change in a future version. +# This is a temporary situation - we'll replace `bumpalo` with our own allocator. +bumpalo = "=3.17.0" compact_str = "0.8.1" console = "0.15.10" console_error_panic_hook = "0.1.7" diff --git a/crates/oxc/Cargo.toml b/crates/oxc/Cargo.toml index 0f9e35bc76361..fd20d6e86fb51 100644 --- a/crates/oxc/Cargo.toml +++ b/crates/oxc/Cargo.toml @@ -65,6 +65,7 @@ isolated_declarations = ["oxc_isolated_declarations"] ast_visit = ["oxc_ast_visit"] serialize = [ + "oxc_allocator/from_raw_parts", "oxc_ast/serialize", "oxc_ast_visit/serialize", "oxc_semantic?/serialize", diff --git a/crates/oxc_allocator/Cargo.toml b/crates/oxc_allocator/Cargo.toml index 3809dbf983578..9c408268091ce 100644 --- a/crates/oxc_allocator/Cargo.toml +++ b/crates/oxc_allocator/Cargo.toml @@ -34,4 +34,5 @@ serde = { workspace = true } serde_json = { workspace = true } [features] +from_raw_parts = [] serialize = ["dep:serde", "oxc_estree/serialize"] diff --git a/crates/oxc_allocator/src/allocator.rs b/crates/oxc_allocator/src/allocator.rs index 0848e5529c621..da3ed9503ddfc 100644 --- a/crates/oxc_allocator/src/allocator.rs +++ b/crates/oxc_allocator/src/allocator.rs @@ -435,6 +435,18 @@ impl Allocator { pub(crate) fn bump(&self) -> &Bump { &self.bump } + + /// Create [`Allocator`] from a [`bumpalo::Bump`]. + /// + /// This method is not public. Only used by [`Allocator::from_raw_parts`]. + // + // `#[inline(always)]` because it's a no-op + #[cfg(feature = "from_raw_parts")] + #[expect(clippy::inline_always)] + #[inline(always)] + pub(crate) fn from_bump(bump: Bump) -> Self { + Self { bump } + } } /// SAFETY: Not actually safe, but for enabling `Send` for downstream crates. diff --git a/crates/oxc_allocator/src/from_raw_parts.rs b/crates/oxc_allocator/src/from_raw_parts.rs new file mode 100644 index 0000000000000..3339a9f582e2c --- /dev/null +++ b/crates/oxc_allocator/src/from_raw_parts.rs @@ -0,0 +1,206 @@ +//! Define additional [`Allocator::from_raw_parts`] method, used only by raw transfer. + +use std::{ + alloc::Layout, + cell::Cell, + ptr::{self, NonNull}, +}; + +use bumpalo::Bump; + +use crate::Allocator; + +/// Minimum alignment for allocator chunks. This is hard-coded on `bumpalo`. +const MIN_ALIGN: usize = 16; + +const CHUNK_FOOTER_SIZE: usize = size_of::(); +const _: () = { + assert!(CHUNK_FOOTER_SIZE >= MIN_ALIGN); + assert!(align_of::() <= MIN_ALIGN); +}; + +impl Allocator { + /// Minimum size for memory chunk passed to [`Allocator::from_raw_parts`]. + pub const RAW_MIN_SIZE: usize = CHUNK_FOOTER_SIZE; + + /// Minimum alignment for memory chunk passed to [`Allocator::from_raw_parts`]. + pub const RAW_MIN_ALIGN: usize = MIN_ALIGN; + + /// Construct a static-sized [`Allocator`] from an existing memory allocation. + /// + /// **IMPORTANT: WE MUST NOT CHANGE THE VERSION OF BUMPALO DEPENDENCY**. + /// + /// This code only remains sound as long as the code in version of `bumpalo` we're using matches + /// the duplicate of `bumpalo`'s internals contained in this file. + /// + /// `bumpalo` is pinned to version `=3.17.0` in `Cargo.toml`. + /// + /// The [`Allocator`] which is returned takes ownership of the memory allocation, + /// and the allocation will be freed if the `Allocator` is dropped. + /// If caller wishes to prevent that happening, they must wrap the `Allocator` in `ManuallyDrop`. + /// + /// The [`Allocator`] returned by this function cannot grow. + /// + /// This hack is all very inadvisable! + /// Only implemented as a temporary stopgap until we replace `bumpalo` with our own allocator. + /// + /// # SAFETY + /// + /// * `ptr` must be aligned on [`RAW_MIN_ALIGN`]. + /// * `size` must be a multiple of [`RAW_MIN_ALIGN`]. + /// * `size` must be at least [`RAW_MIN_SIZE`]. + /// * The memory region starting at `ptr` and encompassing `size` bytes must be within + /// a single allocation. + /// + /// # Panics + /// + /// Panics if cannot determine layout of Bumpalo's `Bump` type. + /// + /// [`RAW_MIN_ALIGN`]: Self::RAW_MIN_ALIGN + /// [`RAW_MIN_SIZE`]: Self::RAW_MIN_SIZE + pub unsafe fn from_raw_parts(ptr: NonNull, size: usize) -> Self { + // Only support little-endian systems. + // Calculating offset of `current_chunk_footer` on big-endian systems would be difficult. + #[cfg(target_endian = "big")] + const { + panic!("`Allocator::from_raw_parts` is not supported on big-endian systems."); + } + + // Debug assert that `ptr` and `size` fulfill size and alignment requirements + debug_assert!(is_multiple_of(ptr.as_ptr() as usize, MIN_ALIGN)); + debug_assert!(is_multiple_of(size, MIN_ALIGN)); + debug_assert!(size >= CHUNK_FOOTER_SIZE); + + // `Bump` is defined as: + // + // ``` + // pub struct Bump { + // current_chunk_footer: Cell>, + // allocation_limit: Cell>, + // } + // ``` + // + // `Bump` is not `#[repr(C)]`, so which order the fields are in is unpredictable. + // Deduce the offset of `current_chunk_footer` field by creating a dummy `Bump` where the value + // of the `allocation_limit` field is known. + // + // This should all be const-folded down by compiler. + let current_chunk_footer_field_offset: usize = { + const { + assert!(size_of::() == size_of::<[usize; 3]>()); + assert!(align_of::() == align_of::<[usize; 3]>()); + assert!(size_of::>>() == size_of::()); + assert!(align_of::>>() == align_of::()); + assert!(size_of::>>() == size_of::<[usize; 2]>()); + assert!(align_of::>>() == align_of::()); + } + + let bump = Bump::new(); + bump.set_allocation_limit(Some(123)); + + // SAFETY: + // `Bump` has same layout as `[usize; 3]` (checked by const assertions above). + // Strictly speaking, reading the fields as `usize`s is UB, as the layout of `Option` + // is not specified. But in practice, `Option` stores its discriminant before its payload, + // so either field order means 3rd `usize` is fully initialized + // (it's either `NonNull>` or the `usize` in `Option`). + // Once we've figured out the field order, should be safe to check the `Option` + // discriminant as a `u8`. + // Const assertion at top of this function ensures this is a little-endian system, + // so first byte of the 8 bytes containing the discriminant will be initialized, regardless + // of whether compiler chooses to represent the discriminant as `u8`, `u16`, `u32` or `u64`. + unsafe { + let ptr = ptr::from_ref(&bump).cast::(); + if *ptr.add(2) == 123 { + // `allocation_limit` is 2nd field. So `current_chunk_footer` is 1st. + assert_eq!(*ptr.add(1).cast::(), 1); + 0 + } else { + // `allocation_limit` is 1st field. So `current_chunk_footer` is 2nd. + assert_eq!(*ptr.add(1), 123); + assert_eq!(*ptr.cast::(), 1); + 2 + } + } + }; + + // Create empty bump with allocation limit of 0 - i.e. it cannot grow. + // This means that the memory chunk we're about to add to the `Bump` will remain its only chunk. + // Therefore it can never be deallocated, until the `Allocator` is dropped. + // `Allocator::reset` would only reset the "cursor" pointer, not deallocate the memory. + let bump = Bump::new(); + bump.set_allocation_limit(Some(0)); + + // Get pointer to `EmptyChunkFooter`. + // SAFETY: We've established the offset of the `current_chunk_footer` field above. + let current_chunk_footer_field = unsafe { + let field_ptr = ptr::addr_of!(bump) + .cast::>>() + .add(current_chunk_footer_field_offset); + &*field_ptr + }; + let empty_chunk_footer_ptr = current_chunk_footer_field.get(); + + // Construct `ChunkFooter` and write into end of allocation. + // SAFETY: Caller guarantees: + // 1. `ptr` is the start of an allocation of `size` bytes. + // 2. `size` is `>= CHUNK_FOOTER_SIZE` - so `size - CHUNK_FOOTER_SIZE` cannot wrap around. + let chunk_footer_ptr = unsafe { ptr.add(size - CHUNK_FOOTER_SIZE) }; + // SAFETY: Caller guarantees `size` is a multiple of 16 + let layout = unsafe { Layout::from_size_align_unchecked(size, 16) }; + let chunk_footer = ChunkFooter { + data: ptr, + layout, + prev: Cell::new(empty_chunk_footer_ptr), + ptr: Cell::new(chunk_footer_ptr), + allocated_bytes: 0, + }; + let chunk_footer_ptr = chunk_footer_ptr.cast::(); + // SAFETY: If caller has upheld safety requirements, `chunk_footer_ptr` is `CHUNK_FOOTER_SIZE` + // bytes from the end of the allocation, and aligned on 16. + // Const assertions at top of this file ensure that is sufficient alignment for `ChunkFooter`. + // Therefore `chunk_footer_ptr` is valid for writing a `ChunkFooter`. + unsafe { chunk_footer_ptr.write(chunk_footer) }; + + // Write chunk header into bump's `chunk_header` field + current_chunk_footer_field.set(chunk_footer_ptr); + + Self::from_bump(bump) + } +} + +/// Allocator chunk footer. +/// +/// Copied exactly from `bumpalo` v3.17.0. +/// +/// This type is not exposed by `bumpalo` crate, but the type is `#[repr(C)]`, so we can rely on our +/// duplicate here having the same layout, as long as we don't change the version of `bumpalo` we use. +#[repr(C)] +#[derive(Debug)] +struct ChunkFooter { + /// Pointer to the start of this chunk allocation. + /// This footer is always at the end of the chunk. + data: NonNull, + + /// The layout of this chunk's allocation. + layout: Layout, + + /// Link to the previous chunk. + /// + /// Note that the last node in the `prev` linked list is the canonical empty + /// chunk, whose `prev` link points to itself. + prev: Cell>, + + /// Bump allocation finger that is always in the range `self.data..=self`. + ptr: Cell>, + + /// The bytes allocated in all chunks so far. + /// The canonical empty chunk has a size of 0 and for all other chunks, `allocated_bytes` will be + /// the allocated_bytes of the current chunk plus the allocated bytes of the `prev` chunk. + allocated_bytes: usize, +} + +/// Returns `true` if `n` is a multiple of `divisor`. +const fn is_multiple_of(n: usize, divisor: usize) -> bool { + n % divisor == 0 +} diff --git a/crates/oxc_allocator/src/lib.rs b/crates/oxc_allocator/src/lib.rs index e06e352e3f720..ea3a3c9cc8e6e 100644 --- a/crates/oxc_allocator/src/lib.rs +++ b/crates/oxc_allocator/src/lib.rs @@ -20,6 +20,8 @@ mod allocator_api2; mod boxed; mod clone_in; mod convert; +#[cfg(feature = "from_raw_parts")] +mod from_raw_parts; pub mod hash_map; pub mod string; mod vec; diff --git a/crates/oxc_ast/src/ast/comment.rs b/crates/oxc_ast/src/ast/comment.rs index 9ca7d9f6c47fb..fc5871911f2d0 100644 --- a/crates/oxc_ast/src/ast/comment.rs +++ b/crates/oxc_ast/src/ast/comment.rs @@ -1,12 +1,14 @@ #![warn(missing_docs)] use oxc_allocator::CloneIn; use oxc_ast_macros::ast; +use oxc_estree::ESTree; use oxc_span::{ContentEq, Span}; /// Indicates a line or block comment. #[ast] -#[generate_derive(CloneIn, ContentEq)] +#[generate_derive(CloneIn, ContentEq, ESTree)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +#[estree(no_rename_variants, no_ts_def)] pub enum CommentKind { /// Line comment #[default] @@ -77,8 +79,9 @@ pub enum CommentAnnotation { /// A comment in source code. #[ast] -#[generate_derive(CloneIn, ContentEq)] +#[generate_derive(CloneIn, ContentEq, ESTree)] #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +#[estree(add_fields(value = CommentValue), field_order(kind, value, span), no_ts_def)] pub struct Comment { /// The span of the comment text, with leading and trailing delimiters. pub span: Span, @@ -87,22 +90,28 @@ pub struct Comment { /// `/* Leading */ token` /// ^ This start /// NOTE: Trailing comment attachment is not computed yet. + #[estree(skip)] pub attached_to: u32, /// Line or block comment + #[estree(rename = "type")] pub kind: CommentKind, /// Leading or trailing comment + #[estree(skip)] pub position: CommentPosition, /// Whether this comment has a preceding newline. /// Used to avoid becoming a trailing comment in codegen. + #[estree(skip)] pub preceded_by_newline: bool, /// Whether this comment has a tailing newline. + #[estree(skip)] pub followed_by_newline: bool, /// Comment Annotation + #[estree(skip)] pub annotation: CommentAnnotation, } diff --git a/crates/oxc_ast/src/generated/derive_estree.rs b/crates/oxc_ast/src/generated/derive_estree.rs index e97ea97e3e02a..f07e82b41668d 100644 --- a/crates/oxc_ast/src/generated/derive_estree.rs +++ b/crates/oxc_ast/src/generated/derive_estree.rs @@ -8,6 +8,7 @@ use oxc_estree::{ ser::{AppendTo, AppendToConcat}, }; +use crate::ast::comment::*; use crate::ast::js::*; use crate::ast::jsx::*; use crate::ast::literal::*; @@ -3338,3 +3339,23 @@ impl ESTree for JSDocUnknownType { state.end(); } } + +impl ESTree for CommentKind { + fn serialize(&self, serializer: S) { + match self { + Self::Line => JsonSafeString("Line").serialize(serializer), + Self::Block => JsonSafeString("Block").serialize(serializer), + } + } +} + +impl ESTree for Comment { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("type", &self.kind); + state.serialize_field("value", &crate::serialize::CommentValue(self)); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.end(); + } +} diff --git a/crates/oxc_ast/src/serialize.rs b/crates/oxc_ast/src/serialize.rs index 33e63bb2b05a7..3fc80c9234b9c 100644 --- a/crates/oxc_ast/src/serialize.rs +++ b/crates/oxc_ast/src/serialize.rs @@ -75,7 +75,7 @@ impl Program<'_> { /// Serialized as `null`. #[ast_meta] -#[estree(ts_type = "null")] +#[estree(ts_type = "null", raw_deser = "null")] pub struct Null<'b, T>(#[expect(dead_code)] pub &'b T); impl ESTree for Null<'_, T> { @@ -86,7 +86,7 @@ impl ESTree for Null<'_, T> { /// Serialized as `true`. #[ast_meta] -#[estree(ts_type = "true")] +#[estree(ts_type = "true", raw_deser = "true")] pub struct True<'b, T>(#[expect(dead_code)] pub &'b T); impl ESTree for True<'_, T> { @@ -97,7 +97,7 @@ impl ESTree for True<'_, T> { /// Serialized as `false`. #[ast_meta] -#[estree(ts_type = "false")] +#[estree(ts_type = "false", raw_deser = "false")] pub struct False<'b, T>(#[expect(dead_code)] pub &'b T); impl ESTree for False<'_, T> { @@ -108,7 +108,7 @@ impl ESTree for False<'_, T> { /// Serialized as `"in"`. #[ast_meta] -#[estree(ts_type = "'in'")] +#[estree(ts_type = "'in'", raw_deser = "'in'")] pub struct In<'b, T>(#[expect(dead_code)] pub &'b T); impl ESTree for In<'_, T> { @@ -119,7 +119,7 @@ impl ESTree for In<'_, T> { /// Serialized as `"init"`. #[ast_meta] -#[estree(ts_type = "'init'")] +#[estree(ts_type = "'init'", raw_deser = "'init'")] pub struct Init<'b, T>(#[expect(dead_code)] pub &'b T); impl ESTree for Init<'_, T> { @@ -134,7 +134,10 @@ impl ESTree for Init<'_, T> { /// Serializer for `raw` field of `BooleanLiteral`. #[ast_meta] -#[estree(ts_type = "string | null")] +#[estree( + ts_type = "string | null", + raw_deser = "(THIS.start === 0 && THIS.end === 0) ? null : THIS.value + ''" +)] pub struct BooleanLiteralRaw<'b>(pub &'b BooleanLiteral); impl ESTree for BooleanLiteralRaw<'_> { @@ -153,7 +156,10 @@ impl ESTree for BooleanLiteralRaw<'_> { /// Serializer for `raw` field of `NullLiteral`. #[ast_meta] -#[estree(ts_type = "'null' | null")] +#[estree( + ts_type = "'null' | null", + raw_deser = "(THIS.start === 0 && THIS.end === 0) ? null : 'null'" +)] pub struct NullLiteralRaw<'b>(pub &'b NullLiteral); impl ESTree for NullLiteralRaw<'_> { @@ -166,7 +172,7 @@ impl ESTree for NullLiteralRaw<'_> { /// Serializer for `bigint` field of `BigIntLiteral`. #[ast_meta] -#[estree(ts_type = "string")] +#[estree(ts_type = "string", raw_deser = "THIS.raw.slice(0, -1).replace(/_/g, '')")] pub struct BigIntLiteralBigint<'a, 'b>(pub &'b BigIntLiteral<'a>); impl ESTree for BigIntLiteralBigint<'_, '_> { @@ -180,7 +186,7 @@ impl ESTree for BigIntLiteralBigint<'_, '_> { /// /// Serialized as `null` in JSON, but updated on JS side to contain a `BigInt`. #[ast_meta] -#[estree(ts_type = "BigInt")] +#[estree(ts_type = "BigInt", raw_deser = "BigInt(THIS.bigint)")] pub struct BigIntLiteralValue<'a, 'b>(#[expect(dead_code)] pub &'b BigIntLiteral<'a>); impl ESTree for BigIntLiteralValue<'_, '_> { @@ -191,7 +197,33 @@ impl ESTree for BigIntLiteralValue<'_, '_> { /// Serializer for `regex` field of `RegExpLiteral`. #[ast_meta] -#[estree(ts_type = "RegExp")] +#[estree( + ts_type = "RegExp", + raw_deser = r#" + let pattern, flags, value = null; + if (THIS.raw === null) { + pattern = DESER[RegExpPattern](POS_OFFSET.regex.pattern); + const flagBits = DESER[u8](POS_OFFSET.regex.flags); + flags = ''; + if (flagBits & 1) flags += 'g'; + if (flagBits & 2) flags += 'i'; + if (flagBits & 4) flags += 'm'; + if (flagBits & 8) flags += 's'; + if (flagBits & 16) flags += 'u'; + if (flagBits & 32) flags += 'y'; + if (flagBits & 64) flags += 'd'; + if (flagBits & 128) flags += 'v'; + } else { + [, pattern, flags] = THIS.raw.match(/^\/(.*)\/([a-z]*)$/); + } + + try { + value = new RegExp(pattern, flags); + } catch (e) {} + + { pattern, flags } + "# +)] pub struct RegExpLiteralRegex<'a, 'b>(pub &'b RegExpLiteral<'a>); impl ESTree for RegExpLiteralRegex<'_, '_> { @@ -218,7 +250,11 @@ impl ESTree for RegExpLiteralRegex<'_, '_> { /// /// Serialized as `null` in JSON, but updated on JS side to contain a `RegExp` if the regexp is valid. #[ast_meta] -#[estree(ts_type = "RegExp | null")] +#[estree( + ts_type = "RegExp | null", + // `value` is defined by `RegExpLiteralRegex` converter + raw_deser = "value", +)] pub struct RegExpLiteralValue<'a, 'b>(#[expect(dead_code)] pub &'b RegExpLiteral<'a>); impl ESTree for RegExpLiteralValue<'_, '_> { @@ -253,7 +289,7 @@ impl ESTree for RegExpFlagsConverter<'_> { /// Serialize `ArrayExpressionElement::Elision` variant as `null`. #[ast_meta] -#[estree(ts_type = "null")] +#[estree(ts_type = "null", raw_deser = "null")] pub struct ElisionConverter<'b>(#[expect(dead_code)] pub &'b Elision); impl ESTree for ElisionConverter<'_> { @@ -265,7 +301,26 @@ impl ESTree for ElisionConverter<'_> { /// Serialize `FormalParameters`, to be estree compatible, with `items` and `rest` fields combined /// and `argument` field flattened. #[ast_meta] -#[estree(ts_type = "ParamPattern[]")] +#[estree( + ts_type = "ParamPattern[]", + raw_deser = " + const params = DESER[Vec](POS_OFFSET.items); + if (uint32[(POS_OFFSET.rest) >> 2] !== 0 && uint32[(POS_OFFSET.rest + 4) >> 2] !== 0) { + pos = uint32[(POS_OFFSET.rest) >> 2]; + params.push({ + type: 'RestElement', + start: DESER[u32]( POS_OFFSET.span.start ), + end: DESER[u32]( POS_OFFSET.span.end ), + argument: DESER[BindingPatternKind]( POS_OFFSET.argument.kind ), + typeAnnotation: DESER[Option>]( + POS_OFFSET.argument.type_annotation + ), + optional: DESER[bool]( POS_OFFSET.argument.optional ), + }); + } + params + " +)] pub struct FormalParametersConverter<'a, 'b>(pub &'b FormalParameters<'a>); impl ESTree for FormalParametersConverter<'_, '_> { @@ -303,7 +358,14 @@ impl ESTree for FormalParametersRest<'_, '_> { /// /// Serialize `specifiers` as an empty array if it's `None`. #[ast_meta] -#[estree(ts_type = "Array")] +#[estree( + ts_type = "Array", + raw_deser = " + let specifiers = DESER[Option>](POS_OFFSET.specifiers); + if (specifiers === null) specifiers = []; + specifiers + " +)] pub struct ImportDeclarationSpecifiers<'a, 'b>(pub &'b ImportDeclaration<'a>); impl ESTree for ImportDeclarationSpecifiers<'_, '_> { @@ -318,6 +380,20 @@ impl ESTree for ImportDeclarationSpecifiers<'_, '_> { /// Serialize `ObjectProperty` with fields in same order as Acorn. #[ast_meta] +#[estree(raw_deser = " + const start = DESER[u32](POS_OFFSET.span.start), + end = DESER[u32](POS_OFFSET.span.end), + method = DESER[bool](POS_OFFSET.method), + shorthand = DESER[bool](POS_OFFSET.shorthand), + computed = DESER[bool](POS_OFFSET.computed), + key = DESER[PropertyKey](POS_OFFSET.key), + kind = DESER[PropertyKind](POS_OFFSET.kind), + value = DESER[Expression](POS_OFFSET.value), + obj = method || shorthand || kind !== 'init' + ? {type: 'Property', start, end, method, shorthand, computed, key, kind, value} + : {type: 'Property', start, end, method, shorthand, computed, key, value, kind}; + obj +")] pub struct ObjectPropertyConverter<'a, 'b>(pub &'b ObjectProperty<'a>); impl ESTree for ObjectPropertyConverter<'_, '_> { @@ -345,6 +421,18 @@ impl ESTree for ObjectPropertyConverter<'_, '_> { /// Serialize `BindingProperty` with fields in same order as Acorn. #[ast_meta] +#[estree(raw_deser = " + const start = DESER[u32](POS_OFFSET.span.start), + end = DESER[u32](POS_OFFSET.span.end), + shorthand = DESER[bool](POS_OFFSET.shorthand), + computed = DESER[bool](POS_OFFSET.computed), + key = DESER[PropertyKey](POS_OFFSET.key), + value = DESER[BindingPattern](POS_OFFSET.value), + obj = shorthand + ? {type: 'Property', start, end, method: false, shorthand, computed, key, kind: 'init', value} + : {type: 'Property', start, end, method: false, shorthand, computed, key, value, kind: 'init'}; + obj +")] pub struct BindingPropertyConverter<'a, 'b>(pub &'b BindingProperty<'a>); impl ESTree for BindingPropertyConverter<'_, '_> { @@ -375,7 +463,13 @@ impl ESTree for BindingPropertyConverter<'_, '_> { /// Serializes as either an expression (if `expression` property is set), /// or a `BlockStatement` (if it's not). #[ast_meta] -#[estree(ts_type = "FunctionBody | Expression")] +#[estree( + ts_type = "FunctionBody | Expression", + raw_deser = " + let body = DESER[Box](POS_OFFSET.body); + DESER[bool](POS_OFFSET.expression) ? body.body[0].expression : body + " +)] pub struct ArrowFunctionExpressionBody<'a>(pub &'a ArrowFunctionExpression<'a>); impl ESTree for ArrowFunctionExpressionBody<'_> { @@ -391,7 +485,23 @@ impl ESTree for ArrowFunctionExpressionBody<'_> { /// Serializer for `AssignmentTargetPropertyIdentifier`'s `init` field /// (which is renamed to `value` in ESTree AST). #[ast_meta] -#[estree(ts_type = "IdentifierReference | AssignmentTargetWithDefault")] +#[estree( + ts_type = "IdentifierReference | AssignmentTargetWithDefault", + raw_deser = " + const init = DESER[Option](POS_OFFSET.init), + binding = DESER[IdentifierReference](POS_OFFSET.binding), + value = init === null + ? binding + : { + type: 'AssignmentPattern', + start: DESER[u32](POS_OFFSET.span.start), + end: DESER[u32](POS_OFFSET.span.end), + left: binding, + right: init, + }; + value + " +)] pub struct AssignmentTargetPropertyIdentifierValue<'a>( pub &'a AssignmentTargetPropertyIdentifier<'a>, ); @@ -417,7 +527,13 @@ impl ESTree for AssignmentTargetPropertyIdentifierValue<'_> { /// /// Serialize only the first expression in `arguments`, or `null` if `arguments` is empty. #[ast_meta] -#[estree(ts_type = "Expression | null")] +#[estree( + ts_type = "Expression | null", + raw_deser = " + const args = DESER[Vec](POS_OFFSET.arguments); + args.length === 0 ? null : args[0] + " +)] pub struct ImportExpressionArguments<'a>(pub &'a ImportExpression<'a>); impl ESTree for ImportExpressionArguments<'_> { @@ -435,6 +551,25 @@ impl ESTree for ImportExpressionArguments<'_> { /// Omit `with_clause` field (which is renamed to `attributes` in ESTree) /// unless `source` field is `Some`. #[ast_meta] +#[estree(raw_deser = " + const start = DESER[u32](POS_OFFSET.span.start), + end = DESER[u32](POS_OFFSET.span.end), + declaration = DESER[Option](POS_OFFSET.declaration), + specifiers = DESER[Vec](POS_OFFSET.specifiers), + source = DESER[Option](POS_OFFSET.source), + exportKind = DESER[ImportOrExportKind](POS_OFFSET.export_kind); + + if (source !== null) { + const withClause = deserializeOptionBoxWithClause(POS_OFFSET.with_clause); + return { + type: 'ExportNamedDeclaration', + start, end, declaration, specifiers, source, exportKind, + attributes: withClause === null ? [] : withClause.withEntries + }; + } + + {type: 'ExportNamedDeclaration', start, end, declaration, specifiers, source, exportKind} +")] pub struct ExportNamedDeclarationConverter<'a, 'b>(pub &'b ExportNamedDeclaration<'a>); impl ESTree for ExportNamedDeclarationConverter<'_, '_> { @@ -467,7 +602,13 @@ impl ESTree for ExportNamedDeclarationConverter<'_, '_> { // https://github.com/estree/estree/blob/master/es2025.md#exportnameddeclaration #[ast_meta] -#[estree(ts_type = "Array")] +#[estree( + ts_type = "Array", + raw_deser = " + const withClause = DESER[Option>](POS_OFFSET.with_clause); + withClause === null ? [] : withClause.withEntries + " +)] pub struct ImportDeclarationWithClause<'a, 'b>(pub &'b ImportDeclaration<'a>); impl ESTree for ImportDeclarationWithClause<'_, '_> { @@ -481,7 +622,13 @@ impl ESTree for ImportDeclarationWithClause<'_, '_> { } #[ast_meta] -#[estree(ts_type = "Array")] +#[estree( + ts_type = "Array", + raw_deser = " + const withClause = DESER[Option>](POS_OFFSET.with_clause); + withClause === null ? [] : withClause.withEntries + " +)] pub struct ExportNamedDeclarationWithClause<'a, 'b>(pub &'b ExportNamedDeclaration<'a>); impl ESTree for ExportNamedDeclarationWithClause<'_, '_> { @@ -495,7 +642,13 @@ impl ESTree for ExportNamedDeclarationWithClause<'_, '_> { } #[ast_meta] -#[estree(ts_type = "Array")] +#[estree( + ts_type = "Array", + raw_deser = " + const withClause = DESER[Option>](POS_OFFSET.with_clause); + withClause === null ? [] : withClause.withEntries + " +)] pub struct ExportAllDeclarationWithClause<'a, 'b>(pub &'b ExportAllDeclaration<'a>); impl ESTree for ExportAllDeclarationWithClause<'_, '_> { @@ -516,7 +669,14 @@ impl ESTree for ExportAllDeclarationWithClause<'_, '_> { /// /// Convert to `JSXIdentifier`. #[ast_meta] -#[estree(ts_type = "JSXIdentifier")] +#[estree( + ts_type = "JSXIdentifier", + raw_deser = " + const ident = DESER[Box](POS); + ident.type = 'JSXIdentifier'; + ident + " +)] pub struct JSXElementIdentifierReference<'a, 'b>(pub &'b IdentifierReference<'a>); impl ESTree for JSXElementIdentifierReference<'_, '_> { @@ -529,7 +689,13 @@ impl ESTree for JSXElementIdentifierReference<'_, '_> { /// /// Convert to `JSXIdentifier`. #[ast_meta] -#[estree(ts_type = "JSXIdentifier")] +#[estree( + ts_type = "JSXIdentifier", + raw_deser = " + const thisExpr = DESER[Box](POS); + {type: 'JSXIdentifier', start: thisExpr.start, end: thisExpr.end, name: 'this'} + " +)] pub struct JSXElementThisExpression<'b>(pub &'b ThisExpression); impl ESTree for JSXElementThisExpression<'_> { @@ -537,3 +703,31 @@ impl ESTree for JSXElementThisExpression<'_> { JSXIdentifier { span: self.0.span, name: Atom::from("this") }.serialize(serializer); } } + +// -------------------- +// Comments +// -------------------- + +/// Serialize `value` field of `Comment`. +/// +/// This serializer does not work for JSON serializer, because there's no access to source text +/// in `fn serialize`. But in any case, comments often contain characters which need escaping in JSON, +/// which is slow, so it's probably faster to transfer comments as NAPI types (which we do). +/// +/// This meta type is only present for raw transfer, which can transfer faster. +#[ast_meta] +#[estree( + ts_type = "string", + raw_deser = " + const endCut = THIS.type === 'Line' ? 0 : 2; + SOURCE_TEXT.slice(THIS.start + 2, THIS.end - endCut) + " +)] +pub struct CommentValue<'b>(#[expect(dead_code)] pub &'b Comment); + +impl ESTree for CommentValue<'_> { + #[expect(clippy::unimplemented)] + fn serialize(&self, _serializer: S) { + unimplemented!(); + } +} diff --git a/crates/oxc_ast_visit/src/generated/visit.rs b/crates/oxc_ast_visit/src/generated/visit.rs index ad642d17401ea..2e9b75e161df1 100644 --- a/crates/oxc_ast_visit/src/generated/visit.rs +++ b/crates/oxc_ast_visit/src/generated/visit.rs @@ -1340,6 +1340,11 @@ pub trait Visit<'a>: Sized { fn visit_ts_import_attribute_list(&mut self, it: &Vec<'a, TSImportAttribute<'a>>) { walk_ts_import_attribute_list(self, it); } + + #[inline] + fn visit_spans(&mut self, it: &Vec<'a, Span>) { + walk_spans(self, it); + } } pub mod walk { @@ -4412,4 +4417,11 @@ pub mod walk { visitor.visit_ts_import_attribute(el); } } + + #[inline] + pub fn walk_spans<'a, V: Visit<'a>>(visitor: &mut V, it: &Vec<'a, Span>) { + for el in it { + visitor.visit_span(el); + } + } } diff --git a/crates/oxc_ast_visit/src/generated/visit_mut.rs b/crates/oxc_ast_visit/src/generated/visit_mut.rs index 65b85a555b771..b7f5a148f7526 100644 --- a/crates/oxc_ast_visit/src/generated/visit_mut.rs +++ b/crates/oxc_ast_visit/src/generated/visit_mut.rs @@ -1335,6 +1335,11 @@ pub trait VisitMut<'a>: Sized { fn visit_ts_import_attribute_list(&mut self, it: &mut Vec<'a, TSImportAttribute<'a>>) { walk_ts_import_attribute_list(self, it); } + + #[inline] + fn visit_spans(&mut self, it: &mut Vec<'a, Span>) { + walk_spans(self, it); + } } pub mod walk_mut { @@ -4657,4 +4662,11 @@ pub mod walk_mut { visitor.visit_ts_import_attribute(el); } } + + #[inline] + pub fn walk_spans<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Vec<'a, Span>) { + for el in it { + visitor.visit_span(el); + } + } } diff --git a/crates/oxc_syntax/src/generated/assert_layouts.rs b/crates/oxc_syntax/src/generated/assert_layouts.rs index f4b27d2f92392..ce49aff1f841a 100644 --- a/crates/oxc_syntax/src/generated/assert_layouts.rs +++ b/crates/oxc_syntax/src/generated/assert_layouts.rs @@ -7,13 +7,53 @@ use std::mem::{align_of, offset_of, size_of}; use nonmax::NonMaxU32; -use crate::{number::*, operator::*, reference::*, scope::*, symbol::*}; +use crate::{module_record::*, number::*, operator::*, reference::*, scope::*, symbol::*}; #[cfg(target_pointer_width = "64")] const _: () = { assert!(size_of::() == 4); assert!(align_of::() == 4); + assert!(size_of::() == 24); + assert!(align_of::() == 8); + assert!(offset_of!(NameSpan, name) == 0); + assert!(offset_of!(NameSpan, span) == 16); + + assert!(size_of::() == 96); + assert!(align_of::() == 8); + assert!(offset_of!(ImportEntry, statement_span) == 0); + assert!(offset_of!(ImportEntry, module_request) == 8); + assert!(offset_of!(ImportEntry, import_name) == 32); + assert!(offset_of!(ImportEntry, local_name) == 64); + assert!(offset_of!(ImportEntry, is_type) == 88); + + assert!(size_of::() == 32); + assert!(align_of::() == 8); + + assert!(size_of::() == 144); + assert!(align_of::() == 8); + assert!(offset_of!(ExportEntry, statement_span) == 0); + assert!(offset_of!(ExportEntry, span) == 8); + assert!(offset_of!(ExportEntry, module_request) == 16); + assert!(offset_of!(ExportEntry, import_name) == 40); + assert!(offset_of!(ExportEntry, export_name) == 72); + assert!(offset_of!(ExportEntry, local_name) == 104); + assert!(offset_of!(ExportEntry, is_type) == 136); + + assert!(size_of::() == 32); + assert!(align_of::() == 8); + + assert!(size_of::() == 32); + assert!(align_of::() == 8); + + assert!(size_of::() == 32); + assert!(align_of::() == 8); + + assert!(size_of::() == 16); + assert!(align_of::() == 8); + assert!(offset_of!(DynamicImport, span) == 0); + assert!(offset_of!(DynamicImport, module_request) == 8); + assert!(size_of::() == 1); assert!(align_of::() == 1); @@ -50,6 +90,46 @@ const _: () = { assert!(size_of::() == 4); assert!(align_of::() == 4); + assert!(size_of::() == 16); + assert!(align_of::() == 4); + assert!(offset_of!(NameSpan, name) == 0); + assert!(offset_of!(NameSpan, span) == 8); + + assert!(size_of::() == 64); + assert!(align_of::() == 4); + assert!(offset_of!(ImportEntry, statement_span) == 0); + assert!(offset_of!(ImportEntry, module_request) == 8); + assert!(offset_of!(ImportEntry, import_name) == 24); + assert!(offset_of!(ImportEntry, local_name) == 44); + assert!(offset_of!(ImportEntry, is_type) == 60); + + assert!(size_of::() == 20); + assert!(align_of::() == 4); + + assert!(size_of::() == 96); + assert!(align_of::() == 4); + assert!(offset_of!(ExportEntry, statement_span) == 0); + assert!(offset_of!(ExportEntry, span) == 8); + assert!(offset_of!(ExportEntry, module_request) == 16); + assert!(offset_of!(ExportEntry, import_name) == 32); + assert!(offset_of!(ExportEntry, export_name) == 52); + assert!(offset_of!(ExportEntry, local_name) == 72); + assert!(offset_of!(ExportEntry, is_type) == 92); + + assert!(size_of::() == 20); + assert!(align_of::() == 4); + + assert!(size_of::() == 20); + assert!(align_of::() == 4); + + assert!(size_of::() == 20); + assert!(align_of::() == 4); + + assert!(size_of::() == 16); + assert!(align_of::() == 4); + assert!(offset_of!(DynamicImport, span) == 0); + assert!(offset_of!(DynamicImport, module_request) == 8); + assert!(size_of::() == 1); assert!(align_of::() == 1); diff --git a/crates/oxc_syntax/src/generated/derive_estree.rs b/crates/oxc_syntax/src/generated/derive_estree.rs index 19f61fdc9236e..343e57278eb54 100644 --- a/crates/oxc_syntax/src/generated/derive_estree.rs +++ b/crates/oxc_syntax/src/generated/derive_estree.rs @@ -8,8 +8,97 @@ use oxc_estree::{ ser::{AppendTo, AppendToConcat}, }; +use crate::module_record::*; use crate::operator::*; +impl ESTree for NameSpan<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("value", &self.name); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.end(); + } +} + +impl ESTree for ImportEntry<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("importName", &self.import_name); + state.serialize_field("localName", &self.local_name); + state.serialize_field("isType", &self.is_type); + state.end(); + } +} + +impl ESTree for ImportImportName<'_> { + fn serialize(&self, serializer: S) { + match self { + Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer), + Self::NamespaceObject => JsonSafeString("namespaceObject").serialize(serializer), + Self::Default(it) => { + crate::serialize::ImportOrExportNameDefault(it).serialize(serializer) + } + } + } +} + +impl ESTree for ExportEntry<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.serialize_field("moduleRequest", &self.module_request); + state.serialize_field("importName", &self.import_name); + state.serialize_field("exportName", &self.export_name); + state.serialize_field("localName", &self.local_name); + state.end(); + } +} + +impl ESTree for ExportImportName<'_> { + fn serialize(&self, serializer: S) { + match self { + Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer), + Self::All => JsonSafeString("all").serialize(serializer), + Self::AllButDefault => JsonSafeString("allButDefault").serialize(serializer), + Self::Null => JsonSafeString("null").serialize(serializer), + } + } +} + +impl ESTree for ExportExportName<'_> { + fn serialize(&self, serializer: S) { + match self { + Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer), + Self::Default(it) => { + crate::serialize::ImportOrExportNameDefault(it).serialize(serializer) + } + Self::Null => JsonSafeString("null").serialize(serializer), + } + } +} + +impl ESTree for ExportLocalName<'_> { + fn serialize(&self, serializer: S) { + match self { + Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer), + Self::Default(it) => crate::serialize::ExportLocalNameDefault(it).serialize(serializer), + Self::Null => JsonSafeString("null").serialize(serializer), + } + } +} + +impl ESTree for DynamicImport { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.serialize_field("moduleRequest", &self.module_request); + state.end(); + } +} + impl ESTree for AssignmentOperator { fn serialize(&self, serializer: S) { match self { diff --git a/crates/oxc_syntax/src/lib.rs b/crates/oxc_syntax/src/lib.rs index b53c48ea12284..04a120876878a 100644 --- a/crates/oxc_syntax/src/lib.rs +++ b/crates/oxc_syntax/src/lib.rs @@ -16,6 +16,8 @@ pub mod operator; pub mod precedence; pub mod reference; pub mod scope; +#[cfg(feature = "serialize")] +mod serialize; pub mod symbol; pub mod xml_entities; diff --git a/crates/oxc_syntax/src/module_record.rs b/crates/oxc_syntax/src/module_record.rs index 4a438d867a411..1346e3124b850 100644 --- a/crates/oxc_syntax/src/module_record.rs +++ b/crates/oxc_syntax/src/module_record.rs @@ -3,6 +3,8 @@ use rustc_hash::FxHashMap; use oxc_allocator::{Allocator, Vec}; +use oxc_ast_macros::ast; +use oxc_estree::ESTree; use oxc_span::{Atom, Span}; /// ESM Module Record @@ -82,9 +84,13 @@ impl<'a> ModuleRecord<'a> { } /// Name and Span +#[ast] #[derive(Debug, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] pub struct NameSpan<'a> { /// Name + #[estree(rename = "value")] pub name: Atom<'a>, /// Span @@ -113,9 +119,13 @@ impl<'a> NameSpan<'a> { /// /// import * as ns from "mod"; /// ``` +#[ast] #[derive(Debug, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] pub struct ImportEntry<'a> { /// Span of the import statement. + #[estree(skip)] pub statement_span: Span, /// String value of the ModuleSpecifier of the ImportDeclaration. @@ -126,6 +136,7 @@ pub struct ImportEntry<'a> { /// import { foo } from "mod"; /// // ^^^ /// ``` + #[estree(skip)] pub module_request: NameSpan<'a>, /// The name under which the desired binding is exported by the module identified by `[[ModuleRequest]]`. @@ -172,14 +183,20 @@ pub struct ImportEntry<'a> { } /// `ImportName` For `ImportEntry` +#[ast] #[derive(Debug, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_ts_def)] pub enum ImportImportName<'a> { /// `import { x } from "mod"` - Name(NameSpan<'a>), + #[estree(via = ImportOrExportNameName)] + Name(NameSpan<'a>) = 0, /// `import * as ns from "mod"` - NamespaceObject, + #[estree(via = ImportImportNameNamespaceObject)] + NamespaceObject = 1, /// `import defaultExport from "mod"` - Default(Span), + #[estree(via = ImportOrExportNameDefault)] + Default(Span) = 2, } impl ImportImportName<'_> { @@ -213,9 +230,13 @@ impl ImportImportName<'_> { /// // ^^^ export_name /// /// ``` +#[ast] #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] pub struct ExportEntry<'a> { /// Span of the import statement. + #[estree(skip)] pub statement_span: Span, /// Span for the entire export entry @@ -249,21 +270,29 @@ pub struct ExportEntry<'a> { /// export { type foo } /// export type { foo } from 'mod' /// ``` + #[estree(skip)] pub is_type: bool, } /// `ImportName` for `ExportEntry` +#[ast] #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_ts_def)] pub enum ExportImportName<'a> { /// Name - Name(NameSpan<'a>), + #[estree(via = ImportOrExportNameName)] + Name(NameSpan<'a>) = 0, /// all is used for export * as ns from "mod" declarations. - All, + #[estree(via = ExportImportNameAll)] + All = 1, /// all-but-default is used for export * from "mod" declarations. - AllButDefault, + #[estree(via = ExportImportNameAllButDefault)] + AllButDefault = 2, /// the ExportDeclaration does not have a ModuleSpecifier #[default] - Null, + #[estree(via = ExportNameNull)] + Null = 3, } /// Export Import Name @@ -280,15 +309,21 @@ impl ExportImportName<'_> { } /// `ExportName` for `ExportEntry` +#[ast] #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_ts_def)] pub enum ExportExportName<'a> { /// Name - Name(NameSpan<'a>), + #[estree(via = ImportOrExportNameName)] + Name(NameSpan<'a>) = 0, /// Default - Default(Span), + #[estree(via = ImportOrExportNameDefault)] + Default(Span) = 1, /// Null + #[estree(via = ExportNameNull)] #[default] - Null, + Null = 2, } impl ExportExportName<'_> { @@ -324,15 +359,21 @@ impl ExportExportName<'_> { } /// `LocalName` for `ExportEntry` +#[ast] #[derive(Debug, Default, Clone, PartialEq, Eq)] +#[generate_derive(ESTree)] +#[estree(no_ts_def)] pub enum ExportLocalName<'a> { /// Name - Name(NameSpan<'a>), + #[estree(via = ImportOrExportNameName)] + Name(NameSpan<'a>) = 0, /// `export default name_span` - Default(NameSpan<'a>), + #[estree(via = ExportLocalNameDefault)] + Default(NameSpan<'a>) = 1, /// Null #[default] - Null, + #[estree(via = ExportNameNull)] + Null = 2, } impl<'a> ExportLocalName<'a> { @@ -379,11 +420,15 @@ pub struct RequestedModule { } /// Dynamic import expression. +#[ast] #[derive(Debug, Clone, Copy)] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] pub struct DynamicImport { /// Span of the import expression. pub span: Span, /// Span the ModuleSpecifier, which is an expression. + #[estree(no_flatten)] pub module_request: Span, } diff --git a/crates/oxc_syntax/src/serialize.rs b/crates/oxc_syntax/src/serialize.rs new file mode 100644 index 0000000000000..5c66d8783a9d2 --- /dev/null +++ b/crates/oxc_syntax/src/serialize.rs @@ -0,0 +1,93 @@ +use oxc_ast_macros::ast_meta; +use oxc_estree::{ESTree, Serializer}; +use oxc_span::Span; + +use crate::module_record::NameSpan; + +/// Macro to create a dummy `ESTree` impl for a type. +/// +/// The meta types in this module are only used for raw transfer, +/// so no need for real `ESTree` impls. +macro_rules! dummy_estree_impl { + ($ty:ty) => { + impl ESTree for $ty { + fn serialize(&self, _serializer: S) { + unimplemented!(); + } + } + }; +} + +/// Serializer for `Name` variant of `ExportLocalName`, `ExportExportName`, `ExportImportName`, +/// and `ImportImportName`. +#[ast_meta] +#[estree( + ts_type = "Dummy", + raw_deser = " + var nameSpan = DESER[NameSpan](POS); + {kind: 'Name', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end} + " +)] +pub struct ImportOrExportNameName<'a, 'b>(#[expect(dead_code)] pub &'b NameSpan<'a>); + +dummy_estree_impl!(ImportOrExportNameName<'_, '_>); + +/// Serializer for `Default` variant of `ExportLocalName`. +#[ast_meta] +#[estree( + ts_type = "Dummy", + raw_deser = " + var nameSpan = DESER[NameSpan](POS); + {kind: 'Default', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end} + " +)] +pub struct ExportLocalNameDefault<'a, 'b>(#[expect(dead_code)] pub &'b NameSpan<'a>); + +dummy_estree_impl!(ExportLocalNameDefault<'_, '_>); + +/// Serializer for `Null` variant of `ExportLocalName`, `ExportExportName`, and `ExportImportName`. +#[ast_meta] +#[estree(ts_type = "Dummy", raw_deser = "{kind: 'None', name: null, start: null, end: null}")] +pub struct ExportNameNull; + +dummy_estree_impl!(ExportNameNull); + +/// Serializer for `Default` variant of `ExportExportName` and `ImportImportName`. +#[ast_meta] +#[estree( + ts_type = "Dummy", + raw_deser = " + var span = DESER[Span](POS); + {kind: 'Default', name: null, start: span.start, end: span.end} + " +)] +pub struct ImportOrExportNameDefault<'b>(#[expect(dead_code)] pub &'b Span); + +dummy_estree_impl!(ImportOrExportNameDefault<'_>); + +/// Serializer for `All` variant of `ExportImportName`. +#[ast_meta] +#[estree(ts_type = "Dummy", raw_deser = "{kind: 'All', name: null, start: null, end: null}")] +pub struct ExportImportNameAll; + +dummy_estree_impl!(ExportImportNameAll); + +/// Serializer for `AllButDefault` variant of `ExportImportName`. +#[ast_meta] +#[estree( + ts_type = "Dummy", + raw_deser = "{kind: 'AllButDefault', name: null, start: null, end: null}" +)] +pub struct ExportImportNameAllButDefault; + +dummy_estree_impl!(ExportImportNameAllButDefault); + +/// Serializer for `NamespaceObject` variant of `ImportImportName`. +#[ast_meta] +#[estree( + ts_type = "Dummy", + raw_deser = "{kind: 'NamespaceObject', name: null, start: null, end: null}" +)] +pub struct ImportImportNameNamespaceObject; + +dummy_estree_impl!(ImportImportNameNamespaceObject); diff --git a/napi/parser/Cargo.toml b/napi/parser/Cargo.toml index a8e97e8500353..c5bcacf2dbd04 100644 --- a/napi/parser/Cargo.toml +++ b/napi/parser/Cargo.toml @@ -23,6 +23,8 @@ doctest = false [dependencies] oxc = { workspace = true, features = ["ast_visit", "semantic", "serialize"] } +oxc_ast_macros = { workspace = true } +oxc_estree = { workspace = true } oxc_napi = { workspace = true } rustc-hash = { workspace = true } diff --git a/napi/parser/bench.bench.mjs b/napi/parser/bench.bench.mjs index 1c2761c428a9b..9aae0da913ec7 100644 --- a/napi/parser/bench.bench.mjs +++ b/napi/parser/bench.bench.mjs @@ -36,6 +36,14 @@ const fixtures = await Promise.all(fixtureUrls.map(async (url) => { // Run benchmarks for (const { filename, code } of fixtures) { bench(`parser_napi[${filename}]`, () => { - parseSync(filename, code); + const ret = parseSync(filename, code); + // Read returned object's properties to execute getters which deserialize + const { program, comments, module, errors } = ret; + }); + + bench(`parser_napi_raw[${filename}]`, () => { + const ret = parseSync(filename, code, { experimentalRawTransfer: true }); + // Read returned object's properties to execute getters + const { program, comments, module, errors } = ret; }); } diff --git a/napi/parser/bindings.js b/napi/parser/bindings.js index 2aef1f358c9c0..fd3b6a8d4759b 100644 --- a/napi/parser/bindings.js +++ b/napi/parser/bindings.js @@ -374,7 +374,9 @@ module.exports.ParseResult = nativeBinding.ParseResult module.exports.ExportExportNameKind = nativeBinding.ExportExportNameKind module.exports.ExportImportNameKind = nativeBinding.ExportImportNameKind module.exports.ExportLocalNameKind = nativeBinding.ExportLocalNameKind +module.exports.getBufferOffset = nativeBinding.getBufferOffset module.exports.ImportNameKind = nativeBinding.ImportNameKind module.exports.parseAsync = nativeBinding.parseAsync module.exports.parseSync = nativeBinding.parseSync +module.exports.parseSyncRaw = nativeBinding.parseSyncRaw module.exports.Severity = nativeBinding.Severity diff --git a/napi/parser/deserialize.js b/napi/parser/deserialize.js new file mode 100644 index 0000000000000..4acf681e9bc50 --- /dev/null +++ b/napi/parser/deserialize.js @@ -0,0 +1,5863 @@ +// Auto-generated code, DO NOT EDIT DIRECTLY! +// To edit this generated file you have to edit `tasks/ast_tools/src/generators/raw_transfer.rs` + +'use strict'; + +module.exports = deserialize; + +let uint8, uint32, float64, sourceText, sourceIsAscii, sourceLen; + +const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), + decodeStr = textDecoder.decode.bind(textDecoder), + { fromCodePoint } = String; + +function deserialize(buffer, sourceTextInput, sourceLenInput) { + uint8 = buffer; + uint32 = new Uint32Array(buffer.buffer, buffer.byteOffset); + float64 = new Float64Array(buffer.buffer, buffer.byteOffset); + + sourceText = sourceTextInput; + sourceLen = sourceLenInput; + sourceIsAscii = sourceText.length === sourceLen; + + // (2 * 1024 * 1024 * 1024 - 16) >> 2 + const metadataPos32 = 536870908; + + const data = deserializeRawTransferData(uint32[metadataPos32]); + + uint8 = + uint32 = + float64 = + sourceText = + undefined; + + return data; +} + +function deserializeProgram(pos) { + const body = deserializeVecDirective(pos + 88); + body.push(...deserializeVecStatement(pos + 120)); + return { + type: 'Program', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body, + sourceType: deserializeModuleKind(pos + 9), + hashbang: deserializeOptionHashbang(pos + 64), + }; +} + +function deserializeExpression(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for Expression`); + } +} + +function deserializeIdentifierName(pos) { + return { + type: 'Identifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeIdentifierReference(pos) { + return { + type: 'Identifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeBindingIdentifier(pos) { + return { + type: 'Identifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeLabelIdentifier(pos) { + return { + type: 'Identifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeThisExpression(pos) { + return { + type: 'ThisExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeArrayExpression(pos) { + return { + type: 'ArrayExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + elements: deserializeVecArrayExpressionElement(pos + 8), + }; +} + +function deserializeArrayExpressionElement(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + case 64: + return deserializeBoxSpreadElement(pos + 8); + case 65: + return deserializeElision(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ArrayExpressionElement`); + } +} + +function deserializeElision(pos) { + return null; +} + +function deserializeObjectExpression(pos) { + return { + type: 'ObjectExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + properties: deserializeVecObjectPropertyKind(pos + 8), + }; +} + +function deserializeObjectPropertyKind(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxObjectProperty(pos + 8); + case 1: + return deserializeBoxSpreadElement(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ObjectPropertyKind`); + } +} + +function deserializeObjectProperty(pos) { + const start = deserializeU32(pos), + end = deserializeU32(pos + 4), + method = deserializeBool(pos + 48), + shorthand = deserializeBool(pos + 49), + computed = deserializeBool(pos + 50), + key = deserializePropertyKey(pos + 16), + kind = deserializePropertyKind(pos + 8), + value = deserializeExpression(pos + 32), + obj = method || shorthand || kind !== 'init' + ? { type: 'Property', start, end, method, shorthand, computed, key, kind, value } + : { type: 'Property', start, end, method, shorthand, computed, key, value, kind }; + return obj; +} + +function deserializePropertyKey(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + case 64: + return deserializeBoxIdentifierName(pos + 8); + case 65: + return deserializeBoxPrivateIdentifier(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for PropertyKey`); + } +} + +function deserializePropertyKind(pos) { + switch (uint8[pos]) { + case 0: + return 'init'; + case 1: + return 'get'; + case 2: + return 'set'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for PropertyKind`); + } +} + +function deserializeTemplateLiteral(pos) { + return { + type: 'TemplateLiteral', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expressions: deserializeVecExpression(pos + 40), + quasis: deserializeVecTemplateElement(pos + 8), + }; +} + +function deserializeTaggedTemplateExpression(pos) { + return { + type: 'TaggedTemplateExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + tag: deserializeExpression(pos + 8), + quasi: deserializeTemplateLiteral(pos + 24), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 96), + }; +} + +function deserializeTemplateElement(pos) { + return { + type: 'TemplateElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value: deserializeTemplateElementValue(pos + 16), + tail: deserializeBool(pos + 8), + }; +} + +function deserializeTemplateElementValue(pos) { + return { + raw: deserializeStr(pos), + cooked: deserializeOptionStr(pos + 16), + }; +} + +function deserializeMemberExpression(pos) { + switch (uint8[pos]) { + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for MemberExpression`); + } +} + +function deserializeComputedMemberExpression(pos) { + return { + type: 'MemberExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + object: deserializeExpression(pos + 8), + property: deserializeExpression(pos + 24), + computed: true, + optional: deserializeBool(pos + 40), + }; +} + +function deserializeStaticMemberExpression(pos) { + return { + type: 'MemberExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + object: deserializeExpression(pos + 8), + property: deserializeIdentifierName(pos + 24), + computed: false, + optional: deserializeBool(pos + 48), + }; +} + +function deserializePrivateFieldExpression(pos) { + return { + type: 'MemberExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + object: deserializeExpression(pos + 8), + property: deserializePrivateIdentifier(pos + 24), + computed: false, + optional: deserializeBool(pos + 48), + }; +} + +function deserializeCallExpression(pos) { + return { + type: 'CallExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + callee: deserializeExpression(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 24), + arguments: deserializeVecArgument(pos + 32), + optional: deserializeBool(pos + 64), + }; +} + +function deserializeNewExpression(pos) { + return { + type: 'NewExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + callee: deserializeExpression(pos + 8), + arguments: deserializeVecArgument(pos + 24), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 56), + }; +} + +function deserializeMetaProperty(pos) { + return { + type: 'MetaProperty', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + meta: deserializeIdentifierName(pos + 8), + property: deserializeIdentifierName(pos + 32), + }; +} + +function deserializeSpreadElement(pos) { + return { + type: 'SpreadElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeExpression(pos + 8), + }; +} + +function deserializeArgument(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + case 64: + return deserializeBoxSpreadElement(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for Argument`); + } +} + +function deserializeUpdateExpression(pos) { + return { + type: 'UpdateExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + operator: deserializeUpdateOperator(pos + 8), + prefix: deserializeBool(pos + 9), + argument: deserializeSimpleAssignmentTarget(pos + 16), + }; +} + +function deserializeUnaryExpression(pos) { + return { + type: 'UnaryExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + operator: deserializeUnaryOperator(pos + 8), + prefix: true, + argument: deserializeExpression(pos + 16), + }; +} + +function deserializeBinaryExpression(pos) { + return { + type: 'BinaryExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializeExpression(pos + 8), + operator: deserializeBinaryOperator(pos + 24), + right: deserializeExpression(pos + 32), + }; +} + +function deserializePrivateInExpression(pos) { + return { + type: 'BinaryExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializePrivateIdentifier(pos + 8), + operator: 'in', + right: deserializeExpression(pos + 32), + }; +} + +function deserializeLogicalExpression(pos) { + return { + type: 'LogicalExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializeExpression(pos + 8), + operator: deserializeLogicalOperator(pos + 24), + right: deserializeExpression(pos + 32), + }; +} + +function deserializeConditionalExpression(pos) { + return { + type: 'ConditionalExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + test: deserializeExpression(pos + 8), + consequent: deserializeExpression(pos + 24), + alternate: deserializeExpression(pos + 40), + }; +} + +function deserializeAssignmentExpression(pos) { + return { + type: 'AssignmentExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + operator: deserializeAssignmentOperator(pos + 8), + left: deserializeAssignmentTarget(pos + 16), + right: deserializeExpression(pos + 32), + }; +} + +function deserializeAssignmentTarget(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSAsExpression(pos + 8); + case 2: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 3: + return deserializeBoxTSNonNullExpression(pos + 8); + case 4: + return deserializeBoxTSTypeAssertion(pos + 8); + case 5: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 8: + return deserializeBoxArrayAssignmentTarget(pos + 8); + case 9: + return deserializeBoxObjectAssignmentTarget(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for AssignmentTarget`); + } +} + +function deserializeSimpleAssignmentTarget(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSAsExpression(pos + 8); + case 2: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 3: + return deserializeBoxTSNonNullExpression(pos + 8); + case 4: + return deserializeBoxTSTypeAssertion(pos + 8); + case 5: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for SimpleAssignmentTarget`); + } +} + +function deserializeAssignmentTargetPattern(pos) { + switch (uint8[pos]) { + case 8: + return deserializeBoxArrayAssignmentTarget(pos + 8); + case 9: + return deserializeBoxObjectAssignmentTarget(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for AssignmentTargetPattern`); + } +} + +function deserializeArrayAssignmentTarget(pos) { + const elements = deserializeVecOptionAssignmentTargetMaybeDefault(pos + 8); + const rest = deserializeOptionAssignmentTargetRest(pos + 40); + if (rest !== null) elements.push(rest); + return { + type: 'ArrayPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + elements, + }; +} + +function deserializeObjectAssignmentTarget(pos) { + const properties = deserializeVecAssignmentTargetProperty(pos + 8); + const rest = deserializeOptionAssignmentTargetRest(pos + 40); + if (rest !== null) properties.push(rest); + return { + type: 'ObjectPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + properties, + }; +} + +function deserializeAssignmentTargetRest(pos) { + return { + type: 'RestElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeAssignmentTarget(pos + 8), + }; +} + +function deserializeAssignmentTargetMaybeDefault(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSAsExpression(pos + 8); + case 2: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 3: + return deserializeBoxTSNonNullExpression(pos + 8); + case 4: + return deserializeBoxTSTypeAssertion(pos + 8); + case 5: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 8: + return deserializeBoxArrayAssignmentTarget(pos + 8); + case 9: + return deserializeBoxObjectAssignmentTarget(pos + 8); + case 16: + return deserializeBoxAssignmentTargetWithDefault(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for AssignmentTargetMaybeDefault`); + } +} + +function deserializeAssignmentTargetWithDefault(pos) { + return { + type: 'AssignmentPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializeAssignmentTarget(pos + 8), + right: deserializeExpression(pos + 24), + }; +} + +function deserializeAssignmentTargetProperty(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxAssignmentTargetPropertyIdentifier(pos + 8); + case 1: + return deserializeBoxAssignmentTargetPropertyProperty(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for AssignmentTargetProperty`); + } +} + +function deserializeAssignmentTargetPropertyIdentifier(pos) { + const init = deserializeOptionExpression(pos + 40), + binding = deserializeIdentifierReference(pos + 8), + value = init === null + ? binding + : { + type: 'AssignmentPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: binding, + right: init, + }; + return { + type: 'Property', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + method: false, + shorthand: true, + computed: false, + key: deserializeIdentifierReference(pos + 8), + kind: 'init', + value, + }; +} + +function deserializeAssignmentTargetPropertyProperty(pos) { + return { + type: 'Property', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + method: false, + shorthand: false, + computed: deserializeBool(pos + 40), + key: deserializePropertyKey(pos + 8), + value: deserializeAssignmentTargetMaybeDefault(pos + 24), + kind: 'init', + }; +} + +function deserializeSequenceExpression(pos) { + return { + type: 'SequenceExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expressions: deserializeVecExpression(pos + 8), + }; +} + +function deserializeSuper(pos) { + return { + type: 'Super', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeAwaitExpression(pos) { + return { + type: 'AwaitExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeExpression(pos + 8), + }; +} + +function deserializeChainExpression(pos) { + return { + type: 'ChainExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeChainElement(pos + 8), + }; +} + +function deserializeChainElement(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxCallExpression(pos + 8); + case 1: + return deserializeBoxTSNonNullExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ChainElement`); + } +} + +function deserializeParenthesizedExpression(pos) { + return { + type: 'ParenthesizedExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + }; +} + +function deserializeStatement(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBlockStatement(pos + 8); + case 1: + return deserializeBoxBreakStatement(pos + 8); + case 2: + return deserializeBoxContinueStatement(pos + 8); + case 3: + return deserializeBoxDebuggerStatement(pos + 8); + case 4: + return deserializeBoxDoWhileStatement(pos + 8); + case 5: + return deserializeBoxEmptyStatement(pos + 8); + case 6: + return deserializeBoxExpressionStatement(pos + 8); + case 7: + return deserializeBoxForInStatement(pos + 8); + case 8: + return deserializeBoxForOfStatement(pos + 8); + case 9: + return deserializeBoxForStatement(pos + 8); + case 10: + return deserializeBoxIfStatement(pos + 8); + case 11: + return deserializeBoxLabeledStatement(pos + 8); + case 12: + return deserializeBoxReturnStatement(pos + 8); + case 13: + return deserializeBoxSwitchStatement(pos + 8); + case 14: + return deserializeBoxThrowStatement(pos + 8); + case 15: + return deserializeBoxTryStatement(pos + 8); + case 16: + return deserializeBoxWhileStatement(pos + 8); + case 17: + return deserializeBoxWithStatement(pos + 8); + case 32: + return deserializeBoxVariableDeclaration(pos + 8); + case 33: + return deserializeBoxFunction(pos + 8); + case 34: + return deserializeBoxClass(pos + 8); + case 35: + return deserializeBoxTSTypeAliasDeclaration(pos + 8); + case 36: + return deserializeBoxTSInterfaceDeclaration(pos + 8); + case 37: + return deserializeBoxTSEnumDeclaration(pos + 8); + case 38: + return deserializeBoxTSModuleDeclaration(pos + 8); + case 39: + return deserializeBoxTSImportEqualsDeclaration(pos + 8); + case 64: + return deserializeBoxImportDeclaration(pos + 8); + case 65: + return deserializeBoxExportAllDeclaration(pos + 8); + case 66: + return deserializeBoxExportDefaultDeclaration(pos + 8); + case 67: + return deserializeBoxExportNamedDeclaration(pos + 8); + case 68: + return deserializeBoxTSExportAssignment(pos + 8); + case 69: + return deserializeBoxTSNamespaceExportDeclaration(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for Statement`); + } +} + +function deserializeDirective(pos) { + return { + type: 'ExpressionStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeStringLiteral(pos + 8), + directive: deserializeStr(pos + 48), + }; +} + +function deserializeHashbang(pos) { + return { + type: 'Hashbang', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value: deserializeStr(pos + 8), + }; +} + +function deserializeBlockStatement(pos) { + return { + type: 'BlockStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeVecStatement(pos + 8), + }; +} + +function deserializeDeclaration(pos) { + switch (uint8[pos]) { + case 32: + return deserializeBoxVariableDeclaration(pos + 8); + case 33: + return deserializeBoxFunction(pos + 8); + case 34: + return deserializeBoxClass(pos + 8); + case 35: + return deserializeBoxTSTypeAliasDeclaration(pos + 8); + case 36: + return deserializeBoxTSInterfaceDeclaration(pos + 8); + case 37: + return deserializeBoxTSEnumDeclaration(pos + 8); + case 38: + return deserializeBoxTSModuleDeclaration(pos + 8); + case 39: + return deserializeBoxTSImportEqualsDeclaration(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for Declaration`); + } +} + +function deserializeVariableDeclaration(pos) { + return { + type: 'VariableDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + declarations: deserializeVecVariableDeclarator(pos + 16), + kind: deserializeVariableDeclarationKind(pos + 8), + declare: deserializeBool(pos + 48), + }; +} + +function deserializeVariableDeclarationKind(pos) { + switch (uint8[pos]) { + case 0: + return 'var'; + case 1: + return 'const'; + case 2: + return 'let'; + case 3: + return 'using'; + case 4: + return 'await using'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for VariableDeclarationKind`); + } +} + +function deserializeVariableDeclarator(pos) { + return { + type: 'VariableDeclarator', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeBindingPattern(pos + 16), + init: deserializeOptionExpression(pos + 48), + definite: deserializeBool(pos + 64), + }; +} + +function deserializeEmptyStatement(pos) { + return { + type: 'EmptyStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeExpressionStatement(pos) { + return { + type: 'ExpressionStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + }; +} + +function deserializeIfStatement(pos) { + return { + type: 'IfStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + test: deserializeExpression(pos + 8), + consequent: deserializeStatement(pos + 24), + alternate: deserializeOptionStatement(pos + 40), + }; +} + +function deserializeDoWhileStatement(pos) { + return { + type: 'DoWhileStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeStatement(pos + 8), + test: deserializeExpression(pos + 24), + }; +} + +function deserializeWhileStatement(pos) { + return { + type: 'WhileStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + test: deserializeExpression(pos + 8), + body: deserializeStatement(pos + 24), + }; +} + +function deserializeForStatement(pos) { + return { + type: 'ForStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + init: deserializeOptionForStatementInit(pos + 8), + test: deserializeOptionExpression(pos + 24), + update: deserializeOptionExpression(pos + 40), + body: deserializeStatement(pos + 56), + }; +} + +function deserializeForStatementInit(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + case 64: + return deserializeBoxVariableDeclaration(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ForStatementInit`); + } +} + +function deserializeForInStatement(pos) { + return { + type: 'ForInStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializeForStatementLeft(pos + 8), + right: deserializeExpression(pos + 24), + body: deserializeStatement(pos + 40), + }; +} + +function deserializeForStatementLeft(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSAsExpression(pos + 8); + case 2: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 3: + return deserializeBoxTSNonNullExpression(pos + 8); + case 4: + return deserializeBoxTSTypeAssertion(pos + 8); + case 5: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 8: + return deserializeBoxArrayAssignmentTarget(pos + 8); + case 9: + return deserializeBoxObjectAssignmentTarget(pos + 8); + case 16: + return deserializeBoxVariableDeclaration(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ForStatementLeft`); + } +} + +function deserializeForOfStatement(pos) { + return { + type: 'ForOfStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + await: deserializeBool(pos + 8), + left: deserializeForStatementLeft(pos + 16), + right: deserializeExpression(pos + 32), + body: deserializeStatement(pos + 48), + }; +} + +function deserializeContinueStatement(pos) { + return { + type: 'ContinueStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + label: deserializeOptionLabelIdentifier(pos + 8), + }; +} + +function deserializeBreakStatement(pos) { + return { + type: 'BreakStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + label: deserializeOptionLabelIdentifier(pos + 8), + }; +} + +function deserializeReturnStatement(pos) { + return { + type: 'ReturnStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeOptionExpression(pos + 8), + }; +} + +function deserializeWithStatement(pos) { + return { + type: 'WithStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + object: deserializeExpression(pos + 8), + body: deserializeStatement(pos + 24), + }; +} + +function deserializeSwitchStatement(pos) { + return { + type: 'SwitchStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + discriminant: deserializeExpression(pos + 8), + cases: deserializeVecSwitchCase(pos + 24), + }; +} + +function deserializeSwitchCase(pos) { + return { + type: 'SwitchCase', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + consequent: deserializeVecStatement(pos + 24), + test: deserializeOptionExpression(pos + 8), + }; +} + +function deserializeLabeledStatement(pos) { + return { + type: 'LabeledStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeStatement(pos + 32), + label: deserializeLabelIdentifier(pos + 8), + }; +} + +function deserializeThrowStatement(pos) { + return { + type: 'ThrowStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeExpression(pos + 8), + }; +} + +function deserializeTryStatement(pos) { + return { + type: 'TryStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + block: deserializeBoxBlockStatement(pos + 8), + handler: deserializeOptionBoxCatchClause(pos + 16), + finalizer: deserializeOptionBoxBlockStatement(pos + 24), + }; +} + +function deserializeCatchClause(pos) { + return { + type: 'CatchClause', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + param: deserializeOptionCatchParameter(pos + 8), + body: deserializeBoxBlockStatement(pos + 48), + }; +} + +function deserializeCatchParameter(pos) { + return { + ...deserializeBindingPatternKind(pos + 8), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 24), + optional: deserializeBool(pos + 32), + }; +} + +function deserializeDebuggerStatement(pos) { + return { + type: 'DebuggerStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeBindingPattern(pos) { + return { + ...deserializeBindingPatternKind(pos), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 16), + optional: deserializeBool(pos + 24), + }; +} + +function deserializeBindingPatternKind(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBindingIdentifier(pos + 8); + case 1: + return deserializeBoxObjectPattern(pos + 8); + case 2: + return deserializeBoxArrayPattern(pos + 8); + case 3: + return deserializeBoxAssignmentPattern(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for BindingPatternKind`); + } +} + +function deserializeAssignmentPattern(pos) { + return { + type: 'AssignmentPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializeBindingPattern(pos + 8), + right: deserializeExpression(pos + 40), + }; +} + +function deserializeObjectPattern(pos) { + const properties = deserializeVecBindingProperty(pos + 8); + const rest = deserializeOptionBoxBindingRestElement(pos + 40); + if (rest !== null) properties.push(rest); + return { + type: 'ObjectPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + properties, + }; +} + +function deserializeBindingProperty(pos) { + const start = deserializeU32(pos), + end = deserializeU32(pos + 4), + shorthand = deserializeBool(pos + 56), + computed = deserializeBool(pos + 57), + key = deserializePropertyKey(pos + 8), + value = deserializeBindingPattern(pos + 24), + obj = shorthand + ? { type: 'Property', start, end, method: false, shorthand, computed, key, kind: 'init', value } + : { type: 'Property', start, end, method: false, shorthand, computed, key, value, kind: 'init' }; + return obj; +} + +function deserializeArrayPattern(pos) { + const elements = deserializeVecOptionBindingPattern(pos + 8); + const rest = deserializeOptionBoxBindingRestElement(pos + 40); + if (rest !== null) elements.push(rest); + return { + type: 'ArrayPattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + elements, + }; +} + +function deserializeBindingRestElement(pos) { + return { + type: 'RestElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeBindingPattern(pos + 8), + }; +} + +function deserializeFunction(pos) { + return { + type: deserializeFunctionType(pos + 8), + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeOptionBindingIdentifier(pos + 16), + expression: false, + generator: deserializeBool(pos + 48), + async: deserializeBool(pos + 49), + params: deserializeBoxFormalParameters(pos + 72), + body: deserializeOptionBoxFunctionBody(pos + 88), + declare: deserializeBool(pos + 50), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 56), + thisParam: deserializeOptionBoxTSThisParameter(pos + 64), + returnType: deserializeOptionBoxTSTypeAnnotation(pos + 80), + }; +} + +function deserializeFunctionType(pos) { + switch (uint8[pos]) { + case 0: + return 'FunctionDeclaration'; + case 1: + return 'FunctionExpression'; + case 2: + return 'TSDeclareFunction'; + case 3: + return 'TSEmptyBodyFunctionExpression'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for FunctionType`); + } +} + +function deserializeFormalParameters(pos) { + const params = deserializeVecFormalParameter(pos + 16); + if (uint32[(pos + 48) >> 2] !== 0 && uint32[(pos + 52) >> 2] !== 0) { + pos = uint32[(pos + 48) >> 2]; + params.push({ + type: 'RestElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeBindingPatternKind(pos + 8), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation( + pos + 24, + ), + optional: deserializeBool(pos + 32), + }); + } + return params; +} + +function deserializeFormalParameter(pos) { + return { + ...deserializeBindingPatternKind(pos + 40), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 56), + optional: deserializeBool(pos + 64), + decorators: deserializeVecDecorator(pos + 8), + accessibility: deserializeOptionTSAccessibility(pos + 72), + readonly: deserializeBool(pos + 73), + override: deserializeBool(pos + 74), + }; +} + +function deserializeFormalParameterKind(pos) { + switch (uint8[pos]) { + case 0: + return 'FormalParameter'; + case 1: + return 'UniqueFormalParameters'; + case 2: + return 'ArrowFormalParameters'; + case 3: + return 'Signature'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for FormalParameterKind`); + } +} + +function deserializeFunctionBody(pos) { + const body = deserializeVecDirective(pos + 8); + body.push(...deserializeVecStatement(pos + 40)); + return { + type: 'BlockStatement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body, + }; +} + +function deserializeArrowFunctionExpression(pos) { + let body = deserializeBoxFunctionBody(pos + 40); + return { + type: 'ArrowFunctionExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: null, + expression: deserializeBool(pos + 8), + generator: false, + async: deserializeBool(pos + 9), + params: deserializeBoxFormalParameters(pos + 24), + body: deserializeBool(pos + 8) ? body.body[0].expression : body, + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 16), + returnType: deserializeOptionBoxTSTypeAnnotation(pos + 32), + }; +} + +function deserializeYieldExpression(pos) { + return { + type: 'YieldExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + delegate: deserializeBool(pos + 8), + argument: deserializeOptionExpression(pos + 16), + }; +} + +function deserializeClass(pos) { + return { + type: deserializeClassType(pos + 8), + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeOptionBindingIdentifier(pos + 48), + superClass: deserializeOptionExpression(pos + 88), + body: deserializeBoxClassBody(pos + 144), + decorators: deserializeVecDecorator(pos + 16), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 80), + superTypeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 104), + implements: deserializeOptionVecTSClassImplements(pos + 112), + abstract: deserializeBool(pos + 152), + declare: deserializeBool(pos + 153), + }; +} + +function deserializeClassType(pos) { + switch (uint8[pos]) { + case 0: + return 'ClassDeclaration'; + case 1: + return 'ClassExpression'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ClassType`); + } +} + +function deserializeClassBody(pos) { + return { + type: 'ClassBody', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeVecClassElement(pos + 8), + }; +} + +function deserializeClassElement(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxStaticBlock(pos + 8); + case 1: + return deserializeBoxMethodDefinition(pos + 8); + case 2: + return deserializeBoxPropertyDefinition(pos + 8); + case 3: + return deserializeBoxAccessorProperty(pos + 8); + case 4: + return deserializeBoxTSIndexSignature(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ClassElement`); + } +} + +function deserializeMethodDefinition(pos) { + return { + type: deserializeMethodDefinitionType(pos + 8), + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + static: deserializeBool(pos + 74), + computed: deserializeBool(pos + 73), + key: deserializePropertyKey(pos + 48), + kind: deserializeMethodDefinitionKind(pos + 72), + value: deserializeBoxFunction(pos + 64), + decorators: deserializeVecDecorator(pos + 16), + override: deserializeBool(pos + 75), + optional: deserializeBool(pos + 76), + accessibility: deserializeOptionTSAccessibility(pos + 77), + }; +} + +function deserializeMethodDefinitionType(pos) { + switch (uint8[pos]) { + case 0: + return 'MethodDefinition'; + case 1: + return 'TSAbstractMethodDefinition'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for MethodDefinitionType`); + } +} + +function deserializePropertyDefinition(pos) { + return { + type: deserializePropertyDefinitionType(pos + 8), + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + static: deserializeBool(pos + 81), + computed: deserializeBool(pos + 80), + key: deserializePropertyKey(pos + 48), + value: deserializeOptionExpression(pos + 64), + decorators: deserializeVecDecorator(pos + 16), + declare: deserializeBool(pos + 82), + override: deserializeBool(pos + 83), + optional: deserializeBool(pos + 84), + definite: deserializeBool(pos + 85), + readonly: deserializeBool(pos + 86), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 88), + accessibility: deserializeOptionTSAccessibility(pos + 96), + }; +} + +function deserializePropertyDefinitionType(pos) { + switch (uint8[pos]) { + case 0: + return 'PropertyDefinition'; + case 1: + return 'TSAbstractPropertyDefinition'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for PropertyDefinitionType`); + } +} + +function deserializeMethodDefinitionKind(pos) { + switch (uint8[pos]) { + case 0: + return 'constructor'; + case 1: + return 'method'; + case 2: + return 'get'; + case 3: + return 'set'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for MethodDefinitionKind`); + } +} + +function deserializePrivateIdentifier(pos) { + return { + type: 'PrivateIdentifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeStaticBlock(pos) { + return { + type: 'StaticBlock', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeVecStatement(pos + 8), + }; +} + +function deserializeModuleDeclaration(pos) { + switch (uint8[pos]) { + case 64: + return deserializeBoxImportDeclaration(pos + 8); + case 65: + return deserializeBoxExportAllDeclaration(pos + 8); + case 66: + return deserializeBoxExportDefaultDeclaration(pos + 8); + case 67: + return deserializeBoxExportNamedDeclaration(pos + 8); + case 68: + return deserializeBoxTSExportAssignment(pos + 8); + case 69: + return deserializeBoxTSNamespaceExportDeclaration(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ModuleDeclaration`); + } +} + +function deserializeAccessorPropertyType(pos) { + switch (uint8[pos]) { + case 0: + return 'AccessorProperty'; + case 1: + return 'TSAbstractAccessorProperty'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for AccessorPropertyType`); + } +} + +function deserializeAccessorProperty(pos) { + return { + type: deserializeAccessorPropertyType(pos + 8), + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + key: deserializePropertyKey(pos + 48), + value: deserializeOptionExpression(pos + 64), + computed: deserializeBool(pos + 80), + static: deserializeBool(pos + 81), + decorators: deserializeVecDecorator(pos + 16), + definite: deserializeBool(pos + 82), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 88), + accessibility: deserializeOptionTSAccessibility(pos + 96), + }; +} + +function deserializeImportExpression(pos) { + const args = deserializeVecExpression(pos + 24); + return { + type: 'ImportExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + source: deserializeExpression(pos + 8), + options: args.length === 0 ? null : args[0], + }; +} + +function deserializeImportDeclaration(pos) { + let specifiers = deserializeOptionVecImportDeclarationSpecifier(pos + 8); + if (specifiers === null) specifiers = []; + const withClause = deserializeOptionBoxWithClause(pos + 88); + return { + type: 'ImportDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + specifiers, + source: deserializeStringLiteral(pos + 40), + attributes: withClause === null ? [] : withClause.withEntries, + importKind: deserializeImportOrExportKind(pos + 96), + }; +} + +function deserializeImportPhase(pos) { + switch (uint8[pos]) { + case 0: + return 'source'; + case 1: + return 'defer'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ImportPhase`); + } +} + +function deserializeImportDeclarationSpecifier(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxImportSpecifier(pos + 8); + case 1: + return deserializeBoxImportDefaultSpecifier(pos + 8); + case 2: + return deserializeBoxImportNamespaceSpecifier(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ImportDeclarationSpecifier`); + } +} + +function deserializeImportSpecifier(pos) { + return { + type: 'ImportSpecifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + imported: deserializeModuleExportName(pos + 8), + local: deserializeBindingIdentifier(pos + 56), + importKind: deserializeImportOrExportKind(pos + 88), + }; +} + +function deserializeImportDefaultSpecifier(pos) { + return { + type: 'ImportDefaultSpecifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + local: deserializeBindingIdentifier(pos + 8), + }; +} + +function deserializeImportNamespaceSpecifier(pos) { + return { + type: 'ImportNamespaceSpecifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + local: deserializeBindingIdentifier(pos + 8), + }; +} + +function deserializeWithClause(pos) { + return { + type: 'WithClause', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + attributesKeyword: deserializeIdentifierName(pos + 8), + withEntries: deserializeVecImportAttribute(pos + 32), + }; +} + +function deserializeImportAttribute(pos) { + return { + type: 'ImportAttribute', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + key: deserializeImportAttributeKey(pos + 8), + value: deserializeStringLiteral(pos + 56), + }; +} + +function deserializeImportAttributeKey(pos) { + switch (uint8[pos]) { + case 0: + return deserializeIdentifierName(pos + 8); + case 1: + return deserializeStringLiteral(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ImportAttributeKey`); + } +} + +function deserializeExportNamedDeclaration(pos) { + const start = deserializeU32(pos), + end = deserializeU32(pos + 4), + declaration = deserializeOptionDeclaration(pos + 8), + specifiers = deserializeVecExportSpecifier(pos + 24), + source = deserializeOptionStringLiteral(pos + 56), + exportKind = deserializeImportOrExportKind(pos + 96); + + if (source !== null) { + const withClause = deserializeOptionBoxWithClause(pos + 104); + return { + type: 'ExportNamedDeclaration', + start, + end, + declaration, + specifiers, + source, + exportKind, + attributes: withClause === null ? [] : withClause.withEntries, + }; + } + + return { type: 'ExportNamedDeclaration', start, end, declaration, specifiers, source, exportKind }; +} + +function deserializeExportDefaultDeclaration(pos) { + return { + type: 'ExportDefaultDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + declaration: deserializeExportDefaultDeclarationKind(pos + 56), + }; +} + +function deserializeExportAllDeclaration(pos) { + const withClause = deserializeOptionBoxWithClause(pos + 96); + return { + type: 'ExportAllDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + exported: deserializeOptionModuleExportName(pos + 8), + source: deserializeStringLiteral(pos + 56), + attributes: withClause === null ? [] : withClause.withEntries, + exportKind: deserializeImportOrExportKind(pos + 104), + }; +} + +function deserializeExportSpecifier(pos) { + return { + type: 'ExportSpecifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + local: deserializeModuleExportName(pos + 8), + exported: deserializeModuleExportName(pos + 56), + exportKind: deserializeImportOrExportKind(pos + 104), + }; +} + +function deserializeExportDefaultDeclarationKind(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + case 64: + return deserializeBoxFunction(pos + 8); + case 65: + return deserializeBoxClass(pos + 8); + case 66: + return deserializeBoxTSInterfaceDeclaration(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ExportDefaultDeclarationKind`); + } +} + +function deserializeModuleExportName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeIdentifierName(pos + 8); + case 1: + return deserializeIdentifierReference(pos + 8); + case 2: + return deserializeStringLiteral(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ModuleExportName`); + } +} + +function deserializeV8IntrinsicExpression(pos) { + return { + type: 'V8IntrinsicExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeIdentifierName(pos + 8), + arguments: deserializeVecArgument(pos + 32), + }; +} + +function deserializeBooleanLiteral(pos) { + const start = deserializeU32(pos), + end = deserializeU32(pos + 4), + value = deserializeBool(pos + 8); + return { + type: 'Literal', + start, + end, + value, + raw: (start === 0 && end === 0) ? null : value + '', + }; +} + +function deserializeNullLiteral(pos) { + const start = deserializeU32(pos), + end = deserializeU32(pos + 4); + return { + type: 'Literal', + start, + end, + value: null, + raw: (start === 0 && end === 0) ? null : 'null', + }; +} + +function deserializeNumericLiteral(pos) { + return { + type: 'Literal', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value: deserializeF64(pos + 8), + raw: deserializeOptionStr(pos + 16), + }; +} + +function deserializeStringLiteral(pos) { + return { + type: 'Literal', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value: deserializeStr(pos + 8), + raw: deserializeOptionStr(pos + 24), + }; +} + +function deserializeBigIntLiteral(pos) { + const raw = deserializeStr(pos + 8), + bigint = raw.slice(0, -1).replace(/_/g, ''); + return { + type: 'Literal', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value: BigInt(bigint), + raw, + bigint, + }; +} + +function deserializeRegExpLiteral(pos) { + const raw = deserializeOptionStr(pos + 40); + let pattern, flags, value = null; + if (raw === null) { + pattern = deserializeRegExpPattern(pos + 8); + const flagBits = deserializeU8(pos + 32); + flags = ''; + if (flagBits & 1) flags += 'g'; + if (flagBits & 2) flags += 'i'; + if (flagBits & 4) flags += 'm'; + if (flagBits & 8) flags += 's'; + if (flagBits & 16) flags += 'u'; + if (flagBits & 32) flags += 'y'; + if (flagBits & 64) flags += 'd'; + if (flagBits & 128) flags += 'v'; + } else { + [, pattern, flags] = raw.match(/^\/(.*)\/([a-z]*)$/); + } + + try { + value = new RegExp(pattern, flags); + } catch (e) {} + return { + type: 'Literal', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value, + raw, + regex: { pattern, flags }, + }; +} + +function deserializeRegExp(pos) { + return { + pattern: deserializeRegExpPattern(pos), + flags: deserializeRegExpFlags(pos + 24), + }; +} + +function deserializeRegExpPattern(pos) { + switch (uint8[pos]) { + case 0: + return deserializeStr(pos + 8); + case 1: + return deserializeStr(pos + 8); + case 2: + return deserializeBoxPattern(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for RegExpPattern`); + } +} + +function deserializeRegExpFlags(pos) { + return { + type: 'RegExpFlags', + 0: deserializeU8(pos), + }; +} + +function deserializeJSXElement(pos) { + return { + type: 'JSXElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + openingElement: deserializeBoxJSXOpeningElement(pos + 8), + closingElement: deserializeOptionBoxJSXClosingElement(pos + 16), + children: deserializeVecJSXChild(pos + 24), + }; +} + +function deserializeJSXOpeningElement(pos) { + return { + type: 'JSXOpeningElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + selfClosing: deserializeBool(pos + 8), + name: deserializeJSXElementName(pos + 16), + attributes: deserializeVecJSXAttributeItem(pos + 32), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 64), + }; +} + +function deserializeJSXClosingElement(pos) { + return { + type: 'JSXClosingElement', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeJSXElementName(pos + 8), + }; +} + +function deserializeJSXFragment(pos) { + return { + type: 'JSXFragment', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + openingFragment: deserializeJSXOpeningFragment(pos + 8), + closingFragment: deserializeJSXClosingFragment(pos + 16), + children: deserializeVecJSXChild(pos + 24), + }; +} + +function deserializeJSXOpeningFragment(pos) { + return { + type: 'JSXOpeningFragment', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeJSXClosingFragment(pos) { + return { + type: 'JSXClosingFragment', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeJSXElementName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxJSXIdentifier(pos + 8); + case 1: + const ident = deserializeBoxIdentifierReference(pos + 8); + ident.type = 'JSXIdentifier'; + return ident; + case 2: + return deserializeBoxJSXNamespacedName(pos + 8); + case 3: + return deserializeBoxJSXMemberExpression(pos + 8); + case 4: + const thisExpr = deserializeBoxThisExpression(pos + 8); + return { type: 'JSXIdentifier', start: thisExpr.start, end: thisExpr.end, name: 'this' }; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXElementName`); + } +} + +function deserializeJSXNamespacedName(pos) { + return { + type: 'JSXNamespacedName', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + namespace: deserializeJSXIdentifier(pos + 8), + property: deserializeJSXIdentifier(pos + 32), + }; +} + +function deserializeJSXMemberExpression(pos) { + return { + type: 'JSXMemberExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + object: deserializeJSXMemberExpressionObject(pos + 8), + property: deserializeJSXIdentifier(pos + 24), + }; +} + +function deserializeJSXMemberExpressionObject(pos) { + switch (uint8[pos]) { + case 0: + const ident = deserializeBoxIdentifierReference(pos + 8); + ident.type = 'JSXIdentifier'; + return ident; + case 1: + return deserializeBoxJSXMemberExpression(pos + 8); + case 2: + const thisExpr = deserializeBoxThisExpression(pos + 8); + return { type: 'JSXIdentifier', start: thisExpr.start, end: thisExpr.end, name: 'this' }; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXMemberExpressionObject`); + } +} + +function deserializeJSXExpressionContainer(pos) { + return { + type: 'JSXExpressionContainer', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeJSXExpression(pos + 8), + }; +} + +function deserializeJSXExpression(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNullLiteral(pos + 8); + case 2: + return deserializeBoxNumericLiteral(pos + 8); + case 3: + return deserializeBoxBigIntLiteral(pos + 8); + case 4: + return deserializeBoxRegExpLiteral(pos + 8); + case 5: + return deserializeBoxStringLiteral(pos + 8); + case 6: + return deserializeBoxTemplateLiteral(pos + 8); + case 7: + return deserializeBoxIdentifierReference(pos + 8); + case 8: + return deserializeBoxMetaProperty(pos + 8); + case 9: + return deserializeBoxSuper(pos + 8); + case 10: + return deserializeBoxArrayExpression(pos + 8); + case 11: + return deserializeBoxArrowFunctionExpression(pos + 8); + case 12: + return deserializeBoxAssignmentExpression(pos + 8); + case 13: + return deserializeBoxAwaitExpression(pos + 8); + case 14: + return deserializeBoxBinaryExpression(pos + 8); + case 15: + return deserializeBoxCallExpression(pos + 8); + case 16: + return deserializeBoxChainExpression(pos + 8); + case 17: + return deserializeBoxClass(pos + 8); + case 18: + return deserializeBoxConditionalExpression(pos + 8); + case 19: + return deserializeBoxFunction(pos + 8); + case 20: + return deserializeBoxImportExpression(pos + 8); + case 21: + return deserializeBoxLogicalExpression(pos + 8); + case 22: + return deserializeBoxNewExpression(pos + 8); + case 23: + return deserializeBoxObjectExpression(pos + 8); + case 24: + return deserializeBoxParenthesizedExpression(pos + 8); + case 25: + return deserializeBoxSequenceExpression(pos + 8); + case 26: + return deserializeBoxTaggedTemplateExpression(pos + 8); + case 27: + return deserializeBoxThisExpression(pos + 8); + case 28: + return deserializeBoxUnaryExpression(pos + 8); + case 29: + return deserializeBoxUpdateExpression(pos + 8); + case 30: + return deserializeBoxYieldExpression(pos + 8); + case 31: + return deserializeBoxPrivateInExpression(pos + 8); + case 32: + return deserializeBoxJSXElement(pos + 8); + case 33: + return deserializeBoxJSXFragment(pos + 8); + case 34: + return deserializeBoxTSAsExpression(pos + 8); + case 35: + return deserializeBoxTSSatisfiesExpression(pos + 8); + case 36: + return deserializeBoxTSTypeAssertion(pos + 8); + case 37: + return deserializeBoxTSNonNullExpression(pos + 8); + case 38: + return deserializeBoxTSInstantiationExpression(pos + 8); + case 39: + return deserializeBoxV8IntrinsicExpression(pos + 8); + case 48: + return deserializeBoxComputedMemberExpression(pos + 8); + case 49: + return deserializeBoxStaticMemberExpression(pos + 8); + case 50: + return deserializeBoxPrivateFieldExpression(pos + 8); + case 64: + return deserializeJSXEmptyExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXExpression`); + } +} + +function deserializeJSXEmptyExpression(pos) { + return { + type: 'JSXEmptyExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeJSXAttributeItem(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxJSXAttribute(pos + 8); + case 1: + return deserializeBoxJSXSpreadAttribute(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXAttributeItem`); + } +} + +function deserializeJSXAttribute(pos) { + return { + type: 'JSXAttribute', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeJSXAttributeName(pos + 8), + value: deserializeOptionJSXAttributeValue(pos + 24), + }; +} + +function deserializeJSXSpreadAttribute(pos) { + return { + type: 'JSXSpreadAttribute', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + argument: deserializeExpression(pos + 8), + }; +} + +function deserializeJSXAttributeName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxJSXIdentifier(pos + 8); + case 1: + return deserializeBoxJSXNamespacedName(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXAttributeName`); + } +} + +function deserializeJSXAttributeValue(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxStringLiteral(pos + 8); + case 1: + return deserializeBoxJSXExpressionContainer(pos + 8); + case 2: + return deserializeBoxJSXElement(pos + 8); + case 3: + return deserializeBoxJSXFragment(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXAttributeValue`); + } +} + +function deserializeJSXIdentifier(pos) { + return { + type: 'JSXIdentifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeJSXChild(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxJSXText(pos + 8); + case 1: + return deserializeBoxJSXElement(pos + 8); + case 2: + return deserializeBoxJSXFragment(pos + 8); + case 3: + return deserializeBoxJSXExpressionContainer(pos + 8); + case 4: + return deserializeBoxJSXSpreadChild(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for JSXChild`); + } +} + +function deserializeJSXSpreadChild(pos) { + return { + type: 'JSXSpreadChild', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + }; +} + +function deserializeJSXText(pos) { + return { + type: 'JSXText', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + value: deserializeStr(pos + 8), + }; +} + +function deserializeTSThisParameter(pos) { + return { + type: 'TSThisParameter', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 16), + }; +} + +function deserializeTSEnumDeclaration(pos) { + return { + type: 'TSEnumDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeBindingIdentifier(pos + 8), + members: deserializeVecTSEnumMember(pos + 40), + const: deserializeBool(pos + 72), + declare: deserializeBool(pos + 73), + }; +} + +function deserializeTSEnumMember(pos) { + return { + type: 'TSEnumMember', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeTSEnumMemberName(pos + 8), + initializer: deserializeOptionExpression(pos + 24), + }; +} + +function deserializeTSEnumMemberName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierName(pos + 8); + case 1: + return deserializeBoxStringLiteral(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSEnumMemberName`); + } +} + +function deserializeTSTypeAnnotation(pos) { + return { + type: 'TSTypeAnnotation', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeTSType(pos + 8), + }; +} + +function deserializeTSLiteralType(pos) { + return { + type: 'TSLiteralType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + literal: deserializeTSLiteral(pos + 8), + }; +} + +function deserializeTSLiteral(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBooleanLiteral(pos + 8); + case 1: + return deserializeBoxNumericLiteral(pos + 8); + case 2: + return deserializeBoxBigIntLiteral(pos + 8); + case 3: + return deserializeBoxStringLiteral(pos + 8); + case 4: + return deserializeBoxTemplateLiteral(pos + 8); + case 5: + return deserializeBoxUnaryExpression(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSLiteral`); + } +} + +function deserializeTSType(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxTSAnyKeyword(pos + 8); + case 1: + return deserializeBoxTSBigIntKeyword(pos + 8); + case 2: + return deserializeBoxTSBooleanKeyword(pos + 8); + case 3: + return deserializeBoxTSIntrinsicKeyword(pos + 8); + case 4: + return deserializeBoxTSNeverKeyword(pos + 8); + case 5: + return deserializeBoxTSNullKeyword(pos + 8); + case 6: + return deserializeBoxTSNumberKeyword(pos + 8); + case 7: + return deserializeBoxTSObjectKeyword(pos + 8); + case 8: + return deserializeBoxTSStringKeyword(pos + 8); + case 9: + return deserializeBoxTSSymbolKeyword(pos + 8); + case 10: + return deserializeBoxTSThisType(pos + 8); + case 11: + return deserializeBoxTSUndefinedKeyword(pos + 8); + case 12: + return deserializeBoxTSUnknownKeyword(pos + 8); + case 13: + return deserializeBoxTSVoidKeyword(pos + 8); + case 14: + return deserializeBoxTSArrayType(pos + 8); + case 15: + return deserializeBoxTSConditionalType(pos + 8); + case 16: + return deserializeBoxTSConstructorType(pos + 8); + case 17: + return deserializeBoxTSFunctionType(pos + 8); + case 18: + return deserializeBoxTSImportType(pos + 8); + case 19: + return deserializeBoxTSIndexedAccessType(pos + 8); + case 20: + return deserializeBoxTSInferType(pos + 8); + case 21: + return deserializeBoxTSIntersectionType(pos + 8); + case 22: + return deserializeBoxTSLiteralType(pos + 8); + case 23: + return deserializeBoxTSMappedType(pos + 8); + case 24: + return deserializeBoxTSNamedTupleMember(pos + 8); + case 26: + return deserializeBoxTSTemplateLiteralType(pos + 8); + case 27: + return deserializeBoxTSTupleType(pos + 8); + case 28: + return deserializeBoxTSTypeLiteral(pos + 8); + case 29: + return deserializeBoxTSTypeOperator(pos + 8); + case 30: + return deserializeBoxTSTypePredicate(pos + 8); + case 31: + return deserializeBoxTSTypeQuery(pos + 8); + case 32: + return deserializeBoxTSTypeReference(pos + 8); + case 33: + return deserializeBoxTSUnionType(pos + 8); + case 34: + return deserializeBoxTSParenthesizedType(pos + 8); + case 35: + return deserializeBoxJSDocNullableType(pos + 8); + case 36: + return deserializeBoxJSDocNonNullableType(pos + 8); + case 37: + return deserializeBoxJSDocUnknownType(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSType`); + } +} + +function deserializeTSConditionalType(pos) { + return { + type: 'TSConditionalType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + checkType: deserializeTSType(pos + 8), + extendsType: deserializeTSType(pos + 24), + trueType: deserializeTSType(pos + 40), + falseType: deserializeTSType(pos + 56), + }; +} + +function deserializeTSUnionType(pos) { + return { + type: 'TSUnionType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + types: deserializeVecTSType(pos + 8), + }; +} + +function deserializeTSIntersectionType(pos) { + return { + type: 'TSIntersectionType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + types: deserializeVecTSType(pos + 8), + }; +} + +function deserializeTSParenthesizedType(pos) { + return { + type: 'TSParenthesizedType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeTSType(pos + 8), + }; +} + +function deserializeTSTypeOperator(pos) { + return { + type: 'TSTypeOperator', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + operator: deserializeTSTypeOperatorOperator(pos + 8), + typeAnnotation: deserializeTSType(pos + 16), + }; +} + +function deserializeTSTypeOperatorOperator(pos) { + switch (uint8[pos]) { + case 0: + return 'keyof'; + case 1: + return 'unique'; + case 2: + return 'readonly'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSTypeOperatorOperator`); + } +} + +function deserializeTSArrayType(pos) { + return { + type: 'TSArrayType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + elementType: deserializeTSType(pos + 8), + }; +} + +function deserializeTSIndexedAccessType(pos) { + return { + type: 'TSIndexedAccessType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + objectType: deserializeTSType(pos + 8), + indexType: deserializeTSType(pos + 24), + }; +} + +function deserializeTSTupleType(pos) { + return { + type: 'TSTupleType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + elementTypes: deserializeVecTSTupleElement(pos + 8), + }; +} + +function deserializeTSNamedTupleMember(pos) { + return { + type: 'TSNamedTupleMember', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + elementType: deserializeTSTupleElement(pos + 8), + label: deserializeIdentifierName(pos + 24), + optional: deserializeBool(pos + 48), + }; +} + +function deserializeTSOptionalType(pos) { + return { + type: 'TSOptionalType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeTSType(pos + 8), + }; +} + +function deserializeTSRestType(pos) { + return { + type: 'TSRestType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeTSType(pos + 8), + }; +} + +function deserializeTSTupleElement(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxTSAnyKeyword(pos + 8); + case 1: + return deserializeBoxTSBigIntKeyword(pos + 8); + case 2: + return deserializeBoxTSBooleanKeyword(pos + 8); + case 3: + return deserializeBoxTSIntrinsicKeyword(pos + 8); + case 4: + return deserializeBoxTSNeverKeyword(pos + 8); + case 5: + return deserializeBoxTSNullKeyword(pos + 8); + case 6: + return deserializeBoxTSNumberKeyword(pos + 8); + case 7: + return deserializeBoxTSObjectKeyword(pos + 8); + case 8: + return deserializeBoxTSStringKeyword(pos + 8); + case 9: + return deserializeBoxTSSymbolKeyword(pos + 8); + case 10: + return deserializeBoxTSThisType(pos + 8); + case 11: + return deserializeBoxTSUndefinedKeyword(pos + 8); + case 12: + return deserializeBoxTSUnknownKeyword(pos + 8); + case 13: + return deserializeBoxTSVoidKeyword(pos + 8); + case 14: + return deserializeBoxTSArrayType(pos + 8); + case 15: + return deserializeBoxTSConditionalType(pos + 8); + case 16: + return deserializeBoxTSConstructorType(pos + 8); + case 17: + return deserializeBoxTSFunctionType(pos + 8); + case 18: + return deserializeBoxTSImportType(pos + 8); + case 19: + return deserializeBoxTSIndexedAccessType(pos + 8); + case 20: + return deserializeBoxTSInferType(pos + 8); + case 21: + return deserializeBoxTSIntersectionType(pos + 8); + case 22: + return deserializeBoxTSLiteralType(pos + 8); + case 23: + return deserializeBoxTSMappedType(pos + 8); + case 24: + return deserializeBoxTSNamedTupleMember(pos + 8); + case 26: + return deserializeBoxTSTemplateLiteralType(pos + 8); + case 27: + return deserializeBoxTSTupleType(pos + 8); + case 28: + return deserializeBoxTSTypeLiteral(pos + 8); + case 29: + return deserializeBoxTSTypeOperator(pos + 8); + case 30: + return deserializeBoxTSTypePredicate(pos + 8); + case 31: + return deserializeBoxTSTypeQuery(pos + 8); + case 32: + return deserializeBoxTSTypeReference(pos + 8); + case 33: + return deserializeBoxTSUnionType(pos + 8); + case 34: + return deserializeBoxTSParenthesizedType(pos + 8); + case 35: + return deserializeBoxJSDocNullableType(pos + 8); + case 36: + return deserializeBoxJSDocNonNullableType(pos + 8); + case 37: + return deserializeBoxJSDocUnknownType(pos + 8); + case 64: + return deserializeBoxTSOptionalType(pos + 8); + case 65: + return deserializeBoxTSRestType(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSTupleElement`); + } +} + +function deserializeTSAnyKeyword(pos) { + return { + type: 'TSAnyKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSStringKeyword(pos) { + return { + type: 'TSStringKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSBooleanKeyword(pos) { + return { + type: 'TSBooleanKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSNumberKeyword(pos) { + return { + type: 'TSNumberKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSNeverKeyword(pos) { + return { + type: 'TSNeverKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSIntrinsicKeyword(pos) { + return { + type: 'TSIntrinsicKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSUnknownKeyword(pos) { + return { + type: 'TSUnknownKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSNullKeyword(pos) { + return { + type: 'TSNullKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSUndefinedKeyword(pos) { + return { + type: 'TSUndefinedKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSVoidKeyword(pos) { + return { + type: 'TSVoidKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSSymbolKeyword(pos) { + return { + type: 'TSSymbolKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSThisType(pos) { + return { + type: 'TSThisType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSObjectKeyword(pos) { + return { + type: 'TSObjectKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSBigIntKeyword(pos) { + return { + type: 'TSBigIntKeyword', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeTSTypeReference(pos) { + return { + type: 'TSTypeReference', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeName: deserializeTSTypeName(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 24), + }; +} + +function deserializeTSTypeName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSQualifiedName(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSTypeName`); + } +} + +function deserializeTSQualifiedName(pos) { + return { + type: 'TSQualifiedName', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + left: deserializeTSTypeName(pos + 8), + right: deserializeIdentifierName(pos + 24), + }; +} + +function deserializeTSTypeParameterInstantiation(pos) { + return { + type: 'TSTypeParameterInstantiation', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + params: deserializeVecTSType(pos + 8), + }; +} + +function deserializeTSTypeParameter(pos) { + return { + type: 'TSTypeParameter', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeBindingIdentifier(pos + 8), + constraint: deserializeOptionTSType(pos + 40), + default: deserializeOptionTSType(pos + 56), + in: deserializeBool(pos + 72), + out: deserializeBool(pos + 73), + const: deserializeBool(pos + 74), + }; +} + +function deserializeTSTypeParameterDeclaration(pos) { + return { + type: 'TSTypeParameterDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + params: deserializeVecTSTypeParameter(pos + 8), + }; +} + +function deserializeTSTypeAliasDeclaration(pos) { + return { + type: 'TSTypeAliasDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeBindingIdentifier(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 40), + typeAnnotation: deserializeTSType(pos + 48), + declare: deserializeBool(pos + 64), + }; +} + +function deserializeTSAccessibility(pos) { + switch (uint8[pos]) { + case 0: + return 'private'; + case 1: + return 'protected'; + case 2: + return 'public'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSAccessibility`); + } +} + +function deserializeTSClassImplements(pos) { + return { + type: 'TSClassImplements', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeTSTypeName(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 24), + }; +} + +function deserializeTSInterfaceDeclaration(pos) { + return { + type: 'TSInterfaceDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeBindingIdentifier(pos + 8), + extends: deserializeOptionVecTSInterfaceHeritage(pos + 40), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 72), + body: deserializeBoxTSInterfaceBody(pos + 80), + declare: deserializeBool(pos + 88), + }; +} + +function deserializeTSInterfaceBody(pos) { + return { + type: 'TSInterfaceBody', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeVecTSSignature(pos + 8), + }; +} + +function deserializeTSPropertySignature(pos) { + return { + type: 'TSPropertySignature', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + computed: deserializeBool(pos + 8), + optional: deserializeBool(pos + 9), + readonly: deserializeBool(pos + 10), + key: deserializePropertyKey(pos + 16), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 32), + }; +} + +function deserializeTSSignature(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxTSIndexSignature(pos + 8); + case 1: + return deserializeBoxTSPropertySignature(pos + 8); + case 2: + return deserializeBoxTSCallSignatureDeclaration(pos + 8); + case 3: + return deserializeBoxTSConstructSignatureDeclaration(pos + 8); + case 4: + return deserializeBoxTSMethodSignature(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSSignature`); + } +} + +function deserializeTSIndexSignature(pos) { + return { + type: 'TSIndexSignature', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + parameters: deserializeVecTSIndexSignatureName(pos + 8), + typeAnnotation: deserializeBoxTSTypeAnnotation(pos + 40), + readonly: deserializeBool(pos + 48), + static: deserializeBool(pos + 49), + }; +} + +function deserializeTSCallSignatureDeclaration(pos) { + return { + type: 'TSCallSignatureDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 8), + thisParam: deserializeOptionTSThisParameter(pos + 16), + params: deserializeBoxFormalParameters(pos + 48), + returnType: deserializeOptionBoxTSTypeAnnotation(pos + 56), + }; +} + +function deserializeTSMethodSignatureKind(pos) { + switch (uint8[pos]) { + case 0: + return 'method'; + case 1: + return 'get'; + case 2: + return 'set'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSMethodSignatureKind`); + } +} + +function deserializeTSMethodSignature(pos) { + return { + type: 'TSMethodSignature', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + key: deserializePropertyKey(pos + 8), + computed: deserializeBool(pos + 24), + optional: deserializeBool(pos + 25), + kind: deserializeTSMethodSignatureKind(pos + 26), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 32), + thisParam: deserializeOptionBoxTSThisParameter(pos + 40), + params: deserializeBoxFormalParameters(pos + 48), + returnType: deserializeOptionBoxTSTypeAnnotation(pos + 56), + }; +} + +function deserializeTSConstructSignatureDeclaration(pos) { + return { + type: 'TSConstructSignatureDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 8), + params: deserializeBoxFormalParameters(pos + 16), + returnType: deserializeOptionBoxTSTypeAnnotation(pos + 24), + }; +} + +function deserializeTSIndexSignatureName(pos) { + return { + type: 'Identifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + typeAnnotation: deserializeBoxTSTypeAnnotation(pos + 24), + }; +} + +function deserializeTSInterfaceHeritage(pos) { + return { + type: 'TSInterfaceHeritage', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 24), + }; +} + +function deserializeTSTypePredicate(pos) { + return { + type: 'TSTypePredicate', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + parameterName: deserializeTSTypePredicateName(pos + 8), + asserts: deserializeBool(pos + 24), + typeAnnotation: deserializeOptionBoxTSTypeAnnotation(pos + 32), + }; +} + +function deserializeTSTypePredicateName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierName(pos + 8); + case 1: + return deserializeTSThisType(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSTypePredicateName`); + } +} + +function deserializeTSModuleDeclaration(pos) { + return { + type: 'TSModuleDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeTSModuleDeclarationName(pos + 8), + body: deserializeOptionTSModuleDeclarationBody(pos + 56), + kind: deserializeTSModuleDeclarationKind(pos + 72), + declare: deserializeBool(pos + 73), + }; +} + +function deserializeTSModuleDeclarationKind(pos) { + switch (uint8[pos]) { + case 0: + return 'global'; + case 1: + return 'module'; + case 2: + return 'namespace'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSModuleDeclarationKind`); + } +} + +function deserializeTSModuleDeclarationName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBindingIdentifier(pos + 8); + case 1: + return deserializeStringLiteral(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSModuleDeclarationName`); + } +} + +function deserializeTSModuleDeclarationBody(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxTSModuleDeclaration(pos + 8); + case 1: + return deserializeBoxTSModuleBlock(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSModuleDeclarationBody`); + } +} + +function deserializeTSModuleBlock(pos) { + const body = deserializeVecDirective(pos + 8); + body.push(...deserializeVecStatement(pos + 40)); + return { + type: 'TSModuleBlock', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body, + }; +} + +function deserializeTSTypeLiteral(pos) { + return { + type: 'TSTypeLiteral', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + members: deserializeVecTSSignature(pos + 8), + }; +} + +function deserializeTSInferType(pos) { + return { + type: 'TSInferType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeParameter: deserializeBoxTSTypeParameter(pos + 8), + }; +} + +function deserializeTSTypeQuery(pos) { + return { + type: 'TSTypeQuery', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + exprName: deserializeTSTypeQueryExprName(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 24), + }; +} + +function deserializeTSTypeQueryExprName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSQualifiedName(pos + 8); + case 2: + return deserializeBoxTSImportType(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSTypeQueryExprName`); + } +} + +function deserializeTSImportType(pos) { + return { + type: 'TSImportType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + isTypeOf: deserializeBool(pos + 8), + parameter: deserializeTSType(pos + 16), + qualifier: deserializeOptionTSTypeName(pos + 32), + attributes: deserializeOptionBoxTSImportAttributes(pos + 48), + typeParameters: deserializeOptionBoxTSTypeParameterInstantiation(pos + 56), + }; +} + +function deserializeTSImportAttributes(pos) { + return { + type: 'TSImportAttributes', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + attributesKeyword: deserializeIdentifierName(pos + 8), + elements: deserializeVecTSImportAttribute(pos + 32), + }; +} + +function deserializeTSImportAttribute(pos) { + return { + type: 'TSImportAttribute', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeTSImportAttributeName(pos + 8), + value: deserializeExpression(pos + 56), + }; +} + +function deserializeTSImportAttributeName(pos) { + switch (uint8[pos]) { + case 0: + return deserializeIdentifierName(pos + 8); + case 1: + return deserializeStringLiteral(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSImportAttributeName`); + } +} + +function deserializeTSFunctionType(pos) { + return { + type: 'TSFunctionType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 8), + thisParam: deserializeOptionBoxTSThisParameter(pos + 16), + params: deserializeBoxFormalParameters(pos + 24), + returnType: deserializeBoxTSTypeAnnotation(pos + 32), + }; +} + +function deserializeTSConstructorType(pos) { + return { + type: 'TSConstructorType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + abstract: deserializeBool(pos + 8), + typeParameters: deserializeOptionBoxTSTypeParameterDeclaration(pos + 16), + params: deserializeBoxFormalParameters(pos + 24), + returnType: deserializeBoxTSTypeAnnotation(pos + 32), + }; +} + +function deserializeTSMappedType(pos) { + return { + type: 'TSMappedType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeParameter: deserializeBoxTSTypeParameter(pos + 8), + nameType: deserializeOptionTSType(pos + 16), + typeAnnotation: deserializeOptionTSType(pos + 32), + optional: deserializeTSMappedTypeModifierOperator(pos + 48), + readonly: deserializeTSMappedTypeModifierOperator(pos + 49), + }; +} + +function deserializeTSMappedTypeModifierOperator(pos) { + switch (uint8[pos]) { + case 0: + return 'true'; + case 1: + return '+'; + case 2: + return '-'; + case 3: + return 'none'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSMappedTypeModifierOperator`); + } +} + +function deserializeTSTemplateLiteralType(pos) { + return { + type: 'TSTemplateLiteralType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + quasis: deserializeVecTemplateElement(pos + 8), + types: deserializeVecTSType(pos + 40), + }; +} + +function deserializeTSAsExpression(pos) { + return { + type: 'TSAsExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + typeAnnotation: deserializeTSType(pos + 24), + }; +} + +function deserializeTSSatisfiesExpression(pos) { + return { + type: 'TSSatisfiesExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + typeAnnotation: deserializeTSType(pos + 24), + }; +} + +function deserializeTSTypeAssertion(pos) { + return { + type: 'TSTypeAssertion', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + typeAnnotation: deserializeTSType(pos + 24), + }; +} + +function deserializeTSImportEqualsDeclaration(pos) { + return { + type: 'TSImportEqualsDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeBindingIdentifier(pos + 8), + moduleReference: deserializeTSModuleReference(pos + 40), + importKind: deserializeImportOrExportKind(pos + 56), + }; +} + +function deserializeTSModuleReference(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxIdentifierReference(pos + 8); + case 1: + return deserializeBoxTSQualifiedName(pos + 8); + case 2: + return deserializeBoxTSExternalModuleReference(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for TSModuleReference`); + } +} + +function deserializeTSExternalModuleReference(pos) { + return { + type: 'TSExternalModuleReference', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeStringLiteral(pos + 8), + }; +} + +function deserializeTSNonNullExpression(pos) { + return { + type: 'TSNonNullExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + }; +} + +function deserializeDecorator(pos) { + return { + type: 'Decorator', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + }; +} + +function deserializeTSExportAssignment(pos) { + return { + type: 'TSExportAssignment', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + }; +} + +function deserializeTSNamespaceExportDeclaration(pos) { + return { + type: 'TSNamespaceExportDeclaration', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + id: deserializeIdentifierName(pos + 8), + }; +} + +function deserializeTSInstantiationExpression(pos) { + return { + type: 'TSInstantiationExpression', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + expression: deserializeExpression(pos + 8), + typeParameters: deserializeBoxTSTypeParameterInstantiation(pos + 24), + }; +} + +function deserializeImportOrExportKind(pos) { + switch (uint8[pos]) { + case 0: + return 'value'; + case 1: + return 'type'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ImportOrExportKind`); + } +} + +function deserializeJSDocNullableType(pos) { + return { + type: 'JSDocNullableType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeTSType(pos + 8), + postfix: deserializeBool(pos + 24), + }; +} + +function deserializeJSDocNonNullableType(pos) { + return { + type: 'JSDocNonNullableType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + typeAnnotation: deserializeTSType(pos + 8), + postfix: deserializeBool(pos + 24), + }; +} + +function deserializeJSDocUnknownType(pos) { + return { + type: 'JSDocUnknownType', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeCommentKind(pos) { + switch (uint8[pos]) { + case 0: + return 'Line'; + case 1: + return 'Block'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for CommentKind`); + } +} + +function deserializeComment(pos) { + const type = deserializeCommentKind(pos + 12), + start = deserializeU32(pos), + end = deserializeU32(pos + 4); + const endCut = type === 'Line' ? 0 : 2; + return { + type, + value: sourceText.slice(start + 2, end - endCut), + start, + end, + }; +} + +function deserializeNameSpan(pos) { + return { + value: deserializeStr(pos), + start: deserializeU32(pos + 16), + end: deserializeU32(pos + 20), + }; +} + +function deserializeImportEntry(pos) { + return { + importName: deserializeImportImportName(pos + 32), + localName: deserializeNameSpan(pos + 64), + isType: deserializeBool(pos + 88), + }; +} + +function deserializeImportImportName(pos) { + switch (uint8[pos]) { + case 0: + var nameSpan = deserializeNameSpan(pos + 8); + return { kind: 'Name', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end }; + case 1: + return { kind: 'NamespaceObject', name: null, start: null, end: null }; + case 2: + var span = deserializeSpan(pos + 8); + return { kind: 'Default', name: null, start: span.start, end: span.end }; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ImportImportName`); + } +} + +function deserializeExportEntry(pos) { + return { + start: deserializeU32(pos + 8), + end: deserializeU32(pos + 12), + moduleRequest: deserializeOptionNameSpan(pos + 16), + importName: deserializeExportImportName(pos + 40), + exportName: deserializeExportExportName(pos + 72), + localName: deserializeExportLocalName(pos + 104), + }; +} + +function deserializeExportImportName(pos) { + switch (uint8[pos]) { + case 0: + var nameSpan = deserializeNameSpan(pos + 8); + return { kind: 'Name', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end }; + case 1: + return { kind: 'All', name: null, start: null, end: null }; + case 2: + return { kind: 'AllButDefault', name: null, start: null, end: null }; + case 3: + return { kind: 'None', name: null, start: null, end: null }; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ExportImportName`); + } +} + +function deserializeExportExportName(pos) { + switch (uint8[pos]) { + case 0: + var nameSpan = deserializeNameSpan(pos + 8); + return { kind: 'Name', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end }; + case 1: + var span = deserializeSpan(pos + 8); + return { kind: 'Default', name: null, start: span.start, end: span.end }; + case 2: + return { kind: 'None', name: null, start: null, end: null }; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ExportExportName`); + } +} + +function deserializeExportLocalName(pos) { + switch (uint8[pos]) { + case 0: + var nameSpan = deserializeNameSpan(pos + 8); + return { kind: 'Name', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end }; + case 1: + var nameSpan = deserializeNameSpan(pos + 8); + return { kind: 'Default', name: nameSpan.value, start: nameSpan.start, end: nameSpan.end }; + case 2: + return { kind: 'None', name: null, start: null, end: null }; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ExportLocalName`); + } +} + +function deserializeDynamicImport(pos) { + return { + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + moduleRequest: deserializeSpan(pos + 8), + }; +} + +function deserializeAssignmentOperator(pos) { + switch (uint8[pos]) { + case 0: + return '='; + case 1: + return '+='; + case 2: + return '-='; + case 3: + return '*='; + case 4: + return '/='; + case 5: + return '%='; + case 6: + return '**='; + case 7: + return '<<='; + case 8: + return '>>='; + case 9: + return '>>>='; + case 10: + return '|='; + case 11: + return '^='; + case 12: + return '&='; + case 13: + return '||='; + case 14: + return '&&='; + case 15: + return '??='; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for AssignmentOperator`); + } +} + +function deserializeBinaryOperator(pos) { + switch (uint8[pos]) { + case 0: + return '=='; + case 1: + return '!='; + case 2: + return '==='; + case 3: + return '!=='; + case 4: + return '<'; + case 5: + return '<='; + case 6: + return '>'; + case 7: + return '>='; + case 8: + return '+'; + case 9: + return '-'; + case 10: + return '*'; + case 11: + return '/'; + case 12: + return '%'; + case 13: + return '**'; + case 14: + return '<<'; + case 15: + return '>>'; + case 16: + return '>>>'; + case 17: + return '|'; + case 18: + return '^'; + case 19: + return '&'; + case 20: + return 'in'; + case 21: + return 'instanceof'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for BinaryOperator`); + } +} + +function deserializeLogicalOperator(pos) { + switch (uint8[pos]) { + case 0: + return '||'; + case 1: + return '&&'; + case 2: + return '??'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for LogicalOperator`); + } +} + +function deserializeUnaryOperator(pos) { + switch (uint8[pos]) { + case 0: + return '+'; + case 1: + return '-'; + case 2: + return '!'; + case 3: + return '~'; + case 4: + return 'typeof'; + case 5: + return 'void'; + case 6: + return 'delete'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for UnaryOperator`); + } +} + +function deserializeUpdateOperator(pos) { + switch (uint8[pos]) { + case 0: + return '++'; + case 1: + return '--'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for UpdateOperator`); + } +} + +function deserializeSpan(pos) { + return { + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeSourceType(pos) { + return { + sourceType: deserializeModuleKind(pos + 1), + }; +} + +function deserializeModuleKind(pos) { + switch (uint8[pos]) { + case 0: + return 'script'; + case 1: + return 'module'; + case 2: + return 'unambiguous'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ModuleKind`); + } +} + +function deserializePattern(pos) { + return { + type: 'Pattern', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeDisjunction(pos + 8), + }; +} + +function deserializeDisjunction(pos) { + return { + type: 'Disjunction', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeVecAlternative(pos + 8), + }; +} + +function deserializeAlternative(pos) { + return { + type: 'Alternative', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + body: deserializeVecTerm(pos + 8), + }; +} + +function deserializeTerm(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxBoundaryAssertion(pos + 8); + case 1: + return deserializeBoxLookAroundAssertion(pos + 8); + case 2: + return deserializeBoxQuantifier(pos + 8); + case 3: + return deserializeBoxCharacter(pos + 8); + case 4: + return deserializeDot(pos + 8); + case 5: + return deserializeBoxCharacterClassEscape(pos + 8); + case 6: + return deserializeBoxUnicodePropertyEscape(pos + 8); + case 7: + return deserializeBoxCharacterClass(pos + 8); + case 8: + return deserializeBoxCapturingGroup(pos + 8); + case 9: + return deserializeBoxIgnoreGroup(pos + 8); + case 10: + return deserializeBoxIndexedReference(pos + 8); + case 11: + return deserializeBoxNamedReference(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for Term`); + } +} + +function deserializeBoundaryAssertion(pos) { + return { + type: 'BoundaryAssertion', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + kind: deserializeBoundaryAssertionKind(pos + 8), + }; +} + +function deserializeBoundaryAssertionKind(pos) { + switch (uint8[pos]) { + case 0: + return 'start'; + case 1: + return 'end'; + case 2: + return 'boundary'; + case 3: + return 'negativeBoundary'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for BoundaryAssertionKind`); + } +} + +function deserializeLookAroundAssertion(pos) { + return { + type: 'LookAroundAssertion', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + kind: deserializeLookAroundAssertionKind(pos + 8), + body: deserializeDisjunction(pos + 16), + }; +} + +function deserializeLookAroundAssertionKind(pos) { + switch (uint8[pos]) { + case 0: + return 'lookahead'; + case 1: + return 'negativeLookahead'; + case 2: + return 'lookbehind'; + case 3: + return 'negativeLookbehind'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for LookAroundAssertionKind`); + } +} + +function deserializeQuantifier(pos) { + return { + type: 'Quantifier', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + min: deserializeU64(pos + 8), + max: deserializeOptionU64(pos + 16), + greedy: deserializeBool(pos + 32), + body: deserializeTerm(pos + 40), + }; +} + +function deserializeCharacter(pos) { + return { + type: 'Character', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + kind: deserializeCharacterKind(pos + 8), + value: deserializeU32(pos + 12), + }; +} + +function deserializeCharacterKind(pos) { + switch (uint8[pos]) { + case 0: + return 'controlLetter'; + case 1: + return 'hexadecimalEscape'; + case 2: + return 'identifier'; + case 3: + return 'null'; + case 4: + return 'octal1'; + case 5: + return 'octal2'; + case 6: + return 'octal3'; + case 7: + return 'singleEscape'; + case 8: + return 'symbol'; + case 9: + return 'unicodeEscape'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for CharacterKind`); + } +} + +function deserializeCharacterClassEscape(pos) { + return { + type: 'CharacterClassEscape', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + kind: deserializeCharacterClassEscapeKind(pos + 8), + }; +} + +function deserializeCharacterClassEscapeKind(pos) { + switch (uint8[pos]) { + case 0: + return 'd'; + case 1: + return 'negativeD'; + case 2: + return 's'; + case 3: + return 'negativeS'; + case 4: + return 'w'; + case 5: + return 'negativeW'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for CharacterClassEscapeKind`); + } +} + +function deserializeUnicodePropertyEscape(pos) { + return { + type: 'UnicodePropertyEscape', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + negative: deserializeBool(pos + 8), + strings: deserializeBool(pos + 9), + name: deserializeStr(pos + 16), + value: deserializeOptionStr(pos + 32), + }; +} + +function deserializeDot(pos) { + return { + type: 'Dot', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + }; +} + +function deserializeCharacterClass(pos) { + return { + type: 'CharacterClass', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + negative: deserializeBool(pos + 8), + strings: deserializeBool(pos + 9), + kind: deserializeCharacterClassContentsKind(pos + 10), + body: deserializeVecCharacterClassContents(pos + 16), + }; +} + +function deserializeCharacterClassContentsKind(pos) { + switch (uint8[pos]) { + case 0: + return 'union'; + case 1: + return 'intersection'; + case 2: + return 'subtraction'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for CharacterClassContentsKind`); + } +} + +function deserializeCharacterClassContents(pos) { + switch (uint8[pos]) { + case 0: + return deserializeBoxCharacterClassRange(pos + 8); + case 1: + return deserializeBoxCharacterClassEscape(pos + 8); + case 2: + return deserializeBoxUnicodePropertyEscape(pos + 8); + case 3: + return deserializeBoxCharacter(pos + 8); + case 4: + return deserializeBoxCharacterClass(pos + 8); + case 5: + return deserializeBoxClassStringDisjunction(pos + 8); + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for CharacterClassContents`); + } +} + +function deserializeCharacterClassRange(pos) { + return { + type: 'CharacterClassRange', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + min: deserializeCharacter(pos + 8), + max: deserializeCharacter(pos + 24), + }; +} + +function deserializeClassStringDisjunction(pos) { + return { + type: 'ClassStringDisjunction', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + strings: deserializeBool(pos + 8), + body: deserializeVecClassString(pos + 16), + }; +} + +function deserializeClassString(pos) { + return { + type: 'ClassString', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + strings: deserializeBool(pos + 8), + body: deserializeVecCharacter(pos + 16), + }; +} + +function deserializeCapturingGroup(pos) { + return { + type: 'CapturingGroup', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeOptionStr(pos + 8), + body: deserializeDisjunction(pos + 24), + }; +} + +function deserializeIgnoreGroup(pos) { + return { + type: 'IgnoreGroup', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + modifiers: deserializeOptionModifiers(pos + 8), + body: deserializeDisjunction(pos + 24), + }; +} + +function deserializeModifiers(pos) { + return { + type: 'Modifiers', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + enabling: deserializeOptionModifier(pos + 8), + disabling: deserializeOptionModifier(pos + 11), + }; +} + +function deserializeModifier(pos) { + return { + type: 'Modifier', + ignoreCase: deserializeBool(pos), + multiline: deserializeBool(pos + 1), + sticky: deserializeBool(pos + 2), + }; +} + +function deserializeIndexedReference(pos) { + return { + type: 'IndexedReference', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + index: deserializeU32(pos + 8), + }; +} + +function deserializeNamedReference(pos) { + return { + type: 'NamedReference', + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + name: deserializeStr(pos + 8), + }; +} + +function deserializeRawTransferData(pos) { + return { + program: deserializeProgram(pos), + comments: deserializeVecComment(pos + 160), + module: deserializeEcmaScriptModule(pos + 192), + errors: deserializeVecError(pos + 328), + }; +} + +function deserializeError(pos) { + return { + severity: deserializeErrorSeverity(pos), + message: deserializeStr(pos + 8), + labels: deserializeVecErrorLabel(pos + 24), + helpMessage: deserializeOptionStr(pos + 56), + }; +} + +function deserializeErrorSeverity(pos) { + switch (uint8[pos]) { + case 0: + return 'Error'; + case 1: + return 'Warning'; + case 2: + return 'Advice'; + default: + throw new Error(`Unexpected discriminant ${uint8[pos]} for ErrorSeverity`); + } +} + +function deserializeErrorLabel(pos) { + return { + message: deserializeOptionStr(pos), + start: deserializeU32(pos + 16), + end: deserializeU32(pos + 20), + }; +} + +function deserializeEcmaScriptModule(pos) { + return { + hasModuleSyntax: deserializeBool(pos), + staticImports: deserializeVecStaticImport(pos + 8), + staticExports: deserializeVecStaticExport(pos + 40), + dynamicImports: deserializeVecDynamicImport(pos + 72), + importMetas: deserializeVecSpan(pos + 104), + }; +} + +function deserializeStaticImport(pos) { + return { + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + moduleRequest: deserializeNameSpan(pos + 8), + entries: deserializeVecImportEntry(pos + 32), + }; +} + +function deserializeStaticExport(pos) { + return { + start: deserializeU32(pos), + end: deserializeU32(pos + 4), + entries: deserializeVecExportEntry(pos + 8), + }; +} + +function deserializeStr(pos) { + const pos32 = pos >> 2, + len = uint32[pos32 + 2]; + if (len === 0) return ''; + + pos = uint32[pos32]; + if (sourceIsAscii && pos < sourceLen) return sourceText.substr(pos, len); + + // Longer strings use `TextDecoder` + // TODO: Find best switch-over point + const end = pos + len; + if (len > 50) return decodeStr(uint8.subarray(pos, end)); + + // Shorter strings decode by hand to avoid native call + let out = '', + c; + do { + c = uint8[pos++]; + if (c < 0x80) { + out += fromCodePoint(c); + } else { + out += decodeStr(uint8.subarray(pos - 1, end)); + break; + } + } while (pos < end); + + return out; +} + +function deserializeVecComment(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeComment(pos)); + pos += 24; + } + return arr; +} + +function deserializeOptionHashbang(pos) { + if (uint32[(pos + 8) >> 2] === 0 && uint32[(pos + 12) >> 2] === 0) return null; + return deserializeHashbang(pos); +} + +function deserializeVecDirective(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeDirective(pos)); + pos += 64; + } + return arr; +} + +function deserializeVecStatement(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeStatement(pos)); + pos += 16; + } + return arr; +} + +function deserializeOptionScopeId(pos) { + if (uint32[pos >> 2] === 0) return null; + return deserializeScopeId(pos); +} + +function deserializeBoxBooleanLiteral(pos) { + return deserializeBooleanLiteral(uint32[pos >> 2]); +} + +function deserializeBoxNullLiteral(pos) { + return deserializeNullLiteral(uint32[pos >> 2]); +} + +function deserializeBoxNumericLiteral(pos) { + return deserializeNumericLiteral(uint32[pos >> 2]); +} + +function deserializeBoxBigIntLiteral(pos) { + return deserializeBigIntLiteral(uint32[pos >> 2]); +} + +function deserializeBoxRegExpLiteral(pos) { + return deserializeRegExpLiteral(uint32[pos >> 2]); +} + +function deserializeBoxStringLiteral(pos) { + return deserializeStringLiteral(uint32[pos >> 2]); +} + +function deserializeBoxTemplateLiteral(pos) { + return deserializeTemplateLiteral(uint32[pos >> 2]); +} + +function deserializeBoxIdentifierReference(pos) { + return deserializeIdentifierReference(uint32[pos >> 2]); +} + +function deserializeBoxMetaProperty(pos) { + return deserializeMetaProperty(uint32[pos >> 2]); +} + +function deserializeBoxSuper(pos) { + return deserializeSuper(uint32[pos >> 2]); +} + +function deserializeBoxArrayExpression(pos) { + return deserializeArrayExpression(uint32[pos >> 2]); +} + +function deserializeBoxArrowFunctionExpression(pos) { + return deserializeArrowFunctionExpression(uint32[pos >> 2]); +} + +function deserializeBoxAssignmentExpression(pos) { + return deserializeAssignmentExpression(uint32[pos >> 2]); +} + +function deserializeBoxAwaitExpression(pos) { + return deserializeAwaitExpression(uint32[pos >> 2]); +} + +function deserializeBoxBinaryExpression(pos) { + return deserializeBinaryExpression(uint32[pos >> 2]); +} + +function deserializeBoxCallExpression(pos) { + return deserializeCallExpression(uint32[pos >> 2]); +} + +function deserializeBoxChainExpression(pos) { + return deserializeChainExpression(uint32[pos >> 2]); +} + +function deserializeBoxClass(pos) { + return deserializeClass(uint32[pos >> 2]); +} + +function deserializeBoxConditionalExpression(pos) { + return deserializeConditionalExpression(uint32[pos >> 2]); +} + +function deserializeBoxFunction(pos) { + return deserializeFunction(uint32[pos >> 2]); +} + +function deserializeBoxImportExpression(pos) { + return deserializeImportExpression(uint32[pos >> 2]); +} + +function deserializeBoxLogicalExpression(pos) { + return deserializeLogicalExpression(uint32[pos >> 2]); +} + +function deserializeBoxNewExpression(pos) { + return deserializeNewExpression(uint32[pos >> 2]); +} + +function deserializeBoxObjectExpression(pos) { + return deserializeObjectExpression(uint32[pos >> 2]); +} + +function deserializeBoxParenthesizedExpression(pos) { + return deserializeParenthesizedExpression(uint32[pos >> 2]); +} + +function deserializeBoxSequenceExpression(pos) { + return deserializeSequenceExpression(uint32[pos >> 2]); +} + +function deserializeBoxTaggedTemplateExpression(pos) { + return deserializeTaggedTemplateExpression(uint32[pos >> 2]); +} + +function deserializeBoxThisExpression(pos) { + return deserializeThisExpression(uint32[pos >> 2]); +} + +function deserializeBoxUnaryExpression(pos) { + return deserializeUnaryExpression(uint32[pos >> 2]); +} + +function deserializeBoxUpdateExpression(pos) { + return deserializeUpdateExpression(uint32[pos >> 2]); +} + +function deserializeBoxYieldExpression(pos) { + return deserializeYieldExpression(uint32[pos >> 2]); +} + +function deserializeBoxPrivateInExpression(pos) { + return deserializePrivateInExpression(uint32[pos >> 2]); +} + +function deserializeBoxJSXElement(pos) { + return deserializeJSXElement(uint32[pos >> 2]); +} + +function deserializeBoxJSXFragment(pos) { + return deserializeJSXFragment(uint32[pos >> 2]); +} + +function deserializeBoxTSAsExpression(pos) { + return deserializeTSAsExpression(uint32[pos >> 2]); +} + +function deserializeBoxTSSatisfiesExpression(pos) { + return deserializeTSSatisfiesExpression(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeAssertion(pos) { + return deserializeTSTypeAssertion(uint32[pos >> 2]); +} + +function deserializeBoxTSNonNullExpression(pos) { + return deserializeTSNonNullExpression(uint32[pos >> 2]); +} + +function deserializeBoxTSInstantiationExpression(pos) { + return deserializeTSInstantiationExpression(uint32[pos >> 2]); +} + +function deserializeBoxV8IntrinsicExpression(pos) { + return deserializeV8IntrinsicExpression(uint32[pos >> 2]); +} + +function deserializeOptionReferenceId(pos) { + if (uint32[pos >> 2] === 0) return null; + return deserializeReferenceId(pos); +} + +function deserializeOptionSymbolId(pos) { + if (uint32[pos >> 2] === 0) return null; + return deserializeSymbolId(pos); +} + +function deserializeVecArrayExpressionElement(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeArrayExpressionElement(pos)); + pos += 16; + } + return arr; +} + +function deserializeOptionSpan(pos) { + if (uint8[pos] === 0) return null; + return deserializeSpan(pos + 8); +} + +function deserializeBoxSpreadElement(pos) { + return deserializeSpreadElement(uint32[pos >> 2]); +} + +function deserializeVecObjectPropertyKind(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeObjectPropertyKind(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxObjectProperty(pos) { + return deserializeObjectProperty(uint32[pos >> 2]); +} + +function deserializeBool(pos) { + return uint8[pos] === 1; +} + +function deserializeBoxIdentifierName(pos) { + return deserializeIdentifierName(uint32[pos >> 2]); +} + +function deserializeBoxPrivateIdentifier(pos) { + return deserializePrivateIdentifier(uint32[pos >> 2]); +} + +function deserializeVecTemplateElement(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTemplateElement(pos)); + pos += 48; + } + return arr; +} + +function deserializeVecExpression(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeExpression(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxTSTypeParameterInstantiation(pos) { + return deserializeTSTypeParameterInstantiation(uint32[pos >> 2]); +} + +function deserializeOptionBoxTSTypeParameterInstantiation(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxTSTypeParameterInstantiation(pos); +} + +function deserializeOptionStr(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeStr(pos); +} + +function deserializeBoxComputedMemberExpression(pos) { + return deserializeComputedMemberExpression(uint32[pos >> 2]); +} + +function deserializeBoxStaticMemberExpression(pos) { + return deserializeStaticMemberExpression(uint32[pos >> 2]); +} + +function deserializeBoxPrivateFieldExpression(pos) { + return deserializePrivateFieldExpression(uint32[pos >> 2]); +} + +function deserializeVecArgument(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeArgument(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxArrayAssignmentTarget(pos) { + return deserializeArrayAssignmentTarget(uint32[pos >> 2]); +} + +function deserializeBoxObjectAssignmentTarget(pos) { + return deserializeObjectAssignmentTarget(uint32[pos >> 2]); +} + +function deserializeOptionAssignmentTargetMaybeDefault(pos) { + if (uint8[pos] === 51) return null; + return deserializeAssignmentTargetMaybeDefault(pos); +} + +function deserializeVecOptionAssignmentTargetMaybeDefault(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeOptionAssignmentTargetMaybeDefault(pos)); + pos += 16; + } + return arr; +} + +function deserializeOptionAssignmentTargetRest(pos) { + if (uint8[pos + 8] === 51) return null; + return deserializeAssignmentTargetRest(pos); +} + +function deserializeVecAssignmentTargetProperty(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeAssignmentTargetProperty(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxAssignmentTargetWithDefault(pos) { + return deserializeAssignmentTargetWithDefault(uint32[pos >> 2]); +} + +function deserializeBoxAssignmentTargetPropertyIdentifier(pos) { + return deserializeAssignmentTargetPropertyIdentifier(uint32[pos >> 2]); +} + +function deserializeBoxAssignmentTargetPropertyProperty(pos) { + return deserializeAssignmentTargetPropertyProperty(uint32[pos >> 2]); +} + +function deserializeOptionExpression(pos) { + if (uint8[pos] === 51) return null; + return deserializeExpression(pos); +} + +function deserializeBoxBlockStatement(pos) { + return deserializeBlockStatement(uint32[pos >> 2]); +} + +function deserializeBoxBreakStatement(pos) { + return deserializeBreakStatement(uint32[pos >> 2]); +} + +function deserializeBoxContinueStatement(pos) { + return deserializeContinueStatement(uint32[pos >> 2]); +} + +function deserializeBoxDebuggerStatement(pos) { + return deserializeDebuggerStatement(uint32[pos >> 2]); +} + +function deserializeBoxDoWhileStatement(pos) { + return deserializeDoWhileStatement(uint32[pos >> 2]); +} + +function deserializeBoxEmptyStatement(pos) { + return deserializeEmptyStatement(uint32[pos >> 2]); +} + +function deserializeBoxExpressionStatement(pos) { + return deserializeExpressionStatement(uint32[pos >> 2]); +} + +function deserializeBoxForInStatement(pos) { + return deserializeForInStatement(uint32[pos >> 2]); +} + +function deserializeBoxForOfStatement(pos) { + return deserializeForOfStatement(uint32[pos >> 2]); +} + +function deserializeBoxForStatement(pos) { + return deserializeForStatement(uint32[pos >> 2]); +} + +function deserializeBoxIfStatement(pos) { + return deserializeIfStatement(uint32[pos >> 2]); +} + +function deserializeBoxLabeledStatement(pos) { + return deserializeLabeledStatement(uint32[pos >> 2]); +} + +function deserializeBoxReturnStatement(pos) { + return deserializeReturnStatement(uint32[pos >> 2]); +} + +function deserializeBoxSwitchStatement(pos) { + return deserializeSwitchStatement(uint32[pos >> 2]); +} + +function deserializeBoxThrowStatement(pos) { + return deserializeThrowStatement(uint32[pos >> 2]); +} + +function deserializeBoxTryStatement(pos) { + return deserializeTryStatement(uint32[pos >> 2]); +} + +function deserializeBoxWhileStatement(pos) { + return deserializeWhileStatement(uint32[pos >> 2]); +} + +function deserializeBoxWithStatement(pos) { + return deserializeWithStatement(uint32[pos >> 2]); +} + +function deserializeBoxVariableDeclaration(pos) { + return deserializeVariableDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeAliasDeclaration(pos) { + return deserializeTSTypeAliasDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSInterfaceDeclaration(pos) { + return deserializeTSInterfaceDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSEnumDeclaration(pos) { + return deserializeTSEnumDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSModuleDeclaration(pos) { + return deserializeTSModuleDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSImportEqualsDeclaration(pos) { + return deserializeTSImportEqualsDeclaration(uint32[pos >> 2]); +} + +function deserializeVecVariableDeclarator(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeVariableDeclarator(pos)); + pos += 72; + } + return arr; +} + +function deserializeOptionStatement(pos) { + if (uint8[pos] === 70) return null; + return deserializeStatement(pos); +} + +function deserializeOptionForStatementInit(pos) { + if (uint8[pos] === 65) return null; + return deserializeForStatementInit(pos); +} + +function deserializeOptionLabelIdentifier(pos) { + if (uint32[(pos + 8) >> 2] === 0 && uint32[(pos + 12) >> 2] === 0) return null; + return deserializeLabelIdentifier(pos); +} + +function deserializeVecSwitchCase(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeSwitchCase(pos)); + pos += 56; + } + return arr; +} + +function deserializeBoxCatchClause(pos) { + return deserializeCatchClause(uint32[pos >> 2]); +} + +function deserializeOptionBoxCatchClause(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxCatchClause(pos); +} + +function deserializeOptionBoxBlockStatement(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxBlockStatement(pos); +} + +function deserializeOptionCatchParameter(pos) { + if (uint8[pos + 32] === 2) return null; + return deserializeCatchParameter(pos); +} + +function deserializeBoxTSTypeAnnotation(pos) { + return deserializeTSTypeAnnotation(uint32[pos >> 2]); +} + +function deserializeOptionBoxTSTypeAnnotation(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxTSTypeAnnotation(pos); +} + +function deserializeBoxBindingIdentifier(pos) { + return deserializeBindingIdentifier(uint32[pos >> 2]); +} + +function deserializeBoxObjectPattern(pos) { + return deserializeObjectPattern(uint32[pos >> 2]); +} + +function deserializeBoxArrayPattern(pos) { + return deserializeArrayPattern(uint32[pos >> 2]); +} + +function deserializeBoxAssignmentPattern(pos) { + return deserializeAssignmentPattern(uint32[pos >> 2]); +} + +function deserializeVecBindingProperty(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeBindingProperty(pos)); + pos += 64; + } + return arr; +} + +function deserializeBoxBindingRestElement(pos) { + return deserializeBindingRestElement(uint32[pos >> 2]); +} + +function deserializeOptionBoxBindingRestElement(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxBindingRestElement(pos); +} + +function deserializeOptionBindingPattern(pos) { + if (uint8[pos + 24] === 2) return null; + return deserializeBindingPattern(pos); +} + +function deserializeVecOptionBindingPattern(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeOptionBindingPattern(pos)); + pos += 32; + } + return arr; +} + +function deserializeOptionBindingIdentifier(pos) { + if (uint32[(pos + 8) >> 2] === 0 && uint32[(pos + 12) >> 2] === 0) return null; + return deserializeBindingIdentifier(pos); +} + +function deserializeBoxTSTypeParameterDeclaration(pos) { + return deserializeTSTypeParameterDeclaration(uint32[pos >> 2]); +} + +function deserializeOptionBoxTSTypeParameterDeclaration(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxTSTypeParameterDeclaration(pos); +} + +function deserializeBoxTSThisParameter(pos) { + return deserializeTSThisParameter(uint32[pos >> 2]); +} + +function deserializeOptionBoxTSThisParameter(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxTSThisParameter(pos); +} + +function deserializeBoxFormalParameters(pos) { + return deserializeFormalParameters(uint32[pos >> 2]); +} + +function deserializeBoxFunctionBody(pos) { + return deserializeFunctionBody(uint32[pos >> 2]); +} + +function deserializeOptionBoxFunctionBody(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxFunctionBody(pos); +} + +function deserializeVecFormalParameter(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeFormalParameter(pos)); + pos += 80; + } + return arr; +} + +function deserializeVecDecorator(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeDecorator(pos)); + pos += 24; + } + return arr; +} + +function deserializeOptionTSAccessibility(pos) { + if (uint8[pos] === 3) return null; + return deserializeTSAccessibility(pos); +} + +function deserializeVecTSClassImplements(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSClassImplements(pos)); + pos += 32; + } + return arr; +} + +function deserializeOptionVecTSClassImplements(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeVecTSClassImplements(pos); +} + +function deserializeBoxClassBody(pos) { + return deserializeClassBody(uint32[pos >> 2]); +} + +function deserializeVecClassElement(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeClassElement(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxStaticBlock(pos) { + return deserializeStaticBlock(uint32[pos >> 2]); +} + +function deserializeBoxMethodDefinition(pos) { + return deserializeMethodDefinition(uint32[pos >> 2]); +} + +function deserializeBoxPropertyDefinition(pos) { + return deserializePropertyDefinition(uint32[pos >> 2]); +} + +function deserializeBoxAccessorProperty(pos) { + return deserializeAccessorProperty(uint32[pos >> 2]); +} + +function deserializeBoxTSIndexSignature(pos) { + return deserializeTSIndexSignature(uint32[pos >> 2]); +} + +function deserializeBoxImportDeclaration(pos) { + return deserializeImportDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxExportAllDeclaration(pos) { + return deserializeExportAllDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxExportDefaultDeclaration(pos) { + return deserializeExportDefaultDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxExportNamedDeclaration(pos) { + return deserializeExportNamedDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSExportAssignment(pos) { + return deserializeTSExportAssignment(uint32[pos >> 2]); +} + +function deserializeBoxTSNamespaceExportDeclaration(pos) { + return deserializeTSNamespaceExportDeclaration(uint32[pos >> 2]); +} + +function deserializeOptionImportPhase(pos) { + if (uint8[pos] === 2) return null; + return deserializeImportPhase(pos); +} + +function deserializeVecImportDeclarationSpecifier(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeImportDeclarationSpecifier(pos)); + pos += 16; + } + return arr; +} + +function deserializeOptionVecImportDeclarationSpecifier(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeVecImportDeclarationSpecifier(pos); +} + +function deserializeBoxWithClause(pos) { + return deserializeWithClause(uint32[pos >> 2]); +} + +function deserializeOptionBoxWithClause(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxWithClause(pos); +} + +function deserializeBoxImportSpecifier(pos) { + return deserializeImportSpecifier(uint32[pos >> 2]); +} + +function deserializeBoxImportDefaultSpecifier(pos) { + return deserializeImportDefaultSpecifier(uint32[pos >> 2]); +} + +function deserializeBoxImportNamespaceSpecifier(pos) { + return deserializeImportNamespaceSpecifier(uint32[pos >> 2]); +} + +function deserializeVecImportAttribute(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeImportAttribute(pos)); + pos += 96; + } + return arr; +} + +function deserializeOptionDeclaration(pos) { + if (uint8[pos] === 31) return null; + return deserializeDeclaration(pos); +} + +function deserializeVecExportSpecifier(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeExportSpecifier(pos)); + pos += 112; + } + return arr; +} + +function deserializeOptionStringLiteral(pos) { + if (uint32[(pos + 8) >> 2] === 0 && uint32[(pos + 12) >> 2] === 0) return null; + return deserializeStringLiteral(pos); +} + +function deserializeOptionModuleExportName(pos) { + if (uint8[pos] === 3) return null; + return deserializeModuleExportName(pos); +} + +function deserializeF64(pos) { + return float64[pos >> 3]; +} + +function deserializeBoxPattern(pos) { + return deserializePattern(uint32[pos >> 2]); +} + +function deserializeU8(pos) { + return uint8[pos]; +} + +function deserializeBoxJSXOpeningElement(pos) { + return deserializeJSXOpeningElement(uint32[pos >> 2]); +} + +function deserializeBoxJSXClosingElement(pos) { + return deserializeJSXClosingElement(uint32[pos >> 2]); +} + +function deserializeOptionBoxJSXClosingElement(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxJSXClosingElement(pos); +} + +function deserializeVecJSXChild(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeJSXChild(pos)); + pos += 16; + } + return arr; +} + +function deserializeVecJSXAttributeItem(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeJSXAttributeItem(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxJSXIdentifier(pos) { + return deserializeJSXIdentifier(uint32[pos >> 2]); +} + +function deserializeBoxJSXNamespacedName(pos) { + return deserializeJSXNamespacedName(uint32[pos >> 2]); +} + +function deserializeBoxJSXMemberExpression(pos) { + return deserializeJSXMemberExpression(uint32[pos >> 2]); +} + +function deserializeBoxJSXAttribute(pos) { + return deserializeJSXAttribute(uint32[pos >> 2]); +} + +function deserializeBoxJSXSpreadAttribute(pos) { + return deserializeJSXSpreadAttribute(uint32[pos >> 2]); +} + +function deserializeOptionJSXAttributeValue(pos) { + if (uint8[pos] === 4) return null; + return deserializeJSXAttributeValue(pos); +} + +function deserializeBoxJSXExpressionContainer(pos) { + return deserializeJSXExpressionContainer(uint32[pos >> 2]); +} + +function deserializeBoxJSXText(pos) { + return deserializeJSXText(uint32[pos >> 2]); +} + +function deserializeBoxJSXSpreadChild(pos) { + return deserializeJSXSpreadChild(uint32[pos >> 2]); +} + +function deserializeVecTSEnumMember(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSEnumMember(pos)); + pos += 40; + } + return arr; +} + +function deserializeBoxTSAnyKeyword(pos) { + return deserializeTSAnyKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSBigIntKeyword(pos) { + return deserializeTSBigIntKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSBooleanKeyword(pos) { + return deserializeTSBooleanKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSIntrinsicKeyword(pos) { + return deserializeTSIntrinsicKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSNeverKeyword(pos) { + return deserializeTSNeverKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSNullKeyword(pos) { + return deserializeTSNullKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSNumberKeyword(pos) { + return deserializeTSNumberKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSObjectKeyword(pos) { + return deserializeTSObjectKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSStringKeyword(pos) { + return deserializeTSStringKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSSymbolKeyword(pos) { + return deserializeTSSymbolKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSUndefinedKeyword(pos) { + return deserializeTSUndefinedKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSUnknownKeyword(pos) { + return deserializeTSUnknownKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSVoidKeyword(pos) { + return deserializeTSVoidKeyword(uint32[pos >> 2]); +} + +function deserializeBoxTSArrayType(pos) { + return deserializeTSArrayType(uint32[pos >> 2]); +} + +function deserializeBoxTSConditionalType(pos) { + return deserializeTSConditionalType(uint32[pos >> 2]); +} + +function deserializeBoxTSConstructorType(pos) { + return deserializeTSConstructorType(uint32[pos >> 2]); +} + +function deserializeBoxTSFunctionType(pos) { + return deserializeTSFunctionType(uint32[pos >> 2]); +} + +function deserializeBoxTSImportType(pos) { + return deserializeTSImportType(uint32[pos >> 2]); +} + +function deserializeBoxTSIndexedAccessType(pos) { + return deserializeTSIndexedAccessType(uint32[pos >> 2]); +} + +function deserializeBoxTSInferType(pos) { + return deserializeTSInferType(uint32[pos >> 2]); +} + +function deserializeBoxTSIntersectionType(pos) { + return deserializeTSIntersectionType(uint32[pos >> 2]); +} + +function deserializeBoxTSLiteralType(pos) { + return deserializeTSLiteralType(uint32[pos >> 2]); +} + +function deserializeBoxTSMappedType(pos) { + return deserializeTSMappedType(uint32[pos >> 2]); +} + +function deserializeBoxTSNamedTupleMember(pos) { + return deserializeTSNamedTupleMember(uint32[pos >> 2]); +} + +function deserializeBoxTSTemplateLiteralType(pos) { + return deserializeTSTemplateLiteralType(uint32[pos >> 2]); +} + +function deserializeBoxTSThisType(pos) { + return deserializeTSThisType(uint32[pos >> 2]); +} + +function deserializeBoxTSTupleType(pos) { + return deserializeTSTupleType(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeLiteral(pos) { + return deserializeTSTypeLiteral(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeOperator(pos) { + return deserializeTSTypeOperator(uint32[pos >> 2]); +} + +function deserializeBoxTSTypePredicate(pos) { + return deserializeTSTypePredicate(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeQuery(pos) { + return deserializeTSTypeQuery(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeReference(pos) { + return deserializeTSTypeReference(uint32[pos >> 2]); +} + +function deserializeBoxTSUnionType(pos) { + return deserializeTSUnionType(uint32[pos >> 2]); +} + +function deserializeBoxTSParenthesizedType(pos) { + return deserializeTSParenthesizedType(uint32[pos >> 2]); +} + +function deserializeBoxJSDocNullableType(pos) { + return deserializeJSDocNullableType(uint32[pos >> 2]); +} + +function deserializeBoxJSDocNonNullableType(pos) { + return deserializeJSDocNonNullableType(uint32[pos >> 2]); +} + +function deserializeBoxJSDocUnknownType(pos) { + return deserializeJSDocUnknownType(uint32[pos >> 2]); +} + +function deserializeVecTSType(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSType(pos)); + pos += 16; + } + return arr; +} + +function deserializeVecTSTupleElement(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSTupleElement(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxTSOptionalType(pos) { + return deserializeTSOptionalType(uint32[pos >> 2]); +} + +function deserializeBoxTSRestType(pos) { + return deserializeTSRestType(uint32[pos >> 2]); +} + +function deserializeBoxTSQualifiedName(pos) { + return deserializeTSQualifiedName(uint32[pos >> 2]); +} + +function deserializeOptionTSType(pos) { + if (uint8[pos] === 38) return null; + return deserializeTSType(pos); +} + +function deserializeVecTSTypeParameter(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSTypeParameter(pos)); + pos += 80; + } + return arr; +} + +function deserializeVecTSInterfaceHeritage(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSInterfaceHeritage(pos)); + pos += 32; + } + return arr; +} + +function deserializeOptionVecTSInterfaceHeritage(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeVecTSInterfaceHeritage(pos); +} + +function deserializeBoxTSInterfaceBody(pos) { + return deserializeTSInterfaceBody(uint32[pos >> 2]); +} + +function deserializeVecTSSignature(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSSignature(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxTSPropertySignature(pos) { + return deserializeTSPropertySignature(uint32[pos >> 2]); +} + +function deserializeBoxTSCallSignatureDeclaration(pos) { + return deserializeTSCallSignatureDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSConstructSignatureDeclaration(pos) { + return deserializeTSConstructSignatureDeclaration(uint32[pos >> 2]); +} + +function deserializeBoxTSMethodSignature(pos) { + return deserializeTSMethodSignature(uint32[pos >> 2]); +} + +function deserializeVecTSIndexSignatureName(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSIndexSignatureName(pos)); + pos += 32; + } + return arr; +} + +function deserializeOptionTSThisParameter(pos) { + if (uint8[pos] === 0) return null; + return deserializeTSThisParameter(pos + 8); +} + +function deserializeOptionTSModuleDeclarationBody(pos) { + if (uint8[pos] === 2) return null; + return deserializeTSModuleDeclarationBody(pos); +} + +function deserializeBoxTSModuleBlock(pos) { + return deserializeTSModuleBlock(uint32[pos >> 2]); +} + +function deserializeBoxTSTypeParameter(pos) { + return deserializeTSTypeParameter(uint32[pos >> 2]); +} + +function deserializeOptionTSTypeName(pos) { + if (uint8[pos] === 2) return null; + return deserializeTSTypeName(pos); +} + +function deserializeBoxTSImportAttributes(pos) { + return deserializeTSImportAttributes(uint32[pos >> 2]); +} + +function deserializeOptionBoxTSImportAttributes(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeBoxTSImportAttributes(pos); +} + +function deserializeVecTSImportAttribute(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTSImportAttribute(pos)); + pos += 72; + } + return arr; +} + +function deserializeBoxTSExternalModuleReference(pos) { + return deserializeTSExternalModuleReference(uint32[pos >> 2]); +} + +function deserializeU32(pos) { + return uint32[pos >> 2]; +} + +function deserializeOptionNameSpan(pos) { + if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null; + return deserializeNameSpan(pos); +} + +function deserializeVecAlternative(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeAlternative(pos)); + pos += 40; + } + return arr; +} + +function deserializeVecTerm(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeTerm(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxBoundaryAssertion(pos) { + return deserializeBoundaryAssertion(uint32[pos >> 2]); +} + +function deserializeBoxLookAroundAssertion(pos) { + return deserializeLookAroundAssertion(uint32[pos >> 2]); +} + +function deserializeBoxQuantifier(pos) { + return deserializeQuantifier(uint32[pos >> 2]); +} + +function deserializeBoxCharacter(pos) { + return deserializeCharacter(uint32[pos >> 2]); +} + +function deserializeBoxCharacterClassEscape(pos) { + return deserializeCharacterClassEscape(uint32[pos >> 2]); +} + +function deserializeBoxUnicodePropertyEscape(pos) { + return deserializeUnicodePropertyEscape(uint32[pos >> 2]); +} + +function deserializeBoxCharacterClass(pos) { + return deserializeCharacterClass(uint32[pos >> 2]); +} + +function deserializeBoxCapturingGroup(pos) { + return deserializeCapturingGroup(uint32[pos >> 2]); +} + +function deserializeBoxIgnoreGroup(pos) { + return deserializeIgnoreGroup(uint32[pos >> 2]); +} + +function deserializeBoxIndexedReference(pos) { + return deserializeIndexedReference(uint32[pos >> 2]); +} + +function deserializeBoxNamedReference(pos) { + return deserializeNamedReference(uint32[pos >> 2]); +} + +function deserializeU64(pos) { + const pos32 = pos >> 2; + return uint32[pos32] + uint32[pos32 + 1] * 4294967296; +} + +function deserializeOptionU64(pos) { + if (uint8[pos] === 0) return null; + return deserializeU64(pos + 8); +} + +function deserializeVecCharacterClassContents(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeCharacterClassContents(pos)); + pos += 16; + } + return arr; +} + +function deserializeBoxCharacterClassRange(pos) { + return deserializeCharacterClassRange(uint32[pos >> 2]); +} + +function deserializeBoxClassStringDisjunction(pos) { + return deserializeClassStringDisjunction(uint32[pos >> 2]); +} + +function deserializeVecClassString(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeClassString(pos)); + pos += 48; + } + return arr; +} + +function deserializeVecCharacter(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeCharacter(pos)); + pos += 16; + } + return arr; +} + +function deserializeOptionModifiers(pos) { + if (uint8[pos + 8] === 3) return null; + return deserializeModifiers(pos); +} + +function deserializeOptionModifier(pos) { + if (uint8[pos] === 2) return null; + return deserializeModifier(pos); +} + +function deserializeVecError(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeError(pos)); + pos += 72; + } + return arr; +} + +function deserializeVecErrorLabel(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeErrorLabel(pos)); + pos += 24; + } + return arr; +} + +function deserializeVecStaticImport(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeStaticImport(pos)); + pos += 64; + } + return arr; +} + +function deserializeVecStaticExport(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeStaticExport(pos)); + pos += 40; + } + return arr; +} + +function deserializeVecDynamicImport(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeDynamicImport(pos)); + pos += 16; + } + return arr; +} + +function deserializeVecSpan(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeSpan(pos)); + pos += 8; + } + return arr; +} + +function deserializeVecImportEntry(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeImportEntry(pos)); + pos += 96; + } + return arr; +} + +function deserializeVecExportEntry(pos) { + const arr = [], + pos32 = pos >> 2, + len = uint32[pos32 + 6]; + pos = uint32[pos32]; + for (let i = 0; i < len; i++) { + arr.push(deserializeExportEntry(pos)); + pos += 144; + } + return arr; +} diff --git a/napi/parser/index.d.ts b/napi/parser/index.d.ts index b8398c5812e21..825a9a8707a90 100644 --- a/napi/parser/index.d.ts +++ b/napi/parser/index.d.ts @@ -100,6 +100,14 @@ export declare const enum ExportLocalNameKind { None = 'None' } +/** + * Get offset within a `Uint8Array` which is aligned on 4 GiB. + * + * Does not check that the offset is within bounds of `buffer`. + * To ensure it always is, provide a `Uint8Array` of at least 4 GiB size. + */ +export declare function getBufferOffset(buffer: Uint8Array): number + export interface ImportName { kind: ImportNameKind name?: string @@ -157,6 +165,34 @@ export interface ParserOptions { /** Parse synchronously. */ export declare function parseSync(filename: string, sourceText: string, options?: ParserOptions | undefined | null): ParseResult +/** + * Parses AST into provided `Uint8Array` buffer. + * + * Source text must be written into the start of the buffer, and its length (in UTF-8 bytes) + * provided as `source_len`. + * + * This function will parse the source, and write the AST into the buffer, starting at the end. + * + * It also writes to the very end of the buffer the offset of `Program` within the buffer. + * + * Caller can deserialize data from the buffer on JS side. + * + * # SAFETY + * + * Caller must ensure: + * * Source text is written into start of the buffer. + * * Source text's UTF-8 byte length is `source_len`. + * * The 1st `source_len` bytes of the buffer comprises a valid UTF-8 string. + * + * If source text is originally a JS string on JS side, and converted to a buffer with + * `Buffer.from(str)` or `new TextEncoder().encode(str)`, this guarantees it's valid UTF-8. + * + * # Panics + * + * Panics if source text is too long, or AST takes more memory than is available in the buffer. + */ +export declare function parseSyncRaw(filename: string, buffer: Uint8Array, sourceLen: number, options?: ParserOptions | undefined | null): void + export declare const enum Severity { Error = 'Error', Warning = 'Warning', diff --git a/napi/parser/index.js b/napi/parser/index.js index c4ac77f7214c7..998d238c5118f 100644 --- a/napi/parser/index.js +++ b/napi/parser/index.js @@ -1,4 +1,5 @@ const bindings = require('./bindings.js'); +const deserialize = require('./deserialize.js'); module.exports.ParseResult = bindings.ParseResult; module.exports.ExportExportNameKind = bindings.ExportExportNameKind; @@ -55,6 +56,77 @@ module.exports.parseAsync = async function parseAsync(...args) { return wrap(await bindings.parseAsync(...args)); }; -module.exports.parseSync = function parseSync(...args) { - return wrap(bindings.parseSync(...args)); +module.exports.parseSync = function parseSync(filename, sourceText, options) { + if (options?.experimentalRawTransfer) { + return parseSyncRaw(filename, sourceText, options); + } + + return wrap(bindings.parseSync(filename, sourceText, options)); }; + +let buffer, encoder; + +function parseSyncRaw(filename, sourceText, options) { + // Delete `experimentalRawTransfer` option + let experimentalRawTransfer; + ({ experimentalRawTransfer, ...options } = options); + + // Create buffer and `TextEncoder` + if (!buffer) { + buffer = createBuffer(); + encoder = new TextEncoder(); + } + + // Write source into start of buffer. + // `TextEncoder` cannot write into a `Uint8Array` larger than 1 GiB, + // so create a view into buffer of this size to write into. + const sourceBuffer = new Uint8Array(buffer.buffer, buffer.byteOffset, ONE_GIB); + const { read, written: sourceByteLen } = encoder.encodeInto(sourceText, sourceBuffer); + if (read !== sourceText.length) { + throw new Error('Failed to write source text into buffer'); + } + + // Parse + bindings.parseSyncRaw(filename, buffer, sourceByteLen, options); + + // Deserialize. + // We cannot lazily deserialize in the getters, because the buffer might be re-used to parse + // another file before the getter is called. + const { program, comments, module, errors } = deserialize(buffer, sourceText, sourceByteLen); + + return { + get program() { + return program; + }, + get module() { + return module; + }, + get comments() { + return comments; + }, + get errors() { + return errors; + }, + }; +} + +const ONE_GIB = 1 << 30, + TWO_GIB = ONE_GIB * 2, + SIX_GIB = ONE_GIB * 6; + +// Create a `Uint8Array` which is 2 GiB in size, with its start aligned on 4 GiB. +// +// Achieve this by creating a 6 GiB `ArrayBuffer`, getting the offset within it that's aligned to 4 GiB, +// chopping off that number of bytes from the start, and shortening to 2 GiB. +// +// It's always possible to obtain a 2 GiB slice aligned on 4 GiB within a 6 GiB buffer, +// no matter how the 6 GiB buffer is aligned. +// +// Note: On systems with virtual memory, this only consumes 6 GiB of *virtual* memory. +// It does not consume physical memory until data is actually written to the `Uint8Array`. +// Physical memory consumed corresponds to the quantity of data actually written. +function createBuffer() { + const arrayBuffer = new ArrayBuffer(SIX_GIB); + const offset = bindings.getBufferOffset(new Uint8Array(arrayBuffer)); + return new Uint8Array(arrayBuffer, offset, TWO_GIB); +} diff --git a/napi/parser/src/generated/assert_layouts.rs b/napi/parser/src/generated/assert_layouts.rs new file mode 100644 index 0000000000000..635b89ed7b907 --- /dev/null +++ b/napi/parser/src/generated/assert_layouts.rs @@ -0,0 +1,99 @@ +// Auto-generated code, DO NOT EDIT DIRECTLY! +// To edit this generated file you have to edit `tasks/ast_tools/src/generators/assert_layouts.rs` + +#![allow(unused_imports)] + +use std::mem::{align_of, offset_of, size_of}; + +use crate::raw_transfer_types::*; + +#[cfg(target_pointer_width = "64")] +const _: () = { + assert!(size_of::() == 360); + assert!(align_of::() == 8); + assert!(offset_of!(RawTransferData, program) == 0); + assert!(offset_of!(RawTransferData, comments) == 160); + assert!(offset_of!(RawTransferData, module) == 192); + assert!(offset_of!(RawTransferData, errors) == 328); + + assert!(size_of::() == 72); + assert!(align_of::() == 8); + assert!(offset_of!(Error, severity) == 0); + assert!(offset_of!(Error, message) == 8); + assert!(offset_of!(Error, labels) == 24); + assert!(offset_of!(Error, help_message) == 56); + + assert!(size_of::() == 1); + assert!(align_of::() == 1); + + assert!(size_of::() == 24); + assert!(align_of::() == 8); + assert!(offset_of!(ErrorLabel, message) == 0); + assert!(offset_of!(ErrorLabel, span) == 16); + + assert!(size_of::() == 136); + assert!(align_of::() == 8); + assert!(offset_of!(EcmaScriptModule, has_module_syntax) == 0); + assert!(offset_of!(EcmaScriptModule, static_imports) == 8); + assert!(offset_of!(EcmaScriptModule, static_exports) == 40); + assert!(offset_of!(EcmaScriptModule, dynamic_imports) == 72); + assert!(offset_of!(EcmaScriptModule, import_metas) == 104); + + assert!(size_of::() == 64); + assert!(align_of::() == 8); + assert!(offset_of!(StaticImport, span) == 0); + assert!(offset_of!(StaticImport, module_request) == 8); + assert!(offset_of!(StaticImport, entries) == 32); + + assert!(size_of::() == 40); + assert!(align_of::() == 8); + assert!(offset_of!(StaticExport, span) == 0); + assert!(offset_of!(StaticExport, entries) == 8); +}; + +#[cfg(target_pointer_width = "32")] +const _: () = { + assert!(size_of::() == 188); + assert!(align_of::() == 4); + assert!(offset_of!(RawTransferData, program) == 0); + assert!(offset_of!(RawTransferData, comments) == 88); + assert!(offset_of!(RawTransferData, module) == 104); + assert!(offset_of!(RawTransferData, errors) == 172); + + assert!(size_of::() == 36); + assert!(align_of::() == 4); + assert!(offset_of!(Error, severity) == 0); + assert!(offset_of!(Error, message) == 4); + assert!(offset_of!(Error, labels) == 12); + assert!(offset_of!(Error, help_message) == 28); + + assert!(size_of::() == 1); + assert!(align_of::() == 1); + + assert!(size_of::() == 16); + assert!(align_of::() == 4); + assert!(offset_of!(ErrorLabel, message) == 0); + assert!(offset_of!(ErrorLabel, span) == 8); + + assert!(size_of::() == 68); + assert!(align_of::() == 4); + assert!(offset_of!(EcmaScriptModule, has_module_syntax) == 0); + assert!(offset_of!(EcmaScriptModule, static_imports) == 4); + assert!(offset_of!(EcmaScriptModule, static_exports) == 20); + assert!(offset_of!(EcmaScriptModule, dynamic_imports) == 36); + assert!(offset_of!(EcmaScriptModule, import_metas) == 52); + + assert!(size_of::() == 40); + assert!(align_of::() == 4); + assert!(offset_of!(StaticImport, span) == 0); + assert!(offset_of!(StaticImport, module_request) == 8); + assert!(offset_of!(StaticImport, entries) == 24); + + assert!(size_of::() == 24); + assert!(align_of::() == 4); + assert!(offset_of!(StaticExport, span) == 0); + assert!(offset_of!(StaticExport, entries) == 8); +}; + +#[cfg(not(any(target_pointer_width = "64", target_pointer_width = "32")))] +const _: () = panic!("Platforms with pointer width other than 64 or 32 bit are not supported"); diff --git a/napi/parser/src/generated/derive_estree.rs b/napi/parser/src/generated/derive_estree.rs new file mode 100644 index 0000000000000..d3b1e75c15a7f --- /dev/null +++ b/napi/parser/src/generated/derive_estree.rs @@ -0,0 +1,86 @@ +// Auto-generated code, DO NOT EDIT DIRECTLY! +// To edit this generated file you have to edit `tasks/ast_tools/src/derives/estree.rs` + +#![allow(unused_imports, clippy::match_same_arms, clippy::semicolon_if_nothing_returned)] + +use oxc_estree::{ + ESTree, FlatStructSerializer, JsonSafeString, Serializer, StructSerializer, + ser::{AppendTo, AppendToConcat}, +}; + +use crate::raw_transfer_types::*; + +impl ESTree for RawTransferData<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("program", &self.program); + state.serialize_field("comments", &self.comments); + state.serialize_field("module", &self.module); + state.serialize_field("errors", &self.errors); + state.end(); + } +} + +impl ESTree for Error<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("severity", &self.severity); + state.serialize_field("message", &self.message); + state.serialize_field("labels", &self.labels); + state.serialize_field("helpMessage", &self.help_message); + state.end(); + } +} + +impl ESTree for ErrorSeverity { + fn serialize(&self, serializer: S) { + match self { + Self::Error => JsonSafeString("Error").serialize(serializer), + Self::Warning => JsonSafeString("Warning").serialize(serializer), + Self::Advice => JsonSafeString("Advice").serialize(serializer), + } + } +} + +impl ESTree for ErrorLabel<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("message", &self.message); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.end(); + } +} + +impl ESTree for EcmaScriptModule<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("hasModuleSyntax", &self.has_module_syntax); + state.serialize_field("staticImports", &self.static_imports); + state.serialize_field("staticExports", &self.static_exports); + state.serialize_field("dynamicImports", &self.dynamic_imports); + state.serialize_field("importMetas", &self.import_metas); + state.end(); + } +} + +impl ESTree for StaticImport<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.serialize_field("moduleRequest", &self.module_request); + state.serialize_field("entries", &self.entries); + state.end(); + } +} + +impl ESTree for StaticExport<'_> { + fn serialize(&self, serializer: S) { + let mut state = serializer.serialize_struct(); + state.serialize_field("start", &self.span.start); + state.serialize_field("end", &self.span.end); + state.serialize_field("entries", &self.entries); + state.end(); + } +} diff --git a/napi/parser/src/lib.rs b/napi/parser/src/lib.rs index b034ed252d1e5..8d817d5d5166a 100644 --- a/napi/parser/src/lib.rs +++ b/napi/parser/src/lib.rs @@ -17,9 +17,18 @@ use oxc::{ use oxc_napi::OxcError; mod convert; +mod raw_transfer; +mod raw_transfer_types; mod types; +pub use raw_transfer::{get_buffer_offset, parse_sync_raw}; pub use types::{Comment, EcmaScriptModule, ParseResult, ParserOptions}; +mod generated { + // Note: We intentionally don't import `generated/derive_estree.rs`. It's not needed. + #[cfg(debug_assertions)] + pub mod assert_layouts; +} + fn get_source_type(filename: &str, options: &ParserOptions) -> SourceType { match options.lang.as_deref() { Some("js") => SourceType::mjs(), diff --git a/napi/parser/src/raw_transfer.rs b/napi/parser/src/raw_transfer.rs new file mode 100644 index 0000000000000..d873e77c1f31f --- /dev/null +++ b/napi/parser/src/raw_transfer.rs @@ -0,0 +1,174 @@ +use std::{ + mem::{self, ManuallyDrop}, + ptr::{self, NonNull}, + str, +}; + +use napi::bindgen_prelude::Uint8Array; +use napi_derive::napi; + +use oxc::{ + allocator::{Allocator, FromIn, Vec as ArenaVec}, + ast_visit::utf8_to_utf16::Utf8ToUtf16, +}; + +use crate::{ + ParserOptions, get_source_type, parse, + raw_transfer_types::{EcmaScriptModule, Error, RawTransferData}, +}; + +// For raw transfer, use a buffer 4 GiB in size, with 4 GiB alignment. +// This ensures that all 64-bit pointers have the same value in upper 32 bits, +// so JS only needs to read the lower 32 bits to get an offset into the buffer. +// However, only use first half of buffer (2 GiB) for the arena, so 32-bit offsets +// don't have the highest bit set. JS bitwise operators interpret the highest bit as sign bit, +// so this enables using `>>` bitshift operator in JS, rather than the more expensive `>>>`, +// without offsets being interpreted as negative. +const TWO_GIB: usize = 1 << 31; +const FOUR_GIB: usize = 1 << 32; + +const BUFFER_SIZE: usize = TWO_GIB; +const BUFFER_ALIGN: usize = FOUR_GIB; +const BUMP_ALIGN: usize = 16; + +/// Get offset within a `Uint8Array` which is aligned on 4 GiB. +/// +/// Does not check that the offset is within bounds of `buffer`. +/// To ensure it always is, provide a `Uint8Array` of at least 4 GiB size. +#[napi] +pub fn get_buffer_offset(buffer: Uint8Array) -> u32 { + let buffer = &*buffer; + let buffer_addr32 = buffer.as_ptr() as u32; + 0u32.wrapping_sub(buffer_addr32) +} + +/// Parses AST into provided `Uint8Array` buffer. +/// +/// Source text must be written into the start of the buffer, and its length (in UTF-8 bytes) +/// provided as `source_len`. +/// +/// This function will parse the source, and write the AST into the buffer, starting at the end. +/// +/// It also writes to the very end of the buffer the offset of `Program` within the buffer. +/// +/// Caller can deserialize data from the buffer on JS side. +/// +/// # SAFETY +/// +/// Caller must ensure: +/// * Source text is written into start of the buffer. +/// * Source text's UTF-8 byte length is `source_len`. +/// * The 1st `source_len` bytes of the buffer comprises a valid UTF-8 string. +/// +/// If source text is originally a JS string on JS side, and converted to a buffer with +/// `Buffer.from(str)` or `new TextEncoder().encode(str)`, this guarantees it's valid UTF-8. +/// +/// # Panics +/// +/// Panics if source text is too long, or AST takes more memory than is available in the buffer. +#[allow(clippy::items_after_statements, clippy::allow_attributes)] +#[napi] +pub unsafe fn parse_sync_raw( + filename: String, + mut buffer: Uint8Array, + source_len: u32, + options: Option, +) { + // 32-bit systems are not supported + const { assert!(std::mem::size_of::() >= 8) }; + + // Check buffer has expected size and alignment + let buffer = &mut *buffer; + assert_eq!(buffer.len(), BUFFER_SIZE); + let buffer_ptr = ptr::from_mut(buffer).cast::(); + assert!(is_multiple_of(buffer_ptr as usize, BUFFER_ALIGN)); + + // Get offsets and size of data region to be managed by arena allocator. + // Leave space for source before it, and 16 bytes for metadata after it. + // Metadata actually only takes 4 bytes, but round everything up to multiple of 16, + // as `bumpalo` requires that alignment. + const METADATA_SIZE: usize = 16; + const { + assert!(METADATA_SIZE >= BUMP_ALIGN); + assert!(is_multiple_of(METADATA_SIZE, BUMP_ALIGN)); + }; + let source_len = source_len as usize; + let data_offset = source_len.next_multiple_of(BUMP_ALIGN); + let data_size = BUFFER_SIZE.saturating_sub(data_offset + METADATA_SIZE); + assert!(data_size >= Allocator::RAW_MIN_SIZE, "Source text is too long"); + + // Create `Allocator`. + // Wrap in `ManuallyDrop` so the allocation doesn't get freed at end of function, or if panic. + // SAFETY: `data_offset` is less than `buffer.len()`, so `.add(data_offset)` cannot wrap + // or be out of bounds. + let data_ptr = unsafe { buffer_ptr.add(data_offset) }; + debug_assert!(is_multiple_of(data_ptr as usize, BUMP_ALIGN)); + debug_assert!(is_multiple_of(data_size, BUMP_ALIGN)); + // SAFETY: `data_ptr` and `data_size` outline a section of the memory in `buffer`. + // `data_ptr` and `data_size` are multiples of 16. + // `data_size` is greater than `Allocator::MIN_SIZE`. + let allocator = + unsafe { Allocator::from_raw_parts(NonNull::new_unchecked(data_ptr), data_size) }; + let allocator = ManuallyDrop::new(allocator); + + // Parse source. + // Enclose parsing logic in a scope to make 100% sure no references to within `Allocator` + // exist after this. + let options = options.unwrap_or_default(); + let source_type = get_source_type(&filename, &options); + + let data_ptr = { + // SAFETY: We checked above that `source_len` does not exceed length of buffer + let source_text = unsafe { buffer.get_unchecked(..source_len) }; + // SAFETY: Caller guarantees source occupies this region of the buffer and is valid UTF-8 + let source_text = unsafe { str::from_utf8_unchecked(source_text) }; + + let ret = parse(&allocator, source_type, source_text, &options); + let mut program = ret.program; + let mut comments = mem::replace(&mut program.comments, ArenaVec::new_in(&allocator)); + let mut module_record = ret.module_record; + + // Convert errors + let mut errors = ArenaVec::from_iter_in( + ret.errors.iter().map(|error| Error::from_in(error, &allocator)), + &allocator, + ); + + // Convert spans to UTF-16 + let span_converter = Utf8ToUtf16::new(source_text); + span_converter.convert_program(&mut program); + span_converter.convert_comments(&mut comments); + span_converter.convert_module_record(&mut module_record); + if let Some(mut converter) = span_converter.converter() { + for error in &mut errors { + for label in &mut error.labels { + converter.convert_span(&mut label.span); + } + } + } + + // Convert module record + let module = EcmaScriptModule::from_in(module_record, &allocator); + + let data = RawTransferData { program, comments, module, errors }; + let data = allocator.alloc(data); + + // Return pointer to `RawTransferData` + ptr::from_ref(data).cast::() + }; + + // Write offset of `RawTransferData` into end of buffer + #[allow(clippy::cast_possible_truncation)] + let data_offset = data_ptr as u32; + const METADATA_OFFSET: usize = BUFFER_SIZE - METADATA_SIZE; + // SAFETY: `METADATA_OFFSET` is less than length of `buffer` + #[expect(clippy::cast_ptr_alignment)] + unsafe { + buffer_ptr.add(METADATA_OFFSET).cast::().write(data_offset); + } +} + +/// Returns `true` if `n` is a multiple of `divisor`. +const fn is_multiple_of(n: usize, divisor: usize) -> bool { + n % divisor == 0 +} diff --git a/napi/parser/src/raw_transfer_types.rs b/napi/parser/src/raw_transfer_types.rs new file mode 100644 index 0000000000000..94b9171a90a0a --- /dev/null +++ b/napi/parser/src/raw_transfer_types.rs @@ -0,0 +1,202 @@ +use rustc_hash::FxHashMap; + +use oxc::{ + allocator::{Allocator, FromIn, Vec}, + ast::ast::{Comment, Program}, + diagnostics::{LabeledSpan, OxcDiagnostic, Severity}, + span::{Atom, Span}, + syntax::module_record::{DynamicImport, ExportEntry, ImportEntry, ModuleRecord, NameSpan}, +}; +use oxc_ast_macros::ast; +use oxc_estree::ESTree; + +/// The main struct containing all deserializable data in raw transfer. +#[ast] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] +pub struct RawTransferData<'a> { + pub program: Program<'a>, + pub comments: Vec<'a, Comment>, + pub module: EcmaScriptModule<'a>, + pub errors: Vec<'a, Error<'a>>, +} + +// Errors. +// +// These types and the `From` / `FromIn` impls mirror the implementation in `types.rs` +// and `crates/oxc_napi/src/lib.rs`. +// Only difference is that these versions of the types are arena-allocated. + +#[ast] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] +pub struct Error<'a> { + pub severity: ErrorSeverity, + pub message: Atom<'a>, + pub labels: Vec<'a, ErrorLabel<'a>>, + pub help_message: Option>, +} + +impl<'a> FromIn<'a, &OxcDiagnostic> for Error<'a> { + fn from_in(diagnostic: &OxcDiagnostic, allocator: &'a Allocator) -> Self { + let labels = diagnostic.labels.as_ref().map_or_else( + || Vec::new_in(allocator), + |labels| { + Vec::from_iter_in( + labels.iter().map(|label| ErrorLabel::from_in(label, allocator)), + allocator, + ) + }, + ); + + Self { + severity: ErrorSeverity::from(diagnostic.severity), + message: Atom::from_in(diagnostic.message.as_ref(), allocator), + labels, + help_message: diagnostic + .help + .as_ref() + .map(|help| Atom::from_in(help.as_ref(), allocator)), + } + } +} + +#[ast] +#[derive(Clone, Copy)] +#[generate_derive(ESTree)] +#[estree(no_rename_variants, no_ts_def)] +pub enum ErrorSeverity { + Error = 0, + Warning = 1, + Advice = 2, +} + +impl From for ErrorSeverity { + fn from(value: Severity) -> Self { + match value { + Severity::Error => Self::Error, + Severity::Warning => Self::Warning, + Severity::Advice => Self::Advice, + } + } +} + +#[ast] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] +pub struct ErrorLabel<'a> { + pub message: Option>, + pub span: Span, +} + +impl<'a> FromIn<'a, &LabeledSpan> for ErrorLabel<'a> { + #[expect(clippy::cast_possible_truncation)] + fn from_in(label: &LabeledSpan, allocator: &'a Allocator) -> Self { + Self { + message: label.label().map(|message| Atom::from_in(message, allocator)), + span: Span::new(label.offset() as u32, (label.offset() + label.len()) as u32), + } + } +} + +// Module record. +// +// These types and the `From` impl mirror the implementation in `types.rs` and `convert.rs`. +// However, a lot of the data can be left as is, because it's already in the arena, +// and that's what raw transfer needs - unlike the other implementation which requires owned types. +// In particular, there's no need to copy or convert the many `Atom`s in `ModuleRecord`. + +#[ast] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] +pub struct EcmaScriptModule<'a> { + /// Has ESM syntax. + /// + /// i.e. `import` and `export` statements, and `import.meta`. + /// + /// Dynamic imports `import('foo')` are ignored since they can be used in non-ESM files. + pub has_module_syntax: bool, + /// Import statements. + pub static_imports: Vec<'a, StaticImport<'a>>, + /// Export statements. + pub static_exports: Vec<'a, StaticExport<'a>>, + /// Dynamic import expressions. + pub dynamic_imports: Vec<'a, DynamicImport>, + /// Span positions` of `import.meta` + pub import_metas: Vec<'a, Span>, +} + +#[ast] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] +pub struct StaticImport<'a> { + /// Span of import statement. + pub span: Span, + /// Import source. + /// + /// ```js + /// import { foo } from "mod"; + /// // ^^^ + /// ``` + pub module_request: NameSpan<'a>, + /// Import specifiers. + /// + /// Empty for `import "mod"`. + pub entries: Vec<'a, ImportEntry<'a>>, +} + +#[ast] +#[generate_derive(ESTree)] +#[estree(no_type, no_ts_def)] +pub struct StaticExport<'a> { + pub span: Span, + pub entries: Vec<'a, ExportEntry<'a>>, +} + +impl<'a> FromIn<'a, ModuleRecord<'a>> for EcmaScriptModule<'a> { + fn from_in(record: ModuleRecord<'a>, allocator: &'a Allocator) -> Self { + let static_imports = + record.requested_modules.iter().flat_map(|(name, requested_modules)| { + requested_modules.iter().filter(|m| m.is_import).map(|m| { + let entries = record + .import_entries + .iter() + .filter(|e| e.statement_span == m.statement_span) + .cloned(); + let entries = Vec::from_iter_in(entries, allocator); + + StaticImport { + span: m.statement_span, + module_request: NameSpan { name: *name, span: m.span }, + entries, + } + }) + }); + let mut static_imports = Vec::from_iter_in(static_imports, allocator); + static_imports.sort_unstable_by_key(|e| e.span.start); + + let static_exports = record + .local_export_entries + .iter() + .chain(&record.indirect_export_entries) + .chain(&record.star_export_entries) + .fold(FxHashMap::>::default(), |mut acc, e| { + acc.entry(e.statement_span) + .or_insert_with(|| Vec::new_in(allocator)) + .push(e.clone()); + acc + }) + .into_iter() + .map(|(span, entries)| StaticExport { span, entries }); + let mut static_exports = Vec::from_iter_in(static_exports, allocator); + static_exports.sort_unstable_by_key(|e| e.span.start); + + Self { + has_module_syntax: record.has_module_syntax, + static_imports, + static_exports, + dynamic_imports: record.dynamic_imports, + import_metas: record.import_metas, + } + } +} diff --git a/napi/parser/test/parse-raw.test.ts b/napi/parser/test/parse-raw.test.ts new file mode 100644 index 0000000000000..157b8bc82c6c3 --- /dev/null +++ b/napi/parser/test/parse-raw.test.ts @@ -0,0 +1,102 @@ +import { readdir, readFile, writeFile } from 'node:fs/promises'; +import { basename, join as pathJoin } from 'node:path'; +import { describe, expect, it } from 'vitest'; + +import { parseSync } from '../index.js'; + +const TARGET_DIR_PATH = pathJoin(import.meta.dirname, '../../../target'); +const TEST262_DIR_PATH = pathJoin(import.meta.dirname, '../../../tasks/coverage/test262/test'); +const ACORN_TEST262_DIR_PATH = pathJoin(import.meta.dirname, '../../../tasks/coverage/acorn-test262/test'); + +// Load/download fixtures. +// Save in `target` directory, same as where benchmarks store them. +const benchFixtureUrls = [ + // TypeScript syntax (2.81MB) + 'https://raw.githubusercontent.com/microsoft/TypeScript/v5.3.3/src/compiler/checker.ts', + // Real world app tsx (1.0M) + 'https://raw.githubusercontent.com/oxc-project/benchmark-files/main/cal.com.tsx', + // Real world content-heavy app jsx (3K) + 'https://raw.githubusercontent.com/oxc-project/benchmark-files/main/RadixUIAdoptionSection.jsx', + // Heavy with classes (554K) + 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4.0.269/build/pdf.mjs', + // ES5 (3.9M) + 'https://cdn.jsdelivr.net/npm/antd@5.12.5/dist/antd.js', +]; + +const benchFixtures = await Promise.all(benchFixtureUrls.map(async (url) => { + const filename = url.split('/').at(-1), + path = pathJoin(TARGET_DIR_PATH, filename); + let sourceText; + try { + sourceText = await readFile(path, 'utf8'); + } catch { + const res = await fetch(url); + sourceText = await res.text(); + await writeFile(path, sourceText); + } + + return [filename, sourceText]; +})); + +// Only test Test262 fixtures which Acorn is able to parse +const test262FixturePaths = (await readdir(ACORN_TEST262_DIR_PATH, { recursive: true })) + .filter(path => path.endsWith('.json')) + .map(path => path.slice(0, -2)); + +// Test raw transfer output matches standard (via JSON) output for some large files +describe('fixtures', () => { + it.each(benchFixtures)('%s', testRaw, { timeout: 10000 }); +}); + +// Test raw transfer output matches standard (via JSON) output for Test262 test cases +describe('test262', () => { + it.each(test262FixturePaths)('%s', async (path) => { + const filename = basename(path); + const sourceText = await readFile(pathJoin(TEST262_DIR_PATH, path), 'utf8'); + testRaw(filename, sourceText); + }); +}); + +function testRaw(filename, sourceText) { + const retStandard = parseSync(filename, sourceText); + const { program: programStandard, comments: commentsStandard, module: moduleStandard, errors: errorsStandard } = + retStandard; + + // @ts-ignore + const retRaw = parseSync(filename, sourceText, { experimentalRawTransfer: true }); + const { program: programRaw, comments: commentsRaw } = retRaw; + // Remove `null` values, to match what NAPI-RS does + const moduleRaw = clean(retRaw.module); + const errorsRaw = clean(retRaw.errors); + + // Compare as objects + expect(programRaw).toEqual(programStandard); + expect(commentsRaw).toEqual(commentsStandard); + expect(moduleRaw).toEqual(moduleStandard); + expect(errorsRaw).toEqual(errorsStandard); + + // Compare as JSON (to ensure same field order) + const jsonStandard = stringify({ + program: programStandard, + comments: commentsStandard, + module: moduleStandard, + errors: errorsStandard, + }); + const jsonRaw = stringify({ program: programRaw, comments: commentsRaw, module: moduleRaw, errors: errorsRaw }); + expect(jsonRaw).toEqual(jsonStandard); +} + +// Stringify to JSON, removing values which are invalid in JSON +function stringify(obj) { + return JSON.stringify(obj, (_key, value) => { + if (typeof value === 'bigint') return `__BIGINT__: ${value}`; + if (typeof value === 'object' && value instanceof RegExp) return `__REGEXP__: ${value}`; + if (value === Infinity) return `__INFINITY__`; + return value; + }); +} + +// Remove `null` values, to match what NAPI-RS does +function clean(obj) { + return JSON.parse(JSON.stringify(obj, (_key, value) => value === null ? undefined : value)); +} diff --git a/tasks/ast_tools/src/derives/estree.rs b/tasks/ast_tools/src/derives/estree.rs index c85e3199e9c73..5c6ad6d5a831f 100644 --- a/tasks/ast_tools/src/derives/estree.rs +++ b/tasks/ast_tools/src/derives/estree.rs @@ -187,6 +187,7 @@ fn parse_estree_attr(location: AttrLocation, part: AttrPart) -> Result<()> { // `#[estree]` attr on meta type AttrLocation::Meta(meta) => match part { AttrPart::String("ts_type", ts_type) => meta.estree.ts_type = Some(ts_type), + AttrPart::String("raw_deser", raw_deser) => meta.estree.raw_deser = Some(raw_deser), _ => return Err(()), }, _ => unreachable!(), @@ -466,7 +467,7 @@ fn generate_body_for_via_override( /// Returns `true` if either the field has an `#[estree(skip)]` attr on it, /// or the type that the field contains has an `#[estree(skip)]` attr. /// -/// This function also used by Typescript generator. +/// This function also used by Typescript and raw transfer generators. pub fn should_skip_field(field: &FieldDef, schema: &Schema) -> bool { if field.estree.skip { true @@ -527,7 +528,7 @@ pub fn can_flatten_field_inline(field: &FieldDef, krate: &str, schema: &Schema) /// * `#[estree(rename)]` attr on variant. /// * `#[estree(no_rename_variants)]` attr on enum. /// -/// This function also used by Typescript generator. +/// This function also used by Typescript and raw transfer generators. pub fn get_fieldless_variant_value<'s>( enum_def: &'s EnumDef, variant: &'s VariantDef, @@ -543,7 +544,7 @@ pub fn get_fieldless_variant_value<'s>( /// Get ESTree name for struct field. /// -/// This function also used by Typescript generator. +/// This function also used by Typescript and raw transfer generators. pub fn get_struct_field_name(field: &FieldDef) -> Cow<'_, str> { if let Some(field_name) = field.estree.rename.as_deref() { Cow::Borrowed(field_name) diff --git a/tasks/ast_tools/src/generators/assert_layouts.rs b/tasks/ast_tools/src/generators/assert_layouts.rs index f97a37f38a6ff..0824e7b41448a 100644 --- a/tasks/ast_tools/src/generators/assert_layouts.rs +++ b/tasks/ast_tools/src/generators/assert_layouts.rs @@ -513,7 +513,10 @@ fn template(krate: &str, assertions_64: &TokenStream, assertions_32: &TokenStrea use nonmax::NonMaxU32; ///@@line_break - use crate::{number::*, operator::*, reference::*, scope::*, symbol::*}; + use crate::{module_record::*, number::*, operator::*, reference::*, scope::*, symbol::*}; + }, + "napi/parser" => quote! { + use crate::raw_transfer_types::*; }, _ => quote! { use crate::*; diff --git a/tasks/ast_tools/src/generators/mod.rs b/tasks/ast_tools/src/generators/mod.rs index 6adfdebdbc21b..83bd7bd818382 100644 --- a/tasks/ast_tools/src/generators/mod.rs +++ b/tasks/ast_tools/src/generators/mod.rs @@ -8,6 +8,7 @@ mod assert_layouts; mod ast_builder; mod ast_kind; mod get_id; +mod raw_transfer; mod typescript; mod utf8_to_utf16; mod visit; @@ -16,6 +17,7 @@ pub use assert_layouts::AssertLayouts; pub use ast_builder::AstBuilderGenerator; pub use ast_kind::AstKindGenerator; pub use get_id::GetIdGenerator; +pub use raw_transfer::RawTransferGenerator; pub use typescript::TypescriptGenerator; pub use utf8_to_utf16::Utf8ToUtf16ConverterGenerator; pub use visit::VisitGenerator; diff --git a/tasks/ast_tools/src/generators/raw_transfer.rs b/tasks/ast_tools/src/generators/raw_transfer.rs new file mode 100644 index 0000000000000..522ec7ea250b3 --- /dev/null +++ b/tasks/ast_tools/src/generators/raw_transfer.rs @@ -0,0 +1,837 @@ +//! Generator for raw transfer deserializer. + +use std::{borrow::Cow, fmt::Debug, str}; + +use cow_utils::CowUtils; +use lazy_static::lazy_static; +use regex::{Captures, Regex, Replacer}; +use rustc_hash::FxHashSet; + +use crate::{ + Generator, RAW_TRANSFER_DESERIALIZER_PATH, + codegen::{Codegen, DeriveId}, + derives::estree::{ + get_fieldless_variant_value, get_struct_field_name, should_flatten_field, should_skip_field, + }, + output::Output, + schema::{ + BoxDef, CellDef, Def, EnumDef, FieldDef, OptionDef, PrimitiveDef, Schema, StructDef, + TypeDef, VecDef, + extensions::layout::{GetLayout, GetOffset}, + }, + utils::{FxIndexMap, format_cow, upper_case_first, write_it}, +}; + +use super::define_generator; + +// Offsets of `Vec`'s fields. +// These are based on observation, and are not stable. +// They will be fully reliable once we implement our own `Vec` type and make it `#[repr(C)]`. +const VEC_PTR_FIELD_OFFSET: usize = 0; +const VEC_LEN_FIELD_OFFSET: usize = 24; + +/// Generator for raw transfer deserializer. +pub struct RawTransferGenerator; + +define_generator!(RawTransferGenerator); + +impl Generator for RawTransferGenerator { + fn generate(&self, schema: &Schema, codegen: &Codegen) -> Output { + let code = generate_deserializers(schema, codegen); + Output::Javascript { path: RAW_TRANSFER_DESERIALIZER_PATH.to_string(), code } + } +} + +/// Prelude to generated deserializer. +/// Defines the main `deserialize` function. +static PRELUDE: &str = " + 'use strict'; + + module.exports = deserialize; + + let uint8, uint32, float64, sourceText, sourceIsAscii, sourceLen; + + const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }), + decodeStr = textDecoder.decode.bind(textDecoder), + { fromCodePoint } = String; + + function deserialize(buffer, sourceTextInput, sourceLenInput) { + uint8 = buffer; + uint32 = new Uint32Array(buffer.buffer, buffer.byteOffset); + float64 = new Float64Array(buffer.buffer, buffer.byteOffset); + + sourceText = sourceTextInput; + sourceLen = sourceLenInput; + sourceIsAscii = sourceText.length === sourceLen; + + // (2 * 1024 * 1024 * 1024 - 16) >> 2 + const metadataPos32 = 536870908; + + const data = deserializeRawTransferData(uint32[metadataPos32]); + + uint8 = uint32 = float64 = sourceText = undefined; + + return data; + } +"; + +/// Generate deserializer functions for all types. +fn generate_deserializers(schema: &Schema, codegen: &Codegen) -> String { + let estree_derive_id = codegen.get_derive_id_by_name("ESTree"); + + let mut code = PRELUDE.to_string(); + + for type_def in &schema.types { + match type_def { + TypeDef::Struct(struct_def) => { + generate_struct(struct_def, &mut code, estree_derive_id, schema); + } + TypeDef::Enum(enum_def) => { + generate_enum(enum_def, &mut code, estree_derive_id, schema); + } + TypeDef::Primitive(primitive_def) => { + generate_primitive(primitive_def, &mut code, schema); + } + TypeDef::Option(option_def) => { + generate_option(option_def, &mut code, schema); + } + TypeDef::Box(box_def) => { + generate_box(box_def, &mut code, schema); + } + TypeDef::Vec(vec_def) => { + generate_vec(vec_def, &mut code, schema); + } + TypeDef::Cell(_cell_def) => { + // No deserializers for `Cell`s - use inner type's deserializer + } + } + } + + code +} + +/// Generate deserialize function for a struct. +fn generate_struct( + struct_def: &StructDef, + code: &mut String, + estree_derive_id: DeriveId, + schema: &Schema, +) { + if !struct_def.generates_derive(estree_derive_id) || struct_def.estree.skip { + return; + } + + let fn_name = struct_def.deser_name(schema); + let mut generator = StructDeserializerGenerator::new(schema); + + let body = if let Some(converter_name) = &struct_def.estree.via { + generator.apply_converter(converter_name, struct_def, 0).map(|value| { + if generator.preamble.is_empty() { + format!("return {value};") + } else { + let preamble = generator.preamble.join(""); + format!( + " + {preamble} + return {value}; + " + ) + } + }) + } else { + None + }; + + let body = if let Some(body) = body { + body + } else { + let mut preamble_str = String::new(); + let mut fields_str = String::new(); + + generator.generate_struct_fields(struct_def, 0); + + for (field_name, value) in generator.fields { + if value.starts_with("...") { + write_it!(&mut fields_str, "{value},"); + } else if generator.dependent_field_names.contains(&field_name) { + if preamble_str.is_empty() { + preamble_str.push_str("const "); + } else { + preamble_str.push_str(",\n"); + } + write_it!(&mut preamble_str, "{field_name} = {value}"); + write_it!(&mut fields_str, "{field_name},"); + } else if value == field_name { + write_it!(&mut fields_str, "{field_name},"); + } else { + write_it!(&mut fields_str, "{field_name}: {value},"); + } + } + + if !preamble_str.is_empty() { + preamble_str.push(';'); + } + + for preamble_part in generator.preamble { + preamble_str.push_str(preamble_part.trim()); + } + + format!( + " + {preamble_str} + return {{ + {fields_str} + }}; + " + ) + }; + + #[rustfmt::skip] + write_it!(code, " + function {fn_name}(pos) {{ + {body} + }} + "); +} + +struct StructDeserializerGenerator<'s> { + /// Dependencies + dependent_field_names: FxHashSet, + /// Preamble + preamble: Vec, + /// Fields, keyed by fields name (field name in ESTree AST) + fields: FxIndexMap, + /// Schema + schema: &'s Schema, +} + +impl<'s> StructDeserializerGenerator<'s> { + fn new(schema: &'s Schema) -> Self { + Self { + dependent_field_names: FxHashSet::default(), + preamble: vec![], + fields: FxIndexMap::default(), + schema, + } + } + + fn generate_struct_fields(&mut self, struct_def: &StructDef, struct_offset: u32) { + if let Some(field_indices) = &struct_def.estree.field_indices { + // Specified field order - serialize in this order + for &field_index in field_indices { + let field_index = field_index as usize; + if let Some(field) = struct_def.fields.get(field_index) { + self.generate_struct_field_owned(field, struct_def, struct_offset); + } else { + let (field_name, converter_name) = + &struct_def.estree.add_fields[field_index - struct_def.fields.len()]; + self.generate_struct_field_added( + struct_def, + field_name, + converter_name, + struct_offset, + ); + } + } + } else { + // No specified field order - serialize in original order + for field in &struct_def.fields { + self.generate_struct_field_owned(field, struct_def, struct_offset); + } + + for (field_name, converter_name) in &struct_def.estree.add_fields { + self.generate_struct_field_added( + struct_def, + field_name, + converter_name, + struct_offset, + ); + } + } + + // Add `type` field if there isn't one already, and struct isn't marked `#[estree(no_type)]` + if !struct_def.estree.no_type && !self.fields.contains_key("type") { + let struct_name = + struct_def.estree.rename.as_deref().unwrap_or_else(|| struct_def.name()); + self.fields.insert_before(0, "type".to_string(), format!("'{struct_name}'")); + } + } + + fn generate_struct_field_owned( + &mut self, + field: &FieldDef, + struct_def: &StructDef, + struct_offset: u32, + ) { + if should_skip_field(field, self.schema) { + return; + } + + let field_name = get_struct_field_name(field).to_string(); + let field_type = field.type_def(self.schema); + let field_offset = struct_offset + field.offset_64(); + + if should_flatten_field(field, self.schema) { + match field_type { + TypeDef::Struct(field_struct_def) => { + self.generate_struct_fields(field_struct_def, field_offset); + } + TypeDef::Enum(field_enum_def) => { + // TODO: Do this better + let value_fn = field_enum_def.deser_name(self.schema); + let pos = pos_offset(field_offset); + self.fields.insert(field_name, format!("...{value_fn}({pos})")); + } + _ => panic!( + "Cannot flatten a field which is not a struct or enum: `{}::{}`", + struct_def.name(), + field.name(), + ), + } + return; + } + + let value_fn = field_type.deser_name(self.schema); + let pos = pos_offset(field_offset); + let mut value = format!("{value_fn}({pos})"); + + if let Some(appended_field_index) = field.estree.append_field_index { + self.preamble.push(format!("const {field_name} = {value};")); + + let appended_field = &struct_def.fields[appended_field_index]; + let appended_field_type = appended_field.type_def(self.schema); + match appended_field_type { + TypeDef::Vec(vec_def) => { + let appended_field_fn = vec_def.deser_name(self.schema); + let appended_pos = pos_offset(struct_offset + appended_field.offset_64()); + self.preamble.push(format!( + "{field_name}.push(...{appended_field_fn}({appended_pos}));" + )); + } + TypeDef::Option(option_def) => { + let appended_field_name = get_struct_field_name(appended_field).to_string(); + let appended_field_fn = option_def.deser_name(self.schema); + let appended_pos = pos_offset(struct_offset + appended_field.offset_64()); + self.preamble.push(format!(" + const {appended_field_name} = {appended_field_fn}({appended_pos}); + if ({appended_field_name} !== null) {field_name}.push({appended_field_name}); + ")); + } + _ => panic!("Cannot append: `{}::{}`", struct_def.name(), field.name()), + } + + value.clone_from(&field_name); + } else if let Some(converter_name) = &field.estree.via { + value = self.apply_converter(converter_name, struct_def, struct_offset).unwrap(); + } + + self.fields.insert(field_name, value); + } + + fn generate_struct_field_added( + &mut self, + struct_def: &StructDef, + field_name: &str, + converter_name: &str, + struct_offset: u32, + ) { + let value = self.apply_converter(converter_name, struct_def, struct_offset).unwrap(); + self.fields.insert(field_name.to_string(), value); + } + + fn apply_converter( + &mut self, + converter_name: &str, + struct_def: &StructDef, + struct_offset: u32, + ) -> Option { + let converter = self.schema.meta_by_name(converter_name); + let raw_deser = converter.estree.raw_deser.as_deref()?; + + let value = THIS_REGEX.replace_all(raw_deser, ThisReplacer::new(self)); + let value = DESER_REGEX.replace_all(&value, DeserReplacer::new(self.schema)); + let value = POS_OFFSET_REGEX + .replace_all(&value, PosOffsetReplacer::new(self, struct_def, struct_offset)); + let value = value.cow_replace("SOURCE_TEXT", "sourceText"); + let value = if let Some((preamble, value)) = value.trim().rsplit_once('\n') { + self.preamble.push(preamble.to_string()); + value.trim().to_string() + } else { + value.trim().to_string() + }; + Some(value) + } +} + +/// Generate deserialize function for an enum. +fn generate_enum( + enum_def: &EnumDef, + code: &mut String, + estree_derive_id: DeriveId, + schema: &Schema, +) { + if !enum_def.generates_derive(estree_derive_id) || enum_def.estree.skip { + return; + } + + let type_name = enum_def.name(); + let fn_name = enum_def.deser_name(schema); + let payload_offset = enum_def.layout_64().align; + + let body = if let Some(converter_name) = &enum_def.estree.via { + apply_converter_for_enum(converter_name, 0, schema) + } else { + None + }; + + let body = body.unwrap_or_else(|| { + let mut variants = enum_def.all_variants(schema).collect::>(); + variants.sort_by_key(|variant| variant.discriminant); + + let switch_cases = variants.into_iter().fold(String::new(), |mut s, variant| { + let discriminant = variant.discriminant; + + let ret = if let Some(converter_name) = &variant.estree.via { + apply_converter_for_enum(converter_name, payload_offset, schema).unwrap() + } else if let Some(variant_type) = variant.field_type(schema) { + let variant_fn_name = variant_type.deser_name(schema); + let payload_pos = pos_offset(payload_offset); + format!("return {variant_fn_name}({payload_pos});") + } else { + format!("return '{}';", get_fieldless_variant_value(enum_def, variant)) + }; + + write_it!(s, "case {discriminant}: {ret}"); + s + }); + + format!( + " + switch(uint8[pos]) {{ + {switch_cases} + default: throw new Error(`Unexpected discriminant ${{uint8[pos]}} for {type_name}`); + }} + " + ) + }); + + #[rustfmt::skip] + write_it!(code, " + function {fn_name}(pos) {{ + {body} + }} + "); +} + +/// Generate deserialize function for a primitive. +fn generate_primitive(primitive_def: &PrimitiveDef, code: &mut String, schema: &Schema) { + #[expect(clippy::match_same_arms)] + let ret = match primitive_def.name() { + // Reuse deserializer for `&str` + "Atom" => return, + // Dummy type + "PointerAlign" => return, + "bool" => "return uint8[pos] === 1;", + "u8" => "return uint8[pos];", + // "u16" => "return uint16[pos >> 1];", + "u32" => "return uint32[pos >> 2];", + #[rustfmt::skip] + "u64" => " + const pos32 = pos >> 2; + return uint32[pos32] + uint32[pos32 + 1] * 4294967296; + ", + "f64" => "return float64[pos >> 3];", + "&str" => STR_DESERIALIZER_BODY, + // Reuse deserializers for zeroed types + type_name if type_name.starts_with("NonZero") => return, + type_name => panic!("Cannot generate deserializer for primitive `{type_name}`"), + }; + + let fn_name = primitive_def.deser_name(schema); + + #[rustfmt::skip] + write_it!(code, " + function {fn_name}(pos) {{ + {ret} + }} + "); +} + +static STR_DESERIALIZER_BODY: &str = " + const pos32 = pos >> 2, + len = uint32[pos32 + 2]; + if (len === 0) return ''; + + pos = uint32[pos32]; + if (sourceIsAscii && pos < sourceLen) return sourceText.substr(pos, len); + + // Longer strings use `TextDecoder` + // TODO: Find best switch-over point + const end = pos + len; + if (len > 50) return decodeStr(uint8.subarray(pos, end)); + + // Shorter strings decode by hand to avoid native call + let out = '', + c; + do { + c = uint8[pos++]; + if (c < 0x80) { + out += fromCodePoint(c); + } else { + out += decodeStr(uint8.subarray(pos - 1, end)); + break; + } + } while (pos < end); + + return out; +"; + +/// Generate deserialize function for an `Option`. +fn generate_option(option_def: &OptionDef, code: &mut String, schema: &Schema) { + let fn_name = option_def.deser_name(schema); + let inner_type = option_def.inner_type(schema); + let inner_fn_name = inner_type.deser_name(schema); + let inner_layout = inner_type.layout_64(); + + let (none_condition, payload_offset) = if option_def.layout_64().size == inner_layout.size { + let niche = inner_layout.niche.clone().unwrap(); + let none_condition = match niche.size { + 1 => format!("uint8[{}] === {}", pos_offset(niche.offset), niche.value()), + // 2 => format!("uint16[{}] === {}", pos_offset_shift(niche.offset, 1), niche.value()), + 4 => format!("uint32[{}] === {}", pos_offset_shift(niche.offset, 2), niche.value()), + 8 => { + // TODO: Use `float64[pos >> 3] === 0` instead of + // `uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0`? + let value = niche.value(); + format!( + "uint32[{}] === {} && uint32[{}] === {}", + pos_offset_shift(niche.offset, 2), + value & u128::from(u32::MAX), + pos_offset_shift(niche.offset + 4, 2), + value >> 32, + ) + } + size => panic!("Invalid niche size: {size}"), + }; + (none_condition, Cow::Borrowed("pos")) + } else { + ("uint8[pos] === 0".to_string(), pos_offset(inner_layout.align)) + }; + + #[rustfmt::skip] + write_it!(code, " + function {fn_name}(pos) {{ + if ({none_condition}) return null; + return {inner_fn_name}({payload_offset}); + }} + "); +} + +/// Generate deserialize function for a `Box`. +fn generate_box(box_def: &BoxDef, code: &mut String, schema: &Schema) { + let fn_name = box_def.deser_name(schema); + let inner_fn_name = box_def.inner_type(schema).deser_name(schema); + + #[rustfmt::skip] + write_it!(code, " + function {fn_name}(pos) {{ + return {inner_fn_name}(uint32[pos >> 2]); + }} + "); +} + +/// Generate deserialize function for a `Vec`. +fn generate_vec(vec_def: &VecDef, code: &mut String, schema: &Schema) { + let fn_name = vec_def.deser_name(schema); + let inner_type = vec_def.inner_type(schema); + let inner_fn_name = inner_type.deser_name(schema); + let inner_type_size = inner_type.layout_64().size; + + let ptr_pos32 = pos32_offset(VEC_PTR_FIELD_OFFSET); + let len_pos32 = pos32_offset(VEC_LEN_FIELD_OFFSET); + + #[rustfmt::skip] + write_it!(code, " + function {fn_name}(pos) {{ + const arr = [], + pos32 = pos >> 2, + len = uint32[{len_pos32}]; + pos = uint32[{ptr_pos32}]; + for (let i = 0; i < len; i++) {{ + arr.push({inner_fn_name}(pos)); + pos += {inner_type_size}; + }} + return arr; + }} + "); +} + +/// Generate pos offset string. +/// +/// * If `offset == 0` -> `pos`. +/// * Otherwise -> `pos + ` (e.g. `pos + 8`). +fn pos_offset(offset: O) -> Cow<'static, str> +where + O: TryInto, + >::Error: Debug, +{ + let offset = offset.try_into().unwrap(); + if offset == 0 { Cow::Borrowed("pos") } else { format_cow!("pos + {offset}") } +} + +/// Generate pos offset and shift string. +/// +/// * If `offset == 0` and `shift == 0` -> `pos`. +/// * If `offset == 0` -> `pos >> ` (e.g. `pos >> 2`). +/// * If `shift == 0` -> `pos + ` (e.g. `pos + 8`). +/// * Otherwise -> `(pos + ) >> ` (e.g. `(pos + 8) >> 2`). +fn pos_offset_shift(offset: O, shift: S) -> Cow<'static, str> +where + O: TryInto, + >::Error: Debug, + S: TryInto, + >::Error: Debug, +{ + let offset = offset.try_into().unwrap(); + let shift = shift.try_into().unwrap(); + match (offset, shift) { + (0, 0) => Cow::Borrowed("pos"), + (0, _) => format_cow!("pos >> {shift}"), + (_, 0) => format_cow!("pos + {offset}"), + (_, _) => format_cow!("(pos + {offset}) >> {shift}"), + } +} + +/// Generate pos32 offset string. +/// +/// * If `offset == 0` -> `pos32`. +/// * Otherwise -> `pos32 + ` (e.g. `pos32 + 4`). +fn pos32_offset(offset: O) -> Cow<'static, str> +where + O: TryInto, + >::Error: Debug, +{ + let offset = offset.try_into().unwrap(); + let offset32 = offset >> 2; + if offset32 == 0 { Cow::Borrowed("pos32") } else { format_cow!("pos32 + {offset32}") } +} + +// `raw_deser` replacements + +/// Get `raw_deser` for converter and replace `POS`, `DESER` and `SOURCE_TEXT` within it. +/// +/// Returns `None` if converter is not annotated `#[estree(raw_deser = "...")]`. +fn apply_converter_for_enum(converter_name: &str, offset: u32, schema: &Schema) -> Option { + let converter = schema.meta_by_name(converter_name); + let raw_deser = converter.estree.raw_deser.as_deref()?; + + let value = POS_REGEX.replace_all(raw_deser, PosReplacer::new(offset)); + let value = DESER_REGEX.replace_all(&value, DeserReplacer::new(schema)); + let value = value.cow_replace("SOURCE_TEXT", "sourceText"); + let value = if let Some((preamble, value)) = value.trim().rsplit_once('\n') { + format!("{preamble} return {value};") + } else { + format!("return {value};") + }; + + Some(value) +} + +lazy_static! { + static ref THIS_REGEX: Regex = Regex::new(r"THIS\.([a-zA-Z_]+)").unwrap(); +} + +struct ThisReplacer<'d> { + dependent_field_names: &'d mut FxHashSet, +} + +impl<'d> ThisReplacer<'d> { + fn new(generator: &'d mut StructDeserializerGenerator<'_>) -> Self { + Self { dependent_field_names: &mut generator.dependent_field_names } + } +} + +impl Replacer for ThisReplacer<'_> { + fn replace_append(&mut self, caps: &Captures, dst: &mut String) { + assert_eq!(caps.len(), 2); + let field_name = caps.get(1).unwrap().as_str(); + dst.push_str(field_name); + self.dependent_field_names.insert(field_name.to_string()); + } +} + +lazy_static! { + static ref DESER_REGEX: Regex = Regex::new(r"DESER\[([A-Za-z0-9<>_]+)\]").unwrap(); +} + +struct DeserReplacer<'s> { + schema: &'s Schema, +} + +impl<'s> DeserReplacer<'s> { + fn new(schema: &'s Schema) -> Self { + Self { schema } + } +} + +impl Replacer for DeserReplacer<'_> { + fn replace_append(&mut self, caps: &Captures, dst: &mut String) { + assert_eq!(caps.len(), 2); + let type_name = caps.get(1).unwrap().as_str(); + let type_def = self.schema.type_by_name(type_name); + let fn_name = type_def.deser_name(self.schema); + dst.push_str(&fn_name); + } +} + +lazy_static! { + static ref POS_REGEX: Regex = { + #[expect(clippy::trivial_regex)] + Regex::new("POS").unwrap() + }; +} + +struct PosReplacer { + offset: u32, +} + +impl PosReplacer { + fn new(offset: u32) -> Self { + Self { offset } + } +} + +impl Replacer for PosReplacer { + fn replace_append(&mut self, _caps: &Captures, dst: &mut String) { + dst.push_str(&pos_offset(self.offset)); + } +} + +lazy_static! { + static ref POS_OFFSET_REGEX: Regex = Regex::new( + r"POS_OFFSET(?:<([A-Za-z]+)>)?\.([a-zA-Z_]+(?:\.[a-zA-Z_]+)*)(?:\s*\+\s*(\d+))?" + ) + .unwrap(); +} + +struct PosOffsetReplacer<'s, 'd> { + schema: &'s Schema, + struct_def: &'d StructDef, + struct_offset: u32, +} + +impl<'s, 'd> PosOffsetReplacer<'s, 'd> { + fn new( + generator: &StructDeserializerGenerator<'s>, + struct_def: &'d StructDef, + struct_offset: u32, + ) -> Self { + Self { schema: generator.schema, struct_def, struct_offset } + } +} + +impl Replacer for PosOffsetReplacer<'_, '_> { + fn replace_append(&mut self, caps: &Captures, dst: &mut String) { + assert_eq!(caps.len(), 4); + + let struct_def = if let Some(struct_name) = caps.get(1) { + self.schema.type_by_name(struct_name.as_str()).as_struct().unwrap() + } else { + self.struct_def + }; + + let mut field_names = caps.get(2).unwrap().as_str().split('.'); + let field_name = field_names.next().unwrap(); + let field = struct_def.fields.iter().find(|field| field.name() == field_name).unwrap(); + let mut offset = self.struct_offset + field.offset_64(); + let mut type_def = field.type_def(self.schema); + for field_name in field_names { + let struct_def = type_def.as_struct().unwrap(); + let field = struct_def.fields.iter().find(|field| field.name() == field_name).unwrap(); + offset += field.offset_64(); + type_def = field.type_def(self.schema); + } + + if let Some(add) = caps.get(3) { + offset += str::parse::(add.as_str()).unwrap(); + } + + if offset == 0 { + write_it!(dst, "pos"); + } else { + write_it!(dst, "pos + {offset}"); + } + } +} + +/// Trait to get deserializer function name for a type. +trait DeserializeFunctionName { + fn deser_name(&self, schema: &Schema) -> String { + format!("deserialize{}", self.plain_name(schema)) + } + + fn plain_name<'s>(&'s self, schema: &'s Schema) -> Cow<'s, str>; +} + +impl DeserializeFunctionName for TypeDef { + fn plain_name<'s>(&'s self, schema: &'s Schema) -> Cow<'s, str> { + match self { + TypeDef::Struct(def) => def.plain_name(schema), + TypeDef::Enum(def) => def.plain_name(schema), + TypeDef::Primitive(def) => def.plain_name(schema), + TypeDef::Option(def) => def.plain_name(schema), + TypeDef::Box(def) => def.plain_name(schema), + TypeDef::Vec(def) => def.plain_name(schema), + TypeDef::Cell(def) => def.plain_name(schema), + } + } +} + +macro_rules! impl_deser_name_simple { + ($ty:ident) => { + impl DeserializeFunctionName for $ty { + fn plain_name<'s>(&'s self, _schema: &'s Schema) -> Cow<'s, str> { + Cow::Borrowed(self.name()) + } + } + }; +} + +impl_deser_name_simple!(StructDef); +impl_deser_name_simple!(EnumDef); + +macro_rules! impl_deser_name_concat { + ($ty:ident, $prefix:expr) => { + impl DeserializeFunctionName for $ty { + fn plain_name<'s>(&'s self, schema: &'s Schema) -> Cow<'s, str> { + format_cow!("{}{}", $prefix, self.inner_type(schema).plain_name(schema)) + } + } + }; +} + +impl_deser_name_concat!(OptionDef, "Option"); +impl_deser_name_concat!(BoxDef, "Box"); +impl_deser_name_concat!(VecDef, "Vec"); + +impl DeserializeFunctionName for PrimitiveDef { + fn plain_name<'s>(&'s self, _schema: &'s Schema) -> Cow<'s, str> { + let type_name = self.name(); + if matches!(type_name, "&str" | "Atom") { + // Use 1 deserializer for both `&str` and `Atom` + Cow::Borrowed("Str") + } else if let Some(type_name) = type_name.strip_prefix("NonZero") { + // Use zeroed type's deserializer for `NonZero*` types + Cow::Borrowed(type_name) + } else { + upper_case_first(type_name) + } + } +} + +impl DeserializeFunctionName for CellDef { + fn plain_name<'s>(&'s self, schema: &'s Schema) -> Cow<'s, str> { + // `Cell`s use same deserializer as inner type, as layout is identical + self.inner_type(schema).plain_name(schema) + } +} diff --git a/tasks/ast_tools/src/generators/utf8_to_utf16.rs b/tasks/ast_tools/src/generators/utf8_to_utf16.rs index 68a61de2acd1c..62fd23667dcde 100644 --- a/tasks/ast_tools/src/generators/utf8_to_utf16.rs +++ b/tasks/ast_tools/src/generators/utf8_to_utf16.rs @@ -43,6 +43,9 @@ impl Generator for Utf8ToUtf16ConverterGenerator { fn generate(schema: &Schema, codegen: &Codegen) -> TokenStream { let estree_derive_id = codegen.get_derive_id_by_name("ESTree"); let span_type_id = schema.type_names["Span"]; + + // Types with custom visitors (see comment above). + // Also skip `Comment` because we handle adjusting comment spans separately. let skip_type_ids = [ "ObjectProperty", "BindingProperty", @@ -50,6 +53,7 @@ fn generate(schema: &Schema, codegen: &Codegen) -> TokenStream { "ExportSpecifier", "WithClause", "TemplateLiteral", + "Comment", ] .map(|type_name| schema.type_names[type_name]); @@ -64,8 +68,12 @@ fn generate(schema: &Schema, codegen: &Codegen) -> TokenStream { return None; } - // Skip `oxc_regular_expression` types. They don't appear in ESTree AST. - if struct_def.file(schema).krate() == "oxc_regular_expression" { + // Skip types in `oxc_regular_expression`, `oxc_syntax`, and `napi/parser` crates. + // They don't appear in ESTree AST. + if matches!( + struct_def.file(schema).krate(), + "oxc_regular_expression" | "oxc_syntax" | "napi/parser" + ) { return None; } diff --git a/tasks/ast_tools/src/main.rs b/tasks/ast_tools/src/main.rs index c4a63bea25186..c80a6aac293b9 100644 --- a/tasks/ast_tools/src/main.rs +++ b/tasks/ast_tools/src/main.rs @@ -214,14 +214,17 @@ static SOURCE_PATHS: &[&str] = &[ "crates/oxc_ast/src/ast/comment.rs", "crates/oxc_ast/src/serialize.rs", "crates/oxc_syntax/src/lib.rs", + "crates/oxc_syntax/src/module_record.rs", "crates/oxc_syntax/src/number.rs", "crates/oxc_syntax/src/operator.rs", "crates/oxc_syntax/src/scope.rs", + "crates/oxc_syntax/src/serialize.rs", "crates/oxc_syntax/src/symbol.rs", "crates/oxc_syntax/src/reference.rs", "crates/oxc_span/src/span.rs", "crates/oxc_span/src/source_type/mod.rs", "crates/oxc_regular_expression/src/ast.rs", + "napi/parser/src/raw_transfer_types.rs", ]; /// Path to `oxc_ast` crate @@ -236,6 +239,9 @@ const AST_MACROS_CRATE_PATH: &str = "crates/oxc_ast_macros"; /// Path to write TS type definitions to const TYPESCRIPT_DEFINITIONS_PATH: &str = "npm/oxc-types/types.d.ts"; +/// Path to write raw deserializer to +const RAW_TRANSFER_DESERIALIZER_PATH: &str = "napi/parser/deserialize.js"; + /// Path to write CI filter list to const GITHUB_WATCH_LIST_PATH: &str = ".github/.generated_ast_watch_list.yml"; @@ -257,6 +263,7 @@ const GENERATORS: &[&(dyn Generator + Sync)] = &[ &generators::GetIdGenerator, &generators::VisitGenerator, &generators::Utf8ToUtf16ConverterGenerator, + &generators::RawTransferGenerator, &generators::TypescriptGenerator, ]; diff --git a/tasks/ast_tools/src/schema/extensions/estree.rs b/tasks/ast_tools/src/schema/extensions/estree.rs index d96f19b0b90c1..70dce87dec892 100644 --- a/tasks/ast_tools/src/schema/extensions/estree.rs +++ b/tasks/ast_tools/src/schema/extensions/estree.rs @@ -74,4 +74,6 @@ pub struct ESTreeEnumVariant { #[derive(Default, Debug)] pub struct ESTreeMeta { pub ts_type: Option, + // JS code for raw transfer deserializer + pub raw_deser: Option, } diff --git a/tasks/ast_tools/src/schema/extensions/layout.rs b/tasks/ast_tools/src/schema/extensions/layout.rs index 6102b1ec48f7f..1815e12608c78 100644 --- a/tasks/ast_tools/src/schema/extensions/layout.rs +++ b/tasks/ast_tools/src/schema/extensions/layout.rs @@ -101,7 +101,6 @@ impl Niche { } /// Get value of the [`Niche`]. - #[expect(unused)] pub fn value(&self) -> u128 { // Prefer to consume niches at start of range over end of range if self.count_start > 0 { diff --git a/tasks/ast_tools/src/schema/mod.rs b/tasks/ast_tools/src/schema/mod.rs index 89688e353556d..1febcfdbc17a8 100644 --- a/tasks/ast_tools/src/schema/mod.rs +++ b/tasks/ast_tools/src/schema/mod.rs @@ -64,7 +64,6 @@ impl Schema { /// /// # Panics /// Panics if no type with supplied name. - #[expect(dead_code)] pub fn type_by_name(&self, name: &str) -> &TypeDef { let type_id = self.type_names[name]; &self.types[type_id] diff --git a/tasks/ast_tools/src/utils.rs b/tasks/ast_tools/src/utils.rs index 7f56157b1ffd2..f6903feca38fc 100644 --- a/tasks/ast_tools/src/utils.rs +++ b/tasks/ast_tools/src/utils.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use indexmap::{IndexMap, IndexSet}; use phf::{Set as PhfSet, phf_set}; use proc_macro2::{Span, TokenStream}; @@ -83,6 +85,17 @@ pub fn pluralize(name: &str) -> String { } } +/// Upper case first character of a string. +pub fn upper_case_first(s: &str) -> Cow<'_, str> { + let mut chars = s.chars(); + let first_char = chars.next().unwrap(); + if first_char.is_uppercase() { + Cow::Borrowed(s) + } else { + Cow::Owned(first_char.to_uppercase().chain(chars).collect::()) + } +} + /// Macro to `format!` arguments, and wrap the formatted string in a `Cow::Owned`. macro_rules! format_cow { ($($tokens:tt)+) => {