Skip to content
This repository has been archived by the owner on May 19, 2018. It is now read-only.

Commit

Permalink
Change Identifier to PrivateName, ban #constructor, fix error position
Browse files Browse the repository at this point in the history
  • Loading branch information
Qantas94Heavy committed Sep 1, 2017
1 parent 6e7175d commit ce87518
Show file tree
Hide file tree
Showing 19 changed files with 576 additions and 240 deletions.
27 changes: 10 additions & 17 deletions src/parser/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -1398,35 +1398,28 @@ export default class ExpressionParser extends LValParser {
}

parsePropertyName(
prop: N.ObjectOrClassMember | N.TsNamedTypeElementBase,
): N.Expression {
prop: N.ObjectOrClassMember | N.ClassPrivateProperty | N.ClassPrivateMethod | N.TsNamedTypeElementBase,
): N.Expression | N.Identifier {
if (this.eat(tt.bracketL)) {
prop.computed = true;
prop.key = this.parseMaybeAssign();
this.expect(tt.bracketR);
} else {
prop.computed = false;
const oldInPropertyName = this.state.inPropertyName;
this.state.inPropertyName = true;
prop.key =
this.match(tt.num) || this.match(tt.string)
? this.parseExprAtom()
: this.parseIdentifier(true);
this.state.inPropertyName = oldInPropertyName;
}
: this.parseMaybePrivateName();

return prop.key;
}
// TODO: if no plugin and is PrivateName, should error be handled here or elsewhere?
if (prop.key.type !== "PrivateName") {
// ClassPrivateProperty is never computed, so we don't assign in that case.
prop.computed = false;
}

// FIXME: does this make sense separate?
parseClassPrivateName(
prop: N.ClassPrivateProperty | N.ClassPrivateMethod,
): N.Expression {
prop.computed = false;
const oldInPropertyName = this.state.inPropertyName;
this.state.inPropertyName = true;
prop.key = this.parseIdentifier(true);
this.state.inPropertyName = oldInPropertyName;
this.state.inPropertyName = oldInPropertyName;
}

