Reduce exprAllowed usage (#13431)

This commit is contained in:
Huáng Jùnliàng 2021-06-09 10:36:09 -04:00 committed by GitHub
parent 9252da782b
commit b9c1884a58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 714 additions and 305 deletions

View File

@ -261,10 +261,6 @@ export default class ExpressionParser extends LValParser {
const startLoc = this.state.startLoc;
if (this.isContextual("yield")) {
if (this.prodParam.hasYield) {
// If we have [Yield] production, `yield` will start a YieldExpression thus
// regex is allowed following. Otherwise `yield` is an identifier and regex
// is disallowed in tt.name.updateContext
this.state.exprAllowed = true;
let left = this.parseYield();
if (afterLeftParse) {
left = afterLeftParse.call(this, left, startPos, startLoc);
@ -988,11 +984,6 @@ export default class ExpressionParser extends LValParser {
// AsyncArrowFunction
parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression {
// If a division operator appears in an expression position, the
// tokenizer got confused, and we force it to read a regexp instead.
if (this.state.type === tt.slash) this.readRegexp();
const canBeArrow = this.state.potentialArrowAt === this.state.start;
let node;
switch (this.state.type) {
@ -1017,24 +1008,12 @@ export default class ExpressionParser extends LValParser {
return this.finishNode(node, "ThisExpression");
case tt.name: {
const canBeArrow = this.state.potentialArrowAt === this.state.start;
const containsEsc = this.state.containsEsc;
const id = this.parseIdentifier();
if (!containsEsc && id.name === "async" && !this.canInsertSemicolon()) {
if (this.match(tt._function)) {
const last = this.state.context.length - 1;
if (this.state.context[last] !== ct.functionStatement) {
// Since "async" is an identifier and normally identifiers
// can't be followed by expression, the tokenizer assumes
// that "function" starts a statement.
// Fixing it in the tokenizer would mean tracking not only the
// previous token ("async"), but also the one before to know
// its beforeExpr value.
// It's easier and more efficient to adjust the context here.
throw new Error("Internal error");
}
this.state.context[last] = ct.functionExpression;
this.next();
return this.parseFunction(
this.startNodeAtNode(id),
@ -1073,7 +1052,9 @@ export default class ExpressionParser extends LValParser {
return this.parseDo(false);
}
case tt.regexp: {
case tt.slash:
case tt.slashAssign: {
this.readRegexp();
return this.parseRegExpLiteral(this.state.value);
}
@ -1097,8 +1078,10 @@ export default class ExpressionParser extends LValParser {
case tt._false:
return this.parseBooleanLiteral(false);
case tt.parenL:
case tt.parenL: {
const canBeArrow = this.state.potentialArrowAt === this.state.start;
return this.parseParenAndDistinguishExpression(canBeArrow);
}
case tt.bracketBarL:
case tt.bracketHashL: {
@ -1720,11 +1703,6 @@ export default class ExpressionParser extends LValParser {
node.properties.push(prop);
}
// The tokenizer uses `braceIsBlock` to detect whether `{` starts a block statement.
// If `{` is a block statement, `exprAllowed` will be `true`.
// However the tokenizer can not handle edge cases like `0 ? a : { a : 1 } / 2`, here
// we update `exprAllowed` when an object-like is parsed.
this.state.exprAllowed = false;
this.next();
this.state.inFSharpPipelineDirectBody = oldInFSharpPipelineDirectBody;
@ -2514,17 +2492,30 @@ export default class ExpressionParser extends LValParser {
);
this.next();
if (
this.match(tt.semi) ||
(!this.match(tt.star) && !this.state.type.startsExpr) ||
this.hasPrecedingLineBreak()
) {
node.delegate = false;
node.argument = null;
} else {
node.delegate = this.eat(tt.star);
node.argument = this.parseMaybeAssign();
let delegating = false;
let argument = null;
if (!this.hasPrecedingLineBreak()) {
delegating = this.eat(tt.star);
switch (this.state.type) {
case tt.semi:
case tt.eof:
case tt.braceR:
case tt.parenR:
case tt.bracketR:
case tt.braceBarR:
case tt.colon:
case tt.comma:
// The above is the complete set of tokens that can
// follow an AssignmentExpression, and none of them
// can start an AssignmentExpression
if (!delegating) break;
/* fallthrough */
default:
argument = this.parseMaybeAssign();
}
}
node.delegate = delegating;
node.argument = argument;
return this.finishNode(node, "YieldExpression");
}

View File

@ -1710,10 +1710,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.state.inType = true;
const type = this.flowParseUnionType();
this.state.inType = oldInType;
// Ensure that a brace after a function generic type annotation is a
// statement, except in arrow functions (noAnonFunctionType)
this.state.exprAllowed =
this.state.exprAllowed || this.state.noAnonFunctionType;
return type;
}
@ -3706,20 +3702,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "EnumDeclaration");
}
updateContext(prevType: TokenType): void {
if (
this.match(tt.name) &&
this.state.value === "of" &&
prevType === tt.name &&
this.input.slice(this.state.lastTokStart, this.state.lastTokEnd) ===
"interface"
) {
this.state.exprAllowed = false;
} else {
super.updateContext(prevType);
}
}
// check if the next token is a tt.relation("<")
isLookaheadToken_lt(): boolean {
const next = this.nextTokenStart();

View File

@ -45,29 +45,18 @@ const JsxErrors = makeErrorTemplates(
// Be aware that this file is always executed and not only when the plugin is enabled.
// Therefore this contexts and tokens do always exist.
tc.j_oTag = new TokContext("<tag", false);
tc.j_cTag = new TokContext("</tag", false);
tc.j_expr = new TokContext("<tag>...</tag>", true, true);
tc.j_oTag = new TokContext("<tag");
tc.j_cTag = new TokContext("</tag");
tc.j_expr = new TokContext("<tag>...</tag>", true);
tt.jsxName = new TokenType("jsxName");
tt.jsxText = new TokenType("jsxText", { beforeExpr: true });
tt.jsxTagStart = new TokenType("jsxTagStart", { startsExpr: true });
tt.jsxTagEnd = new TokenType("jsxTagEnd");
tt.jsxTagStart.updateContext = function () {
this.state.context.push(tc.j_expr); // treat as beginning of JSX expression
this.state.context.push(tc.j_oTag); // start opening tag context
this.state.exprAllowed = false;
};
tt.jsxTagEnd.updateContext = function (prevType) {
const out = this.state.context.pop();
if ((out === tc.j_oTag && prevType === tt.slash) || out === tc.j_cTag) {
this.state.context.pop();
this.state.exprAllowed = this.curContext() === tc.j_expr;
} else {
this.state.exprAllowed = true;
}
tt.jsxTagStart.updateContext = context => {
context.push(tc.j_expr); // treat as beginning of JSX expression
context.push(tc.j_oTag); // start opening tag context
};
function isFragment(object: ?N.JSXElement): boolean {
@ -625,22 +614,35 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
updateContext(prevType: TokenType): void {
if (this.match(tt.braceL)) {
const curContext = this.curContext();
if (curContext === tc.j_oTag) {
this.state.context.push(tc.braceExpression);
} else if (curContext === tc.j_expr) {
this.state.context.push(tc.templateQuasi);
} else {
super.updateContext(prevType);
const { context, type } = this.state;
if (type === tt.braceL) {
const curContext = context[context.length - 1];
if (curContext === tc.j_oTag) {
context.push(tc.brace);
} else if (curContext === tc.j_expr) {
context.push(tc.templateQuasi);
}
this.state.exprAllowed = true;
} else if (this.match(tt.slash) && prevType === tt.jsxTagStart) {
this.state.context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore
this.state.context.push(tc.j_cTag); // reconsider as closing tag context
} else if (type === tt.slash && prevType === tt.jsxTagStart) {
context.length -= 2; // do not consider JSX expr -> JSX open tag -> ... anymore
context.push(tc.j_cTag); // reconsider as closing tag context
this.state.exprAllowed = false;
} else if (type === tt.jsxTagEnd) {
const out = context.pop();
if ((out === tc.j_oTag && prevType === tt.slash) || out === tc.j_cTag) {
context.pop();
this.state.exprAllowed = context[context.length - 1] === tc.j_expr;
} else {
this.state.exprAllowed = true;
}
} else if (
type.keyword &&
(prevType === tt.dot || prevType === tt.questionDot)
) {
this.state.exprAllowed = false;
} else {
return super.updateContext(prevType);
this.state.exprAllowed = type.beforeExpr;
}
}
};

View File

@ -1887,9 +1887,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (node.params.length === 0) {
this.raise(node.start, TSErrors.EmptyTypeArguments);
}
// This reads the next token after the `>` too, so do this in the enclosing context.
// But be sure not to parse a regex in the jsx expression `<C<number> />`, so set exprAllowed = false
this.state.exprAllowed = false;
this.expectRelational(">");
return this.finishNode(node, "TSTypeParameterInstantiation");
}
@ -2046,7 +2043,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
state: N.ParseSubscriptState,
): N.Expression {
if (!this.hasPrecedingLineBreak() && this.match(tt.bang)) {
this.state.exprAllowed = false;
this.next();
const nonNullExpression: N.TsNonNullExpression = this.startNodeAt(

View File

@ -1,35 +1,27 @@
// @flow
// The algorithm used to determine whether a regexp can appear at a
// given point in the program is loosely based on sweet.js' approach.
// See https://github.com/mozilla/sweet.js/wiki/design
// The token context is used to track whether `}` matches
// a template quasi `${` or other tokens containing `{`:
// namely tt.braceL and tt.dollarBraceL
import { types as tt } from "./types";
export class TokContext {
constructor(token: string, isExpr?: boolean, preserveSpace?: boolean) {
constructor(token: string, preserveSpace?: boolean) {
this.token = token;
this.isExpr = !!isExpr;
this.preserveSpace = !!preserveSpace;
}
token: string;
isExpr: boolean;
preserveSpace: boolean;
}
export const types: {
[key: string]: TokContext,
} = {
braceStatement: new TokContext("{", false),
braceExpression: new TokContext("{", true),
recordExpression: new TokContext("#{", true),
templateQuasi: new TokContext("${", false),
parenStatement: new TokContext("(", false),
parenExpression: new TokContext("(", true),
template: new TokContext("`", true, true),
functionExpression: new TokContext("function", true),
functionStatement: new TokContext("function", false),
brace: new TokContext("{"),
templateQuasi: new TokContext("${"),
template: new TokContext("`", true),
};
// Token-specific context update code
@ -42,93 +34,25 @@ export const types: {
// When `=>` is eaten, the context update of `yield` is executed, however,
// `this.prodParam` still has `[Yield]` production because it is not yet updated
tt.parenR.updateContext = tt.braceR.updateContext = function () {
if (this.state.context.length === 1) {
this.state.exprAllowed = true;
return;
tt.braceR.updateContext = context => {
if (context.length > 1) {
context.pop();
}
let out = this.state.context.pop();
if (out === types.braceStatement && this.curContext().token === "function") {
out = this.state.context.pop();
}
this.state.exprAllowed = !out.isExpr;
};
tt.name.updateContext = function (prevType) {
let allowed = false;
if (prevType !== tt.dot) {
if (
this.state.value === "of" &&
!this.state.exprAllowed &&
prevType !== tt._function &&
prevType !== tt._class
) {
allowed = true;
}
}
this.state.exprAllowed = allowed;
};
tt.braceL.updateContext = function (prevType) {
this.state.context.push(
this.braceIsBlock(prevType) ? types.braceStatement : types.braceExpression,
);
this.state.exprAllowed = true;
};
tt.dollarBraceL.updateContext = function () {
this.state.context.push(types.templateQuasi);
this.state.exprAllowed = true;
};
tt.parenL.updateContext = function (prevType) {
const statementParens =
prevType === tt._if ||
prevType === tt._for ||
prevType === tt._with ||
prevType === tt._while;
this.state.context.push(
statementParens ? types.parenStatement : types.parenExpression,
);
this.state.exprAllowed = true;
};
tt.incDec.updateContext = function () {
// tokExprAllowed stays unchanged
};
tt._function.updateContext = tt._class.updateContext = function (prevType) {
if (
prevType.beforeExpr &&
prevType !== tt.semi &&
prevType !== tt._else &&
!(prevType === tt._return && this.hasPrecedingLineBreak()) &&
!(
(prevType === tt.colon || prevType === tt.braceL) &&
this.curContext() === types.braceStatement
)
) {
this.state.context.push(types.functionExpression);
} else {
this.state.context.push(types.functionStatement);
}
this.state.exprAllowed = false;
};
tt.backQuote.updateContext = function () {
if (this.curContext() === types.template) {
this.state.context.pop();
} else {
this.state.context.push(types.template);
}
this.state.exprAllowed = false;
};
// we don't need to update context for tt.braceBarL because we do not pop context for tt.braceBarR
tt.braceHashL.updateContext = function () {
this.state.context.push(types.recordExpression);
this.state.exprAllowed = true; /* tt.braceHashL.beforeExpr */
tt.braceL.updateContext = tt.braceHashL.updateContext = context => {
context.push(types.brace);
};
tt.dollarBraceL.updateContext = context => {
context.push(types.templateQuasi);
};
tt.backQuote.updateContext = context => {
if (context[context.length - 1] === types.template) {
context.pop();
} else {
context.push(types.template);
}
};

View File

@ -190,7 +190,6 @@ export default class Tokenizer extends ParserErrors {
end: state.end,
lastTokEnd: state.end,
context: [this.curContext()],
exprAllowed: state.exprAllowed,
inType: state.inType,
};
}
@ -525,16 +524,9 @@ export default class Tokenizer extends ParserErrors {
}
readToken_slash(): void {
// '/'
if (this.state.exprAllowed && !this.state.inType) {
++this.state.pos;
this.readRegexp();
return;
}
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(tt.assign, 2);
this.finishOp(tt.slashAssign, 2);
} else {
this.finishOp(tt.slash, 1);
}
@ -565,7 +557,6 @@ export default class Tokenizer extends ParserErrors {
let type = code === charCodes.asterisk ? tt.star : tt.modulo;
let width = 1;
let next = this.input.charCodeAt(this.state.pos + 1);
const exprAllowed = this.state.exprAllowed;
// Exponentiation operator **
if (code === charCodes.asterisk && next === charCodes.asterisk) {
@ -574,7 +565,7 @@ export default class Tokenizer extends ParserErrors {
type = tt.exponent;
}
if (next === charCodes.equalsTo && !exprAllowed) {
if (next === charCodes.equalsTo && !this.state.inType) {
width++;
type = tt.assign;
}
@ -983,7 +974,7 @@ export default class Tokenizer extends ParserErrors {
}
readRegexp(): void {
const start = this.state.pos;
const start = this.state.start + 1;
let escaped, inClass;
for (;;) {
if (this.state.pos >= this.length) {
@ -1565,68 +1556,9 @@ export default class Tokenizer extends ParserErrors {
}
}
braceIsBlock(prevType: TokenType): boolean {
const parent = this.curContext();
if (parent === ct.functionExpression || parent === ct.functionStatement) {
return true;
}
if (
prevType === tt.colon &&
(parent === ct.braceStatement || parent === ct.braceExpression)
) {
return !parent.isExpr;
}
// The check for `tt.name && exprAllowed` detects whether we are
// after a `yield` or `of` construct. See the `updateContext` for
// `tt.name`.
if (
prevType === tt._return ||
(prevType === tt.name && this.state.exprAllowed)
) {
return this.hasPrecedingLineBreak();
}
if (
prevType === tt._else ||
prevType === tt.semi ||
prevType === tt.eof ||
prevType === tt.parenR ||
prevType === tt.arrow
) {
return true;
}
if (prevType === tt.braceL) {
return parent === ct.braceStatement;
}
if (
prevType === tt._var ||
prevType === tt._const ||
prevType === tt.name
) {
return false;
}
if (prevType === tt.relational) {
// `class C<T> { ... }`
return true;
}
return !this.state.exprAllowed;
}
// the prevType is required by the jsx plugin
// eslint-disable-next-line no-unused-vars
updateContext(prevType: TokenType): void {
const type = this.state.type;
let update;
if (type.keyword && (prevType === tt.dot || prevType === tt.questionDot)) {
this.state.exprAllowed = false;
} else if ((update = type.updateContext)) {
update.call(this, prevType);
} else {
this.state.exprAllowed = type.beforeExpr;
}
this.state.type.updateContext?.(this.state.context);
}
}

View File

@ -130,7 +130,7 @@ export default class State {
// The context stack is used to superficially track syntactic
// context to predict whether a regular expression is allowed in a
// given position.
context: Array<TokContext> = [ct.braceStatement];
context: Array<TokContext> = [ct.brace];
exprAllowed: boolean = true;
// Used to signal to callers of `readWord1` whether the word
@ -181,7 +181,6 @@ export type LookaheadState = {
type: TokenType,
start: number,
end: number,
/* Used only in readSlashToken */
exprAllowed: boolean,
/* Used only in readToken_mult_modulo */
inType: boolean,
};

View File

@ -1,5 +1,5 @@
// @flow
import type { TokContext } from "./context";
// ## Token types
// The assignment of fine-grained, information-carrying type objects
@ -9,10 +9,9 @@
// All token type variables start with an underscore, to make them
// easy to recognize.
// The `beforeExpr` property is used to disambiguate between regular
// expressions and divisions. It is set on all token types that can
// be followed by an expression (thus, a slash after them would be a
// regular expression).
// The `beforeExpr` property is used to disambiguate between 1) binary
// expression (<) and JSX Tag start (<name>); 2) object literal and JSX
// texts. It is set on the `updateContext` function in the JSX plugin.
// The `startsExpr` property is used to determine whether an expression
// may be the “argument” subexpression of a `yield` expression or
@ -53,7 +52,7 @@ export class TokenType {
prefix: boolean;
postfix: boolean;
binop: ?number;
updateContext: ?(prevType: TokenType) => void;
updateContext: ?(context: Array<TokContext>) => void;
constructor(label: string, conf: TokenOptions = {}) {
this.label = label;
@ -102,7 +101,7 @@ export const types: { [name: string]: TokenType } = {
braceL: new TokenType("{", { beforeExpr, startsExpr }),
braceBarL: new TokenType("{|", { beforeExpr, startsExpr }),
braceHashL: new TokenType("#{", { beforeExpr, startsExpr }),
braceR: new TokenType("}"),
braceR: new TokenType("}", { beforeExpr }),
braceBarR: new TokenType("|}"),
parenL: new TokenType("(", { beforeExpr, startsExpr }),
parenR: new TokenType(")"),
@ -140,6 +139,7 @@ export const types: { [name: string]: TokenType } = {
eq: new TokenType("=", { beforeExpr, isAssign }),
assign: new TokenType("_=", { beforeExpr, isAssign }),
slashAssign: new TokenType("_=", { beforeExpr, isAssign }),
incDec: new TokenType("++/--", { prefix, postfix, startsExpr }),
bang: new TokenType("!", { beforeExpr, prefix, startsExpr }),
tilde: new TokenType("~", { beforeExpr, prefix, startsExpr }),

View File

@ -53,7 +53,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "class",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}}
@ -68,7 +69,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "C",
"start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7}}
@ -113,7 +115,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "p",
"start":13,"end":14,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4}}
@ -121,7 +124,7 @@
{
"type": {
"label": "}",
"beforeExpr": false,
"beforeExpr": true,
"startsExpr": false,
"rightAssociative": false,
"isLoop": false,

View File

@ -53,7 +53,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "class",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}}
@ -68,7 +69,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "C",
"start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7}}
@ -106,7 +108,7 @@
{
"type": {
"label": "}",
"beforeExpr": false,
"beforeExpr": true,
"startsExpr": false,
"rightAssociative": false,
"isLoop": false,

View File

@ -98,7 +98,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "a",
"start":4,"end":5,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}}
@ -177,7 +178,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "b",
"start":16,"end":17,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":5}}
@ -208,7 +210,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "a",
"start":20,"end":21,"loc":{"start":{"line":3,"column":8},"end":{"line":3,"column":9}}

View File

@ -0,0 +1,10 @@
function *f1() {
yield / 1 /g
yield
/ 1 /g
}
function *f2() {
yield /=2 /i
yield
/=2 /i
}

View File

@ -0,0 +1,133 @@
{
"type": "File",
"start":0,"end":101,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}},
"program": {
"type": "Program",
"start":0,"end":101,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start":0,"end":50,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"id": {
"type": "Identifier",
"start":10,"end":12,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":12},"identifierName":"f1"},
"name": "f1"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":15,"end":50,"loc":{"start":{"line":1,"column":15},"end":{"line":5,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":19,"end":31,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":14}},
"expression": {
"type": "YieldExpression",
"start":19,"end":31,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":14}},
"delegate": false,
"argument": {
"type": "RegExpLiteral",
"start":25,"end":31,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":14}},
"extra": {
"raw": "/ 1 /g"
},
"pattern": " 1 ",
"flags": "g"
}
}
},
{
"type": "ExpressionStatement",
"start":34,"end":39,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":7}},
"expression": {
"type": "YieldExpression",
"start":34,"end":39,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":7}},
"delegate": false,
"argument": null
}
},
{
"type": "ExpressionStatement",
"start":42,"end":48,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":8}},
"expression": {
"type": "RegExpLiteral",
"start":42,"end":48,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":8}},
"extra": {
"raw": "/ 1 /g"
},
"pattern": " 1 ",
"flags": "g"
}
}
],
"directives": []
}
},
{
"type": "FunctionDeclaration",
"start":51,"end":101,"loc":{"start":{"line":6,"column":0},"end":{"line":10,"column":1}},
"id": {
"type": "Identifier",
"start":61,"end":63,"loc":{"start":{"line":6,"column":10},"end":{"line":6,"column":12},"identifierName":"f2"},
"name": "f2"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":66,"end":101,"loc":{"start":{"line":6,"column":15},"end":{"line":10,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":70,"end":82,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":14}},
"expression": {
"type": "YieldExpression",
"start":70,"end":82,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":14}},
"delegate": false,
"argument": {
"type": "RegExpLiteral",
"start":76,"end":82,"loc":{"start":{"line":7,"column":8},"end":{"line":7,"column":14}},
"extra": {
"raw": "/=2 /i"
},
"pattern": "=2 ",
"flags": "i"
}
}
},
{
"type": "ExpressionStatement",
"start":85,"end":90,"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":7}},
"expression": {
"type": "YieldExpression",
"start":85,"end":90,"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":7}},
"delegate": false,
"argument": null
}
},
{
"type": "ExpressionStatement",
"start":93,"end":99,"loc":{"start":{"line":9,"column":2},"end":{"line":9,"column":8}},
"expression": {
"type": "RegExpLiteral",
"start":93,"end":99,"loc":{"start":{"line":9,"column":2},"end":{"line":9,"column":8}},
"extra": {
"raw": "/=2 /i"
},
"pattern": "=2 ",
"flags": "i"
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,8 @@
function* f() {
(yield);
[yield];
{ yield };
yield;
true ? yield : 1;
yield, 1;
}

View File

@ -0,0 +1,146 @@
{
"type": "File",
"start":0,"end":93,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}},
"program": {
"type": "Program",
"start":0,"end":93,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start":0,"end":93,"loc":{"start":{"line":1,"column":0},"end":{"line":8,"column":1}},
"id": {
"type": "Identifier",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"f"},
"name": "f"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":14,"end":93,"loc":{"start":{"line":1,"column":14},"end":{"line":8,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":18,"end":26,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":10}},
"expression": {
"type": "YieldExpression",
"start":19,"end":24,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":8}},
"extra": {
"parenthesized": true,
"parenStart": 18
},
"delegate": false,
"argument": null
}
},
{
"type": "ExpressionStatement",
"start":29,"end":37,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":10}},
"expression": {
"type": "ArrayExpression",
"start":29,"end":36,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":9}},
"elements": [
{
"type": "YieldExpression",
"start":30,"end":35,"loc":{"start":{"line":3,"column":3},"end":{"line":3,"column":8}},
"delegate": false,
"argument": null
}
]
}
},
{
"type": "BlockStatement",
"start":40,"end":49,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":11}},
"body": [
{
"type": "ExpressionStatement",
"start":42,"end":47,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":9}},
"expression": {
"type": "YieldExpression",
"start":42,"end":47,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":9}},
"delegate": false,
"argument": null
}
}
],
"directives": []
},
{
"type": "EmptyStatement",
"start":49,"end":50,"loc":{"start":{"line":4,"column":11},"end":{"line":4,"column":12}}
},
{
"type": "ExpressionStatement",
"start":53,"end":59,"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":8}},
"expression": {
"type": "YieldExpression",
"start":53,"end":58,"loc":{"start":{"line":5,"column":2},"end":{"line":5,"column":7}},
"delegate": false,
"argument": null
}
},
{
"type": "ExpressionStatement",
"start":62,"end":79,"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":19}},
"expression": {
"type": "ConditionalExpression",
"start":62,"end":78,"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":18}},
"test": {
"type": "BooleanLiteral",
"start":62,"end":66,"loc":{"start":{"line":6,"column":2},"end":{"line":6,"column":6}},
"value": true
},
"consequent": {
"type": "YieldExpression",
"start":69,"end":74,"loc":{"start":{"line":6,"column":9},"end":{"line":6,"column":14}},
"delegate": false,
"argument": null
},
"alternate": {
"type": "NumericLiteral",
"start":77,"end":78,"loc":{"start":{"line":6,"column":17},"end":{"line":6,"column":18}},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
}
},
{
"type": "ExpressionStatement",
"start":82,"end":91,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":11}},
"expression": {
"type": "SequenceExpression",
"start":82,"end":90,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":10}},
"expressions": [
{
"type": "YieldExpression",
"start":82,"end":87,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":7}},
"delegate": false,
"argument": null
},
{
"type": "NumericLiteral",
"start":89,"end":90,"loc":{"start":{"line":7,"column":9},"end":{"line":7,"column":10}},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
]
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,10 @@
function f1() {
yield / 1 /g
yield
/ 1 /g
}
function f2() {
yield /=2 /i
yield
/=2 /i
}

View File

@ -0,0 +1,183 @@
{
"type": "File",
"start":0,"end":99,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}},
"program": {
"type": "Program",
"start":0,"end":99,"loc":{"start":{"line":1,"column":0},"end":{"line":10,"column":1}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start":0,"end":49,"loc":{"start":{"line":1,"column":0},"end":{"line":5,"column":1}},
"id": {
"type": "Identifier",
"start":9,"end":11,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":11},"identifierName":"f1"},
"name": "f1"
},
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":14,"end":49,"loc":{"start":{"line":1,"column":14},"end":{"line":5,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":18,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":14}},
"expression": {
"type": "BinaryExpression",
"start":18,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":14}},
"left": {
"type": "BinaryExpression",
"start":18,"end":27,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":11}},
"left": {
"type": "Identifier",
"start":18,"end":23,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":7},"identifierName":"yield"},
"name": "yield"
},
"operator": "/",
"right": {
"type": "NumericLiteral",
"start":26,"end":27,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":11}},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
"operator": "/",
"right": {
"type": "Identifier",
"start":29,"end":30,"loc":{"start":{"line":2,"column":13},"end":{"line":2,"column":14},"identifierName":"g"},
"name": "g"
}
}
},
{
"type": "ExpressionStatement",
"start":33,"end":47,"loc":{"start":{"line":3,"column":2},"end":{"line":4,"column":8}},
"expression": {
"type": "BinaryExpression",
"start":33,"end":47,"loc":{"start":{"line":3,"column":2},"end":{"line":4,"column":8}},
"left": {
"type": "BinaryExpression",
"start":33,"end":44,"loc":{"start":{"line":3,"column":2},"end":{"line":4,"column":5}},
"left": {
"type": "Identifier",
"start":33,"end":38,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":7},"identifierName":"yield"},
"name": "yield"
},
"operator": "/",
"right": {
"type": "NumericLiteral",
"start":43,"end":44,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":5}},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
"operator": "/",
"right": {
"type": "Identifier",
"start":46,"end":47,"loc":{"start":{"line":4,"column":7},"end":{"line":4,"column":8},"identifierName":"g"},
"name": "g"
}
}
}
],
"directives": []
}
},
{
"type": "FunctionDeclaration",
"start":50,"end":99,"loc":{"start":{"line":6,"column":0},"end":{"line":10,"column":1}},
"id": {
"type": "Identifier",
"start":59,"end":61,"loc":{"start":{"line":6,"column":9},"end":{"line":6,"column":11},"identifierName":"f2"},
"name": "f2"
},
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":64,"end":99,"loc":{"start":{"line":6,"column":14},"end":{"line":10,"column":1}},
"body": [
{
"type": "ExpressionStatement",
"start":68,"end":80,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":14}},
"expression": {
"type": "AssignmentExpression",
"start":68,"end":80,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":14}},
"operator": "/=",
"left": {
"type": "Identifier",
"start":68,"end":73,"loc":{"start":{"line":7,"column":2},"end":{"line":7,"column":7},"identifierName":"yield"},
"name": "yield"
},
"right": {
"type": "BinaryExpression",
"start":76,"end":80,"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":14}},
"left": {
"type": "NumericLiteral",
"start":76,"end":77,"loc":{"start":{"line":7,"column":10},"end":{"line":7,"column":11}},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
},
"operator": "/",
"right": {
"type": "Identifier",
"start":79,"end":80,"loc":{"start":{"line":7,"column":13},"end":{"line":7,"column":14},"identifierName":"i"},
"name": "i"
}
}
}
},
{
"type": "ExpressionStatement",
"start":83,"end":97,"loc":{"start":{"line":8,"column":2},"end":{"line":9,"column":8}},
"expression": {
"type": "AssignmentExpression",
"start":83,"end":97,"loc":{"start":{"line":8,"column":2},"end":{"line":9,"column":8}},
"operator": "/=",
"left": {
"type": "Identifier",
"start":83,"end":88,"loc":{"start":{"line":8,"column":2},"end":{"line":8,"column":7},"identifierName":"yield"},
"name": "yield"
},
"right": {
"type": "BinaryExpression",
"start":93,"end":97,"loc":{"start":{"line":9,"column":4},"end":{"line":9,"column":8}},
"left": {
"type": "NumericLiteral",
"start":93,"end":94,"loc":{"start":{"line":9,"column":4},"end":{"line":9,"column":5}},
"extra": {
"rawValue": 2,
"raw": "2"
},
"value": 2
},
"operator": "/",
"right": {
"type": "Identifier",
"start":96,"end":97,"loc":{"start":{"line":9,"column":7},"end":{"line":9,"column":8},"identifierName":"i"},
"name": "i"
}
}
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
function *f() {
return {| foo: yield |}
}

View File

@ -0,0 +1,3 @@
{
"plugins": [["recordAndTuple", { "syntaxType": "bar" }]]
}

View File

@ -0,0 +1,60 @@
{
"type": "File",
"start":0,"end":43,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"program": {
"type": "Program",
"start":0,"end":43,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start":0,"end":43,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
"id": {
"type": "Identifier",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11},"identifierName":"f"},
"name": "f"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":14,"end":43,"loc":{"start":{"line":1,"column":14},"end":{"line":3,"column":1}},
"body": [
{
"type": "ReturnStatement",
"start":18,"end":41,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":25}},
"argument": {
"type": "RecordExpression",
"start":25,"end":41,"loc":{"start":{"line":2,"column":9},"end":{"line":2,"column":25}},
"properties": [
{
"type": "ObjectProperty",
"start":28,"end":38,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":22}},
"method": false,
"key": {
"type": "Identifier",
"start":28,"end":31,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":15},"identifierName":"foo"},
"name": "foo"
},
"computed": false,
"shorthand": false,
"value": {
"type": "YieldExpression",
"start":33,"end":38,"loc":{"start":{"line":2,"column":17},"end":{"line":2,"column":22}},
"delegate": false,
"argument": null
}
}
]
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@ -179,7 +179,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "key",
"start":13,"end":16,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":16}}
@ -209,7 +210,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "value",
"start":18,"end":23,"loc":{"start":{"line":1,"column":18},"end":{"line":1,"column":23}}
@ -232,7 +234,7 @@
{
"type": {
"label": "}",
"beforeExpr": false,
"beforeExpr": true,
"startsExpr": false,
"rightAssociative": false,
"isLoop": false,
@ -269,7 +271,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"start":27,"end":28,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":28}}
},

View File

@ -81,7 +81,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "async",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}}
@ -112,7 +113,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "T",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":8}}
@ -143,7 +145,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10}}
},
@ -157,7 +160,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "a",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":11}}
@ -187,7 +191,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "T",
"start":13,"end":14,"loc":{"start":{"line":1,"column":13},"end":{"line":1,"column":14}}
@ -202,7 +207,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"start":14,"end":15,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":15}}
},
@ -231,7 +237,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "T",
"start":17,"end":18,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":18}}
@ -261,7 +268,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "a",
"start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23}}

View File

@ -93,7 +93,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "type",
"start":0,"end":4,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":4}}
@ -108,7 +109,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "T",
"start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6}}
@ -139,7 +141,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "U",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":8}}
@ -171,7 +174,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "object",
"start":17,"end":23,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":23}}
@ -216,7 +220,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "x",
"start":28,"end":29,"loc":{"start":{"line":1,"column":28},"end":{"line":1,"column":29}}
@ -246,7 +251,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "number",
"start":31,"end":37,"loc":{"start":{"line":1,"column":31},"end":{"line":1,"column":37}}
@ -254,7 +260,7 @@
{
"type": {
"label": "}",
"beforeExpr": false,
"beforeExpr": true,
"startsExpr": false,
"rightAssociative": false,
"isLoop": false,
@ -307,7 +313,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "Array",
"start":43,"end":48,"loc":{"start":{"line":1,"column":43},"end":{"line":1,"column":48}}
@ -338,7 +345,8 @@
"isAssign": false,
"prefix": false,
"postfix": false,
"binop": null
"binop": null,
"updateContext": null
},
"value": "U",
"start":49,"end":50,"loc":{"start":{"line":1,"column":49},"end":{"line":1,"column":50}}