Skip to main content

ecma_syntax_cat/
expression.rs

1//! ECMAScript expressions.
2
3use crate::class::Class;
4use crate::function::{ArrowFunction, Function};
5use crate::identifier::{Identifier, PrivateIdentifier};
6use crate::literal::Literal;
7use crate::operator::{
8    AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
9};
10use crate::span::Spanned;
11
12/// An expression paired with its source span.
13pub type Expression = Spanned<ExpressionKind>;
14
15/// The shape of an ECMAScript expression.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub enum ExpressionKind {
18    /// The `this` keyword.
19    This,
20    /// The `super` keyword (only valid in certain method bodies).
21    Super,
22    /// A variable reference.
23    Identifier(Identifier),
24    /// A private class-field identifier (`#foo`) used as a value.
25    PrivateIdentifier(PrivateIdentifier),
26    /// A static literal value.
27    Literal(Literal),
28    /// A template literal (`` `hello ${name}` ``).  The number of `quasis`
29    /// must satisfy `quasis.len() == expressions.len() + 1`.
30    Template {
31        /// Literal text chunks in source order.
32        quasis: Vec<String>,
33        /// Interpolated expressions, each appearing between two quasis.
34        expressions: Vec<Expression>,
35    },
36    /// A tagged template (`` tag`hello ${name}` ``).
37    TaggedTemplate {
38        /// The tag function expression.
39        tag: Box<Expression>,
40        /// Literal text chunks.
41        quasis: Vec<String>,
42        /// Interpolated expressions.
43        expressions: Vec<Expression>,
44    },
45    /// An array expression.  `None` entries represent holes
46    /// (`[1, , 3]`), and any element may be a [`ExpressionKind::Spread`].
47    Array {
48        /// Array elements; `None` for holes.
49        elements: Vec<Option<Expression>>,
50    },
51    /// An object expression.
52    Object {
53        /// Object members in source order.
54        properties: Vec<ObjectMember>,
55    },
56    /// Property access: `object.property` or `object[property]`, optionally
57    /// `?.`-qualified.
58    Member {
59        /// The object expression.
60        object: Box<Expression>,
61        /// The property selector.
62        property: MemberProperty,
63        /// True when the access used `?.` (optional chaining).
64        optional: bool,
65    },
66    /// Function application: `callee(args)`, optionally `?.()`-qualified.
67    Call {
68        /// The callee expression.
69        callee: Box<Expression>,
70        /// The argument list (each may be a spread).
71        arguments: Vec<Expression>,
72        /// True when the call used `?.()`.
73        optional: bool,
74    },
75    /// `new` invocation: `new callee(args)`.
76    New {
77        /// The constructor expression.
78        callee: Box<Expression>,
79        /// The argument list.
80        arguments: Vec<Expression>,
81    },
82    /// `++` or `--` applied to an argument, prefix or postfix.
83    Update {
84        /// `++` or `--`.
85        operator: UpdateOperator,
86        /// The target being updated.
87        argument: Box<Expression>,
88        /// True for `++x` / `--x`, false for `x++` / `x--`.
89        prefix: bool,
90    },
91    /// A unary prefix operator (`!x`, `-x`, `typeof x`, ...).
92    Unary {
93        /// The operator.
94        operator: UnaryOperator,
95        /// The operand.
96        argument: Box<Expression>,
97    },
98    /// A binary operator without short-circuit semantics.
99    Binary {
100        /// The operator.
101        operator: BinaryOperator,
102        /// The left operand.
103        left: Box<Expression>,
104        /// The right operand.
105        right: Box<Expression>,
106    },
107    /// A short-circuit logical operator (`&&`, `||`, `??`).
108    Logical {
109        /// The operator.
110        operator: LogicalOperator,
111        /// The left operand.
112        left: Box<Expression>,
113        /// The right operand (evaluated lazily).
114        right: Box<Expression>,
115    },
116    /// The ternary conditional (`test ? consequent : alternate`).
117    Conditional {
118        /// The test expression.
119        test: Box<Expression>,
120        /// The branch when `test` is truthy.
121        consequent: Box<Expression>,
122        /// The branch when `test` is falsy.
123        alternate: Box<Expression>,
124    },
125    /// An assignment expression (`x = v`, `x += v`, etc.).
126    Assignment {
127        /// The assignment operator (plain `=` or compound).
128        operator: AssignmentOperator,
129        /// The target (an expression that must be a valid assignment target;
130        /// patterns are validated structurally rather than at the type level).
131        left: Box<Expression>,
132        /// The right-hand value.
133        right: Box<Expression>,
134    },
135    /// A comma expression (`a, b, c`).  Evaluates all in order and yields
136    /// the last value.
137    Sequence {
138        /// Sub-expressions in source order.
139        expressions: Vec<Expression>,
140    },
141    /// A spread element (`...expr`).
142    Spread {
143        /// The expression being spread.
144        argument: Box<Expression>,
145    },
146    /// An arrow function expression.
147    ArrowFunction(Box<ArrowFunction>),
148    /// A `function` expression (named or anonymous).
149    FunctionExpression(Box<Function>),
150    /// A `class` expression.
151    ClassExpression(Box<Class>),
152    /// `yield` or `yield*` in a generator.
153    Yield {
154        /// Optional argument; `yield;` with no value gives `None`.
155        argument: Option<Box<Expression>>,
156        /// True for `yield*`, false for plain `yield`.
157        delegate: bool,
158    },
159    /// `await expr` in an async function.
160    Await {
161        /// The promise-valued expression to await.
162        argument: Box<Expression>,
163    },
164    /// Optional-chaining wrapper (`(obj?.a.b)`).  `ESTree` wraps the chain
165    /// root so consumers can detect optional-chain shortcircuiting cheaply.
166    Chain {
167        /// The optional-chain expression (a `Member` or `Call` with
168        /// `optional: true` at some point in its descent).
169        expression: Box<Expression>,
170    },
171    /// Dynamic `import(source, options?)`.
172    ImportExpression {
173        /// The module specifier expression.
174        source: Box<Expression>,
175        /// Optional second-argument options bag.
176        options: Option<Box<Expression>>,
177    },
178    /// A meta property: `new.target` or `import.meta`.
179    MetaProperty {
180        /// The meta keyword (`new` or `import`).
181        meta: Identifier,
182        /// The property name (`target` or `meta`).
183        property: Identifier,
184    },
185    /// A parenthesised expression.  Some tools care about whether the user
186    /// wrote parens; for those, this variant preserves the distinction.
187    Parenthesized {
188        /// The inner expression.
189        expression: Box<Expression>,
190    },
191}
192
193/// How a member access selects its property.
194#[derive(Debug, Clone, PartialEq, Eq)]
195pub enum MemberProperty {
196    /// `object.name`.
197    Identifier(Identifier),
198    /// `object[expr]`.
199    Computed(Box<Expression>),
200    /// `object.#name`.
201    Private(PrivateIdentifier),
202}
203
204/// A property key as used in object literals, class members, and
205/// destructuring patterns.
206#[derive(Debug, Clone, PartialEq)]
207pub enum PropertyKey {
208    /// A plain identifier key.
209    Identifier(Identifier),
210    /// A string-literal key.
211    String(String),
212    /// A numeric-literal key.
213    Number(f64),
214    /// A computed key written in brackets.
215    Computed(Box<Expression>),
216    /// A private class-field key (`#name`).
217    Private(PrivateIdentifier),
218}
219
220impl Eq for PropertyKey {}
221
222impl std::fmt::Display for PropertyKey {
223    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224        match self {
225            Self::Identifier(name) => write!(f, "{name}"),
226            Self::String(s) => write!(f, "{s:?}"),
227            Self::Number(n) => write!(f, "{n}"),
228            Self::Computed(expr) => write!(f, "[{expr}]"),
229            Self::Private(p) => write!(f, "{p}"),
230        }
231    }
232}
233
234/// One member of an object literal.
235#[derive(Debug, Clone, PartialEq, Eq)]
236pub enum ObjectMember {
237    /// A named property or method.
238    Property {
239        /// The property key.
240        key: PropertyKey,
241        /// The property value (or method definition for shorthand methods).
242        value: Expression,
243        /// Whether the member is a getter, setter, ordinary method, or
244        /// plain data property.
245        kind: ObjectPropertyKind,
246        /// Whether the key was a computed expression (`[k]`).
247        computed: bool,
248        /// Whether the property used shorthand (`{ x }`).
249        shorthand: bool,
250    },
251    /// A spread member (`{ ...other }`).
252    Spread {
253        /// The expression being spread into the object.
254        argument: Expression,
255    },
256}
257
258/// Distinguishes the kinds of object-literal members.
259#[derive(Debug, Clone, Copy, PartialEq, Eq)]
260pub enum ObjectPropertyKind {
261    /// A plain data property (`{ x: 1 }`).
262    Init,
263    /// A getter (`{ get x() { ... } }`).
264    Get,
265    /// A setter (`{ set x(v) { ... } }`).
266    Set,
267    /// A shorthand method (`{ x() { ... } }`).
268    Method,
269}
270
271impl std::fmt::Display for ExpressionKind {
272    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273        match self {
274            Self::This => f.write_str("this"),
275            Self::Super => f.write_str("super"),
276            Self::Identifier(id) => write!(f, "{id}"),
277            Self::PrivateIdentifier(id) => write!(f, "{id}"),
278            Self::Literal(lit) => write!(f, "{lit}"),
279            Self::Template {
280                quasis,
281                expressions,
282            } => write_template(f, None, quasis, expressions),
283            Self::TaggedTemplate {
284                tag,
285                quasis,
286                expressions,
287            } => write_template(f, Some(tag), quasis, expressions),
288            Self::Array { elements } => write_array(f, elements),
289            Self::Object { properties } => write_object(f, properties),
290            Self::Member {
291                object,
292                property,
293                optional,
294            } => write_member(f, object, property, *optional),
295            Self::Call {
296                callee,
297                arguments,
298                optional,
299            } => write_call(f, callee, arguments, *optional),
300            Self::New { callee, arguments } => write_new(f, callee, arguments),
301            Self::Update {
302                operator,
303                argument,
304                prefix,
305            } => write_update(f, *operator, argument, *prefix),
306            Self::Unary { operator, argument } => write!(f, "({operator} {argument})"),
307            Self::Binary {
308                operator,
309                left,
310                right,
311            } => write!(f, "({left} {operator} {right})"),
312            Self::Logical {
313                operator,
314                left,
315                right,
316            } => write!(f, "({left} {operator} {right})"),
317            Self::Conditional {
318                test,
319                consequent,
320                alternate,
321            } => write!(f, "({test} ? {consequent} : {alternate})"),
322            Self::Assignment {
323                operator,
324                left,
325                right,
326            } => write!(f, "({left} {operator} {right})"),
327            Self::Sequence { expressions } => write_sequence(f, expressions),
328            Self::Spread { argument } => write!(f, "...{argument}"),
329            Self::ArrowFunction(arrow) => write!(f, "{arrow}"),
330            Self::FunctionExpression(func) => write!(f, "{func}"),
331            Self::ClassExpression(class) => write!(f, "{class}"),
332            Self::Yield { argument, delegate } => write_yield(f, argument.as_deref(), *delegate),
333            Self::Await { argument } => write!(f, "(await {argument})"),
334            Self::Chain { expression } => write!(f, "{expression}"),
335            Self::ImportExpression { source, options } => {
336                write_import_expression(f, source, options.as_deref())
337            }
338            Self::MetaProperty { meta, property } => write!(f, "{meta}.{property}"),
339            Self::Parenthesized { expression } => write!(f, "({expression})"),
340        }
341    }
342}
343
344fn write_template(
345    f: &mut std::fmt::Formatter<'_>,
346    tag: Option<&Expression>,
347    quasis: &[String],
348    expressions: &[Expression],
349) -> std::fmt::Result {
350    if let Some(tag) = tag {
351        write!(f, "{tag}")?;
352    }
353    f.write_str("`")?;
354    let pieces: String = quasis
355        .iter()
356        .enumerate()
357        .map(|(i, quasi)| {
358            expressions
359                .get(i)
360                .map_or_else(|| quasi.clone(), |expr| format!("{quasi}${{{expr}}}"))
361        })
362        .collect();
363    f.write_str(&pieces)?;
364    f.write_str("`")
365}
366
367fn write_array(
368    f: &mut std::fmt::Formatter<'_>,
369    elements: &[Option<Expression>],
370) -> std::fmt::Result {
371    let body = elements
372        .iter()
373        .map(|e| {
374            e.as_ref()
375                .map_or_else(String::new, |expr| format!("{expr}"))
376        })
377        .collect::<Vec<_>>()
378        .join(", ");
379    write!(f, "[{body}]")
380}
381
382fn write_object(f: &mut std::fmt::Formatter<'_>, properties: &[ObjectMember]) -> std::fmt::Result {
383    let body = properties
384        .iter()
385        .map(|m| format!("{m}"))
386        .collect::<Vec<_>>()
387        .join(", ");
388    write!(f, "{{{body}}}")
389}
390
391fn write_member(
392    f: &mut std::fmt::Formatter<'_>,
393    object: &Expression,
394    property: &MemberProperty,
395    optional: bool,
396) -> std::fmt::Result {
397    let connector = if optional { "?." } else { "" };
398    match property {
399        MemberProperty::Identifier(name) => write!(f, "{object}{connector}.{name}"),
400        MemberProperty::Computed(expr) => write!(f, "{object}{connector}[{expr}]"),
401        MemberProperty::Private(p) => write!(f, "{object}{connector}.{p}"),
402    }
403}
404
405fn write_call(
406    f: &mut std::fmt::Formatter<'_>,
407    callee: &Expression,
408    arguments: &[Expression],
409    optional: bool,
410) -> std::fmt::Result {
411    let args = arguments
412        .iter()
413        .map(|a| format!("{a}"))
414        .collect::<Vec<_>>()
415        .join(", ");
416    let connector = if optional { "?." } else { "" };
417    write!(f, "{callee}{connector}({args})")
418}
419
420fn write_new(
421    f: &mut std::fmt::Formatter<'_>,
422    callee: &Expression,
423    arguments: &[Expression],
424) -> std::fmt::Result {
425    let args = arguments
426        .iter()
427        .map(|a| format!("{a}"))
428        .collect::<Vec<_>>()
429        .join(", ");
430    write!(f, "(new {callee}({args}))")
431}
432
433fn write_update(
434    f: &mut std::fmt::Formatter<'_>,
435    operator: UpdateOperator,
436    argument: &Expression,
437    prefix: bool,
438) -> std::fmt::Result {
439    if prefix {
440        write!(f, "({operator}{argument})")
441    } else {
442        write!(f, "({argument}{operator})")
443    }
444}
445
446fn write_sequence(f: &mut std::fmt::Formatter<'_>, expressions: &[Expression]) -> std::fmt::Result {
447    let body = expressions
448        .iter()
449        .map(|e| format!("{e}"))
450        .collect::<Vec<_>>()
451        .join(", ");
452    write!(f, "({body})")
453}
454
455fn write_yield(
456    f: &mut std::fmt::Formatter<'_>,
457    argument: Option<&Expression>,
458    delegate: bool,
459) -> std::fmt::Result {
460    let star = if delegate { "*" } else { "" };
461    match argument {
462        Some(arg) => write!(f, "(yield{star} {arg})"),
463        None => write!(f, "(yield{star})"),
464    }
465}
466
467fn write_import_expression(
468    f: &mut std::fmt::Formatter<'_>,
469    source: &Expression,
470    options: Option<&Expression>,
471) -> std::fmt::Result {
472    match options {
473        Some(opts) => write!(f, "import({source}, {opts})"),
474        None => write!(f, "import({source})"),
475    }
476}
477
478impl std::fmt::Display for ObjectMember {
479    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
480        match self {
481            Self::Property {
482                key,
483                value,
484                kind,
485                computed,
486                shorthand,
487            } => write_object_member_property(f, key, value, *kind, *computed, *shorthand),
488            Self::Spread { argument } => write!(f, "...{argument}"),
489        }
490    }
491}
492
493fn write_object_member_property(
494    f: &mut std::fmt::Formatter<'_>,
495    key: &PropertyKey,
496    value: &Expression,
497    kind: ObjectPropertyKind,
498    computed: bool,
499    shorthand: bool,
500) -> std::fmt::Result {
501    let key_repr = if computed {
502        format!("[{key}]")
503    } else {
504        format!("{key}")
505    };
506    match kind {
507        ObjectPropertyKind::Init if shorthand => write!(f, "{key_repr}"),
508        ObjectPropertyKind::Init => write!(f, "{key_repr}: {value}"),
509        ObjectPropertyKind::Get => write!(f, "get {key_repr}() {{ ... }}"),
510        ObjectPropertyKind::Set => write!(f, "set {key_repr}(v) {{ ... }}"),
511        ObjectPropertyKind::Method => write!(f, "{key_repr}() {{ ... }}"),
512    }
513}