Skip to content

Commit

Permalink
Add optional chaining (#204)
Browse files Browse the repository at this point in the history
* add ChainingExpression

* update es2020.md

* fix "where are" → "that are"
  • Loading branch information
mysticatea committed Jun 11, 2020
1 parent a603a7c commit d1cb85c
Showing 1 changed file with 169 additions and 1 deletion.
170 changes: 169 additions & 1 deletion es2020.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,174 @@ interface BigIntLiteral <: Literal {

# Expressions

## ChainExpression

```js
interface ChainExpression <: Expression {
type: "ChainExpression"
expression: ChainElement
}

interface ChainElement <: Node {
optional: boolean
}

extend interface CallExpression <: ChainElement {}
extend interface MemberExpression <: ChainElement {}
```

- The `ChainExpression` node is the root of optional chaining.
- The `ChainExpression` node contains one or more `ChainElement` nodes that are `optional:true`. On the other hand, `ChainElement` nodes that are `optional:true` belong to a `ChainExpression` node.
- For backward compatibility, if all `ChainElement` nodes of a chain are `optional:false`, the `ChainExpression` node isn't inserted as the root of the chain.
- Evaluation:
- The `ChainExpression` node is evaluated to the result of the `expression` property's node.
- If the `callee|object` property is evaluated to nullish and the `optional` property is `true`, then the node and ancestor nodes are skipped until the closest `ChainExpression` node, and the result of the `ChainExpression` node becomes `undefined`.

<details><summary>For Examples:</summary>

```jsonc
// obj.aaa.bbb
{
"type": "MemberExpression",
"optional": false,
"object": {
"type": "MemberExpression",
"optional": false,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
},
"property": { "type": "Identifier", "name": "bbb" }
}
```

```jsonc
// obj.aaa?.bbb
{
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": true,
"object": {
"type": "MemberExpression",
"optional": false,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
},
"property": { "type": "Identifier", "name": "bbb" }
}
}
```

```jsonc
// obj?.aaa.bbb
{
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": false,
"object": {
"type": "MemberExpression",
"optional": true,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
},
"property": { "type": "Identifier", "name": "bbb" }
}
}
```

```jsonc
// obj?.aaa?.bbb
{
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": true,
"object": {
"type": "MemberExpression",
"optional": true,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
},
"property": { "type": "Identifier", "name": "bbb" }
}
}
```

```jsonc
// (obj.aaa).bbb
{
"type": "MemberExpression",
"optional": false,
"object": {
"type": "MemberExpression",
"optional": false,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
},
"property": { "type": "Identifier", "name": "bbb" }
}
```

```jsonc
// (obj.aaa)?.bbb
{
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": true,
"object": {
"type": "MemberExpression",
"optional": false,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
},
"property": { "type": "Identifier", "name": "bbb" }
}
}
```

```jsonc
// (obj?.aaa).bbb
{
"type": "MemberExpression",
"optional": false,
"object": {
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": true,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
}
},
"property": { "type": "Identifier", "name": "bbb" }
}
```

```jsonc
// (obj?.aaa)?.bbb
{
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": true,
"object": {
"type": "ChainExpression",
"expression": {
"type": "MemberExpression",
"optional": true,
"object": { "type": "Identifier", "name": "obj" },
"property": { "type": "Identifier", "name": "aaa" }
}
},
"property": { "type": "Identifier", "name": "bbb" }
}
}
```

</details>

## ImportExpression

```js
Expand All @@ -39,7 +207,7 @@ interface ImportExpression <: Expression {
- `ImportExpression` node represents Dynamic Imports such as `import(source)`.
The `source` property is the importing source as similar to [ImportDeclaration]
node, but it can be an arbitrary expression node.

## LogicalExpression

```js
Expand Down

0 comments on commit d1cb85c

Please sign in to comment.