return prop.key;
}
Expand Down
113 changes: 40 additions & 73 deletions src/parser/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -978,12 +978,11 @@ export default class StatementParser extends ExpressionParser {
if (this.eat(tt.star)) {
// a generator
method.kind = "method";
this.parseClassPropertyName(method);

if (this.match(tt.hash)) {
this.expectPlugin("classPrivateMethods");
this.next();
if (method.key.type === "PrivateName") {
this.expectPlugin("classPrivateMethods", method.key.start);
// Private generator method
this.parseClassPrivateName(method);
this.parseClassPrivateMethod(
classBody,
method,
Expand All @@ -994,52 +993,42 @@ export default class StatementParser extends ExpressionParser {
return;
}

this.parsePropertyName(method);

if (this.isNonstaticConstructor(method)) {
this.raise(method.key.start, "Constructor can't be a generator");
}
if (
!method.computed &&
method.static &&
(method.key.name === "prototype" || method.key.value === "prototype")
) {
this.raise(
method.key.start,
"Classes may not have static property named prototype",
);
}

this.parseClassMethod(
classBody,
method,
true,
false,
/* isConstructor */ false,
);

return;
}

const isPrivate = this.match(tt.hash);
if (isPrivate) {
this.expectOnePlugin(["classPrivateProperties", "classPrivateMethods"]);
// Skip over the hash.
this.next();
}
const key = this.parseClassPropertyName(methodOrProp);
let isPrivate = key.type === "PrivateName";
const isSimple = !isPrivate && !key.computed;

const isSimple = this.match(tt.name);
const key = isPrivate
? this.parseClassPrivateName(methodOrProp)
: this.parseClassPropertyName(methodOrProp);
const handleClassProperty = () => {
if (isPrivate) {
this.expectPlugin("classPrivateProperties", key.start);
// Private property
classBody.body.push(this.parseClassPrivateProperty(prop));
} else {
this.pushClassProperty(classBody, prop);
}
};

this.parsePostMemberNameModifiers(methodOrProp);

if (this.isClassMethod()) {
method.kind = "method";

if (isPrivate) {
// TODO: seems a bit inconsistent error throwing: in some cases we've already
// eaten the #, but in other cases we haven't. How to solve?
this.expectPlugin("classPrivateMethods");
this.expectPlugin("classPrivateMethods", key.start);
this.parseClassPrivateMethod(
classBody,
method,
Expand Down Expand Up @@ -1072,13 +1061,7 @@ export default class StatementParser extends ExpressionParser {

this.parseClassMethod(classBody, method, false, false, isConstructor);
} else if (this.isClassProperty()) {
if (isPrivate) {
this.expectPlugin("classPrivateProperties");
// Private property
classBody.body.push(this.parseClassPrivateProperty(prop));
} else {
this.pushClassProperty(classBody, prop);
}
handleClassProperty();
} else if (isSimple && key.name === "async" && !this.isLineTerminator()) {
// an async method
let isGenerator = false;
Expand All @@ -1088,14 +1071,12 @@ export default class StatementParser extends ExpressionParser {
isGenerator = true;
}
method.kind = "method";
// The so-called parsed name would have been "async": get the real name.
this.parseClassPropertyName(method);

if (this.match(tt.hash)) {
if (method.key.type === "PrivateName") {
this.expectPlugin("classPrivateMethods", method.key.start);
// private async method
this.expectPlugin("classPrivateMethods");
// The private # wouldn't have been eaten yet as the "async" was in front of it.
this.next();
// The so-called parsed name would have been "async": get the real name.
this.parseClassPrivateName(method);
this.parseClassPrivateMethod(
classBody,
method,
Expand All @@ -1104,7 +1085,6 @@ export default class StatementParser extends ExpressionParser {
/* isConstructor */ false,
);
} else {
this.parsePropertyName(method);
if (this.isNonstaticConstructor(method)) {
this.raise(
method.key.start,
Expand All @@ -1127,14 +1107,12 @@ export default class StatementParser extends ExpressionParser {
// `get\n*` is an uninitialized property named 'get' followed by a generator.
// a getter or setter
method.kind = key.name;
// The so-called parsed name would have been "get/set": get the real name.
this.parseClassPropertyName(method);

if (this.match(tt.hash)) {
if (method.key.type === "PrivateName") {
this.expectPlugin("classPrivateMethods", method.key.start);
// private getter/setter
this.expectPlugin("classPrivateMethods");
// The private # wouldn't have been eaten yet as the "get/set" was in front of it.
this.next();
// The so-called parsed name would have been "get/set": get the real name.
this.parseClassPrivateName(method);
this.parseClassPrivateMethod(
classBody,
method,
Expand All @@ -1143,7 +1121,6 @@ export default class StatementParser extends ExpressionParser {
/* isConstructor */ false,
);
} else {
this.parsePropertyName(method);
if (this.isNonstaticConstructor(method)) {
this.raise(
method.key.start,
Expand All @@ -1162,43 +1139,37 @@ export default class StatementParser extends ExpressionParser {
this.checkGetterSetterParamCount(method);
} else if (this.isLineTerminator()) {
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
if (isPrivate) {
this.expectPlugin("classPrivateProperties");
// Private property
classBody.body.push(this.parseClassPrivateProperty(prop));
} else {
if (this.isNonstaticConstructor(prop)) {
this.raise(
prop.key.start,
"Classes may not have a non-static field named 'constructor'",
);
}
classBody.body.push(this.parseClassProperty(prop));
}
handleClassProperty();
} else {
this.unexpected();
}
}

parseClassPropertyName(
methodOrProp: N.ClassMethod | N.ClassProperty,
): N.Expression {
methodOrProp: N.ClassMethod | N.ClassProperty | N.ClassPrivateProperty | N.ClassPrivateMethod,
): N.Expression | N.Identifier {
const key = this.parsePropertyName(methodOrProp);
if (
!methodOrProp.computed &&
methodOrProp.static &&
(methodOrProp.key.name === "prototype" ||
methodOrProp.key.value === "prototype")
(key.name === "prototype" || key.value === "prototype")
) {
this.raise(
methodOrProp.key.start,
key.start,
"Classes may not have static property named prototype",
);
}
if (key.type === 'PrivateName' && key.id.name === 'constructor') {
this.raise(
key.start,
"Classes may not have a private field named '#constructor'",
);
}
return key;
}

pushClassProperty(classBody: N.ClassBody, prop: N.ClassProperty) {
// FIXME: inconsistent placement?
if (this.isNonstaticConstructor(prop)) {
this.raise(
prop.key.start,
Expand All @@ -1223,10 +1194,7 @@ export default class StatementParser extends ExpressionParser {
node: N.ClassPrivateProperty,
): N.ClassPrivateProperty {
this.state.inClassProperty = true;

if (node.computed !== undefined) node.computed = undefined;
node.value = this.eat(tt.eq) ? this.parseMaybeAssign() : null;

this.semicolon();
this.state.inClassProperty = false;
return this.finishNode(node, "ClassPrivateProperty");
Expand Down Expand Up @@ -1275,14 +1243,13 @@ export default class StatementParser extends ExpressionParser {
method: N.ClassMethod,
isGenerator: boolean,
isAsync: boolean,
isConstructor: boolean,
): void {
classBody.body.push(
this.parseMethod(
method,
isGenerator,
isAsync,
isConstructor,
/* isConstructor */ false,
"ClassPrivateMethod",
),
);
Expand Down
8 changes: 4 additions & 4 deletions src/parser/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,20 @@ export default class UtilParser extends Tokenizer {
throw this.raise(pos != null ? pos : this.state.start, messageOrType);
}

expectPlugin(name: string): void {
expectPlugin(name: string, pos?: ?number): void {
if (!this.hasPlugin(name)) {
throw this.raise(
this.state.start,
pos != null ? pos : this.state.start,
`This experimental syntax requires enabling the parser plugin: '${name}'`,
[name],
);
}
}

expectOnePlugin(names: Array<string>): void {
expectOnePlugin(names: Array<string>, pos?: ?number): void {
if (!names.some(n => this.hasPlugin(n))) {
throw this.raise(
this.state.start,
pos != null ? pos : this.state.start,
`This experimental syntax requires enabling one of the following parser plugin(s): '${names.join(
", ",
)}'`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@
}
},
"static": false,
"computed": false,
"key": {
"type": "Identifier",
"type": "PrivateName",
"start": 22,
"end": 31,
"loc": {
Expand All @@ -103,11 +102,27 @@
"end": {
"line": 2,
"column": 19
},
"identifierName": "readLines"
}
},
"name": "readLines"
"id": {
"type": "Identifier",
"start": 22,
"end": 31,
"loc": {
"start": {
"line": 2,
"column": 10
},
"end": {
"line": 2,
"column": 19
},
"identifierName": "readLines"
},
"name": "readLines"
}
},
"computed": false,
"kind": "method",
"id": null,
"generator": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,8 @@
}
},
"static": false,
"computed": false,
"key": {
"type": "Identifier",
"type": "PrivateName",
"start": 23,
"end": 27,
"loc": {
Expand All @@ -103,11 +102,27 @@
"end": {
"line": 2,
"column": 13
},
"identifierName": "evil"
}
},
"name": "evil"
"id": {
"type": "Identifier",
"start": 23,
"end": 27,
"loc": {
"start": {
"line": 2,
"column": 9
},
"end": {
"line": 2,
"column": 13
},
"identifierName": "evil"
},
"name": "evil"
}
},
"computed": false,
"kind": "method",
"id": null,
"generator": false,
Expand Down
Loading

0 comments on commit ce87518

Please sign in to comment.