Skip to main content

react_compiler_ast/
statements.rs

1use serde::Serialize;
2use serde::Serializer;
3
4use crate::common::BaseNode;
5use crate::common::RawNode;
6use crate::expressions::Expression;
7use crate::expressions::Identifier;
8use crate::patterns::PatternLike;
9
10fn is_false(v: &bool) -> bool {
11    !v
12}
13
14#[derive(Debug, Clone, Serialize)]
15#[serde(tag = "type")]
16pub enum Statement {
17    // Statements
18    BlockStatement(BlockStatement),
19    ReturnStatement(ReturnStatement),
20    IfStatement(IfStatement),
21    ForStatement(ForStatement),
22    WhileStatement(WhileStatement),
23    DoWhileStatement(DoWhileStatement),
24    ForInStatement(ForInStatement),
25    ForOfStatement(ForOfStatement),
26    SwitchStatement(SwitchStatement),
27    ThrowStatement(ThrowStatement),
28    TryStatement(TryStatement),
29    BreakStatement(BreakStatement),
30    ContinueStatement(ContinueStatement),
31    LabeledStatement(LabeledStatement),
32    ExpressionStatement(ExpressionStatement),
33    EmptyStatement(EmptyStatement),
34    DebuggerStatement(DebuggerStatement),
35    WithStatement(WithStatement),
36    // Declarations are also statements
37    VariableDeclaration(VariableDeclaration),
38    FunctionDeclaration(FunctionDeclaration),
39    ClassDeclaration(ClassDeclaration),
40    // Import/export declarations
41    ImportDeclaration(crate::declarations::ImportDeclaration),
42    ExportNamedDeclaration(crate::declarations::ExportNamedDeclaration),
43    ExportDefaultDeclaration(crate::declarations::ExportDefaultDeclaration),
44    ExportAllDeclaration(crate::declarations::ExportAllDeclaration),
45    // TypeScript declarations
46    TSTypeAliasDeclaration(crate::declarations::TSTypeAliasDeclaration),
47    TSInterfaceDeclaration(crate::declarations::TSInterfaceDeclaration),
48    TSEnumDeclaration(crate::declarations::TSEnumDeclaration),
49    TSModuleDeclaration(crate::declarations::TSModuleDeclaration),
50    TSDeclareFunction(crate::declarations::TSDeclareFunction),
51    // Flow declarations
52    TypeAlias(crate::declarations::TypeAlias),
53    OpaqueType(crate::declarations::OpaqueType),
54    InterfaceDeclaration(crate::declarations::InterfaceDeclaration),
55    DeclareVariable(crate::declarations::DeclareVariable),
56    DeclareFunction(crate::declarations::DeclareFunction),
57    DeclareClass(crate::declarations::DeclareClass),
58    DeclareModule(crate::declarations::DeclareModule),
59    DeclareModuleExports(crate::declarations::DeclareModuleExports),
60    DeclareExportDeclaration(crate::declarations::DeclareExportDeclaration),
61    DeclareExportAllDeclaration(crate::declarations::DeclareExportAllDeclaration),
62    DeclareInterface(crate::declarations::DeclareInterface),
63    DeclareTypeAlias(crate::declarations::DeclareTypeAlias),
64    DeclareOpaqueType(crate::declarations::DeclareOpaqueType),
65    EnumDeclaration(crate::declarations::EnumDeclaration),
66    /// Catch-all for statement `type`s the typed AST does not model, e.g. the
67    /// TypeScript module-interop statements `import x = require(...)`,
68    /// `export = x`, and `export as namespace X`. Carries the complete raw
69    /// Babel node so the Babel path can preserve unmodeled top-level
70    /// statements verbatim instead of failing the whole file.
71    ///
72    /// Deserialization dispatches through [`KnownStatement`]: a modeled `type`
73    /// whose body is malformed errors with the typed variant's precise message
74    /// rather than degrading to `Unknown`. Adding a variant to this enum
75    /// requires adding it to the `known_statements!` list below, which is the
76    /// single source for the dispatch enum, its `From` mapping, and
77    /// [`KNOWN_STATEMENT_TYPES`]. A variant added here but not there degrades
78    /// to `Unknown` silently; that is the one drift case structure cannot
79    /// catch.
80    #[serde(untagged)]
81    Unknown(UnknownStatement),
82}
83
84// NOTE: `Deserialize` for `Statement` is hand-written below; the
85// `#[serde(tag = "type")]` and `#[serde(untagged)]` attributes on the enum
86// configure only the derived `Serialize`.
87
88#[derive(Debug, Clone)]
89pub struct UnknownStatement {
90    raw: RawNode,
91    base: BaseNode,
92}
93
94impl UnknownStatement {
95    pub fn from_raw(raw: RawNode) -> Result<Self, String> {
96        match raw.type_name() {
97            Some(_) => {
98                // Parsing into BaseNode reads only the fields BaseNode declares,
99                // not the whole (arbitrarily large) unknown subtree.
100                let base = crate::common::from_json_str_unbounded::<BaseNode>(raw.get())
101                    .map_err(|err| format!("failed to read unknown statement base: {err}"))?;
102                Ok(Self { raw, base })
103            }
104            None => Err("unknown statement is missing a string `type` field".to_string()),
105        }
106    }
107
108    /// The node's `type` discriminant, read from the captured [`BaseNode`].
109    /// Falls back to `"Unknown"` rather than panicking if the raw node was
110    /// mutated out from under it.
111    pub fn node_type(&self) -> &str {
112        self.base.node_type.as_deref().unwrap_or("Unknown")
113    }
114
115    pub fn raw(&self) -> &RawNode {
116        &self.raw
117    }
118
119    /// Mutate the raw node, then refresh the cached [`BaseNode`] so `base()`
120    /// and `node_type()` cannot drift from `raw`. Mutations that remove the
121    /// string `type` field are rejected and rolled back.
122    pub fn with_raw_mut<R>(&mut self, f: impl FnOnce(&mut RawNode) -> R) -> Result<R, String> {
123        let saved = self.raw.clone();
124        let result = f(&mut self.raw);
125        if self.raw.type_name().is_none() {
126            self.raw = saved;
127            return Err("unknown statement mutation removed the string `type` field".to_string());
128        }
129        match crate::common::from_json_str_unbounded::<BaseNode>(self.raw.get()) {
130            Ok(base) => {
131                self.base = base;
132                Ok(result)
133            }
134            Err(err) => {
135                self.raw = saved;
136                Err(format!("failed to refresh unknown statement base: {err}"))
137            }
138        }
139    }
140
141    pub fn base(&self) -> &BaseNode {
142        &self.base
143    }
144}
145
146impl Serialize for UnknownStatement {
147    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
148    where
149        S: Serializer,
150    {
151        self.raw.serialize(serializer)
152    }
153}
154
155#[derive(Debug, Clone, Serialize)]
156pub struct BlockStatement {
157    #[serde(flatten)]
158    pub base: BaseNode,
159    pub body: Vec<Statement>,
160    #[serde(default)]
161    pub directives: Vec<Directive>,
162}
163
164#[derive(Debug, Clone, Serialize)]
165pub struct Directive {
166    #[serde(flatten)]
167    pub base: BaseNode,
168    pub value: DirectiveLiteral,
169}
170
171#[derive(Debug, Clone, Serialize)]
172pub struct DirectiveLiteral {
173    #[serde(flatten)]
174    pub base: BaseNode,
175    pub value: String,
176}
177
178#[derive(Debug, Clone, Serialize)]
179pub struct ReturnStatement {
180    #[serde(flatten)]
181    pub base: BaseNode,
182    pub argument: Option<Box<Expression>>,
183}
184
185#[derive(Debug, Clone, Serialize)]
186pub struct ExpressionStatement {
187    #[serde(flatten)]
188    pub base: BaseNode,
189    pub expression: Box<Expression>,
190}
191
192#[derive(Debug, Clone, Serialize)]
193pub struct IfStatement {
194    #[serde(flatten)]
195    pub base: BaseNode,
196    pub test: Box<Expression>,
197    pub consequent: Box<Statement>,
198    pub alternate: Option<Box<Statement>>,
199}
200
201#[derive(Debug, Clone, Serialize)]
202pub struct ForStatement {
203    #[serde(flatten)]
204    pub base: BaseNode,
205    pub init: Option<Box<ForInit>>,
206    pub test: Option<Box<Expression>>,
207    pub update: Option<Box<Expression>>,
208    pub body: Box<Statement>,
209}
210
211#[derive(Debug, Clone, Serialize)]
212#[serde(tag = "type")]
213pub enum ForInit {
214    VariableDeclaration(VariableDeclaration),
215    #[serde(untagged)]
216    Expression(Box<Expression>),
217}
218
219#[derive(Debug, Clone, Serialize)]
220pub struct WhileStatement {
221    #[serde(flatten)]
222    pub base: BaseNode,
223    pub test: Box<Expression>,
224    pub body: Box<Statement>,
225}
226
227#[derive(Debug, Clone, Serialize)]
228pub struct DoWhileStatement {
229    #[serde(flatten)]
230    pub base: BaseNode,
231    pub test: Box<Expression>,
232    pub body: Box<Statement>,
233}
234
235#[derive(Debug, Clone, Serialize)]
236pub struct ForInStatement {
237    #[serde(flatten)]
238    pub base: BaseNode,
239    pub left: Box<ForInOfLeft>,
240    pub right: Box<Expression>,
241    pub body: Box<Statement>,
242}
243
244#[derive(Debug, Clone, Serialize)]
245pub struct ForOfStatement {
246    #[serde(flatten)]
247    pub base: BaseNode,
248    pub left: Box<ForInOfLeft>,
249    pub right: Box<Expression>,
250    pub body: Box<Statement>,
251    #[serde(default, rename = "await")]
252    pub is_await: bool,
253}
254
255#[derive(Debug, Clone, Serialize)]
256#[serde(tag = "type")]
257pub enum ForInOfLeft {
258    VariableDeclaration(VariableDeclaration),
259    #[serde(untagged)]
260    Pattern(Box<PatternLike>),
261}
262
263#[derive(Debug, Clone, Serialize)]
264pub struct SwitchStatement {
265    #[serde(flatten)]
266    pub base: BaseNode,
267    pub discriminant: Box<Expression>,
268    pub cases: Vec<SwitchCase>,
269}
270
271#[derive(Debug, Clone, Serialize)]
272pub struct SwitchCase {
273    #[serde(flatten)]
274    pub base: BaseNode,
275    pub test: Option<Box<Expression>>,
276    pub consequent: Vec<Statement>,
277}
278
279#[derive(Debug, Clone, Serialize)]
280pub struct ThrowStatement {
281    #[serde(flatten)]
282    pub base: BaseNode,
283    pub argument: Box<Expression>,
284}
285
286#[derive(Debug, Clone, Serialize)]
287pub struct TryStatement {
288    #[serde(flatten)]
289    pub base: BaseNode,
290    pub block: BlockStatement,
291    pub handler: Option<CatchClause>,
292    pub finalizer: Option<BlockStatement>,
293}
294
295#[derive(Debug, Clone, Serialize)]
296pub struct CatchClause {
297    #[serde(flatten)]
298    pub base: BaseNode,
299    pub param: Option<PatternLike>,
300    pub body: BlockStatement,
301}
302
303#[derive(Debug, Clone, Serialize)]
304pub struct BreakStatement {
305    #[serde(flatten)]
306    pub base: BaseNode,
307    pub label: Option<Identifier>,
308}
309
310#[derive(Debug, Clone, Serialize)]
311pub struct ContinueStatement {
312    #[serde(flatten)]
313    pub base: BaseNode,
314    pub label: Option<Identifier>,
315}
316
317#[derive(Debug, Clone, Serialize)]
318pub struct LabeledStatement {
319    #[serde(flatten)]
320    pub base: BaseNode,
321    pub label: Identifier,
322    pub body: Box<Statement>,
323}
324
325#[derive(Debug, Clone, Serialize)]
326pub struct EmptyStatement {
327    #[serde(flatten)]
328    pub base: BaseNode,
329}
330
331#[derive(Debug, Clone, Serialize)]
332pub struct DebuggerStatement {
333    #[serde(flatten)]
334    pub base: BaseNode,
335}
336
337#[derive(Debug, Clone, Serialize)]
338pub struct WithStatement {
339    #[serde(flatten)]
340    pub base: BaseNode,
341    pub object: Box<Expression>,
342    pub body: Box<Statement>,
343}
344
345#[derive(Debug, Clone, Serialize)]
346pub struct VariableDeclaration {
347    #[serde(flatten)]
348    pub base: BaseNode,
349    pub declarations: Vec<VariableDeclarator>,
350    pub kind: VariableDeclarationKind,
351    #[serde(default, skip_serializing_if = "Option::is_none")]
352    pub declare: Option<bool>,
353}
354
355#[derive(Debug, Clone, Serialize)]
356#[serde(rename_all = "lowercase")]
357pub enum VariableDeclarationKind {
358    Var,
359    Let,
360    Const,
361    Using,
362}
363
364#[derive(Debug, Clone, Serialize)]
365pub struct VariableDeclarator {
366    #[serde(flatten)]
367    pub base: BaseNode,
368    pub id: PatternLike,
369    pub init: Option<Box<Expression>>,
370    #[serde(default, skip_serializing_if = "Option::is_none")]
371    pub definite: Option<bool>,
372}
373
374#[derive(Debug, Clone, Serialize)]
375pub struct FunctionDeclaration {
376    #[serde(flatten)]
377    pub base: BaseNode,
378    pub id: Option<Identifier>,
379    pub params: Vec<PatternLike>,
380    pub body: BlockStatement,
381    #[serde(default)]
382    pub generator: bool,
383    #[serde(default, rename = "async")]
384    pub is_async: bool,
385    #[serde(default, skip_serializing_if = "Option::is_none")]
386    pub declare: Option<bool>,
387    #[serde(
388        default,
389        skip_serializing_if = "Option::is_none",
390        rename = "returnType"
391    )]
392    pub return_type: Option<RawNode>,
393    #[serde(
394        default,
395        skip_serializing_if = "Option::is_none",
396        rename = "typeParameters"
397    )]
398    pub type_parameters: Option<RawNode>,
399    #[serde(default, skip_serializing_if = "Option::is_none", rename = "predicate")]
400    pub predicate: Option<RawNode>,
401    /// Set by the Hermes parser for Flow `component Foo(...) { ... }` syntax
402    #[serde(
403        default,
404        skip_serializing_if = "is_false",
405        rename = "__componentDeclaration"
406    )]
407    pub component_declaration: bool,
408    /// Set by the Hermes parser for Flow `hook useFoo(...) { ... }` syntax
409    #[serde(
410        default,
411        skip_serializing_if = "is_false",
412        rename = "__hookDeclaration"
413    )]
414    pub hook_declaration: bool,
415}
416
417#[derive(Debug, Clone, Serialize)]
418pub struct ClassDeclaration {
419    #[serde(flatten)]
420    pub base: BaseNode,
421    pub id: Option<Identifier>,
422    #[serde(rename = "superClass")]
423    pub super_class: Option<Box<Expression>>,
424    pub body: crate::expressions::ClassBody,
425    #[serde(default, skip_serializing_if = "Option::is_none")]
426    pub decorators: Option<Vec<RawNode>>,
427    #[serde(default, skip_serializing_if = "Option::is_none", rename = "abstract")]
428    pub is_abstract: Option<bool>,
429    #[serde(default, skip_serializing_if = "Option::is_none")]
430    pub declare: Option<bool>,
431    #[serde(
432        default,
433        skip_serializing_if = "Option::is_none",
434        rename = "implements"
435    )]
436    pub implements: Option<Vec<RawNode>>,
437    #[serde(
438        default,
439        skip_serializing_if = "Option::is_none",
440        rename = "superTypeParameters"
441    )]
442    pub super_type_parameters: Option<RawNode>,
443    #[serde(
444        default,
445        skip_serializing_if = "Option::is_none",
446        rename = "typeParameters"
447    )]
448    pub type_parameters: Option<RawNode>,
449    #[serde(default, skip_serializing_if = "Option::is_none")]
450    pub mixins: Option<Vec<RawNode>>,
451}