Skip to content

Commit 294664d

Browse files
Cameron McHenrycamchenry
authored andcommitted
refactor(ast): add AstKind for StaticMemberExpression
1 parent 190e390 commit 294664d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+722
-617
lines changed

crates/oxc_ast/src/ast_impl/js.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ impl<'a> MemberExpression<'a> {
594594
/// - `a.b` would return `Some("b")`
595595
/// - `a["b"]` would return `Some("b")`
596596
/// - `a[b]` would return `None`
597-
/// - `a.#b` would return `Some("b")`
597+
/// - `a.#b` would return `None`
598598
pub fn static_property_name(&self) -> Option<&'a str> {
599599
match self {
600600
MemberExpression::ComputedMemberExpression(expr) => {
@@ -702,6 +702,12 @@ impl<'a> StaticMemberExpression<'a> {
702702
return object;
703703
}
704704
}
705+
706+
/// Returns the static property name of this static member expression, if it has one, along with the source code [`Span`],
707+
/// or `None` otherwise.
708+
pub fn static_property_info(&self) -> (Span, &'a str) {
709+
(self.property.span, self.property.name.as_str())
710+
}
705711
}
706712

707713
impl<'a> ChainElement<'a> {

crates/oxc_ast/src/ast_kind_impl.rs

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![expect(missing_docs)] // FIXME
2-
use oxc_span::Atom;
2+
use oxc_span::{Atom, GetSpan};
33

44
use super::{AstKind, ast::*};
55

@@ -81,6 +81,28 @@ impl<'a> AstKind<'a> {
8181
}
8282
}
8383

84+
/// Returns whether this expression is a member expression, such as `obj.prop`, `obj["prop"]`, or `obj.#prop`.
85+
pub fn is_member_expression_kind(&self) -> bool {
86+
self.as_member_expression_kind().is_some()
87+
}
88+
89+
/// If this is some kind of member expression, returns it as a
90+
/// [`MemberExpressionKind`]. Otherwise, returns `None`.
91+
pub fn as_member_expression_kind(&self) -> Option<MemberExpressionKind<'a>> {
92+
match self {
93+
Self::ComputedMemberExpression(member_expr) => {
94+
Some(MemberExpressionKind::Computed(member_expr))
95+
}
96+
Self::StaticMemberExpression(member_expr) => {
97+
Some(MemberExpressionKind::Static(member_expr))
98+
}
99+
Self::PrivateFieldExpression(member_expr) => {
100+
Some(MemberExpressionKind::PrivateField(member_expr))
101+
}
102+
_ => None,
103+
}
104+
}
105+
84106
pub fn from_expression(e: &'a Expression<'a>) -> Self {
85107
match e {
86108
Expression::BooleanLiteral(e) => Self::BooleanLiteral(e),
@@ -101,16 +123,16 @@ impl<'a> AstKind<'a> {
101123
Expression::CallExpression(e) => Self::CallExpression(e),
102124
Expression::ChainExpression(e) => Self::ChainExpression(e),
103125
Expression::ClassExpression(e) => Self::Class(e),
126+
Expression::ComputedMemberExpression(e) => Self::ComputedMemberExpression(e),
104127
Expression::ConditionalExpression(e) => Self::ConditionalExpression(e),
105128
Expression::FunctionExpression(e) => Self::Function(e),
106129
Expression::ImportExpression(e) => Self::ImportExpression(e),
107130
Expression::LogicalExpression(e) => Self::LogicalExpression(e),
108-
match_member_expression!(Expression) => {
109-
Self::MemberExpression(e.to_member_expression())
110-
}
111131
Expression::NewExpression(e) => Self::NewExpression(e),
112132
Expression::ObjectExpression(e) => Self::ObjectExpression(e),
113133
Expression::ParenthesizedExpression(e) => Self::ParenthesizedExpression(e),
134+
Expression::PrivateFieldExpression(e) => Self::PrivateFieldExpression(e),
135+
Expression::StaticMemberExpression(e) => Self::StaticMemberExpression(e),
114136
Expression::SequenceExpression(e) => Self::SequenceExpression(e),
115137
Expression::TaggedTemplateExpression(e) => Self::TaggedTemplateExpression(e),
116138
Expression::ThisExpression(e) => Self::ThisExpression(e),
@@ -220,7 +242,6 @@ impl AstKind<'_> {
220242
Self::ComputedMemberExpression(_) => "ComputedMemberExpression".into(),
221243
Self::ConditionalExpression(_) => "ConditionalExpression".into(),
222244
Self::LogicalExpression(_) => "LogicalExpression".into(),
223-
Self::MemberExpression(_) => "MemberExpression".into(),
224245
Self::NewExpression(n) => {
225246
let callee = match &n.callee {
226247
Expression::Identifier(id) => Some(id.name.as_str()),
@@ -233,6 +254,8 @@ impl AstKind<'_> {
233254
}
234255
Self::ObjectExpression(_) => "ObjectExpression".into(),
235256
Self::ParenthesizedExpression(_) => "ParenthesizedExpression".into(),
257+
Self::PrivateFieldExpression(_) => "PrivateFieldExpression".into(),
258+
Self::StaticMemberExpression(_) => "StaticMemberExpression".into(),
236259
Self::SequenceExpression(_) => "SequenceExpression".into(),
237260
Self::TaggedTemplateExpression(_) => "TaggedTemplateExpression".into(),
238261
Self::ThisExpression(_) => "ThisExpression".into(),
@@ -388,3 +411,64 @@ impl AstKind<'_> {
388411
}
389412
}
390413
}
414+
415+
/// This is a subset of [`AstKind`] that represents member expressions.
416+
///
417+
/// Having a separate enum for this allows us to implement helpful methods that are specific to member expressions,
418+
/// such as getting the property name or the object of the member expression.
419+
pub enum MemberExpressionKind<'a> {
420+
/// A static member expression, such as `obj.prop`.
421+
Static(&'a StaticMemberExpression<'a>),
422+
/// A computed member expression, such as `obj["prop"]`.
423+
Computed(&'a ComputedMemberExpression<'a>),
424+
/// A private field expression, such as `obj.#field`.
425+
PrivateField(&'a PrivateFieldExpression<'a>),
426+
}
427+
428+
impl<'a> MemberExpressionKind<'a> {
429+
/// Returns the property name of the member expression, otherwise `None`.
430+
///
431+
/// Example: returns the `prop` in `obj.prop` or `obj["prop"]`.
432+
pub fn static_property_name(&self) -> Option<Atom<'a>> {
433+
match self {
434+
Self::Computed(member_expr) => member_expr.static_property_name(),
435+
Self::Static(member_expr) => Some(member_expr.property.name),
436+
Self::PrivateField(_) => None,
437+
}
438+
}
439+
440+
/// Returns the object of the member expression, otherwise `None`.
441+
///
442+
/// Example: returns the `obj` in `obj.prop` or `obj["prop"]`.
443+
pub fn object(&self) -> &Expression<'a> {
444+
match self {
445+
Self::Computed(member_expr) => &member_expr.object,
446+
Self::Static(member_expr) => &member_expr.object,
447+
Self::PrivateField(member_expr) => &member_expr.object,
448+
}
449+
}
450+
451+
/// Returns whether the member expression is optional, i.e. if it uses the
452+
/// optional chaining operator (`?.`).
453+
///
454+
/// Example:
455+
/// - Returns `true` for `obj?.prop` or `obj?.["prop"]`.
456+
/// - Returns `false` for `obj.prop` or `obj["prop"]`.
457+
pub fn optional(&self) -> bool {
458+
match self {
459+
Self::Computed(member_expr) => member_expr.optional,
460+
Self::Static(member_expr) => member_expr.optional,
461+
Self::PrivateField(member_expr) => member_expr.optional,
462+
}
463+
}
464+
}
465+
466+
impl GetSpan for MemberExpressionKind<'_> {
467+
fn span(&self) -> Span {
468+
match self {
469+
Self::Computed(member_expr) => member_expr.span,
470+
Self::Static(member_expr) => member_expr.span,
471+
Self::PrivateField(member_expr) => member_expr.span,
472+
}
473+
}
474+
}

0 commit comments

Comments
 (0)