From 2376b758fd2daefe408ff8c7bc4dd80f6d85242c Mon Sep 17 00:00:00 2001 From: "William C. Johnson" Date: Mon, 25 Sep 2017 15:41:14 -0400 Subject: [PATCH] 2.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Syntactic placeholders - Pipe calls `|>`, `<|` - Track block nesting level in parser state - Fix bang call subscript unwinding crossing block boundaries - Fix premature “comprehensions are illegal” error disallowing patterns with “for” or “case” keys - Don’t lint when testing commit 64f066f2274d45931a55964b099a4ce05bd6c637 Author: William C. Johnson Date: Mon Sep 25 15:36:41 2017 -0400 Fix for bang call subscripting issue across block boundaries commit bda54e57ddd33afaa4af9b99b2878e1616702248 Author: William C. Johnson Date: Mon Sep 25 14:38:44 2017 -0400 Comprehension fixes commit 476419a8dbe3fadf058c1ece887700bdc8da1194 Author: William C. Johnson Date: Sat Sep 23 15:53:55 2017 -0400 Run lint and flow at `preversion`, not `test` commit 266f94800542bfd5e8974e28b5d5f30e4d40a8fa Author: William C. Johnson Date: Mon Sep 18 23:16:07 2017 -0400 @oigroup/babylon-lightscript@2.3.0-alpha.3 commit 2342c39c57a7beb75bb939b02181350a7f4149bf Author: William C. Johnson Date: Tue Sep 5 16:51:01 2017 -0400 @oigroup/babylon-lightscript@2.3.0-alpha.2 commit 21a26a892493ef56bfab47f3b9c1f23b69ad8e94 Merge: e61679ce 7c5e20ea Author: William C. Johnson Date: Tue Sep 5 15:24:38 2017 -0400 Merge branch 'prerelease/2.3.0' of https://github.com/wcjohnson/babylon-lightscript into prerelease/2.3.0 commit e61679ce6e034aaef3971e7de66404c8e27c7b81 Author: William C. Johnson Date: Tue Sep 5 15:24:20 2017 -0400 Unit test for unfortunate flow typecast in if test clause commit 7c5e20ea5aec13fe29ed667f0764f6033a75adba Author: William C. Johnson Date: Sun Aug 6 12:58:46 2017 -0400 Misc cleanup - Remove errant copypasta from tildeCall.js - Clean up spacing/comments commit ffb7ddb07eda14deb9bf8c4b7f2507c26d80e04f Author: William C. Johnson Date: Wed Jul 19 21:43:42 2017 -0400 @oigroup/babylon-lightscript@2.3.0-alpha.1 commit fb570ee0983e5c816d82dd1d8559317305886e1d Author: William C. Johnson Date: Wed Jul 19 21:28:23 2017 -0400 Pipe call improvements - Support arrows as pipe call operands - Support leftward-pointing pipe calls commit f248451c485361c492c4f02097bef8dc1ae593b1 Author: William C. Johnson Date: Mon Jul 17 16:09:12 2017 -0400 @oigroup/babylon-lightscript@2.3.0-alpha.0 commit 00a76ef0d04778614e5a60521a5de99c7117a64e Author: William C. Johnson Date: Mon Jul 17 15:52:31 2017 -0400 Fix for left-associativity and subscripts of pipeCalls commit 6d4d300ef3f3af40d46696540d3b45833b32f0e9 Author: William C. Johnson Date: Mon Jul 17 00:43:08 2017 -0400 `pipeCall` tests commit 4e579c79b928a146e1e969b1530289b46cb24ce0 Author: William C. Johnson Date: Mon Jul 17 00:28:40 2017 -0400 @oigroup/babylon-lightscript@2.3.0-2 commit 17f5a4455d9d0e174253b4377fa3e1509973345f Author: William C. Johnson Date: Sun Jul 16 23:19:22 2017 -0400 @oigroup/babylon-lightscript@2.3.0-1 commit 0bcd865d7f3a0c79178b6f4fa02b7094f760ce63 Author: William C. Johnson Date: Sun Jul 16 23:07:36 2017 -0400 @oigroup/babylon-lightscript@2.3.0-0 commit 69750535c0f219679ffab8b193fd1e2be4ecbb21 Author: William C. Johnson Date: Sun Jul 16 23:03:53 2017 -0400 Parsing for pipe operator commit b10a5e48d1552ff389de314762e863197bc0da7e Author: William C. Johnson Date: Sun Jul 16 22:55:34 2017 -0400 Fix associativity commit 0fac7c226b9cd9cda94a5956a45a067a145e2976 Author: William C. Johnson Date: Sun Jul 16 22:22:34 2017 -0400 Parse pipe operator as subscript commit b21acb2f12941d9d7d4279320de4c55c7ee3b50f Author: William C. Johnson Date: Sun Jul 16 21:17:17 2017 -0400 Basic pipeCall parsing commit 70ee2c810886bc8373ebffa771d3ad9a29345843 Author: William C. Johnson Date: Sun Jul 16 20:46:52 2017 -0400 Syntactic placeholders commit d5d4e7491de9a8b4e99128197534ca411aee2289 Author: William C. Johnson Date: Sun Jul 16 20:41:48 2017 -0400 Allow placeholder to be changed via config commit 32e43a0f51ef1e62c48a6b52cd5af0843ab4b4c7 Author: William C. Johnson Date: Sun Jul 16 20:24:59 2017 -0400 Spread placeholder tests commit 73b9d329505a49a4024997299f90dc20190d65cc Author: William C. Johnson Date: Sun Jul 16 15:31:50 2017 -0400 Initial implementation of syntactic placeholders --- package.json | 6 +- src/options.js | 5 +- src/parser/expression.js | 39 +++- src/parser/statement.js | 4 + src/plugins/bangCall.js | 7 +- src/plugins/lightscript.js | 20 +- src/plugins/pipeCall.js | 50 +++++ src/plugins/syntacticPlaceholder.js | 51 +++++ src/plugins/tildeCall.js | 2 +- src/registerPlugins.js | 9 + src/tokenizer/index.js | 9 + src/tokenizer/state.js | 1 + .../actual.js | 1 + .../options.json | 3 + .../subscripts/ambiguous-arrow-body/actual.js | 3 + .../ambiguous-arrow-body/expected.json | 193 +++++++++++++++++ .../ambiguous-arrow-body/options.json | 11 + .../object-comprehension/actual.js | 3 + .../object-comprehension/expected.json | 199 ++++++++++++++++++ .../expected.objectBlockAmbiguity.json | 168 +++++++++++++++ .../no-enforced-indentation-tilde/actual.js | 2 + .../expected.json | 99 +++++++++ .../options.json | 11 + test/fixtures/pipe-call/basic/arrow/actual.js | 1 + .../pipe-call/basic/arrow/expected.json | 137 ++++++++++++ .../pipe-call/basic/associativity/actual.js | 1 + .../basic/associativity/expected.json | 130 ++++++++++++ test/fixtures/pipe-call/basic/pipe/actual.js | 1 + .../pipe-call/basic/pipe/expected.json | 98 +++++++++ .../pipe-call/basic/rhs-expr/actual.js | 1 + .../pipe-call/basic/rhs-expr/expected.json | 132 ++++++++++++ .../pipe-call/leftward/pipe/actual.js | 1 + .../pipe-call/leftward/pipe/expected.json | 132 ++++++++++++ test/fixtures/pipe-call/options.json | 8 + .../basic/basic/actual.js | 1 + .../basic/basic/expected.json | 64 ++++++ .../basic/indexed/actual.js | 1 + .../basic/indexed/expected.json | 65 ++++++ .../basic/spread-indexed/actual.js | 1 + .../basic/spread-indexed/expected.json | 118 +++++++++++ .../basic/spread/actual.js | 1 + .../basic/spread/expected.json | 117 ++++++++++ .../syntactic-placeholder/options.json | 8 + .../opts/change-placeholder/actual.js | 1 + .../expected.changePlaceholder.json | 64 ++++++ .../opts/change-placeholder/expected.json | 66 ++++++ .../opts/change-placeholder/options.json | 12 ++ test/utils/TestRunner.js | 4 + 48 files changed, 2043 insertions(+), 18 deletions(-) create mode 100644 src/plugins/pipeCall.js create mode 100644 src/plugins/syntacticPlaceholder.js create mode 100644 test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/actual.js create mode 100644 test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/options.json create mode 100644 test/fixtures/bang-call/subscripts/ambiguous-arrow-body/actual.js create mode 100644 test/fixtures/bang-call/subscripts/ambiguous-arrow-body/expected.json create mode 100644 test/fixtures/bang-call/subscripts/ambiguous-arrow-body/options.json create mode 100644 test/fixtures/lightscript/object-block-ambiguity/object-comprehension/actual.js create mode 100644 test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.json create mode 100644 test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.objectBlockAmbiguity.json create mode 100644 test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/actual.js create mode 100644 test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/expected.json create mode 100644 test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/options.json create mode 100644 test/fixtures/pipe-call/basic/arrow/actual.js create mode 100644 test/fixtures/pipe-call/basic/arrow/expected.json create mode 100644 test/fixtures/pipe-call/basic/associativity/actual.js create mode 100644 test/fixtures/pipe-call/basic/associativity/expected.json create mode 100644 test/fixtures/pipe-call/basic/pipe/actual.js create mode 100644 test/fixtures/pipe-call/basic/pipe/expected.json create mode 100644 test/fixtures/pipe-call/basic/rhs-expr/actual.js create mode 100644 test/fixtures/pipe-call/basic/rhs-expr/expected.json create mode 100644 test/fixtures/pipe-call/leftward/pipe/actual.js create mode 100644 test/fixtures/pipe-call/leftward/pipe/expected.json create mode 100644 test/fixtures/pipe-call/options.json create mode 100644 test/fixtures/syntactic-placeholder/basic/basic/actual.js create mode 100644 test/fixtures/syntactic-placeholder/basic/basic/expected.json create mode 100644 test/fixtures/syntactic-placeholder/basic/indexed/actual.js create mode 100644 test/fixtures/syntactic-placeholder/basic/indexed/expected.json create mode 100644 test/fixtures/syntactic-placeholder/basic/spread-indexed/actual.js create mode 100644 test/fixtures/syntactic-placeholder/basic/spread-indexed/expected.json create mode 100644 test/fixtures/syntactic-placeholder/basic/spread/actual.js create mode 100644 test/fixtures/syntactic-placeholder/basic/spread/expected.json create mode 100644 test/fixtures/syntactic-placeholder/options.json create mode 100644 test/fixtures/syntactic-placeholder/opts/change-placeholder/actual.js create mode 100644 test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.changePlaceholder.json create mode 100644 test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.json create mode 100644 test/fixtures/syntactic-placeholder/opts/change-placeholder/options.json diff --git a/package.json b/package.json index 0c20b7704e..3a1f692194 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@oigroup/babylon-lightscript", - "version": "2.2.1", + "version": "2.3.0-alpha.3", "description": "A LightScript parser, based on babylon (a JavaScript parser)", "author": "Alex Rattray ", "homepage": "http://lightscript.org/", @@ -53,8 +53,8 @@ "clean": "rimraf lib", "flow": "flow", "prepublish": "cross-env BABEL_ENV=production npm run build", - "preversion": "npm run test", - "test": "npm run lint && npm run flow && npm run build -- -m && npm run test-only", + "preversion": "npm run lint && npm run flow && npm run test", + "test": "npm run build -- -m && npm run test-only", "test-only": "ava", "test-ci": "nyc npm run test-only", "changelog": "git log `git describe --tags --abbrev=0`..HEAD --pretty=format:' * %s (%an)' | grep -v 'Merge pull request'", diff --git a/src/options.js b/src/options.js index 72c65f34a6..513069be70 100755 --- a/src/options.js +++ b/src/options.js @@ -9,7 +9,8 @@ export const defaultOptions: { allowImportExportEverywhere: boolean, allowSuperOutsideMethod: boolean, plugins: Array, - strictMode: any + strictMode: any, + placeholder: string } = { // Source type ("script" or "module") for different semantics sourceType: "script", @@ -30,6 +31,8 @@ export const defaultOptions: { plugins: [], // TODO strictMode: null, + // Default placeholder for use with syntacticPlaceholder plugin + placeholder: "_" }; // Interpret and default an options object diff --git a/src/parser/expression.js b/src/parser/expression.js index 4a05f1c992..76328d47a8 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -379,6 +379,12 @@ pp.parseExprSubscripts = function (refShorthandDefaultPos) { }; pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { + + // pipeCall plugin hack: pass noPipes via state to avoid changing args + // to core parser function. + const noPipes = this.state.noPipeSubscripts; + this.state.noPipeSubscripts = false; + for (;;) { if (this.hasPlugin("bangCall") && this.shouldUnwindBangSubscript()) { return base; @@ -412,7 +418,7 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { node.property = this.parseExprAtom(); node.computed = true; } else { - node.property = this.parseIdentifier(true); + node.property = this.parseIdentifierOrPlaceholder(true); node.computed = false; } base = this.finishNode(node, "MemberExpression"); @@ -431,7 +437,7 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { node.property = this.parseLiteral(this.state.value, "NumericLiteral"); node.computed = true; } else { - node.property = this.parseIdentifier(true); + node.property = this.parseIdentifierOrPlaceholder(true); node.computed = false; } } else if (op === "?[") { @@ -468,6 +474,14 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) { node.callee = base; const next = this.parseBangCall(node, "CallExpression"); if (next) base = next; else return node; + } else if ( + !noCalls && + !noPipes && + this.hasPlugin("pipeCall") && + this.match(tt.pipeCall) + ) { + const node = this.startNodeAt(startPos, startLoc); + base = this.parsePipeCall(node, base); } else if (!(this.hasPlugin("lightscript") && this.isNonIndentedBreakFrom(startPos)) && this.eat(tt.bracketL)) { const node = this.startNodeAt(startPos, startLoc); node.object = base; @@ -651,7 +665,7 @@ pp.parseExprAtom = function (refShorthandDefaultPos) { node = this.startNode(); const allowAwait = this.state.value === "await" && this.state.inAsync; const allowYield = this.shouldAllowYieldIdentifier(); - const id = this.parseIdentifier(allowAwait || allowYield); + const id = this.parseIdentifierOrPlaceholder(allowAwait || allowYield); if (id.name === "await") { if (this.state.inAsync || this.inModule) { @@ -661,7 +675,7 @@ pp.parseExprAtom = function (refShorthandDefaultPos) { this.next(); return this.parseFunction(node, false, false, true); } else if (canBeArrow && id.name === "async" && this.match(tt.name)) { - const params = [this.parseIdentifier()]; + const params = [this.parseIdentifierOrPlaceholder()]; this.check(tt.arrow); // let foo = bar => {}; return this.parseArrowExpression(node, params, true); @@ -1075,10 +1089,10 @@ pp.parseObj = function (isPattern, refShorthandDefaultPos) { this.hasPlugin("enhancedComprehension") && (this.match(tt._for) || this.match(tt._case)) ) { - if (isPattern) { - this.unexpected(null, "Comprehensions are illegal in patterns."); - } if (this.lookahead().type !== tt.colon) { + if (isPattern) { + this.unexpected(null, "Comprehensions are illegal in patterns."); + } node.properties.push(this.parseSomeComprehension()); hasComprehension = true; continue; @@ -1134,6 +1148,7 @@ pp.parseObj = function (isPattern, refShorthandDefaultPos) { if (!isPattern && this.isContextual("async")) { if (isGenerator) this.unexpected(); + // TODO: syntacticPlaceholder: is a placeholder legal here? const asyncId = this.parseIdentifier(); if (this.match(tt.colon) || this.match(tt.parenL) || this.match(tt.braceR) || this.match(tt.eq) || this.match(tt.comma) || (this.hasPlugin("lightscript") && this.isLineBreak())) { prop.key = asyncId; @@ -1262,6 +1277,7 @@ pp.parsePropertyName = function (prop) { prop.computed = false; const oldInPropertyName = this.state.inPropertyName; this.state.inPropertyName = true; + // TODO: syntacticPlaceholder: is a placeholder legal here? prop.key = (this.match(tt.num) || this.match(tt.string)) ? this.parseExprAtom() : this.parseIdentifier(true); this.state.inPropertyName = oldInPropertyName; } @@ -1465,6 +1481,15 @@ pp.parseIdentifier = function (liberal) { return this.finishNode(node, "Identifier"); }; +// Syntactic placeholders: shunt based on plugin status +pp.parseIdentifierOrPlaceholder = function(liberal) { + if (this.hasPlugin("syntacticPlaceholder")) { + return this._parseIdentifierOrPlaceholder(liberal); + } else { + return this.parseIdentifier(liberal); + } +}; + pp.checkReservedWord = function (word, startLoc, checkKeywords, isBinding) { if (this.isReservedWord(word) || (checkKeywords && this.isKeyword(word))) { this.raise(startLoc, word + " is a reserved word"); diff --git a/src/parser/statement.js b/src/parser/statement.js index 46f4a6c332..9ebfe55279 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -608,6 +608,8 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) { let oldStrict; let octalPosition; + this.state.nestedBlockLevel++; + let isEnd; if (this.hasPlugin("lightscript") && typeof end === "number") { isEnd = () => this.state.indentLevel <= end || this.match(tt.eof); @@ -642,6 +644,8 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) { node.body.push(stmt); } + this.state.nestedBlockLevel--; + if (oldStrict === false) { this.setStrict(false); } diff --git a/src/plugins/bangCall.js b/src/plugins/bangCall.js index 87932e2f73..f21200d92b 100644 --- a/src/plugins/bangCall.js +++ b/src/plugins/bangCall.js @@ -43,6 +43,8 @@ export default function(parser) { // Read args let first = true; const oldBangUnwindLevel = this.state.bangUnwindLevel; + const oldBangBlockLevel = this.state.bangBlockLevel; + this.state.bangBlockLevel = this.state.nestedBlockLevel; this.state.bangUnwindLevel = bangIndentLevel + 1; while (true) { @@ -81,6 +83,7 @@ export default function(parser) { } this.state.bangUnwindLevel = oldBangUnwindLevel; + this.state.bangBlockLevel = oldBangBlockLevel; node = this.finishNode(node, nodeType); @@ -93,6 +96,8 @@ export default function(parser) { // Subscripts to a bang call must appear at the arg indent level pp.shouldUnwindBangSubscript = function() { - return this.isLineBreak() && (this.state.indentLevel <= this.state.bangUnwindLevel); + return this.isLineBreak() && + (this.state.bangBlockLevel == this.state.nestedBlockLevel) && + (this.state.indentLevel <= this.state.bangUnwindLevel); }; } diff --git a/src/plugins/lightscript.js b/src/plugins/lightscript.js index 30acec5da5..ad1ee6ca0b 100644 --- a/src/plugins/lightscript.js +++ b/src/plugins/lightscript.js @@ -187,7 +187,9 @@ pp.rethrowObjParseError = function(objParseResult, blockParseError) { pp.parseInlineWhiteBlock = function(node) { if (this.state.type.startsExpr) return this.parseMaybeAssign(); // oneline statement case + this.state.nestedBlockLevel++; node.body = [this.parseStatement(true)]; + this.state.nestedBlockLevel--; node.directives = []; this.addExtra(node, "curly", false); return this.finishNode(node, "BlockStatement"); @@ -198,15 +200,20 @@ pp.parseMultilineWhiteBlock = function(node, indentLevel) { if (this.match(tt.braceL) && this.hasPlugin("objectBlockAmbiguity_preferObject")) { objParseResult = this.tryParseObjectWhiteBlock(node, indentLevel); if (objParseResult[0]) return objParseResult[0]; - } - try { + try { + this.parseBlockBody(node, false, false, indentLevel); + if (!node.body.length) { + this.unexpected(node.start, "Expected an Indent or Statement"); + } + } catch (err) { + this.rethrowObjParseError(objParseResult, err); + } + } else { this.parseBlockBody(node, false, false, indentLevel); if (!node.body.length) { this.unexpected(node.start, "Expected an Indent or Statement"); } - } catch (err) { - this.rethrowObjParseError(objParseResult, err); } this.addExtra(node, "curly", false); @@ -230,7 +237,10 @@ pp.parseWhiteBlock = function (isExpression?) { if (objParseResult[0]) return objParseResult[0]; } try { - return this.parseStatement(false); + this.state.nestedBlockLevel++; + const stmt = this.parseStatement(false); + this.state.nestedBlockLevel--; + return stmt; } catch (err) { this.rethrowObjParseError(objParseResult, err); } diff --git a/src/plugins/pipeCall.js b/src/plugins/pipeCall.js new file mode 100644 index 0000000000..cd3b1a74d0 --- /dev/null +++ b/src/plugins/pipeCall.js @@ -0,0 +1,50 @@ +import Parser from "../parser"; +import { types as tt, TokenType } from "../tokenizer/types"; +const pp = Parser.prototype; + +export default function(parser) { + if (parser.__pipeCallPluginInstalled) return; + parser.__pipeCallPluginInstalled = true; + + tt.pipeCall = new TokenType("|>"); + + pp.parsePipeCall = function(node, left) { + if (this.state.value === "|>") { + return this.parseRightPointingPipeCall(node, left); + } else { + return this.parseLeftPointingPipeCall(node, left); + } + }; + + pp.parseRightPointingPipeCall = function(node, left) { + this.next(); + + node.left = left; + + // To get left-associative parsing for pipe calls, we can't let the RHS + // of a pipe call subscript into another pipe call. + // Thus we use a state flag to prevent deep parsing of pipe calls + // Hackish but avoids changing the core args of parseSubscripts + if (this.match(tt.parenL) || this.match(tt.name)) { + this.state.potentialArrowAt = this.state.start; + } + const right = this.parseExprAtom(); + this.state.noPipeSubscripts = true; + node.right = this.parseSubscripts(right, this.state.start, this.state.startLoc); + + return this.finishNode(node, "PipeCallExpression"); + }; + + pp.parseLeftPointingPipeCall = function(node, left) { + this.next(); + + node.left = left; + if (this.match(tt.parenL) || this.match(tt.name)) { + this.state.potentialArrowAt = this.state.start; + } + node.right = this.parseSubscripts(this.parseExprAtom(), this.state.start, this.state.startLoc); + node.reversed = true; + + return this.finishNode(node, "PipeCallExpression"); + }; +} diff --git a/src/plugins/syntacticPlaceholder.js b/src/plugins/syntacticPlaceholder.js new file mode 100644 index 0000000000..e54b5a0103 --- /dev/null +++ b/src/plugins/syntacticPlaceholder.js @@ -0,0 +1,51 @@ +import Parser from "../parser"; +import { types as tt } from "../tokenizer/types"; +const pp = Parser.prototype; + +export default function(parser) { + if (parser.__syntacticPlaceholderPluginInstalled) return; + parser.__syntacticPlaceholderPluginInstalled = true; + + const ph = parser.options.placeholder || "_"; + const quotedPh = (ph + "").replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&"); + const phRegex = new RegExp("^" + quotedPh + "([0-9]*)$"); + + pp.isPlaceholderName = function(name) { + return phRegex.test(name); + }; + + // c/p parseIdentifier + pp._parseIdentifierOrPlaceholder = function(liberal) { + const node = this.startNode(); + if (!liberal) { + this.checkReservedWord(this.state.value, this.state.start, !!this.state.type.keyword, false); + } + + let name; + if (this.match(tt.name)) { + name = this.state.value; + } else if (this.state.type.keyword) { + name = this.state.type.keyword; + } else { + this.unexpected(); + } + + const matches = phRegex.exec(name); + if (matches) { + if (matches[1]) node.index = parseInt(matches[1]); + this.next(); + return this.finishNode(node, "PlaceholderExpression"); + } + + node.name = name; + + if (!liberal && node.name === "await" && this.state.inAsync) { + this.raise(node.start, "invalid use of await inside of an async function"); + } + + node.loc.identifierName = node.name; + + this.next(); + return this.finishNode(node, "Identifier"); + }; +} diff --git a/src/plugins/tildeCall.js b/src/plugins/tildeCall.js index 456fa49be9..76a0c08556 100644 --- a/src/plugins/tildeCall.js +++ b/src/plugins/tildeCall.js @@ -13,7 +13,7 @@ export default function(parser) { node.left = left; // allow `this`, Identifier or MemberExpression, but not calls - const right = this.match(tt._this) ? this.parseExprAtom() : this.parseIdentifier(); + const right = this.match(tt._this) ? this.parseExprAtom() : this.parseIdentifierOrPlaceholder(); node.right = this.parseSubscripts(right, this.state.start, this.state.startLoc, true); // Allow safe tilde calls (a~b?(c)) diff --git a/src/registerPlugins.js b/src/registerPlugins.js index 8ca0b97c39..c5c45e4a12 100644 --- a/src/registerPlugins.js +++ b/src/registerPlugins.js @@ -7,6 +7,8 @@ import safeCallExistentialPlugin from "./plugins/safeCallExistential"; import bangCallPlugin from "./plugins/bangCall"; import significantWhitespacePlugin from "./plugins/significantWhitespace"; import enhancedComprehensionPlugin from "./plugins/enhancedComprehension"; +import syntacticPlaceholderPlugin from "./plugins/syntacticPlaceholder"; +import pipeCallPlugin from "./plugins/pipeCall"; import { matchCoreSyntax, match } from "./plugins/match"; function noncePlugin() {} @@ -79,4 +81,11 @@ export default function registerPlugins(plugins, metadata) { registerPlugin("objectBlockAmbiguity_preferObject", noncePlugin, { dependencies: ["lightscript"] }); + + // Parse identifiers beginning with `_` or another user-chosen symbol + // as PlaceholderExpressions. + registerPlugin("syntacticPlaceholder", syntacticPlaceholderPlugin); + + // |> infix operator for piped function calls + registerPlugin("pipeCall", pipeCallPlugin); } diff --git a/src/tokenizer/index.js b/src/tokenizer/index.js index a01e0be16c..e0b225360b 100644 --- a/src/tokenizer/index.js +++ b/src/tokenizer/index.js @@ -341,6 +341,10 @@ export default class Tokenizer { if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2); if (next === 61) return this.finishOp(tt.assign, 2); if (code === 124 && next === 125 && this.hasPlugin("flow")) return this.finishOp(tt.braceBarR, 2); + if (code === 124 && next === 62 && this.hasPlugin("pipeCall")) { + this.state.pos += 2; + return this.finishToken(tt.pipeCall, "|>"); + } return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1); } @@ -433,6 +437,11 @@ export default class Tokenizer { size = 2; } + if (code === 60 && next === 124 && this.hasPlugin("pipeCall")) { + this.state.pos += 2; + return this.finishToken(tt.pipeCall, "<|"); + } + return this.finishOp(tt.relational, size); } diff --git a/src/tokenizer/state.js b/src/tokenizer/state.js index 9e19e9f21c..bdcd1c0d67 100644 --- a/src/tokenizer/state.js +++ b/src/tokenizer/state.js @@ -40,6 +40,7 @@ export default class State { // for lightscript this.indentLevel = 0; + this.nestedBlockLevel = 0; this.inMatchCaseTest = false; this.type = tt.eof; diff --git a/test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/actual.js b/test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/actual.js new file mode 100644 index 0000000000..c740c2f24d --- /dev/null +++ b/test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/actual.js @@ -0,0 +1 @@ +if a~b! c: d diff --git a/test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/options.json b/test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/options.json new file mode 100644 index 0000000000..6b5243adc0 --- /dev/null +++ b/test/fixtures/bang-call/punctuation/paren-free-flow-typecast-unfortunate/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Paren-free test expressions must be followed by braces or a colon. (1:12)" +} diff --git a/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/actual.js b/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/actual.js new file mode 100644 index 0000000000..cb8d38dd00 --- /dev/null +++ b/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/actual.js @@ -0,0 +1,3 @@ +a! -> + b + ~c() diff --git a/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/expected.json b/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/expected.json new file mode 100644 index 0000000000..50ff524695 --- /dev/null +++ b/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/expected.json @@ -0,0 +1,193 @@ +{ + "type": "File", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "callee": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "arguments": [ + { + "type": "ArrowFunctionExpression", + "start": 3, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "skinny": true, + "body": { + "type": "BlockStatement", + "start": 3, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 8, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "expression": { + "type": "TildeCallExpression", + "start": 8, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 3, + "column": 6 + } + }, + "left": { + "type": "Identifier", + "start": 8, + "end": 9, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 3 + }, + "identifierName": "b" + }, + "name": "b" + }, + "right": { + "type": "Identifier", + "start": 13, + "end": 14, + "loc": { + "start": { + "line": 3, + "column": 3 + }, + "end": { + "line": 3, + "column": 4 + }, + "identifierName": "c" + }, + "name": "c" + }, + "arguments": [] + } + } + ], + "directives": [], + "extra": { + "curly": false + } + } + } + ], + "extra": { + "bang": true + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/options.json b/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/options.json new file mode 100644 index 0000000000..90325625ce --- /dev/null +++ b/test/fixtures/bang-call/subscripts/ambiguous-arrow-body/options.json @@ -0,0 +1,11 @@ +{ + "alternatives": { + "default": { + "throws": "Indentation required. (3:2)" + }, + "noEnforcedSubscriptIndentation": { + "allPlugins": true, + "excludePlugins": ["enforceSubscriptIndentation"] + } + } +} diff --git a/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/actual.js b/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/actual.js new file mode 100644 index 0000000000..497e7c4086 --- /dev/null +++ b/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/actual.js @@ -0,0 +1,3 @@ +if true: { + for elem e in arr: e +} diff --git a/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.json b/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.json new file mode 100644 index 0000000000..814c1eb48e --- /dev/null +++ b/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.json @@ -0,0 +1,199 @@ +{ + "type": "File", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "IfStatement", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "test": { + "type": "BooleanLiteral", + "start": 3, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "value": true + }, + "consequent": { + "type": "BlockStatement", + "start": 7, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 9, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "expression": { + "type": "ObjectComprehension", + "start": 9, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "properties": [], + "loop": { + "type": "ForInArrayStatement", + "start": 13, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "elem": { + "type": "Identifier", + "start": 22, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "e" + }, + "name": "e" + }, + "body": { + "type": "ExpressionStatement", + "start": 32, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "expression": { + "type": "Identifier", + "start": 32, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + }, + "identifierName": "e" + }, + "name": "e" + } + }, + "array": { + "type": "Identifier", + "start": 27, + "end": 30, + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 19 + }, + "identifierName": "arr" + }, + "name": "arr" + } + } + } + } + ], + "directives": [], + "extra": { + "curly": false + } + }, + "alternate": null + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.objectBlockAmbiguity.json b/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.objectBlockAmbiguity.json new file mode 100644 index 0000000000..f2b3febedc --- /dev/null +++ b/test/fixtures/lightscript/object-block-ambiguity/object-comprehension/expected.objectBlockAmbiguity.json @@ -0,0 +1,168 @@ +{ + "type": "File", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "IfStatement", + "start": 0, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "test": { + "type": "BooleanLiteral", + "start": 3, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "value": true + }, + "consequent": { + "type": "BlockStatement", + "start": 9, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ForInArrayStatement", + "start": 13, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "elem": { + "type": "Identifier", + "start": 22, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "e" + }, + "name": "e" + }, + "body": { + "type": "ExpressionStatement", + "start": 32, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + } + }, + "expression": { + "type": "Identifier", + "start": 32, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 21 + }, + "end": { + "line": 2, + "column": 22 + }, + "identifierName": "e" + }, + "name": "e" + } + }, + "array": { + "type": "Identifier", + "start": 27, + "end": 30, + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 19 + }, + "identifierName": "arr" + }, + "name": "arr" + } + } + ], + "directives": [], + "extra": { + "curly": true + } + }, + "alternate": null + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/actual.js b/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/actual.js new file mode 100644 index 0000000000..81e8f27db2 --- /dev/null +++ b/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/actual.js @@ -0,0 +1,2 @@ +a +~b() diff --git a/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/expected.json b/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/expected.json new file mode 100644 index 0000000000..963fe9bfda --- /dev/null +++ b/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/expected.json @@ -0,0 +1,99 @@ +{ + "type": "File", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "expression": { + "type": "TildeCallExpression", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "Identifier", + "start": 3, + "end": 4, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 2 + }, + "identifierName": "b" + }, + "name": "b" + }, + "arguments": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/options.json b/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/options.json new file mode 100644 index 0000000000..c804431ad7 --- /dev/null +++ b/test/fixtures/lightscript/whitespace/no-enforced-indentation-tilde/options.json @@ -0,0 +1,11 @@ +{ + "alternatives": { + "all": { + "throws": "Indentation required. (2:0)" + }, + "noEnforcedSubscriptIndentation": { + "allPlugins": true, + "excludePlugins": ["existentialExpression", "safeCallExpression", "enhancedComprehension", "bangCall", "flippedImports", "enforceSubscriptIndentation"] + } + } +} diff --git a/test/fixtures/pipe-call/basic/arrow/actual.js b/test/fixtures/pipe-call/basic/arrow/actual.js new file mode 100644 index 0000000000..b72bfbb7f6 --- /dev/null +++ b/test/fixtures/pipe-call/basic/arrow/actual.js @@ -0,0 +1 @@ +a |> (b) -> c diff --git a/test/fixtures/pipe-call/basic/arrow/expected.json b/test/fixtures/pipe-call/basic/arrow/expected.json new file mode 100644 index 0000000000..bea2c40caa --- /dev/null +++ b/test/fixtures/pipe-call/basic/arrow/expected.json @@ -0,0 +1,137 @@ +{ + "type": "File", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "expression": { + "type": "PipeCallExpression", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "ArrowFunctionExpression", + "start": 5, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "id": null, + "generator": false, + "expression": true, + "async": false, + "params": [ + { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "b" + }, + "name": "b" + } + ], + "skinny": true, + "body": { + "type": "Identifier", + "start": 12, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "c" + }, + "name": "c" + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/pipe-call/basic/associativity/actual.js b/test/fixtures/pipe-call/basic/associativity/actual.js new file mode 100644 index 0000000000..f7ad5ea59e --- /dev/null +++ b/test/fixtures/pipe-call/basic/associativity/actual.js @@ -0,0 +1 @@ +a |> b |> c diff --git a/test/fixtures/pipe-call/basic/associativity/expected.json b/test/fixtures/pipe-call/basic/associativity/expected.json new file mode 100644 index 0000000000..51e5530e5c --- /dev/null +++ b/test/fixtures/pipe-call/basic/associativity/expected.json @@ -0,0 +1,130 @@ +{ + "type": "File", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "expression": { + "type": "PipeCallExpression", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "left": { + "type": "PipeCallExpression", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "b" + }, + "name": "b" + } + }, + "right": { + "type": "Identifier", + "start": 10, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 11 + }, + "identifierName": "c" + }, + "name": "c" + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/pipe-call/basic/pipe/actual.js b/test/fixtures/pipe-call/basic/pipe/actual.js new file mode 100644 index 0000000000..cf3443941f --- /dev/null +++ b/test/fixtures/pipe-call/basic/pipe/actual.js @@ -0,0 +1 @@ +a |> b diff --git a/test/fixtures/pipe-call/basic/pipe/expected.json b/test/fixtures/pipe-call/basic/pipe/expected.json new file mode 100644 index 0000000000..30a9978691 --- /dev/null +++ b/test/fixtures/pipe-call/basic/pipe/expected.json @@ -0,0 +1,98 @@ +{ + "type": "File", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "expression": { + "type": "PipeCallExpression", + "start": 0, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "b" + }, + "name": "b" + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/pipe-call/basic/rhs-expr/actual.js b/test/fixtures/pipe-call/basic/rhs-expr/actual.js new file mode 100644 index 0000000000..c3ecd0849c --- /dev/null +++ b/test/fixtures/pipe-call/basic/rhs-expr/actual.js @@ -0,0 +1 @@ +a |> b(c) diff --git a/test/fixtures/pipe-call/basic/rhs-expr/expected.json b/test/fixtures/pipe-call/basic/rhs-expr/expected.json new file mode 100644 index 0000000000..856c241654 --- /dev/null +++ b/test/fixtures/pipe-call/basic/rhs-expr/expected.json @@ -0,0 +1,132 @@ +{ + "type": "File", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "expression": { + "type": "PipeCallExpression", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "CallExpression", + "start": 6, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "callee": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "b" + }, + "name": "b" + }, + "arguments": [ + { + "type": "Identifier", + "start": 7, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + }, + "identifierName": "c" + }, + "name": "c" + } + ] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/pipe-call/leftward/pipe/actual.js b/test/fixtures/pipe-call/leftward/pipe/actual.js new file mode 100644 index 0000000000..3eb1fe523c --- /dev/null +++ b/test/fixtures/pipe-call/leftward/pipe/actual.js @@ -0,0 +1 @@ +a <| b <| c diff --git a/test/fixtures/pipe-call/leftward/pipe/expected.json b/test/fixtures/pipe-call/leftward/pipe/expected.json new file mode 100644 index 0000000000..c465c08960 --- /dev/null +++ b/test/fixtures/pipe-call/leftward/pipe/expected.json @@ -0,0 +1,132 @@ +{ + "type": "File", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "expression": { + "type": "PipeCallExpression", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "a" + }, + "name": "a" + }, + "right": { + "type": "PipeCallExpression", + "start": 7, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "left": { + "type": "Identifier", + "start": 5, + "end": 6, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + }, + "identifierName": "b" + }, + "name": "b" + }, + "right": { + "type": "Identifier", + "start": 10, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 11 + }, + "identifierName": "c" + }, + "name": "c" + }, + "reversed": true + }, + "reversed": true + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/pipe-call/options.json b/test/fixtures/pipe-call/options.json new file mode 100644 index 0000000000..634ff57aaf --- /dev/null +++ b/test/fixtures/pipe-call/options.json @@ -0,0 +1,8 @@ +{ + "alternatives": { + "default": { + "allPlugins": true, + "excludePlugins": ["estree"] + } + } +} diff --git a/test/fixtures/syntactic-placeholder/basic/basic/actual.js b/test/fixtures/syntactic-placeholder/basic/basic/actual.js new file mode 100644 index 0000000000..31354ec138 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/basic/actual.js @@ -0,0 +1 @@ +_ diff --git a/test/fixtures/syntactic-placeholder/basic/basic/expected.json b/test/fixtures/syntactic-placeholder/basic/basic/expected.json new file mode 100644 index 0000000000..dd674cdc43 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/basic/expected.json @@ -0,0 +1,64 @@ +{ + "type": "File", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "expression": { + "type": "PlaceholderExpression", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/syntactic-placeholder/basic/indexed/actual.js b/test/fixtures/syntactic-placeholder/basic/indexed/actual.js new file mode 100644 index 0000000000..77d26c76e0 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/indexed/actual.js @@ -0,0 +1 @@ +_1 diff --git a/test/fixtures/syntactic-placeholder/basic/indexed/expected.json b/test/fixtures/syntactic-placeholder/basic/indexed/expected.json new file mode 100644 index 0000000000..c0ab205a92 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/indexed/expected.json @@ -0,0 +1,65 @@ +{ + "type": "File", + "start": 0, + "end": 2, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 2 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 2, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 2 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 2, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 2 + } + }, + "expression": { + "type": "PlaceholderExpression", + "start": 0, + "end": 2, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 2 + } + }, + "index": 1 + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/syntactic-placeholder/basic/spread-indexed/actual.js b/test/fixtures/syntactic-placeholder/basic/spread-indexed/actual.js new file mode 100644 index 0000000000..374c6a6ea2 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/spread-indexed/actual.js @@ -0,0 +1 @@ +-> [..._1] diff --git a/test/fixtures/syntactic-placeholder/basic/spread-indexed/expected.json b/test/fixtures/syntactic-placeholder/basic/spread-indexed/expected.json new file mode 100644 index 0000000000..9896c70ccc --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/spread-indexed/expected.json @@ -0,0 +1,118 @@ +{ + "type": "File", + "start": 0, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "id": null, + "generator": false, + "expression": true, + "async": false, + "params": [], + "skinny": true, + "body": { + "type": "ArrayExpression", + "start": 3, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "elements": [ + { + "type": "SpreadElement", + "start": 4, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "argument": { + "type": "PlaceholderExpression", + "start": 7, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "index": 1 + } + } + ] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/syntactic-placeholder/basic/spread/actual.js b/test/fixtures/syntactic-placeholder/basic/spread/actual.js new file mode 100644 index 0000000000..43e03d1cd0 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/spread/actual.js @@ -0,0 +1 @@ +-> [..._] diff --git a/test/fixtures/syntactic-placeholder/basic/spread/expected.json b/test/fixtures/syntactic-placeholder/basic/spread/expected.json new file mode 100644 index 0000000000..758c275d60 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/basic/spread/expected.json @@ -0,0 +1,117 @@ +{ + "type": "File", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "id": null, + "generator": false, + "expression": true, + "async": false, + "params": [], + "skinny": true, + "body": { + "type": "ArrayExpression", + "start": 3, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "elements": [ + { + "type": "SpreadElement", + "start": 4, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 8 + } + }, + "argument": { + "type": "PlaceholderExpression", + "start": 7, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 7 + }, + "end": { + "line": 1, + "column": 8 + } + } + } + } + ] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/syntactic-placeholder/options.json b/test/fixtures/syntactic-placeholder/options.json new file mode 100644 index 0000000000..60bbeba2ff --- /dev/null +++ b/test/fixtures/syntactic-placeholder/options.json @@ -0,0 +1,8 @@ +{ + "alternatives": { + "all": { + "allPlugins": true, + "excludePlugins": ["estree"] + } + } +} diff --git a/test/fixtures/syntactic-placeholder/opts/change-placeholder/actual.js b/test/fixtures/syntactic-placeholder/opts/change-placeholder/actual.js new file mode 100644 index 0000000000..52c184f186 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/opts/change-placeholder/actual.js @@ -0,0 +1 @@ +P diff --git a/test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.changePlaceholder.json b/test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.changePlaceholder.json new file mode 100644 index 0000000000..dd674cdc43 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.changePlaceholder.json @@ -0,0 +1,64 @@ +{ + "type": "File", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "expression": { + "type": "PlaceholderExpression", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.json b/test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.json new file mode 100644 index 0000000000..f254aba2d4 --- /dev/null +++ b/test/fixtures/syntactic-placeholder/opts/change-placeholder/expected.json @@ -0,0 +1,66 @@ +{ + "type": "File", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "expression": { + "type": "Identifier", + "start": 0, + "end": 1, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + }, + "identifierName": "P" + }, + "name": "P" + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/syntactic-placeholder/opts/change-placeholder/options.json b/test/fixtures/syntactic-placeholder/opts/change-placeholder/options.json new file mode 100644 index 0000000000..4674015b3c --- /dev/null +++ b/test/fixtures/syntactic-placeholder/opts/change-placeholder/options.json @@ -0,0 +1,12 @@ +{ + "alternatives": { + "changePlaceholder": { + "allPlugins": true, + "excludePlugins": ["estree"], + "expected": "expected.changePlaceholder.json", + "parserOpts": { + "placeholder": "P" + } + } + } +} diff --git a/test/utils/TestRunner.js b/test/utils/TestRunner.js index 55acd4e0dd..18a90bfa85 100644 --- a/test/utils/TestRunner.js +++ b/test/utils/TestRunner.js @@ -235,6 +235,10 @@ exports.Test = class Test { } } } + + if (alt.parserOpts) { + this.parserOpts = Object.assign({}, this.parserOpts, alt.parserOpts); + } } includePlugins(plugins, list) {