From 1eaf01661b2af969463e9726b445de3ca8bed018 Mon Sep 17 00:00:00 2001 From: Kristof Degrave Date: Sat, 11 Feb 2017 21:09:27 +0100 Subject: [PATCH] babel/babylon#328 babel/babylon#205 ?. as nullPropagation. For now it only works for member access. (.? or ?.[) If the object is undefined this will return undefined. If the object on which you want to access the property is defined, the value of the propery will be given back. --- ast/spec.md | 2 +- src/parser/expression.js | 32 ++++---- src/tokenizer/index.js | 26 +++---- src/tokenizer/types.js | 3 +- .../experimental/uncategorised/63/actual.js | 2 +- .../uncategorised/63/expected.json | 78 +++++++++---------- 6 files changed, 68 insertions(+), 75 deletions(-) diff --git a/ast/spec.md b/ast/spec.md index f75e121ee9..5bc39185c8 100644 --- a/ast/spec.md +++ b/ast/spec.md @@ -857,7 +857,7 @@ interface MemberExpression <: Expression, Pattern { object: Expression | Super; property: Expression; computed: boolean; - nullPropagation: boolean; + nullPropagation: boolean | null; } ``` diff --git a/src/parser/expression.js b/src/parser/expression.js index a1d709f06a..24b35c4ee3 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -284,27 +284,29 @@ 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.questionDot)) { - let node = this.startNodeAt(startPos, startLoc); - node.object = base; - node.property = this.parseIdentifier(true); - node.computed = false; - node.nullPropagation = true; - base = this.finishNode(node, "MemberExpression"); + } else if (this.eat(tt.questionDot)) { + base.nullPropagation = 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; node.property = this.parseIdentifier(true); node.computed = false; - node.nullPropagation = false; base = this.finishNode(node, "MemberExpression"); - } else if (this.eat(tt.questionBracketL)) { - let node = this.startNodeAt(startPos, startLoc); - node.object = base; - node.property = this.parseExpression(); - node.computed = true; - node.nullPropagation = true; - this.expect(tt.bracketR); } else if (this.eat(tt.bracketL)) { const node = this.startNodeAt(startPos, startLoc); node.object = base; diff --git a/src/tokenizer/index.js b/src/tokenizer/index.js index 9809c6820d..5a2326c296 100644 --- a/src/tokenizer/index.js +++ b/src/tokenizer/index.js @@ -392,20 +392,16 @@ export default class Tokenizer { } readToken_question() { // '?' - let next = this.input.charCodeAt(this.state.pos + 1); - if(next === 46){ // 46 = question '.' - this.state.pos += 2; - return this.finishToken(tt.questionDot); - } - else if(next === 91){ // 91 = question '[' - this.state.pos += 2; - return this.finishToken(tt.questionBracketL); - } - else { - ++this.state.pos; - return this.finishToken(tt.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) { @@ -825,7 +821,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); diff --git a/src/tokenizer/types.js b/src/tokenizer/types.js index 77a77e40d4..e7f32619fc 100644 --- a/src/tokenizer/types.js +++ b/src/tokenizer/types.js @@ -75,8 +75,7 @@ export const types = { doubleColon: new TokenType("::", { beforeExpr }), dot: new TokenType("."), question: new TokenType("?", { beforeExpr }), - questionBracketL: new TokenType("?[", { beforeExpr, startsExpr }), - questionBracketL: new TokenType("?."), + questionDot: new TokenType("?."), arrow: new TokenType("=>", { beforeExpr }), template: new TokenType("template"), ellipsis: new TokenType("...", { beforeExpr }), diff --git a/test/fixtures/experimental/uncategorised/63/actual.js b/test/fixtures/experimental/uncategorised/63/actual.js index 85718cbd72..eeb713af30 100644 --- a/test/fixtures/experimental/uncategorised/63/actual.js +++ b/test/fixtures/experimental/uncategorised/63/actual.js @@ -2,4 +2,4 @@ o?.x?.y o?.x ? o.x.z?.w : o.y?.z?.w -o?[0]?[1]?.x \ No newline at end of file +o?.[0]?.["1"]?.x \ No newline at end of file diff --git a/test/fixtures/experimental/uncategorised/63/expected.json b/test/fixtures/experimental/uncategorised/63/expected.json index bead29a860..7f36efbc14 100644 --- a/test/fixtures/experimental/uncategorised/63/expected.json +++ b/test/fixtures/experimental/uncategorised/63/expected.json @@ -1,7 +1,7 @@ { "type": "File", "start": 0, - "end": 50, + "end": 54, "loc": { "start": { "line": 1, @@ -9,13 +9,13 @@ }, "end": { "line": 5, - "column": 12 + "column": 16 } }, "program": { "type": "Program", "start": 0, - "end": 50, + "end": 54, "loc": { "start": { "line": 1, @@ -23,7 +23,7 @@ }, "end": { "line": 5, - "column": 12 + "column": 16 } }, "sourceType": "script", @@ -85,7 +85,7 @@ } }, "name": "o", - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", @@ -104,7 +104,7 @@ "name": "x" }, "computed": false, - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", @@ -182,7 +182,7 @@ } }, "name": "o", - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", @@ -295,7 +295,7 @@ "name": "z" }, "computed": false, - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", @@ -390,7 +390,7 @@ "name": "y" }, "computed": false, - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", @@ -409,7 +409,7 @@ "name": "z" }, "computed": false, - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", @@ -434,7 +434,7 @@ { "type": "ExpressionStatement", "start": 38, - "end": 50, + "end": 54, "loc": { "start": { "line": 5, @@ -442,13 +442,13 @@ }, "end": { "line": 5, - "column": 12 + "column": 16 } }, "expression": { "type": "MemberExpression", "start": 38, - "end": 50, + "end": 54, "loc": { "start": { "line": 5, @@ -456,13 +456,13 @@ }, "end": { "line": 5, - "column": 12 + "column": 16 } }, "object": { "type": "MemberExpression", "start": 38, - "end": 47, + "end": 51, "loc": { "start": { "line": 5, @@ -470,13 +470,13 @@ }, "end": { "line": 5, - "column": 9 + "column": 13 } }, "object": { "type": "MemberExpression", "start": 38, - "end": 43, + "end": 44, "loc": { "start": { "line": 5, @@ -484,7 +484,7 @@ }, "end": { "line": 5, - "column": 5 + "column": 6 } }, "object": { @@ -502,62 +502,58 @@ } }, "name": "o", - "existentialOperator": true + "nullPropagation": true }, "property": { - "type": "Literal", - "start": 41, - "end": 42, + "type": "NumericLiteral", + "start": 42, + "end": 43, "loc": { "start": { "line": 5, - "column": 3 + "column": 4 }, "end": { "line": 5, - "column": 4 + "column": 5 } }, - "value": 0, - "rawValue": 0, - "raw": "0" + "value": 0 }, "computed": true, - "existentialOperator": true + "nullPropagation": true }, "property": { - "type": "Literal", - "start": 45, - "end": 46, + "type": "StringLiteral", + "start": 47, + "end": 50, "loc": { "start": { "line": 5, - "column": 7 + "column": 9 }, "end": { "line": 5, - "column": 8 + "column": 12 } }, - "value": 1, - "rawValue": 1, - "raw": "1" + "value": "1" }, "computed": true, - "existentialOperator": true + "nullPropagation": true }, "property": { "type": "Identifier", - "start": 49, - "end": 50, + "start": 53, + "end": 54, "loc": { "start": { "line": 5, - "column": 11 + "column": 15 }, "end": { "line": 5, - "column": 12 + "column": 16 } }, "name": "x"