Merge remote-tracking branch 'kristofdegrave/nullPropagation' into feat-optional-chaining

This commit is contained in:
Sven SAULEAU 2017-04-17 13:21:35 +02:00
commit 0927e24ac6
No known key found for this signature in database
GPG Key ID: 7C3212582FBA1BA2
6 changed files with 606 additions and 11 deletions

View File

@ -845,10 +845,11 @@ interface MemberExpression <: Expression, Pattern {
object: Expression | Super;
property: Expression;
computed: boolean;
nullPropagation: boolean | null;
}
```
A member expression. If `computed` is `true`, the node corresponds to a computed (`a[b]`) member expression and `property` is an `Expression`. If `computed` is `false`, the node corresponds to a static (`a.b`) member expression and `property` is an `Identifier`.
A member expression. If `computed` is `true`, the node corresponds to a computed (`a[b]`) member expression and `property` is an `Expression`. If `computed` is `false`, the node corresponds to a static (`a.b`) member expression and `property` is an `Identifier`. The `nullPropagation` flags indecates that the member expression can be called even if the object is null or undefined. If this is the object value (null/undefined) should be returned.
### BindExpression

View File

@ -284,14 +284,23 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
node.object = base;
node.callee = this.parseNoCallExpr();
return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls);
} else if (this.eat(tt.question)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.optional = true;
this.next();
node.property = this.parseIdentifier(true);
node.computed = false;
base = this.finishNode(node, "MemberExpression");
} else if (this.eat(tt.questionDot)) {
base.optional = true;
if (this.eat(tt.bracketL)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.parseExpression();
node.computed = true;
this.expect(tt.bracketR);
base = this.finishNode(node, "MemberExpression");
} else {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
node.property = this.parseIdentifier(true);
node.computed = false;
base = this.finishNode(node, "MemberExpression");
}
} else if (this.eat(tt.dot)) {
const node = this.startNodeAt(startPos, startLoc);
node.object = base;
@ -303,6 +312,7 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
node.object = base;
node.property = this.parseExpression();
node.computed = true;
delete node.nullPropagation;
this.expect(tt.bracketR);
base = this.finishNode(node, "MemberExpression");
} else if (!noCalls && this.match(tt.parenL)) {

View File

@ -391,6 +391,18 @@ export default class Tokenizer {
return this.finishOp(code === 61 ? tt.eq : tt.prefix, 1);
}
readToken_question() { // '?'
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === 46) { // 46 = question '.'
this.state.pos += 2;
return this.finishToken(tt.questionDot);
}
else {
++this.state.pos;
return this.finishToken(tt.question);
}
}
getTokenFromCode(code) {
switch (code) {
// The interpretation of a dot depends on whether it is followed
@ -425,7 +437,7 @@ export default class Tokenizer {
return this.finishToken(tt.colon);
}
case 63: ++this.state.pos; return this.finishToken(tt.question);
case 63: return this.readToken_question();
case 64: ++this.state.pos; return this.finishToken(tt.at);
case 96: // '`'
@ -844,7 +856,7 @@ export default class Tokenizer {
const type = this.state.type;
let update;
if (type.keyword && prevType === tt.dot) {
if (type.keyword && (prevType === tt.dot || prevType === tt.questionDot)) {
this.state.exprAllowed = false;
} else if (update = type.updateContext) {
update.call(this, prevType);

View File

@ -75,6 +75,7 @@ export const types = {
doubleColon: new TokenType("::", { beforeExpr }),
dot: new TokenType("."),
question: new TokenType("?", { beforeExpr }),
questionDot: new TokenType("?."),
arrow: new TokenType("=>", { beforeExpr }),
template: new TokenType("template"),
ellipsis: new TokenType("...", { beforeExpr }),

View File

@ -0,0 +1,5 @@
o?.x?.y
o?.x ? o.x.z?.w : o.y?.z?.w
o?.[0]?.["1"]?.x

View File

@ -0,0 +1,566 @@
{
"type": "File",
"start": 0,
"end": 54,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 5,
"column": 16
}
},
"program": {
"type": "Program",
"start": 0,
"end": 54,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 5,
"column": 16
}
},
"sourceType": "script",
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 7
}
},
"expression": {
"type": "MemberExpression",
"start": 0,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 7
}
},
"object": {
"type": "MemberExpression",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"object": {
"type": "Identifier",
"start": 0,
"end": 1,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 1
}
},
"name": "o",
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 3,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 3
},
"end": {
"line": 1,
"column": 4
}
},
"name": "x"
},
"computed": false,
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 7
}
},
"name": "y"
},
"computed": false
}
},
{
"type": "ExpressionStatement",
"start": 9,
"end": 36,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 27
}
},
"expression": {
"type": "ConditionalExpression",
"start": 9,
"end": 36,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 27
}
},
"test": {
"type": "MemberExpression",
"start": 9,
"end": 13,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 4
}
},
"object": {
"type": "Identifier",
"start": 9,
"end": 10,
"loc": {
"start": {
"line": 3,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"name": "o",
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 3,
"column": 3
},
"end": {
"line": 3,
"column": 4
}
},
"name": "x"
},
"computed": false
},
"consequent": {
"type": "MemberExpression",
"start": 16,
"end": 24,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 15
}
},
"object": {
"type": "MemberExpression",
"start": 16,
"end": 21,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 12
}
},
"object": {
"type": "MemberExpression",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 10
}
},
"object": {
"type": "Identifier",
"start": 16,
"end": 17,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 8
}
},
"name": "o"
},
"property": {
"type": "Identifier",
"start": 18,
"end": 19,
"loc": {
"start": {
"line": 3,
"column": 9
},
"end": {
"line": 3,
"column": 10
}
},
"name": "x"
},
"computed": false
},
"property": {
"type": "Identifier",
"start": 20,
"end": 21,
"loc": {
"start": {
"line": 3,
"column": 11
},
"end": {
"line": 3,
"column": 12
}
},
"name": "z"
},
"computed": false,
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 23,
"end": 24,
"loc": {
"start": {
"line": 3,
"column": 14
},
"end": {
"line": 3,
"column": 15
}
},
"name": "w"
},
"computed": false
},
"alternate": {
"type": "MemberExpression",
"start": 27,
"end": 36,
"loc": {
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 27
}
},
"object": {
"type": "MemberExpression",
"start": 27,
"end": 33,
"loc": {
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 24
}
},
"object": {
"type": "MemberExpression",
"start": 27,
"end": 30,
"loc": {
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 21
}
},
"object": {
"type": "Identifier",
"start": 27,
"end": 28,
"loc": {
"start": {
"line": 3,
"column": 18
},
"end": {
"line": 3,
"column": 19
}
},
"name": "o"
},
"property": {
"type": "Identifier",
"start": 29,
"end": 30,
"loc": {
"start": {
"line": 3,
"column": 20
},
"end": {
"line": 3,
"column": 21
}
},
"name": "y"
},
"computed": false,
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 32,
"end": 33,
"loc": {
"start": {
"line": 3,
"column": 23
},
"end": {
"line": 3,
"column": 24
}
},
"name": "z"
},
"computed": false,
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 35,
"end": 36,
"loc": {
"start": {
"line": 3,
"column": 26
},
"end": {
"line": 3,
"column": 27
}
},
"name": "w"
},
"computed": false
}
}
},
{
"type": "ExpressionStatement",
"start": 38,
"end": 54,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 16
}
},
"expression": {
"type": "MemberExpression",
"start": 38,
"end": 54,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 16
}
},
"object": {
"type": "MemberExpression",
"start": 38,
"end": 51,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 13
}
},
"object": {
"type": "MemberExpression",
"start": 38,
"end": 44,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 6
}
},
"object": {
"type": "Identifier",
"start": 38,
"end": 39,
"loc": {
"start": {
"line": 5,
"column": 0
},
"end": {
"line": 5,
"column": 1
}
},
"name": "o",
"nullPropagation": true
},
"property": {
"type": "NumericLiteral",
"start": 42,
"end": 43,
"loc": {
"start": {
"line": 5,
"column": 4
},
"end": {
"line": 5,
"column": 5
}
},
"value": 0
},
"computed": true,
"nullPropagation": true
},
"property": {
"type": "StringLiteral",
"start": 47,
"end": 50,
"loc": {
"start": {
"line": 5,
"column": 9
},
"end": {
"line": 5,
"column": 12
}
},
"value": "1"
},
"computed": true,
"nullPropagation": true
},
"property": {
"type": "Identifier",
"start": 53,
"end": 54,
"loc": {
"start": {
"line": 5,
"column": 15
},
"end": {
"line": 5,
"column": 16
}
},
"name": "x"
},
"computed": false
}
}
]
}
}