Skip to content

Commit 8b6abaf

Browse files
authored
Fix await identifiers in property names (#249)
* port shift-parser-js#418 * fixes * fix whitespace, yields
1 parent c8d8d10 commit 8b6abaf

File tree

6 files changed

+40
-5
lines changed

6 files changed

+40
-5
lines changed

src/main/java/com/shapesecurity/shift/es2017/parser/ErrorMessages.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ interface ErrorMessages {
4141
String UNEXPECTED_RESERVED_WORD = "Unexpected reserved word";
4242
String UNEXPECTED_TEMPLATE = "Unexpected template";
4343
String UNEXPECTED_EOS = "Unexpected end of input";
44+
String UNEXPECTED_REST_PARAMETERS_INITIALIZATION = "Rest parameter may not have a default initializer";
4445
String NEWLINE_AFTER_THROW = "Illegal newline after throw";
4546
String NEWLINE_AFTER_ARROW_PARAMS = "Illegal newline after arrow parameters";
4647
String UNTERMINATED_REGEXP = "Invalid regular expression: missing /";

src/main/java/com/shapesecurity/shift/es2017/parser/GenericParser.java

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -364,14 +364,15 @@ protected BindingProperty parseBindingProperty() throws JsError {
364364

365365
if ((token.type == TokenType.IDENTIFIER || token.type == TokenType.LET || token.type == TokenType.YIELD) && name instanceof StaticPropertyName) {
366366
if (!this.match(TokenType.COLON)) {
367+
if (token.type == TokenType.YIELD && this.allowYieldExpression) {
368+
throw this.createUnexpected(token);
369+
}
367370
Maybe<Expression> defaultValue = Maybe.empty();
368371
if (this.eat(TokenType.ASSIGN)) {
369372
boolean previousAllowYieldExpression = this.allowYieldExpression;
370373
Either<Expression, AssignmentTarget> expr = this.parseAssignmentExpression();
371374
defaultValue = expr.left();
372375
this.allowYieldExpression = previousAllowYieldExpression;
373-
} else if (token.type == TokenType.YIELD && this.allowYieldExpression) {
374-
throw this.createUnexpected(token);
375376
}
376377
return this.finishNode(startState, new BindingPropertyIdentifier((BindingIdentifier) binding.fromJust(), defaultValue));
377378
}
@@ -551,6 +552,11 @@ protected FormalParameters parseParams() throws JsError {
551552
while (!this.eof()) {
552553
if (this.eat(TokenType.ELLIPSIS)) {
553554
rest = parseBindingTarget();
555+
if (this.match(TokenType.ASSIGN)) {
556+
throw this.createError(ErrorMessages.UNEXPECTED_REST_PARAMETERS_INITIALIZATION);
557+
} else if (this.match(TokenType.COMMA)) {
558+
throw this.createUnexpected(this.lookahead);
559+
}
554560
break;
555561
}
556562
items.add(this.parseParam());
@@ -1589,7 +1595,11 @@ protected Either3<ExpressionSuper, Pair<FormalParameters, Boolean>, AssignmentTa
15891595
Maybe<Binding> rest = Maybe.empty();
15901596
Maybe<SpreadElementExpression> lastArgument = arguments.maybeLast();
15911597
if (lastArgument.isJust() && lastArgument.fromJust() instanceof SpreadElement) {
1592-
rest = Maybe.of(this.targetToBinding(this.transformDestructuring(((SpreadElement) lastArgument.fromJust()).expression)));
1598+
BindingBindingWithDefault binding = this.targetToBindingPossiblyWithDefault(this.transformDestructuringWithDefault(((SpreadElement) lastArgument.fromJust()).expression));
1599+
if (binding instanceof BindingWithDefault) {
1600+
throw this.createError(ErrorMessages.UNEXPECTED_REST_PARAMETERS_INITIALIZATION);
1601+
}
1602+
rest = Maybe.of((Binding) binding);
15931603
arguments = arguments.take(arguments.length - 1);
15941604
}
15951605
// evil java hack
@@ -2191,16 +2201,31 @@ protected Either<ObjectProperty, AssignmentTargetProperty> parsePropertyDefiniti
21912201
this.isBindingElement = this.isAssignmentTarget = false;
21922202
return Either.left(keyOrMethod.right().fromJust());
21932203
} else if (keyOrMethod.isLeft()) {
2204+
if (token.type == TokenType.AWAIT && this.firstAwaitLocation == null) {
2205+
this.firstAwaitLocation = this.getLocation();
2206+
}
21942207
PropertyName propName = keyOrMethod.left().fromJust();
21952208
if (propName instanceof StaticPropertyName) {
21962209
StaticPropertyName staticPropertyName = (StaticPropertyName) propName;
21972210
if (this.eat(TokenType.ASSIGN)) {
2211+
if (this.allowYieldExpression && token.type == TokenType.YIELD) {
2212+
throw this.createError(ErrorMessages.INVALID_TOKEN_CONTEXT, "yield");
2213+
}
2214+
if (this.allowAwaitExpression && token.type == TokenType.AWAIT) {
2215+
throw this.createError(ErrorMessages.INVALID_TOKEN_CONTEXT, "await");
2216+
}
21982217
Expression init = this.isolateCoverGrammar(this::parseAssignmentExpression).left().fromJust();
21992218
this.firstExprError = this.createErrorWithLocation(startLocation, ErrorMessages.ILLEGAL_PROPERTY);
22002219
AssignmentTargetPropertyIdentifier toReturn = new AssignmentTargetPropertyIdentifier(this.transformDestructuring(staticPropertyName), Maybe.of(init));
22012220
return Either.right(this.finishNode(startState, toReturn));
22022221
}
22032222
if (!this.match(TokenType.COLON)) {
2223+
if (this.allowYieldExpression && token.type == TokenType.YIELD) {
2224+
throw this.createError(ErrorMessages.INVALID_TOKEN_CONTEXT, "yield");
2225+
}
2226+
if (this.allowAwaitExpression && token.type == TokenType.AWAIT) {
2227+
throw this.createError(ErrorMessages.INVALID_TOKEN_CONTEXT, "await");
2228+
}
22042229
if (token.type != TokenType.IDENTIFIER && token.type != TokenType.YIELD && token.type != TokenType.LET && token.type != TokenType.ASYNC && token.type != TokenType.AWAIT) {
22052230
throw this.createUnexpected(token);
22062231
}
@@ -2302,7 +2327,6 @@ protected Either<PropertyName, MethodDefinition> parseMethodDefinition() throws
23022327
if (isGenerator && this.match(TokenType.COLON)) {
23032328
throw this.createUnexpected(this.lookahead);
23042329
}
2305-
23062330
return Either.left(name);
23072331
}
23082332

src/test/java/com/shapesecurity/shift/es2017/parser/expressions/ObjectExpressionTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,5 +182,7 @@ public void testObjectExpression() throws JsError {
182182
ImmutableList.of(Maybe.of(new ObjectBinding(ImmutableList.of(new BindingPropertyIdentifier(
183183
new BindingIdentifier("b"), Maybe.of(new LiteralNumericExpression(0.0))))))), Maybe.empty()),
184184
new FunctionBody(ImmutableList.empty(), ImmutableList.empty())))));
185+
186+
testScriptFailure("(function* (){return {yield = 5} = {}})", 30, "\"yield\" may not be used as an identifier in this context");
185187
}
186188
}

src/test/java/com/shapesecurity/shift/es2017/parser/expressions/YieldExpressionTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
import com.shapesecurity.shift.es2017.ast.LiteralRegExpExpression;
2525
import com.shapesecurity.shift.es2017.ast.ObjectExpression;
2626
import com.shapesecurity.shift.es2017.ast.Setter;
27+
import com.shapesecurity.shift.es2017.parser.Parser;
2728
import com.shapesecurity.shift.es2017.parser.ParserTestCase;
2829
import com.shapesecurity.shift.es2017.parser.JsError;
2930

31+
import com.shapesecurity.shift.es2017.serialization.Serializer;
3032
import org.junit.Test;
3133

3234
public class YieldExpressionTest extends ParserTestCase {
@@ -101,5 +103,7 @@ public void testYieldExpression() throws JsError {
101103
new FormalParameters(ImmutableList.empty(), Maybe.empty()), new FunctionBody(ImmutableList.empty(),
102104
ImmutableList.of(new ExpressionStatement(new YieldExpression(Maybe.of(new UpdateExpression(true,
103105
UpdateOperator.Decrement, new AssignmentTargetIdentifier("a")))))))));
106+
testScriptFailure("function *a({yield}){}", 18, "Unexpected token \"yield\"");
107+
testScriptFailure("function *a({yield = 0}){}", 19, "Unexpected token \"yield\"");
104108
}
105109
}

