Skip to content

Commit d3b999e

Browse files
committed
JS: Allow destructuring rest patterns
1 parent 0e6e942 commit d3b999e

2 files changed

Lines changed: 12 additions & 25 deletions

File tree

‎javascript/extractor/src/com/semmle/jcorn/Parser.java‎

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,7 +1778,7 @@ protected boolean parseParenthesisedExpression(
17781778
return false;
17791779
} else if (this.type == TokenType.ellipsis) {
17801780
parenExprs.spreadStart = this.start;
1781-
parenExprs.exprList.add(this.parseParenItem(this.parseRest(false), -1, null));
1781+
parenExprs.exprList.add(this.parseParenItem(this.parseRest(), -1, null));
17821782
this.eat(TokenType.comma);
17831783
return false;
17841784
} else {
@@ -2081,7 +2081,7 @@ protected FunctionExpression parseMethod(boolean isGenerator, boolean isAsync) {
20812081

20822082
this.expect(TokenType.parenL);
20832083
List<Expression> params =
2084-
this.parseBindingList(TokenType.parenR, false, this.options.ecmaVersion() >= 8, false);
2084+
this.parseBindingList(TokenType.parenR, false, this.options.ecmaVersion() >= 8);
20852085
this.checkYieldAwaitInDefaultParams();
20862086
boolean generator = this.options.ecmaVersion() >= 6 && isGenerator;
20872087
Node body = this.parseFunctionBody(null, params, false);
@@ -2359,17 +2359,9 @@ protected List<Expression> toAssignableList(List<Expression> exprList, boolean i
23592359
} else if (last != null && last instanceof SpreadElement) {
23602360
Expression arg = ((SpreadElement) last).getArgument();
23612361
arg = (Expression) this.toAssignable(arg, isBinding);
2362-
if (!(arg instanceof Identifier
2363-
|| arg instanceof MemberExpression
2364-
|| arg instanceof ArrayPattern)) this.unexpected(arg.getLoc().getStart());
23652362
exprList.set(end - 1, last = new RestElement(last.getLoc(), arg));
23662363
--end;
23672364
}
2368-
2369-
if (isBinding
2370-
&& last instanceof RestElement
2371-
&& !(((RestElement) last).getArgument() instanceof Identifier))
2372-
this.unexpected(((RestElement) last).getArgument().getLoc().getStart());
23732365
}
23742366
for (int i = 0; i < end; ++i)
23752367
exprList.set(i, (Expression) this.toAssignable(exprList.get(i), isBinding));
@@ -2385,18 +2377,10 @@ protected SpreadElement parseSpread() {
23852377
return this.finishNode(node);
23862378
}
23872379

2388-
protected RestElement parseRest(boolean allowNonIdent) {
2380+
protected RestElement parseRest() {
23892381
Position start = this.startLoc;
23902382
this.next();
2391-
2392-
// RestElement inside of a function parameter must be an identifier
2393-
Expression argument = null;
2394-
if (allowNonIdent)
2395-
if (this.type == TokenType.name) argument = this.parseIdent(false);
2396-
else this.unexpected();
2397-
else if (this.type == TokenType.name || this.type == TokenType.bracketL)
2398-
argument = this.parseBindingAtom();
2399-
else this.unexpected();
2383+
Expression argument = this.parseBindingAtom();
24002384
RestElement node = new RestElement(new SourceLocation(start), argument);
24012385
return this.finishNode(node);
24022386
}
@@ -2408,7 +2392,7 @@ protected Expression parseBindingAtom() {
24082392
if (this.type == TokenType.bracketL) {
24092393
Position start = this.startLoc;
24102394
this.next();
2411-
List<Expression> elements = this.parseBindingList(TokenType.bracketR, true, true, false);
2395+
List<Expression> elements = this.parseBindingList(TokenType.bracketR, true, true);
24122396
ArrayPattern node = new ArrayPattern(new SourceLocation(start), elements);
24132397
return this.finishNode(node);
24142398
}
@@ -2419,7 +2403,7 @@ protected Expression parseBindingAtom() {
24192403
}
24202404

24212405
protected List<Expression> parseBindingList(
2422-
TokenType close, boolean allowEmpty, boolean allowTrailingComma, boolean allowNonIdent) {
2406+
TokenType close, boolean allowEmpty, boolean allowTrailingComma) {
24232407
List<Expression> result = new ArrayList<Expression>();
24242408
boolean first = true;
24252409
while (!this.eat(close)) {
@@ -2430,7 +2414,7 @@ protected List<Expression> parseBindingList(
24302414
} else if (allowTrailingComma && this.afterTrailingComma(close, false)) {
24312415
break;
24322416
} else if (this.type == TokenType.ellipsis) {
2433-
result.add(this.processBindingListItem(this.parseRest(allowNonIdent)));
2417+
result.add(this.processBindingListItem(this.parseRest()));
24342418
this.eat(TokenType.comma);
24352419
this.expect(close);
24362420
break;
@@ -3200,7 +3184,7 @@ protected IFunction parseFunctionRest(
32003184
protected List<Expression> parseFunctionParams() {
32013185
this.expect(TokenType.parenL);
32023186
List<Expression> params =
3203-
this.parseBindingList(TokenType.parenR, false, this.options.ecmaVersion() >= 8, true);
3187+
this.parseBindingList(TokenType.parenR, false, this.options.ecmaVersion() >= 8);
32043188
this.checkYieldAwaitInDefaultParams();
32053189
return params;
32063190
}

‎javascript/extractor/test/com/semmle/js/extractor/test/RobustnessTests.java‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,11 @@ public void permissiveDestructuringTest() {
2323
"({ shorthand = 1 });\n"
2424
+ "([...rest,] = values);\n"
2525
+ "function f(...args,) {}\n"
26+
+ "function g(...[first, { nested }],) {}\n"
2627
+ "const arrow = (...args,) => args;\n"
27-
+ "async (...args,) => args;\n";
28+
+ "const destructuringArrow = (...{ value },) => value;\n"
29+
+ "async (...[first, { nested }],) => first;\n"
30+
+ "({ method(...{ value },) {} });\n";
2831
new Parser(new Options(), src, 0).parse();
2932
}
3033
}

0 commit comments

Comments
 (0)