Type-check LValParser (#487)
This commit is contained in:
parent
e1a06544bc
commit
d8ff63181e
@ -1,11 +1,28 @@
|
|||||||
import { types as tt } from "../tokenizer/types";
|
// @flow
|
||||||
|
|
||||||
|
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||||
|
import type { Decorator, Expression, Identifier, Node, ObjectExpression, ObjectPattern, Pattern, RestElement,
|
||||||
|
SpreadElement } from "../types";
|
||||||
|
import type { Pos, Position } from "../util/location";
|
||||||
import { NodeUtils } from "./node";
|
import { NodeUtils } from "./node";
|
||||||
|
|
||||||
export default class LValParser extends NodeUtils {
|
export default class LValParser extends NodeUtils {
|
||||||
|
// Forward-declaration: defined in expression.js
|
||||||
|
+checkReservedWord: (word: string, startLoc: number, checkKeywords: boolean, isBinding: boolean) => void;
|
||||||
|
+parseIdentifier: (liberal?: boolean) => Identifier;
|
||||||
|
+parseMaybeAssign: (
|
||||||
|
noIn?: ?boolean,
|
||||||
|
refShorthandDefaultPos?: ?Pos,
|
||||||
|
afterLeftParse?: Function,
|
||||||
|
refNeedsArrowPos?: ?Pos) => Expression;
|
||||||
|
+parseObj: <T : ObjectPattern | ObjectExpression>(isPattern: boolean, refShorthandDefaultPos?: ?Pos) => T;
|
||||||
|
// Forward-declaration: defined in statement.js
|
||||||
|
+parseDecorator: () => Decorator;
|
||||||
|
|
||||||
// Convert existing expression atom to assignable pattern
|
// Convert existing expression atom to assignable pattern
|
||||||
// if possible.
|
// if possible.
|
||||||
|
|
||||||
toAssignable(node, isBinding, contextDescription) {
|
toAssignable(node: Node, isBinding: ?boolean, contextDescription: string): Node {
|
||||||
if (node) {
|
if (node) {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case "Identifier":
|
case "Identifier":
|
||||||
@ -16,7 +33,7 @@ export default class LValParser extends NodeUtils {
|
|||||||
|
|
||||||
case "ObjectExpression":
|
case "ObjectExpression":
|
||||||
node.type = "ObjectPattern";
|
node.type = "ObjectPattern";
|
||||||
for (const prop of (node.properties: Array<Object>)) {
|
for (const prop of node.properties) {
|
||||||
if (prop.type === "ObjectMethod") {
|
if (prop.type === "ObjectMethod") {
|
||||||
if (prop.kind === "get" || prop.kind === "set") {
|
if (prop.kind === "get" || prop.kind === "set") {
|
||||||
this.raise(prop.key.start, "Object pattern can't contain getter or setter");
|
this.raise(prop.key.start, "Object pattern can't contain getter or setter");
|
||||||
@ -66,7 +83,8 @@ export default class LValParser extends NodeUtils {
|
|||||||
|
|
||||||
// Convert list of expression atoms to binding list.
|
// Convert list of expression atoms to binding list.
|
||||||
|
|
||||||
toAssignableList(exprList, isBinding, contextDescription) {
|
toAssignableList(
|
||||||
|
exprList: Expression[], isBinding: ?boolean, contextDescription: string): $ReadOnlyArray<Pattern> {
|
||||||
let end = exprList.length;
|
let end = exprList.length;
|
||||||
if (end) {
|
if (end) {
|
||||||
const last = exprList[end - 1];
|
const last = exprList[end - 1];
|
||||||
@ -93,36 +111,36 @@ export default class LValParser extends NodeUtils {
|
|||||||
|
|
||||||
// Convert list of expression atoms to a list of
|
// Convert list of expression atoms to a list of
|
||||||
|
|
||||||
toReferencedList(exprList) {
|
toReferencedList(exprList: $ReadOnlyArray<?Expression>): $ReadOnlyArray<?Expression> {
|
||||||
return exprList;
|
return exprList;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses spread element.
|
// Parses spread element.
|
||||||
|
|
||||||
parseSpread(refShorthandDefaultPos) {
|
parseSpread<T : RestElement | SpreadElement>(refShorthandDefaultPos: ?Pos): T {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
node.argument = this.parseMaybeAssign(false, refShorthandDefaultPos);
|
node.argument = this.parseMaybeAssign(false, refShorthandDefaultPos);
|
||||||
return this.finishNode(node, "SpreadElement");
|
return this.finishNode(node, "SpreadElement");
|
||||||
}
|
}
|
||||||
|
|
||||||
parseRest() {
|
parseRest(): RestElement {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
node.argument = this.parseBindingAtom();
|
node.argument = this.parseBindingAtom();
|
||||||
return this.finishNode(node, "RestElement");
|
return this.finishNode(node, "RestElement");
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldAllowYieldIdentifier() {
|
shouldAllowYieldIdentifier(): boolean {
|
||||||
return this.match(tt._yield) && !this.state.strict && !this.state.inGenerator;
|
return this.match(tt._yield) && !this.state.strict && !this.state.inGenerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseBindingIdentifier() {
|
parseBindingIdentifier(): Identifier {
|
||||||
return this.parseIdentifier(this.shouldAllowYieldIdentifier());
|
return this.parseIdentifier(this.shouldAllowYieldIdentifier());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses lvalue (assignable) atom.
|
// Parses lvalue (assignable) atom.
|
||||||
parseBindingAtom() {
|
parseBindingAtom(): Pattern {
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt._yield:
|
case tt._yield:
|
||||||
case tt.name:
|
case tt.name:
|
||||||
@ -138,11 +156,11 @@ export default class LValParser extends NodeUtils {
|
|||||||
return this.parseObj(true);
|
return this.parseObj(true);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.unexpected();
|
throw this.unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parseBindingList(close, allowEmpty) {
|
parseBindingList(close: TokenType, allowEmpty?: boolean): $ReadOnlyArray<Pattern> {
|
||||||
const elts = [];
|
const elts = [];
|
||||||
let first = true;
|
let first = true;
|
||||||
while (!this.eat(close)) {
|
while (!this.eat(close)) {
|
||||||
@ -152,6 +170,7 @@ export default class LValParser extends NodeUtils {
|
|||||||
this.expect(tt.comma);
|
this.expect(tt.comma);
|
||||||
}
|
}
|
||||||
if (allowEmpty && this.match(tt.comma)) {
|
if (allowEmpty && this.match(tt.comma)) {
|
||||||
|
// $FlowFixMe This method returns `$ReadOnlyArray<?Pattern>` if `allowEmpty` is set.
|
||||||
elts.push(null);
|
elts.push(null);
|
||||||
} else if (this.eat(close)) {
|
} else if (this.eat(close)) {
|
||||||
break;
|
break;
|
||||||
@ -175,13 +194,13 @@ export default class LValParser extends NodeUtils {
|
|||||||
return elts;
|
return elts;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseAssignableListItemTypes(param) {
|
parseAssignableListItemTypes(param: Pattern): Pattern {
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parses assignment pattern around given atom if possible.
|
// Parses assignment pattern around given atom if possible.
|
||||||
|
|
||||||
parseMaybeDefault(startPos, startLoc, left) {
|
parseMaybeDefault(startPos?: ?number, startLoc?: ?Position, left?: ?Pattern): Pattern {
|
||||||
startLoc = startLoc || this.state.startLoc;
|
startLoc = startLoc || this.state.startLoc;
|
||||||
startPos = startPos || this.state.start;
|
startPos = startPos || this.state.start;
|
||||||
left = left || this.parseBindingAtom();
|
left = left || this.parseBindingAtom();
|
||||||
@ -196,7 +215,11 @@ export default class LValParser extends NodeUtils {
|
|||||||
// Verify that a node is an lval — something that can be assigned
|
// Verify that a node is an lval — something that can be assigned
|
||||||
// to.
|
// to.
|
||||||
|
|
||||||
checkLVal(expr, isBinding, checkClashes, contextDescription) {
|
checkLVal(
|
||||||
|
expr: Expression,
|
||||||
|
isBinding: ?boolean,
|
||||||
|
checkClashes: ?{ [key: string]: boolean },
|
||||||
|
contextDescription: string): void {
|
||||||
switch (expr.type) {
|
switch (expr.type) {
|
||||||
case "Identifier":
|
case "Identifier":
|
||||||
this.checkReservedWord(expr.name, expr.start, false, true);
|
this.checkReservedWord(expr.name, expr.start, false, true);
|
||||||
@ -229,14 +252,14 @@ export default class LValParser extends NodeUtils {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "ObjectPattern":
|
case "ObjectPattern":
|
||||||
for (let prop of (expr.properties: Array<Object>)) {
|
for (let prop of expr.properties) {
|
||||||
if (prop.type === "ObjectProperty") prop = prop.value;
|
if (prop.type === "ObjectProperty") prop = prop.value;
|
||||||
this.checkLVal(prop, isBinding, checkClashes, "object destructuring pattern");
|
this.checkLVal(prop, isBinding, checkClashes, "object destructuring pattern");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ArrayPattern":
|
case "ArrayPattern":
|
||||||
for (const elem of (expr.elements: Array<Object>)) {
|
for (const elem of expr.elements) {
|
||||||
if (elem) this.checkLVal(elem, isBinding, checkClashes, "array destructuring pattern");
|
if (elem) this.checkLVal(elem, isBinding, checkClashes, "array destructuring pattern");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user