src/test/java/com/shapesecurity/shift/es2017/parser/expressions/YieldGeneratorExpressionTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ public void testYieldGeneratorExpression() throws JsError {
3030

3131
testScriptFailure("function *a(){yield\n*a}", 2, 0, 20, "Unexpected token \"*\"");
3232
testScriptFailure("function *a(){yield*}", 20, "Unexpected token \"}\"");
33-
testScriptFailure("function *a(){({yield} = {})}", 23, "Unexpected token \"yield\"");
33+
testScriptFailure("function *a(){({yield} = {})}", 21, "\"yield\" may not be used as an identifier in this context");
3434
}
3535
}

src/test/java/com/shapesecurity/shift/es2017/parser/miscellaneous/AsyncAwaitTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,5 +131,9 @@ public void testAsyncFailure() {
131131
testScriptFailure("async (a = (await) => {}) => {}", 12, "Async arrow parameters may not contain \"await\"");
132132
testScriptFailure("async (a = aw\\u{61}it => {}) => {}", 11, "Async arrow parameters may not contain \"await\"");
133133
testScriptFailure("async (a = (b = await (0)) => {}) => {}", 16, "Async arrow parameters may not contain \"await\"");
134+
testScriptFailure("async ({await}) => 1", 13, "Async arrow parameters may not contain \"await\"");
135+
testScriptFailure("async function x({await}) { return 1 }", 23, "Unexpected token \"}\"");
136+
testScriptFailure("async function f() { return {await}; }", 34, "\"await\" may not be used as an identifier in this context");
137+
testScriptFailure("async function f() { return {await = 0} = {}; }", 37, "\"await\" may not be used as an identifier in this context");
134138
}
135139
}

0 commit comments

Comments
 (0)