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
194
195
196
197
198
199
200
//! Move an authenticated selected header into its original arena, once.
use oxc_ast::ast::{Expression, FormalParameters, FunctionBody, Statement};
use oxc_diagnostics::Diagnostics;
use oxc_span::{GetSpan, SourceType, Span};
use super::{EmbeddingGoal, EmbeddingHole, EmbeddingObservation};
use crate::ParseOptions;
macro_rules! projection {
($owner:ident, $proof:ident, $root:ty, $accessor:ident) => {
/// An ordinarily owned complete parser observation and selected arena root.
pub struct $owner<'a> {
observation: EmbeddingObservation<'a>,
root: Option<&'a $root>,
}
impl core::fmt::Debug for $owner<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple(stringify!($owner)).field(&self.observation).finish()
}
}
/// A short private-origin borrow; raw ASTs and numeric windows cannot mint it.
pub struct $proof<'p, 'a> {
owner: &'p $owner<'a>,
root: &'a $root,
}
impl<'a> $owner<'a> {
#[must_use]
pub fn admitted(&self) -> Option<$proof<'_, 'a>> {
self.root
.filter(|_| self.observation.hole.is_none())
.map(|root| $proof { owner: self, root })
}
#[must_use]
pub const fn hole(&self) -> Option<EmbeddingHole> {
self.observation.hole
}
#[must_use]
pub fn diagnostics(&self) -> &Diagnostics {
self.observation.diagnostics()
}
#[must_use]
pub fn comments(&self) -> &[oxc_ast::ast::Comment] {
self.observation.comments()
}
#[must_use]
pub const fn content(&self) -> &'a str {
self.observation.content
}
#[must_use]
pub const fn source_type(&self) -> SourceType {
self.observation.source_type
}
#[must_use]
pub const fn parser_content_span(&self) -> Span {
self.observation.content_span
}
}
impl<'p, 'a> $proof<'p, 'a> {
#[must_use]
pub const fn $accessor(&self) -> &'a $root {
self.root
}
#[must_use]
pub const fn content(&self) -> &'a str {
self.owner.observation.content
}
#[must_use]
pub const fn parser_content_span(&self) -> Span {
self.owner.observation.content_span
}
#[must_use]
pub fn parser_container_span(&self) -> Span {
self.root.span()
}
#[must_use]
pub const fn source_type(&self) -> SourceType {
self.owner.observation.source_type
}
#[must_use]
pub const fn options(&self) -> ParseOptions {
self.owner.observation.options
}
}
};
}
projection!(ExpressionObservation, AdmittedExpression, Expression<'a>, expression);
projection!(HandlerBodyObservation, AdmittedHandlerBody, FunctionBody<'a>, body);
projection!(ParametersObservation, AdmittedParameters, FormalParameters<'a>, parameters);
impl AdmittedExpression<'_, '_> {
/// Whether the original stock lexer decoded a legacy numeric literal or
/// string escape forbidden in a strict module. This borrows the complete
/// original parser observation; it adds no parse or source/AST scan.
/// Syntax admission is unchanged, and false does not certify semantics.
#[must_use]
pub const fn has_legacy_literals(&self) -> bool {
self.owner.observation.parsed.has_legacy_literals
}
}
impl<'a> EmbeddingObservation<'a> {
/// Consumption uses only the original stored arena, not a caller arena.
///
/// ```compile_fail,E0061
/// use oxc_allocator::Allocator;
/// use oxc_parser::EmbeddingObservation;
/// fn substitute<'a>(owner: EmbeddingObservation<'a>, other: &'a Allocator) {
/// owner.into_expression(other);
/// }
/// ```
///
/// ```compile_fail,E0451
/// use oxc_ast::ast::Expression;
/// use oxc_parser::{AdmittedExpression, ExpressionObservation};
/// fn forge<'p, 'a>(owner: &'p ExpressionObservation<'a>, root: &'a Expression<'a>) -> AdmittedExpression<'p, 'a> {
/// AdmittedExpression { owner, root }
/// }
/// ```
pub fn into_expression(mut self) -> Result<ExpressionObservation<'a>, Box<Self>> {
if self.goal != EmbeddingGoal::Expr {
return Err(Box::new(self));
}
let root = if self.hole.is_none()
&& let Some(Statement::ExpressionStatement(statement)) = self.parsed.program.body.pop()
&& let Expression::ParenthesizedExpression(wrapper) = statement.unbox().expression
{
Some(&*self.allocator.alloc(wrapper.unbox().expression))
} else {
None
};
if self.hole.is_none() && root.is_none() {
self.hole = Some(EmbeddingHole::InvalidExpressionShape);
}
Ok(ExpressionObservation { observation: self, root })
}
/// Raw FunctionBody roots cannot mint original-parser authority.
///
/// ```compile_fail,E0451
/// use oxc_ast::ast::FunctionBody;
/// use oxc_parser::{AdmittedHandlerBody, HandlerBodyObservation};
/// fn forge<'p, 'a>(owner: &'p HandlerBodyObservation<'a>, root: &'a FunctionBody<'a>) -> AdmittedHandlerBody<'p, 'a> {
/// AdmittedHandlerBody { owner, root }
/// }
/// ```
///
/// ```compile_fail,E0308
/// use oxc_ast::ast::FunctionBody;
/// use oxc_parser::AdmittedHandlerBody;
/// fn mutate<'p, 'a>(token: AdmittedHandlerBody<'p, 'a>) -> &'a mut FunctionBody<'a> {
/// token.body()
/// }
/// ```
pub fn into_handler_body(mut self) -> Result<HandlerBodyObservation<'a>, Box<Self>> {
if self.goal != EmbeddingGoal::HandlerBody {
return Err(Box::new(self));
}
let root = if self.hole.is_none()
&& let Some(Statement::ExpressionStatement(statement)) = self.parsed.program.body.pop()
&& let Expression::ArrowFunctionExpression(arrow) = statement.unbox().expression
{
Some(&*self.allocator.alloc(arrow.unbox().body.unbox()))
} else {
None
};
if self.hole.is_none() && root.is_none() {
self.hole = Some(EmbeddingHole::InvalidWrappedShape);
}
Ok(HandlerBodyObservation { observation: self, root })
}
/// Raw formal parameters cannot replace the original selected owner.
///
/// ```compile_fail,E0451
/// use oxc_ast::ast::FormalParameters;
/// use oxc_parser::{AdmittedParameters, ParametersObservation};
/// fn forge<'p, 'a>(owner: &'p ParametersObservation<'a>, root: &'a FormalParameters<'a>) -> AdmittedParameters<'p, 'a> {
/// AdmittedParameters { owner, root }
/// }
/// ```
pub fn into_parameters(mut self) -> Result<ParametersObservation<'a>, Box<Self>> {
if self.goal != EmbeddingGoal::Parameters {
return Err(Box::new(self));
}
let root = if self.hole.is_none()
&& let Some(Statement::ExpressionStatement(statement)) = self.parsed.program.body.pop()
&& let Expression::ArrowFunctionExpression(arrow) = statement.unbox().expression
{
Some(&*self.allocator.alloc(arrow.unbox().params.unbox()))
} else {
None
};
if self.hole.is_none() && root.is_none() {
self.hole = Some(EmbeddingHole::InvalidWrappedShape);
}
Ok(ParametersObservation { observation: self, root })
}
}