oxc_ast/ast/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
//! 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,
//! into_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.
pub(crate) mod comment;
pub(crate) mod js;
pub(crate) mod jsx;
pub(crate) mod literal;
pub(crate) mod macros;
pub(crate) mod ts;
use macros::inherit_variants;
// Re-export AST types from other crates
pub use oxc_span::{Atom, Language, LanguageVariant, ModuleKind, SourceType, Span};
pub use oxc_syntax::{
number::{BigintBase, NumberBase},
operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
},
};
pub use self::{comment::*, js::*, jsx::*, literal::*, ts::*};