From da0af5fd99a9b747370a2240df3abf2940b9649c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Fri, 6 Sep 2019 11:43:19 -0400 Subject: [PATCH] V8intrinsic syntax plugin (#10148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: v8intrinsic syntax plugin Implement V8 Intrinsic Syntax Extension. Here we check the execution branch inside the parseSubscript to make sure the V8IntrinsicIdentifier is immediately followed by a call expression. * feat: disable combining placeholders and v8intrisic per https://github.com/babel/babel/issues/10104#issuecomment-506950969 * test: add more error cases * refactor: parse v8 intrinsic in parseExprAtom This approach is identical to V8’s implementation. Move the test cases as the behaviour changes. * fix: plugin-name typo * test: add yield-expression test case * feat: require startsExpr on modulo for v8intrinsic * perf: skip eof and braceR check as they must return false * Print V8IntrinsicIdentifier * feat: add v8intrinsic to parser typings * Add generated type helpers * fix: incorrect type definition * fix: allow V8IntrinsicIdentifier to be callee --- .../src/generators/expressions.js | 5 + .../misc/V8IntrinsicIdentifier/input.js | 1 + .../misc/V8IntrinsicIdentifier/options.json | 3 + .../misc/V8IntrinsicIdentifier/output.js | 1 + .../babel-parser/src/parser/expression.js | 2 +- packages/babel-parser/src/plugin-utils.js | 6 + .../babel-parser/src/plugins/v8intrinsic.js | 32 +++ packages/babel-parser/src/tokenizer/types.js | 3 +- .../_errors/in-bind-expression/input.js | 1 + .../_errors/in-bind-expression/options.json | 6 + .../_errors/in-member-expression/input.js | 1 + .../_errors/in-member-expression/options.json | 6 + .../v8intrinsic/_errors/no-plugin/input.js | 1 + .../_errors/no-plugin/options.json | 4 + .../_errors/not-in-call-expression/input.js | 2 + .../not-in-call-expression/options.json | 4 + .../_errors/optional-call-expression/input.js | 1 + .../optional-call-expression/options.json | 7 + .../expression/await-expression/input.js | 1 + .../expression/await-expression/output.json | 191 +++++++++++++++++ .../expression/call-expression/input.js | 1 + .../expression/call-expression/output.json | 101 +++++++++ .../expression/in-new-expression/input.js | 1 + .../expression/in-new-expression/output.json | 99 +++++++++ .../expression/multiple-arguments/input.js | 1 + .../expression/multiple-arguments/output.json | 124 +++++++++++ .../expression/yield-expression/input.js | 3 + .../expression/yield-expression/output.json | 193 ++++++++++++++++++ .../fixtures/v8intrinsic/modulo/01/input.js | 1 + .../v8intrinsic/modulo/01/output.json | 116 +++++++++++ .../test/fixtures/v8intrinsic/options.json | 3 + .../babel-parser/typings/babel-parser.d.ts | 1 + .../scripts/utils/formatBuilderName.js | 3 +- .../src/asserts/generated/index.js | 6 + .../src/builders/generated/index.js | 4 + packages/babel-types/src/definitions/core.js | 2 +- packages/babel-types/src/definitions/misc.js | 15 +- .../src/validators/generated/index.js | 14 ++ 38 files changed, 961 insertions(+), 5 deletions(-) create mode 100644 packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/input.js create mode 100644 packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/options.json create mode 100644 packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/output.js create mode 100644 packages/babel-parser/src/plugins/v8intrinsic.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/options.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/options.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/options.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/options.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/options.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/output.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/output.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/output.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/output.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/output.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/input.js create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/output.json create mode 100644 packages/babel-parser/test/fixtures/v8intrinsic/options.json diff --git a/packages/babel-generator/src/generators/expressions.js b/packages/babel-generator/src/generators/expressions.js index 4f9a525bd05e..62c3aca83bc0 100644 --- a/packages/babel-generator/src/generators/expressions.js +++ b/packages/babel-generator/src/generators/expressions.js @@ -264,3 +264,8 @@ export function PrivateName(node: Object) { this.token("#"); this.print(node.id, node); } + +export function V8IntrinsicIdentifier(node: Object) { + this.token("%"); + this.word(node.name); +} diff --git a/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/input.js b/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/input.js new file mode 100644 index 000000000000..613a26cd98c7 --- /dev/null +++ b/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/input.js @@ -0,0 +1 @@ +%DebugPrint(foo); diff --git a/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/options.json b/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/options.json new file mode 100644 index 000000000000..609458c2c65e --- /dev/null +++ b/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["v8intrinsic"] +} diff --git a/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/output.js b/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/output.js new file mode 100644 index 000000000000..613a26cd98c7 --- /dev/null +++ b/packages/babel-generator/test/fixtures/misc/V8IntrinsicIdentifier/output.js @@ -0,0 +1 @@ +%DebugPrint(foo); diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 05580e017a32..565d75e77a52 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -2191,7 +2191,7 @@ export default class ExpressionParser extends LValParser { if ( this.match(tt.semi) || (!this.match(tt.star) && !this.state.type.startsExpr) || - this.canInsertSemicolon() + this.hasPrecedingLineBreak() ) { node.delegate = false; node.argument = null; diff --git a/packages/babel-parser/src/plugin-utils.js b/packages/babel-parser/src/plugin-utils.js index c1cb6a6b7e92..2cf522532197 100644 --- a/packages/babel-parser/src/plugin-utils.js +++ b/packages/babel-parser/src/plugin-utils.js @@ -69,6 +69,10 @@ export function validatePlugins(plugins: PluginList) { throw new Error("Cannot combine flow and typescript plugins."); } + if (hasPlugin(plugins, "placeholders") && hasPlugin(plugins, "v8intrinsic")) { + throw new Error("Cannot combine placeholders and v8intrinsic plugins."); + } + if ( hasPlugin(plugins, "pipelineOperator") && !PIPELINE_PROPOSALS.includes( @@ -89,6 +93,7 @@ import flow from "./plugins/flow"; import jsx from "./plugins/jsx"; import typescript from "./plugins/typescript"; import placeholders from "./plugins/placeholders"; +import v8intrinsic from "./plugins/v8intrinsic"; // NOTE: order is important. estree must come first; placeholders must come last. export const mixinPlugins: { [name: string]: MixinPlugin } = { @@ -96,6 +101,7 @@ export const mixinPlugins: { [name: string]: MixinPlugin } = { jsx, flow, typescript, + v8intrinsic, placeholders, }; diff --git a/packages/babel-parser/src/plugins/v8intrinsic.js b/packages/babel-parser/src/plugins/v8intrinsic.js new file mode 100644 index 000000000000..be3a1fbaae0d --- /dev/null +++ b/packages/babel-parser/src/plugins/v8intrinsic.js @@ -0,0 +1,32 @@ +import type Parser from "../parser"; +import { types as tt } from "../tokenizer/types"; +import * as N from "../types"; + +export default (superClass: Class): Class => + class extends superClass { + parseV8Intrinsic(): N.Expression { + if (this.match(tt.modulo)) { + const v8IntrinsicStart = this.state.start; + // let the `loc` of Identifier starts from `%` + const node = this.startNode(); + this.eat(tt.modulo); + if (this.match(tt.name)) { + const name = this.parseIdentifierName(this.state.start); + const identifier = this.createIdentifier(node, name); + identifier.type = "V8IntrinsicIdentifier"; + if (this.match(tt.parenL)) { + return identifier; + } + } + this.unexpected(v8IntrinsicStart); + } + } + + /* ============================================================ * + * parser/expression.js * + * ============================================================ */ + + parseExprAtom(): N.Expression { + return this.parseV8Intrinsic() || super.parseExprAtom(...arguments); + } + }; diff --git a/packages/babel-parser/src/tokenizer/types.js b/packages/babel-parser/src/tokenizer/types.js index 47b4ced9f14e..ecb1e8376571 100644 --- a/packages/babel-parser/src/tokenizer/types.js +++ b/packages/babel-parser/src/tokenizer/types.js @@ -148,7 +148,8 @@ export const types: { [name: string]: TokenType } = { relational: createBinop("/<=/>=", 8), bitShift: createBinop("<>/>>>", 9), plusMin: new TokenType("+/-", { beforeExpr, binop: 10, prefix, startsExpr }), - modulo: createBinop("%", 11), + // startsExpr: required by v8intrinsic plugin + modulo: new TokenType("%", { beforeExpr, binop: 11, startsExpr }), star: createBinop("*", 11), slash: createBinop("/", 11), exponent: new TokenType("**", { diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/input.js new file mode 100644 index 000000000000..2828ef73abc6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/input.js @@ -0,0 +1 @@ +::%DebugPrint(null) diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/options.json b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/options.json new file mode 100644 index 000000000000..8df61c77cf09 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-bind-expression/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "v8intrinsic" + ], + "throws": "Unexpected token (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/input.js new file mode 100644 index 000000000000..11f5e1b795e5 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/input.js @@ -0,0 +1 @@ +a.%DebugPrint(); diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/options.json b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/options.json new file mode 100644 index 000000000000..2339aca027fa --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/in-member-expression/options.json @@ -0,0 +1,6 @@ +{ + "plugins": [ + "v8intrinsic" + ], + "throws": "Unexpected token (1:2)" +} diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/input.js new file mode 100644 index 000000000000..3f654b116269 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/input.js @@ -0,0 +1 @@ +%DebugPrint(foo) diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/options.json b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/options.json new file mode 100644 index 000000000000..550f9f8667f9 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/no-plugin/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [], + "throws": "Unexpected token (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/input.js new file mode 100644 index 000000000000..1743e18ef4f1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/input.js @@ -0,0 +1,2 @@ +const i = %DebugPrint; +i(foo); diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/options.json b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/options.json new file mode 100644 index 000000000000..9f69797fc3b1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/not-in-call-expression/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["v8intrinsic"], + "throws": "Unexpected token (1:10)" +} diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/input.js new file mode 100644 index 000000000000..0f2bb372f3f4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/input.js @@ -0,0 +1 @@ +%DebugPrint?.(null) diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/options.json b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/options.json new file mode 100644 index 000000000000..5a3c25f8b9cc --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/_errors/optional-call-expression/options.json @@ -0,0 +1,7 @@ +{ + "plugins": [ + "optionalChaining", + "v8intrinsic" + ], + "throws": "Unexpected token (1:0)" +} diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/input.js new file mode 100644 index 000000000000..43d5cb818781 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/input.js @@ -0,0 +1 @@ +async () => { await %StringParseInt("42", 10) } diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/output.json b/packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/output.json new file mode 100644 index 000000000000..417906511ce0 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/await-expression/output.json @@ -0,0 +1,191 @@ +{ + "type": "File", + "start": 0, + "end": 47, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 47, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 47, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "expression": { + "type": "ArrowFunctionExpression", + "start": 0, + "end": 47, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "id": null, + "generator": false, + "async": true, + "params": [], + "body": { + "type": "BlockStatement", + "start": 12, + "end": 47, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 47 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 14, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "expression": { + "type": "AwaitExpression", + "start": 14, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "argument": { + "type": "CallExpression", + "start": 20, + "end": 45, + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 45 + } + }, + "callee": { + "type": "V8IntrinsicIdentifier", + "start": 20, + "end": 35, + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 35 + }, + "identifierName": "StringParseInt" + }, + "name": "StringParseInt" + }, + "arguments": [ + { + "type": "StringLiteral", + "start": 36, + "end": 40, + "loc": { + "start": { + "line": 1, + "column": 36 + }, + "end": { + "line": 1, + "column": 40 + } + }, + "extra": { + "rawValue": "42", + "raw": "\"42\"" + }, + "value": "42" + }, + { + "type": "NumericLiteral", + "start": 42, + "end": 44, + "loc": { + "start": { + "line": 1, + "column": 42 + }, + "end": { + "line": 1, + "column": 44 + } + }, + "extra": { + "rawValue": 10, + "raw": "10" + }, + "value": 10 + } + ] + } + } + } + ], + "directives": [] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/input.js new file mode 100644 index 000000000000..3f654b116269 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/input.js @@ -0,0 +1 @@ +%DebugPrint(foo) diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/output.json b/packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/output.json new file mode 100644 index 000000000000..e44d316e19ce --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/call-expression/output.json @@ -0,0 +1,101 @@ +{ + "type": "File", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 16 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 16 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 16 + } + }, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 16, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 16 + } + }, + "callee": { + "type": "V8IntrinsicIdentifier", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + }, + "identifierName": "DebugPrint" + }, + "name": "DebugPrint" + }, + "arguments": [ + { + "type": "Identifier", + "start": 12, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 12 + }, + "end": { + "line": 1, + "column": 15 + }, + "identifierName": "foo" + }, + "name": "foo" + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/input.js new file mode 100644 index 000000000000..cacf4eb63800 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/input.js @@ -0,0 +1 @@ +new %DebugPrint(null); diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/output.json b/packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/output.json new file mode 100644 index 000000000000..c02efb12aecc --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/in-new-expression/output.json @@ -0,0 +1,99 @@ +{ + "type": "File", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 22 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 22 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 22, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 22 + } + }, + "expression": { + "type": "NewExpression", + "start": 0, + "end": 21, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 21 + } + }, + "callee": { + "type": "V8IntrinsicIdentifier", + "start": 4, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 15 + }, + "identifierName": "DebugPrint" + }, + "name": "DebugPrint" + }, + "arguments": [ + { + "type": "NullLiteral", + "start": 16, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 20 + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/input.js new file mode 100644 index 000000000000..82600e018602 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/input.js @@ -0,0 +1 @@ +%StringParseInt("42", 10); diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/output.json b/packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/output.json new file mode 100644 index 000000000000..3843e6652fc3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/multiple-arguments/output.json @@ -0,0 +1,124 @@ +{ + "type": "File", + "start": 0, + "end": 26, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 26, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 26, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 26 + } + }, + "expression": { + "type": "CallExpression", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 25 + } + }, + "callee": { + "type": "V8IntrinsicIdentifier", + "start": 0, + "end": 15, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 15 + }, + "identifierName": "StringParseInt" + }, + "name": "StringParseInt" + }, + "arguments": [ + { + "type": "StringLiteral", + "start": 16, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "extra": { + "rawValue": "42", + "raw": "\"42\"" + }, + "value": "42" + }, + { + "type": "NumericLiteral", + "start": 22, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 24 + } + }, + "extra": { + "rawValue": 10, + "raw": "10" + }, + "value": 10 + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/input.js new file mode 100644 index 000000000000..da2dc0b2bf49 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/input.js @@ -0,0 +1,3 @@ +function *foo() { + yield %StringParseInt("42", 10) +} diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/output.json b/packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/output.json new file mode 100644 index 000000000000..50294da42d99 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/expression/yield-expression/output.json @@ -0,0 +1,193 @@ +{ + "type": "File", + "start": 0, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "FunctionDeclaration", + "start": 0, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 10, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "generator": true, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 16, + "end": 53, + "loc": { + "start": { + "line": 1, + "column": 16 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 20, + "end": 51, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "expression": { + "type": "YieldExpression", + "start": 20, + "end": 51, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "delegate": false, + "argument": { + "type": "CallExpression", + "start": 26, + "end": 51, + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "callee": { + "type": "V8IntrinsicIdentifier", + "start": 26, + "end": 41, + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 2, + "column": 23 + }, + "identifierName": "StringParseInt" + }, + "name": "StringParseInt" + }, + "arguments": [ + { + "type": "StringLiteral", + "start": 42, + "end": 46, + "loc": { + "start": { + "line": 2, + "column": 24 + }, + "end": { + "line": 2, + "column": 28 + } + }, + "extra": { + "rawValue": "42", + "raw": "\"42\"" + }, + "value": "42" + }, + { + "type": "NumericLiteral", + "start": 48, + "end": 50, + "loc": { + "start": { + "line": 2, + "column": 30 + }, + "end": { + "line": 2, + "column": 32 + } + }, + "extra": { + "rawValue": 10, + "raw": "10" + }, + "value": 10 + } + ] + } + } + } + ], + "directives": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/input.js b/packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/input.js new file mode 100644 index 000000000000..72f7312444c3 --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/input.js @@ -0,0 +1 @@ +foo%bar() diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/output.json b/packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/output.json new file mode 100644 index 000000000000..6233a3f2dd7d --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/modulo/01/output.json @@ -0,0 +1,116 @@ +{ + "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", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "expression": { + "type": "BinaryExpression", + "start": 0, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "left": { + "type": "Identifier", + "start": 0, + "end": 3, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 3 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "operator": "%", + "right": { + "type": "CallExpression", + "start": 4, + "end": 9, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 9 + } + }, + "callee": { + "type": "Identifier", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "bar" + }, + "name": "bar" + }, + "arguments": [] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/v8intrinsic/options.json b/packages/babel-parser/test/fixtures/v8intrinsic/options.json new file mode 100644 index 000000000000..609458c2c65e --- /dev/null +++ b/packages/babel-parser/test/fixtures/v8intrinsic/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["v8intrinsic"] +} diff --git a/packages/babel-parser/typings/babel-parser.d.ts b/packages/babel-parser/typings/babel-parser.d.ts index 799e9e8945d1..371b9a4633da 100644 --- a/packages/babel-parser/typings/babel-parser.d.ts +++ b/packages/babel-parser/typings/babel-parser.d.ts @@ -124,6 +124,7 @@ export type ParserPlugin = 'placeholders' | 'throwExpressions' | 'typescript' | + 'v8intrinsic' | ParserPluginWithOptions; export type ParserPluginWithOptions = diff --git a/packages/babel-types/scripts/utils/formatBuilderName.js b/packages/babel-types/scripts/utils/formatBuilderName.js index 1b543a9bfaf5..621c46821951 100644 --- a/packages/babel-types/scripts/utils/formatBuilderName.js +++ b/packages/babel-types/scripts/utils/formatBuilderName.js @@ -5,5 +5,6 @@ const toLowerCase = Function.call.bind("".toLowerCase); module.exports = function formatBuilderName(type) { // FunctionExpression -> functionExpression // JSXIdentifier -> jsxIdentifier - return type.replace(/^([A-Z](?=[a-z])|[A-Z]+(?=[A-Z]))/, toLowerCase); + // V8IntrinsicIdentifier -> v8IntrinsicIdentifier + return type.replace(/^([A-Z](?=[a-z0-9])|[A-Z]+(?=[A-Z]))/, toLowerCase); }; diff --git a/packages/babel-types/src/asserts/generated/index.js b/packages/babel-types/src/asserts/generated/index.js index 93c911d9004f..60a91b88178d 100644 --- a/packages/babel-types/src/asserts/generated/index.js +++ b/packages/babel-types/src/asserts/generated/index.js @@ -662,6 +662,12 @@ export function assertNoop(node: Object, opts?: Object = {}): void { export function assertPlaceholder(node: Object, opts?: Object = {}): void { assert("Placeholder", node, opts); } +export function assertV8IntrinsicIdentifier( + node: Object, + opts?: Object = {}, +): void { + assert("V8IntrinsicIdentifier", node, opts); +} export function assertArgumentPlaceholder( node: Object, opts?: Object = {}, diff --git a/packages/babel-types/src/builders/generated/index.js b/packages/babel-types/src/builders/generated/index.js index af48f24ec876..2cb9d5490c9d 100644 --- a/packages/babel-types/src/builders/generated/index.js +++ b/packages/babel-types/src/builders/generated/index.js @@ -600,6 +600,10 @@ export function Placeholder(...args: Array): Object { return builder("Placeholder", ...args); } export { Placeholder as placeholder }; +export function V8IntrinsicIdentifier(...args: Array): Object { + return builder("V8IntrinsicIdentifier", ...args); +} +export { V8IntrinsicIdentifier as v8IntrinsicIdentifier }; export function ArgumentPlaceholder(...args: Array): Object { return builder("ArgumentPlaceholder", ...args); } diff --git a/packages/babel-types/src/definitions/core.js b/packages/babel-types/src/definitions/core.js index 1e4de3ebbfa0..09c41c9119a9 100644 --- a/packages/babel-types/src/definitions/core.js +++ b/packages/babel-types/src/definitions/core.js @@ -132,7 +132,7 @@ defineType("CallExpression", { aliases: ["Expression"], fields: { callee: { - validate: assertNodeType("Expression"), + validate: assertNodeType("Expression", "V8IntrinsicIdentifier"), }, arguments: { validate: chain( diff --git a/packages/babel-types/src/definitions/misc.js b/packages/babel-types/src/definitions/misc.js index e319235b2c15..da67c68706fc 100644 --- a/packages/babel-types/src/definitions/misc.js +++ b/packages/babel-types/src/definitions/misc.js @@ -1,5 +1,9 @@ // @flow -import defineType, { assertNodeType, assertOneOf } from "./utils"; +import defineType, { + assertNodeType, + assertOneOf, + assertValueType, +} from "./utils"; import { PLACEHOLDERS } from "./placeholders"; defineType("Noop", { @@ -19,3 +23,12 @@ defineType("Placeholder", { }, }, }); + +defineType("V8IntrinsicIdentifier", { + builder: ["name"], + fields: { + name: { + validate: assertValueType("string"), + }, + }, +}); diff --git a/packages/babel-types/src/validators/generated/index.js b/packages/babel-types/src/validators/generated/index.js index 259e37d90430..84f44ef882cd 100644 --- a/packages/babel-types/src/validators/generated/index.js +++ b/packages/babel-types/src/validators/generated/index.js @@ -2107,6 +2107,20 @@ export function isPlaceholder(node: ?Object, opts?: Object): boolean { return false; } +export function isV8IntrinsicIdentifier(node: ?Object, opts?: Object): boolean { + if (!node) return false; + + const nodeType = node.type; + if (nodeType === "V8IntrinsicIdentifier") { + if (typeof opts === "undefined") { + return true; + } else { + return shallowEqual(node, opts); + } + } + + return false; +} export function isArgumentPlaceholder(node: ?Object, opts?: Object): boolean { if (!node) return false;