Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add optional chaining #204

Merged
merged 4 commits into from
Jun 11, 2020
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 where are `optional:true`. On the other hand, `ChainElement` nodes where 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