mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
docs(ast): document enum inheritance (#3192)
Add more docs for AST type enum inheritance and the `inherit_variants!` macro. This covers the changes made in #3115.
This commit is contained in:
parent
82bd97d420
commit
c6bd616456
5 changed files with 235 additions and 16 deletions
|
|
@ -69,7 +69,9 @@ impl<'a> Program<'a> {
|
|||
inherit_variants! {
|
||||
/// Expression
|
||||
///
|
||||
/// Inherits variants from [`MemberExpression`].
|
||||
/// Inherits variants from [`MemberExpression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -505,7 +507,9 @@ pub struct ArrayExpression<'a> {
|
|||
inherit_variants! {
|
||||
/// Array Expression Element
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -583,7 +587,9 @@ pub struct ObjectProperty<'a> {
|
|||
inherit_variants! {
|
||||
/// Property Key
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -973,7 +979,9 @@ pub struct SpreadElement<'a> {
|
|||
inherit_variants! {
|
||||
/// Argument
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1086,6 +1094,9 @@ inherit_variants! {
|
|||
/// Destructuring Assignment
|
||||
///
|
||||
/// Inherits variants from [`SimpleAssignmentTarget`] and [`AssignmentTargetPattern`].
|
||||
/// See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1121,7 +1132,9 @@ pub use match_assignment_target;
|
|||
inherit_variants! {
|
||||
/// Simple Assignment Target
|
||||
///
|
||||
/// Inherits variants from [`MemberExpression`].
|
||||
/// Inherits variants from [`MemberExpression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1262,7 +1275,9 @@ pub struct AssignmentTargetRest<'a> {
|
|||
inherit_variants! {
|
||||
/// Assignment Target Maybe Default
|
||||
///
|
||||
/// Inherits variants from [`AssignmentTarget`].
|
||||
/// Inherits variants from [`AssignmentTarget`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1379,7 +1394,9 @@ pub struct ChainExpression<'a> {
|
|||
inherit_variants! {
|
||||
/// Chain Element
|
||||
///
|
||||
/// Inherits variants from [`MemberExpression`].
|
||||
/// Inherits variants from [`MemberExpression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1407,6 +1424,9 @@ inherit_variants! {
|
|||
/// Statement
|
||||
///
|
||||
/// Inherits variants from [`Declaration`] and [`ModuleDeclaration`].
|
||||
/// See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1722,7 +1742,9 @@ pub struct ForStatement<'a> {
|
|||
inherit_variants! {
|
||||
/// For Statement Init
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1774,7 +1796,9 @@ pub struct ForOfStatement<'a> {
|
|||
inherit_variants! {
|
||||
/// For Statement Left
|
||||
///
|
||||
/// Inherits variants from [`AssignmentTarget`].
|
||||
/// Inherits variants from [`AssignmentTarget`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -2854,7 +2878,9 @@ impl<'a> ExportSpecifier<'a> {
|
|||
inherit_variants! {
|
||||
/// Export Default Declaration Kind
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
|
|||
|
|
@ -162,7 +162,9 @@ pub struct JSXExpressionContainer<'a> {
|
|||
inherit_variants! {
|
||||
/// JSX Expression
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
/// Macro to inherit enum variants from another enum.
|
||||
///
|
||||
/// (for further details see <https://github.com/oxc-project/oxc/pull/3115>)
|
||||
///
|
||||
/// # Types which can be inherited
|
||||
///
|
||||
/// The following types' variants can be inherited:
|
||||
///
|
||||
/// * `Expression`
|
||||
/// * `MemberExpression`
|
||||
/// * `AssignmentTarget`
|
||||
|
|
@ -11,6 +16,8 @@
|
|||
/// * `TSType`
|
||||
/// * `TSTypeName`
|
||||
///
|
||||
/// # Expansion
|
||||
///
|
||||
/// ```
|
||||
/// inherit_variants! {
|
||||
/// #[repr(C, u8)]
|
||||
|
|
@ -240,12 +247,15 @@ macro_rules! inherit_variants {
|
|||
$($(#[$variant_attr])* $variant_name($variant_type) = $variant_discrim,)*
|
||||
|
||||
/// Inherited from [`MemberExpression`].
|
||||
///
|
||||
/// `MemberExpression[?Yield, ?Await] [ Expression[+In, ?Yield, ?Await] ]`
|
||||
ComputedMemberExpression(Box<'a, ComputedMemberExpression<'a>>) = 48,
|
||||
/// Inherited from [`MemberExpression`].
|
||||
///
|
||||
/// `MemberExpression[?Yield, ?Await] . IdentifierName`
|
||||
StaticMemberExpression(Box<'a, StaticMemberExpression<'a>>) = 49,
|
||||
/// Inherited from [`MemberExpression`].
|
||||
///
|
||||
/// `MemberExpression[?Yield, ?Await] . PrivateIdentifier`
|
||||
PrivateFieldExpression(Box<'a, PrivateFieldExpression<'a>>) = 50,
|
||||
|
||||
|
|
@ -712,7 +722,8 @@ pub(crate) use inherit_variants;
|
|||
/// # SAFETY
|
||||
/// Both enums must be `#[repr(C, u8)]` or using this macro is unsound.
|
||||
///
|
||||
/// # Example
|
||||
/// # Expansion
|
||||
///
|
||||
/// NB: For illustration only - `Statement` and `Declaration` in reality share 9 variants, not 2.
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -1,4 +1,176 @@
|
|||
//! AST Definitions
|
||||
//!
|
||||
//! # Enum inheritance
|
||||
//!
|
||||
//! Some enum AST types inherit variants from other enums using the `inherit_variants!` macro.
|
||||
//!
|
||||
//! "Inherit" means: If `enum Y` inherits the variants of `enum X`,
|
||||
//! then all `X`'s variants are duplicated as variants of `Y`.
|
||||
//!
|
||||
//! This is mainly an explanation of the consumer-facing API. For further details on implementation,
|
||||
//! see comments in `src/ast/macros.rs`.
|
||||
//!
|
||||
//! ## Defining enum inheritance
|
||||
//!
|
||||
//! Instead of nested enums:
|
||||
//!
|
||||
//! ```
|
||||
//! pub enum Expression<'a> {
|
||||
//! BooleanLiteral(Box<'a, BooleanLiteral>),
|
||||
//! NullLiteral(Box<'a, NullLiteral>),
|
||||
//! // ...more variants
|
||||
//! MemberExpression(MemberExpression<'a>),
|
||||
//! }
|
||||
//!
|
||||
//! pub enum MemberExpression<'a> {
|
||||
//! ComputedMemberExpression(Box<'a, ComputedMemberExpression<'a>>),
|
||||
//! StaticMemberExpression(Box<'a, StaticMemberExpression<'a>>),
|
||||
//! PrivateFieldExpression(Box<'a, PrivateFieldExpression<'a>>),
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! We define the types using `inherit_variants!` macro:
|
||||
//!
|
||||
//! ```
|
||||
//! inherit_variants! {
|
||||
//! #[repr(C, u8)]
|
||||
//! pub enum Expression<'a> {
|
||||
//! BooleanLiteral(Box<'a, BooleanLiteral>) = 0,
|
||||
//! NullLiteral(Box<'a, NullLiteral>) = 1,
|
||||
//! // ...more variants
|
||||
//! @inherit MemberExpression,
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
//! #[repr(C, u8)]
|
||||
//! pub enum MemberExpression<'a> {
|
||||
//! ComputedMemberExpression(Box<'a, ComputedMemberExpression<'a>>) = 48,
|
||||
//! StaticMemberExpression(Box<'a, StaticMemberExpression<'a>>) = 49,
|
||||
//! PrivateFieldExpression(Box<'a, PrivateFieldExpression<'a>>) = 50,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! `inherit_variants!` macro expands `Expression` to:
|
||||
//!
|
||||
//! ```
|
||||
//! #[repr(C, u8)]
|
||||
//! pub enum Expression<'a> {
|
||||
//! BooleanLiteral(Box<'a, BooleanLiteral>) = 0,
|
||||
//! NullLiteral(Box<'a, NullLiteral>) = 1,
|
||||
//! // ...more variants
|
||||
//!
|
||||
//! // Inherited from `MemberExpression`
|
||||
//! ComputedMemberExpression(Box<'a, ComputedMemberExpression<'a>>) = 48,
|
||||
//! StaticMemberExpression(Box<'a, StaticMemberExpression<'a>>) = 49,
|
||||
//! PrivateFieldExpression(Box<'a, PrivateFieldExpression<'a>>) = 50,
|
||||
//! }
|
||||
//!
|
||||
//! shared_enum_variants!(
|
||||
//! Expression, MemberExpression,
|
||||
//! is_member_expression,
|
||||
//! as_member_expression, as_member_expression_mut,
|
||||
//! to_member_expression, to_member_expression_mut,
|
||||
//! [ComputedMemberExpression, StaticMemberExpression, PrivateFieldExpression]
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! See `src/ast/macros.rs` for what `shared_enum_variants!` macro expands to.
|
||||
//! It provides the APIs listed below.
|
||||
//!
|
||||
//! ## Using inherited variants
|
||||
//!
|
||||
//! #### Creation
|
||||
//!
|
||||
//! ```
|
||||
//! // Old
|
||||
//! let expr = Expression::MemberExpression(
|
||||
//! MemberExpression::ComputedMemberExpression(computed_member_expr)
|
||||
//! );
|
||||
//!
|
||||
//! // New
|
||||
//! let expr = Expression::ComputedMemberExpression(computed_member_expr);
|
||||
//! ```
|
||||
//!
|
||||
//! #### Conversion
|
||||
//!
|
||||
//! ```
|
||||
//! // Old
|
||||
//! let expr = Expression::MemberExpression(member_expr);
|
||||
//!
|
||||
//! // New
|
||||
//! let expr = Expression::from(member_expr);
|
||||
//! ```
|
||||
//!
|
||||
//! ```
|
||||
//! // Old
|
||||
//! let maybe_member_expr = match expr {
|
||||
//! Expression::MemberExpression(member_expr) => Some(member_expr),
|
||||
//! _ => None,
|
||||
//! };
|
||||
//!
|
||||
//! // New
|
||||
//! let maybe_member_expr = MemberExpression::try_from(expr).ok();
|
||||
//! ```
|
||||
//!
|
||||
//! #### Testing
|
||||
//!
|
||||
//! ```
|
||||
//! // Old
|
||||
//! if matches!(expr, Expression::MemberExpression(_)) { }
|
||||
//!
|
||||
//! // New
|
||||
//! if expr.is_member_expression() { }
|
||||
//! // or
|
||||
//! if matches!(expr, match_member_expression!(Expression)) { }
|
||||
//! ```
|
||||
//!
|
||||
//! #### Branching
|
||||
//!
|
||||
//! ```
|
||||
//! // Old
|
||||
//! if let Expression::MemberExpression(member_expr) = &expr { }
|
||||
//!
|
||||
//! // New
|
||||
//! if let Some(member_expr) = expr.as_member_expression() { }
|
||||
//! ```
|
||||
//!
|
||||
//! #### Matching
|
||||
//!
|
||||
//! ```
|
||||
//! // Old
|
||||
//! match get_expression() {
|
||||
//! Expression::MemberExpression(member_expr) => visitor.visit(member_expr),
|
||||
//! }
|
||||
//!
|
||||
//! // New (exhaustive match)
|
||||
//! match get_expression() {
|
||||
//! expr @ match_member_expression!(Expression) => visitor.visit(expr.to_member_expression()),
|
||||
//! }
|
||||
//!
|
||||
//! // New (alternative)
|
||||
//! match get_expression() {
|
||||
//! expr if expr.is_member_expression() => visitor.visit(expr.to_member_expression()),
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! ## Why `#[repr(C, u8)]` on enums?
|
||||
//!
|
||||
//! `#[repr(C, u8)]` allows us to define the discriminants for variants in both the "inherited"
|
||||
//! and "inheritee" enums.
|
||||
//!
|
||||
//! The discriminants and "payloads" match between the 2 types for the inherited variants.
|
||||
//! Therefore `MemberExpression::ComputedMemberExpression` and `Expression::ComputedMemberExpression`
|
||||
//! have identical representations in memory, and a `MemberExpression` can be converted to an
|
||||
//! `Expression` with a zero-cost transmute.
|
||||
//!
|
||||
//! The APIs listed above use this property.
|
||||
//!
|
||||
//! It is **essential** that the discriminants and "payload" types match between the "inherited"
|
||||
//! and "inheritee" types, or using the APIs below would be instant UB.
|
||||
//! The `shared_enum_variants!` macro generates const assertions to ensure
|
||||
//! these invariants are upheld, and it will be caught at compile time if they don't.
|
||||
//!
|
||||
//! If you are seeing compile-time errors in `src/ast/macros.rs`, this will be the cause.
|
||||
|
||||
mod js;
|
||||
mod jsx;
|
||||
|
|
|
|||
|
|
@ -70,7 +70,9 @@ pub struct TSEnumMember<'a> {
|
|||
inherit_variants! {
|
||||
/// TS Enum Member Name
|
||||
///
|
||||
/// Inherits variants from [`Expression`].
|
||||
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -368,7 +370,9 @@ pub struct TSRestType<'a> {
|
|||
inherit_variants! {
|
||||
/// TS Tuple Element
|
||||
///
|
||||
/// Inherits variants from [`TSType`].
|
||||
/// Inherits variants from [`TSType`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -918,7 +922,9 @@ pub struct TSTypeQuery<'a> {
|
|||
inherit_variants! {
|
||||
/// TS Type Query Expr Name
|
||||
///
|
||||
/// Inherits variants from [`TSTypeName`].
|
||||
/// Inherits variants from [`TSTypeName`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
@ -1085,7 +1091,9 @@ pub struct TSImportEqualsDeclaration<'a> {
|
|||
inherit_variants! {
|
||||
/// TS Module Reference
|
||||
///
|
||||
/// Inherits variants from [`TSTypeName`].
|
||||
/// Inherits variants from [`TSTypeName`]. See [`ast` module docs] for explanation of inheritance.
|
||||
///
|
||||
/// [`ast` module docs]: `super`
|
||||
#[visited_node]
|
||||
#[repr(C, u8)]
|
||||
#[derive(Debug, Hash)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue