resast/
expr.rs

1use crate::pat::Pat;
2use crate::{AssignOp, BinaryOp, LogicalOp, PropKind, UnaryOp, UpdateOp};
3use crate::{Class, Func, FuncArg, FuncBody, Ident};
4use std::borrow::Cow;
5/// A slightly more granular program part that a statement
6#[derive(Debug, Clone, PartialEq)]
7#[cfg_attr(
8    all(feature = "serde", not(feature = "esprima")),
9    derive(Deserialize, Serialize)
10)]
11#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))]
12#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))]
13pub enum Expr<'a> {
14    /// `[0,,]`
15    Array(ArrayExpr<'a>),
16    /// An arrow function
17    /// ```js
18    /// () => console.log();
19    /// x => {
20    ///     return x;
21    /// }
22    /// ```
23    ArrowFunc(ArrowFuncExpr<'a>),
24    /// Used for resolving possible sequence expressions
25    /// that are arrow parameters
26    ArrowParamPlaceHolder(Vec<FuncArg<'a>>, bool),
27    /// Assignment or update assignment
28    /// ```js
29    /// a = 0
30    /// b += 1
31    /// ```
32    Assign(AssignExpr<'a>),
33    /// The `await` keyword followed by another `Expr`
34    Await(Box<Expr<'a>>),
35    /// An operation that has two arguments
36    Binary(BinaryExpr<'a>),
37    /// A class expression see `Class`
38    Class(Class<'a>),
39    /// Calling a function or method
40    Call(CallExpr<'a>),
41    /// A ternery expression
42    Conditional(ConditionalExpr<'a>),
43    /// see `Function`
44    Func(Func<'a>),
45    /// An identifier
46    Ident(Ident<'a>),
47    /// A literal value, see `Literal`
48    Lit(Lit<'a>),
49    /// A specialized `BinaryExpr` for logical evaluation
50    /// ```js
51    /// true && true
52    /// false || true
53    /// ```
54    Logical(LogicalExpr<'a>),
55    /// Accessing the member of a value
56    /// ```js
57    /// b['thing'];
58    /// c.stuff;
59    /// ```
60    Member(MemberExpr<'a>),
61    /// currently just `new.target`
62    MetaProp(MetaProp<'a>),
63    /// ```js
64    /// var a = true ? 'stuff' : 'things';
65    /// ```
66    /// `{}`
67    /// Calling a constructor
68    New(NewExpr<'a>),
69    Obj(ObjExpr<'a>),
70    /// Any sequence of expressions separated with a comma
71    Sequence(SequenceExpr<'a>),
72    /// `...` followed by an `Expr`
73    Spread(Box<Expr<'a>>),
74    /// `super`
75    Super,
76    /// A template literal preceded by a tag function identifier
77    TaggedTemplate(TaggedTemplateExpr<'a>),
78    /// `this`
79    This,
80    /// An operation that has one argument
81    /// ```js
82    /// typeof 'a';
83    /// +9;
84    /// ```
85    Unary(UnaryExpr<'a>),
86    /// Increment or decrement
87    /// ```js
88    /// 1++
89    /// --2
90    /// ```
91    Update(UpdateExpr<'a>),
92    /// yield a value from inside of a generator function
93    Yield(YieldExpr<'a>),
94}
95
96impl<'a> Expr<'a> {
97    pub fn ident_from(s: &'a str) -> Self {
98        Expr::Ident(Ident::from(s))
99    }
100}
101
102/// `[a, b, c]`
103pub type ArrayExpr<'a> = Vec<Option<Expr<'a>>>;
104/// `{a: 'b', c, ...d}`
105pub type ObjExpr<'a> = Vec<ObjProp<'a>>;
106/// A single part of an object literal
107#[derive(PartialEq, Debug, Clone)]
108#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
109#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))]
110pub enum ObjProp<'a> {
111    Prop(Prop<'a>),
112    Spread(Expr<'a>),
113}
114
115/// A single part of an object literal or class
116#[derive(Debug, Clone, PartialEq)]
117#[cfg_attr(
118    all(feature = "serde", not(feature = "esprima")),
119    derive(Deserialize, Serialize)
120)]
121#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))]
122pub struct Prop<'a> {
123    pub key: PropKey<'a>,
124    pub value: PropValue<'a>,
125    pub kind: PropKind,
126    pub method: bool,
127    pub computed: bool,
128    pub short_hand: bool,
129    pub is_static: bool,
130}
131
132/// An object literal or class property identifier
133#[derive(PartialEq, Debug, Clone)]
134#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
135#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))]
136pub enum PropKey<'a> {
137    Lit(Lit<'a>),
138    Expr(Expr<'a>),
139    Pat(Pat<'a>),
140}
141
142/// The value of an object literal or class property
143#[derive(PartialEq, Debug, Clone)]
144#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
145#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))]
146pub enum PropValue<'a> {
147    Expr(Expr<'a>),
148    Pat(Pat<'a>),
149    None,
150}
151
152/// An operation that takes one argument
153#[derive(PartialEq, Debug, Clone)]
154#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
155pub struct UnaryExpr<'a> {
156    pub operator: UnaryOp,
157    pub prefix: bool,
158    pub argument: Box<Expr<'a>>,
159}
160
161/// Increment or decrementing a value
162#[derive(PartialEq, Debug, Clone)]
163#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
164pub struct UpdateExpr<'a> {
165    pub operator: UpdateOp,
166    pub argument: Box<Expr<'a>>,
167    pub prefix: bool,
168}
169
170/// An operation that requires 2 arguments
171#[derive(PartialEq, Debug, Clone)]
172#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
173pub struct BinaryExpr<'a> {
174    pub operator: BinaryOp,
175    pub left: Box<Expr<'a>>,
176    pub right: Box<Expr<'a>>,
177}
178
179/// An assignment or update + assignment operation
180#[derive(PartialEq, Debug, Clone)]
181#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
182pub struct AssignExpr<'a> {
183    pub operator: AssignOp,
184    pub left: AssignLeft<'a>,
185    pub right: Box<Expr<'a>>,
186}
187
188/// The value being assigned to
189#[derive(PartialEq, Debug, Clone)]
190#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
191#[cfg_attr(all(feature = "serde", feature = "esprima"), serde(untagged))]
192pub enum AssignLeft<'a> {
193    Pat(Pat<'a>),
194    Expr(Box<Expr<'a>>),
195}
196
197/// A specialized `BinaryExpr` for logical evaluation
198/// ```js
199/// true && true
200/// false || true
201/// ```
202#[derive(PartialEq, Debug, Clone)]
203#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
204pub struct LogicalExpr<'a> {
205    pub operator: LogicalOp,
206    pub left: Box<Expr<'a>>,
207    pub right: Box<Expr<'a>>,
208}
209
210/// Accessing the member of a value
211/// ```js
212/// b['thing'];
213/// c.stuff;
214/// ```
215#[derive(PartialEq, Debug, Clone)]
216#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
217pub struct MemberExpr<'a> {
218    pub object: Box<Expr<'a>>,
219    pub property: Box<Expr<'a>>,
220    pub computed: bool,
221}
222
223/// A ternery expression
224/// ```js
225/// var a = true ? 'stuff' : 'things';
226/// ```
227#[derive(PartialEq, Debug, Clone)]
228#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
229pub struct ConditionalExpr<'a> {
230    pub test: Box<Expr<'a>>,
231    pub alternate: Box<Expr<'a>>,
232    pub consequent: Box<Expr<'a>>,
233}
234
235/// Calling a function or method
236/// ```js
237/// Math.random()
238/// ```
239#[derive(PartialEq, Debug, Clone)]
240#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
241pub struct CallExpr<'a> {
242    pub callee: Box<Expr<'a>>,
243    pub arguments: Vec<Expr<'a>>,
244}
245
246/// Calling a constructor
247/// ```js
248/// new Uint8Array(32);
249/// ```
250#[derive(PartialEq, Debug, Clone)]
251#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
252pub struct NewExpr<'a> {
253    pub callee: Box<Expr<'a>>,
254    pub arguments: Vec<Expr<'a>>,
255}
256
257/// A collection of `Exprs` separated by commas
258pub type SequenceExpr<'a> = Vec<Expr<'a>>;
259
260/// An arrow function
261/// ```js
262/// let x = () => y;
263/// let q = x => {
264///     return x + 1;
265/// }
266/// ```
267#[derive(PartialEq, Debug, Clone)]
268#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
269pub struct ArrowFuncExpr<'a> {
270    pub id: Option<Ident<'a>>,
271    pub params: Vec<FuncArg<'a>>,
272    pub body: ArrowFuncBody<'a>,
273    pub expression: bool,
274    pub generator: bool,
275    pub is_async: bool,
276}
277
278/// The body portion of an arrow function can be either an expression or a block of statements
279#[derive(PartialEq, Debug, Clone)]
280#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
281pub enum ArrowFuncBody<'a> {
282    FuncBody(FuncBody<'a>),
283    Expr(Box<Expr<'a>>),
284}
285
286/// yield a value from inside of a generator function
287/// ```js
288/// function *gen() {
289///     while ((new Date() / 1000) < Number.MAX_VALUE) {
290///         yield new Date() / 1000;
291///     }
292/// }
293/// ```
294#[derive(PartialEq, Debug, Clone)]
295#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
296pub struct YieldExpr<'a> {
297    pub argument: Option<Box<Expr<'a>>>,
298    pub delegate: bool,
299}
300
301/// A Template literal preceded by a function identifier
302/// see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_templates) for more details
303#[derive(PartialEq, Debug, Clone)]
304#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
305pub struct TaggedTemplateExpr<'a> {
306    pub tag: Box<Expr<'a>>,
307    pub quasi: TemplateLit<'a>,
308}
309
310/// A template string literal
311/// ```js
312/// `I own ${0} birds`;
313/// ```
314#[derive(Debug, Clone, PartialEq)]
315#[cfg_attr(
316    all(feature = "serde", not(feature = "esprima")),
317    derive(Deserialize, Serialize)
318)]
319#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))]
320pub struct TemplateLit<'a> {
321    pub quasis: Vec<TemplateElement<'a>>,
322    pub expressions: Vec<Expr<'a>>,
323}
324
325/// The text part of a `TemplateLiteral`
326#[derive(Debug, Clone, PartialEq)]
327#[cfg_attr(
328    all(feature = "serde", not(feature = "esprima")),
329    derive(Deserialize, Serialize)
330)]
331#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))]
332pub struct TemplateElement<'a> {
333    pub tail: bool,
334    /// The non-quoted version
335    pub cooked: Cow<'a, str>,
336    /// The quoted version
337    pub raw: Cow<'a, str>,
338}
339
340impl<'a> TemplateElement<'a> {
341    pub fn from(tail: bool, cooked: &'a str, raw: &'a str) -> TemplateElement<'a> {
342        Self {
343            tail,
344            cooked: Cow::Borrowed(cooked),
345            raw: Cow::Borrowed(raw),
346        }
347    }
348}
349
350/// pretty much just `new.target`
351/// ```js
352/// function Thing(one, two) {
353///     if (!new.target) {
354///         return new Thing(one, two);
355///     }
356///     this.one = one;
357///     this.two = two;
358/// }
359/// ```
360#[derive(PartialEq, Debug, Clone)]
361#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
362pub struct MetaProp<'a> {
363    pub meta: Ident<'a>,
364    pub property: Ident<'a>,
365}
366
367/// A literal value
368#[derive(Debug, Clone, PartialEq)]
369#[cfg_attr(
370    all(feature = "serde", not(feature = "esprima")),
371    derive(Deserialize, Serialize)
372)]
373#[cfg_attr(all(feature = "serde", feature = "esprima"), derive(Deserialize))]
374pub enum Lit<'a> {
375    /// `null`
376    Null,
377    /// `"string"`
378    /// `'string'`
379    String(StringLit<'a>),
380    /// `0`
381    /// `0.0`
382    /// `.0`
383    /// `0.0e1`
384    /// `.0E1`
385    /// `0xf`
386    /// `0o7`
387    /// `0b1`
388    Number(Cow<'a, str>),
389    /// `true`
390    /// `false`
391    Boolean(bool),
392    /// `/.+/g`
393    RegEx(RegEx<'a>),
394    /// ```js
395    /// `I have ${0} apples`
396    /// ```
397    Template(TemplateLit<'a>),
398}
399
400impl<'a> Lit<'a> {
401    pub fn number_from(s: &'a str) -> Self {
402        Lit::Number(Cow::Borrowed(s))
403    }
404    pub fn single_string_from(s: &'a str) -> Self {
405        Lit::String(StringLit::single_from(s))
406    }
407    pub fn double_string_from(s: &'a str) -> Self {
408        Lit::String(StringLit::double_from(s))
409    }
410}
411
412#[derive(PartialEq, Debug, Clone)]
413#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
414pub enum StringLit<'a> {
415    Double(Cow<'a, str>),
416    Single(Cow<'a, str>),
417}
418
419impl<'a> StringLit<'a> {
420    pub fn double_from(s: &'a str) -> StringLit<'a> {
421        StringLit::Double(Cow::Borrowed(s))
422    }
423    pub fn single_from(s: &'a str) -> StringLit<'a> {
424        StringLit::Single(Cow::Borrowed(s))
425    }
426    pub fn clone_inner(&self) -> Cow<'a, str> {
427        match self {
428            StringLit::Single(ref s) => s.clone(),
429            StringLit::Double(ref s) => s.clone(),
430        }
431    }
432    pub fn inner_matches(&self, o: &str) -> bool {
433        match self {
434            StringLit::Single(ref s) => s == o,
435            StringLit::Double(ref d) => d == o,
436        }
437    }
438}
439/// A regular expression literal
440#[derive(PartialEq, Debug, Clone)]
441#[cfg_attr(all(feature = "serialization"), derive(Deserialize, Serialize))]
442#[cfg_attr(all(feature = "serialization"), serde(rename_all = "camelCase"))]
443pub struct RegEx<'a> {
444    pub pattern: Cow<'a, str>,
445    pub flags: Cow<'a, str>,
446}
447
448impl<'a> RegEx<'a> {
449    pub fn from(p: &'a str, f: &'a str) -> Self {
450        RegEx {
451            pattern: Cow::Borrowed(p),
452            flags: Cow::Borrowed(f),
453        }
454    }
455}