Skip to main content

oxc_parser/embedding/
projection.rs

1//! Move an authenticated selected header into its original arena, once.
2
3use oxc_ast::ast::{Expression, FormalParameters, FunctionBody, Statement};
4use oxc_diagnostics::Diagnostics;
5use oxc_span::{GetSpan, SourceType, Span};
6
7use super::{EmbeddingGoal, EmbeddingHole, EmbeddingObservation};
8use crate::ParseOptions;
9
10macro_rules! projection {
11    ($owner:ident, $proof:ident, $root:ty, $accessor:ident) => {
12        /// An ordinarily owned complete parser observation and selected arena root.
13        pub struct $owner<'a> {
14            observation: EmbeddingObservation<'a>,
15            root: Option<&'a $root>,
16        }
17        impl core::fmt::Debug for $owner<'_> {
18            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
19                f.debug_tuple(stringify!($owner)).field(&self.observation).finish()
20            }
21        }
22        /// A short private-origin borrow; raw ASTs and numeric windows cannot mint it.
23        pub struct $proof<'p, 'a> {
24            owner: &'p $owner<'a>,
25            root: &'a $root,
26        }
27        impl<'a> $owner<'a> {
28            #[must_use]
29            pub fn admitted(&self) -> Option<$proof<'_, 'a>> {
30                self.root
31                    .filter(|_| self.observation.hole.is_none())
32                    .map(|root| $proof { owner: self, root })
33            }
34            #[must_use]
35            pub const fn hole(&self) -> Option<EmbeddingHole> {
36                self.observation.hole
37            }
38            #[must_use]
39            pub fn diagnostics(&self) -> &Diagnostics {
40                self.observation.diagnostics()
41            }
42            #[must_use]
43            pub fn comments(&self) -> &[oxc_ast::ast::Comment] {
44                self.observation.comments()
45            }
46            #[must_use]
47            pub const fn content(&self) -> &'a str {
48                self.observation.content
49            }
50            #[must_use]
51            pub const fn source_type(&self) -> SourceType {
52                self.observation.source_type
53            }
54            #[must_use]
55            pub const fn parser_content_span(&self) -> Span {
56                self.observation.content_span
57            }
58        }
59        impl<'p, 'a> $proof<'p, 'a> {
60            #[must_use]
61            pub const fn $accessor(&self) -> &'a $root {
62                self.root
63            }
64            #[must_use]
65            pub const fn content(&self) -> &'a str {
66                self.owner.observation.content
67            }
68            #[must_use]
69            pub const fn parser_content_span(&self) -> Span {
70                self.owner.observation.content_span
71            }
72            #[must_use]
73            pub fn parser_container_span(&self) -> Span {
74                self.root.span()
75            }
76            #[must_use]
77            pub const fn source_type(&self) -> SourceType {
78                self.owner.observation.source_type
79            }
80            #[must_use]
81            pub const fn options(&self) -> ParseOptions {
82                self.owner.observation.options
83            }
84        }
85    };
86}
87
88projection!(ExpressionObservation, AdmittedExpression, Expression<'a>, expression);
89projection!(HandlerBodyObservation, AdmittedHandlerBody, FunctionBody<'a>, body);
90projection!(ParametersObservation, AdmittedParameters, FormalParameters<'a>, parameters);
91
92impl<'a> EmbeddingObservation<'a> {
93    /// Consumption uses only the original stored arena, not a caller arena.
94    ///
95    /// ```compile_fail,E0061
96    /// use oxc_allocator::Allocator;
97    /// use oxc_parser::EmbeddingObservation;
98    /// fn substitute<'a>(owner: EmbeddingObservation<'a>, other: &'a Allocator) {
99    ///     owner.into_expression(other);
100    /// }
101    /// ```
102    ///
103    /// ```compile_fail,E0451
104    /// use oxc_ast::ast::Expression;
105    /// use oxc_parser::{AdmittedExpression, ExpressionObservation};
106    /// fn forge<'p, 'a>(owner: &'p ExpressionObservation<'a>, root: &'a Expression<'a>) -> AdmittedExpression<'p, 'a> {
107    ///     AdmittedExpression { owner, root }
108    /// }
109    /// ```
110    pub fn into_expression(mut self) -> Result<ExpressionObservation<'a>, Box<Self>> {
111        if self.goal != EmbeddingGoal::Expr {
112            return Err(Box::new(self));
113        }
114        let root = if self.hole.is_none()
115            && let Some(Statement::ExpressionStatement(statement)) = self.parsed.program.body.pop()
116            && let Expression::ParenthesizedExpression(wrapper) = statement.unbox().expression
117        {
118            Some(&*self.allocator.alloc(wrapper.unbox().expression))
119        } else {
120            None
121        };
122        if self.hole.is_none() && root.is_none() {
123            self.hole = Some(EmbeddingHole::InvalidExpressionShape);
124        }
125        Ok(ExpressionObservation { observation: self, root })
126    }
127
128    /// Raw FunctionBody roots cannot mint original-parser authority.
129    ///
130    /// ```compile_fail,E0451
131    /// use oxc_ast::ast::FunctionBody;
132    /// use oxc_parser::{AdmittedHandlerBody, HandlerBodyObservation};
133    /// fn forge<'p, 'a>(owner: &'p HandlerBodyObservation<'a>, root: &'a FunctionBody<'a>) -> AdmittedHandlerBody<'p, 'a> {
134    ///     AdmittedHandlerBody { owner, root }
135    /// }
136    /// ```
137    ///
138    /// ```compile_fail,E0308
139    /// use oxc_ast::ast::FunctionBody;
140    /// use oxc_parser::AdmittedHandlerBody;
141    /// fn mutate<'p, 'a>(token: AdmittedHandlerBody<'p, 'a>) -> &'a mut FunctionBody<'a> {
142    ///     token.body()
143    /// }
144    /// ```
145    pub fn into_handler_body(mut self) -> Result<HandlerBodyObservation<'a>, Box<Self>> {
146        if self.goal != EmbeddingGoal::HandlerBody {
147            return Err(Box::new(self));
148        }
149        let root = if self.hole.is_none()
150            && let Some(Statement::ExpressionStatement(statement)) = self.parsed.program.body.pop()
151            && let Expression::ArrowFunctionExpression(arrow) = statement.unbox().expression
152        {
153            Some(&*self.allocator.alloc(arrow.unbox().body.unbox()))
154        } else {
155            None
156        };
157        if self.hole.is_none() && root.is_none() {
158            self.hole = Some(EmbeddingHole::InvalidWrappedShape);
159        }
160        Ok(HandlerBodyObservation { observation: self, root })
161    }
162
163    /// Raw formal parameters cannot replace the original selected owner.
164    ///
165    /// ```compile_fail,E0451
166    /// use oxc_ast::ast::FormalParameters;
167    /// use oxc_parser::{AdmittedParameters, ParametersObservation};
168    /// fn forge<'p, 'a>(owner: &'p ParametersObservation<'a>, root: &'a FormalParameters<'a>) -> AdmittedParameters<'p, 'a> {
169    ///     AdmittedParameters { owner, root }
170    /// }
171    /// ```
172    pub fn into_parameters(mut self) -> Result<ParametersObservation<'a>, Box<Self>> {
173        if self.goal != EmbeddingGoal::Parameters {
174            return Err(Box::new(self));
175        }
176        let root = if self.hole.is_none()
177            && let Some(Statement::ExpressionStatement(statement)) = self.parsed.program.body.pop()
178            && let Expression::ArrowFunctionExpression(arrow) = statement.unbox().expression
179        {
180            Some(&*self.allocator.alloc(arrow.unbox().params.unbox()))
181        } else {
182            None
183        };
184        if self.hole.is_none() && root.is_none() {
185            self.hole = Some(EmbeddingHole::InvalidWrappedShape);
186        }
187        Ok(ParametersObservation { observation: self, root })
188    }
189}