Skip to content

Commit

Permalink
Support ES2017 object rest/spread properties
Browse files Browse the repository at this point in the history
  • Loading branch information
ariya committed Jan 17, 2017
1 parent 5a46bf8 commit dec2b98
Show file tree
Hide file tree
Showing 37 changed files with 6,384 additions and 12 deletions.
2 changes: 2 additions & 0 deletions src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const Messages = {
ConstructorSpecialMethod: 'Class constructor may not be an accessor',
DeclarationMissingInitializer: 'Missing initializer in %0 declaration',
DefaultRestParameter: 'Unexpected token =',
DefaultRestProperty: 'Unexpected token =',
DuplicateBinding: 'Duplicate binding %0',
DuplicateConstructor: 'A class may only have one constructor',
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
Expand All @@ -32,6 +33,7 @@ export const Messages = {
NoAsAfterImportNamespace: 'Unexpected token',
NoCatchOrFinally: 'Missing catch or finally after try',
ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
PropertyAfterRestProperty: 'Unexpected token',
Redeclaration: '%0 \'%1\' has already been declared',
StaticPrototype: 'Classes may not have static property named prototype',
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
Expand Down
28 changes: 24 additions & 4 deletions src/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export type Expression = ArrayExpression | ArrowFunctionExpression | AssignmentE
ThisExpression | UnaryExpression | UpdateExpression | YieldExpression;
export type FunctionParameter = AssignmentPattern | BindingIdentifier | BindingPattern;
export type ImportDeclarationSpecifier = ImportDefaultSpecifier | ImportNamespaceSpecifier | ImportSpecifier;
export type ObjectExpressionProperty = Property | SpreadProperty;
export type ObjectPatternProperty = Property | RestProperty;
export type Statement = AsyncFunctionDeclaration | BreakStatement | ContinueStatement | DebuggerStatement | DoWhileStatement |
EmptyStatement | ExpressionStatement | Directive | ForStatement | ForInStatement | ForOfStatement |
FunctionDeclaration | IfStatement | ReturnStatement | SwitchStatement | ThrowStatement |
Expand Down Expand Up @@ -581,17 +583,17 @@ export class NewExpression {

export class ObjectExpression {
readonly type: string;
readonly properties: Property[];
constructor(properties: Property[]) {
readonly properties: ObjectExpressionProperty[];
constructor(properties: ObjectExpressionProperty[]) {
this.type = Syntax.ObjectExpression;
this.properties = properties;
}
}

export class ObjectPattern {
readonly type: string;
readonly properties: Property[];
constructor(properties: Property[]) {
readonly properties: ObjectPatternProperty[];
constructor(properties: ObjectPatternProperty[]) {
this.type = Syntax.ObjectPattern;
this.properties = properties;
}
Expand Down Expand Up @@ -638,6 +640,15 @@ export class RestElement {
}
}

export class RestProperty {
readonly type: string;
readonly argument: Expression;
constructor(argument: Expression) {
this.type = Syntax.RestProperty;
this.argument = argument;
}
}

export class ReturnStatement {
readonly type: string;
readonly argument: Expression | null;
Expand Down Expand Up @@ -676,6 +687,15 @@ export class SpreadElement {
}
}

export class SpreadProperty {
readonly type: string;
readonly argument: Expression;
constructor(argument: Expression) {
this.type = Syntax.SpreadProperty;
this.argument = argument;
}
}

export class StaticMemberExpression {
readonly type: string;
readonly computed: boolean;
Expand Down
39 changes: 33 additions & 6 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -926,14 +926,21 @@ export class Parser {
return this.finalize(node, new Node.Property(kind, key as Node.PropertyKey, computed, value, method, shorthand));
}

parseSpreadProperty(): Node.SpreadProperty {
const node = this.createNode();
this.expect('...');
const arg = this.inheritCoverGrammar(this.parseAssignmentExpression);
return this.finalize(node, new Node.SpreadProperty(arg));
}

parseObjectInitializer(): Node.ObjectExpression {
const node = this.createNode();

this.expect('{');
const properties: Node.Property[] = [];
const properties: Node.ObjectExpressionProperty[] = [];
let hasProto = { value: false };
while (!this.match('}')) {
properties.push(this.parseObjectProperty(hasProto));
properties.push(this.match('...') ? this.parseSpreadProperty() : this.parseObjectProperty(hasProto));
if (!this.match('}')) {
this.expectCommaSeparator();
}
Expand Down Expand Up @@ -999,6 +1006,10 @@ export class Parser {
expr.type = Syntax.RestElement;
this.reinterpretExpressionAsPattern(expr.argument);
break;
case Syntax.SpreadProperty:
expr.type = Syntax.RestProperty;
this.reinterpretExpressionAsPattern(expr.argument);
break;
case Syntax.ArrayExpression:
expr.type = Syntax.ArrayPattern;
for (let i = 0; i < expr.elements.length; i++) {
Expand All @@ -1010,7 +1021,8 @@ export class Parser {
case Syntax.ObjectExpression:
expr.type = Syntax.ObjectPattern;
for (let i = 0; i < expr.properties.length; i++) {
this.reinterpretExpressionAsPattern(expr.properties[i].value);
const property = expr.properties[i];
this.reinterpretExpressionAsPattern(property.type === Syntax.SpreadProperty ? property : property.value);
}
break;
case Syntax.AssignmentExpression:
Expand Down Expand Up @@ -1553,6 +1565,7 @@ export class Parser {
this.validateParam(options, param, param.name);
break;
case Syntax.RestElement:
case Syntax.RestProperty:
this.checkPatternParam(options, param.argument);
break;
case Syntax.AssignmentPattern:
Expand All @@ -1567,7 +1580,8 @@ export class Parser {
break;
case Syntax.ObjectPattern:
for (let i = 0; i < param.properties.length; i++) {
this.checkPatternParam(options, param.properties[i].value);
const property = param.properties[i];
this.checkPatternParam(options, (property.type === Syntax.RestProperty) ? property : property.value);
}
break;
default:
Expand Down Expand Up @@ -1961,13 +1975,26 @@ export class Parser {
return this.finalize(node, new Node.Property('init', key, computed, value, method, shorthand));
}

parseRestProperty(params, kind): Node.RestProperty {
const node = this.createNode();
this.expect('...');
const arg = this.parsePattern(params);
if (this.match('=')) {
this.throwError(Messages.DefaultRestProperty);
}
if (!this.match('}')) {
this.throwError(Messages.PropertyAfterRestProperty);
}
return this.finalize(node, new Node.RestProperty(arg));
}

parseObjectPattern(params, kind?: string): Node.ObjectPattern {
const node = this.createNode();
const properties: Node.Property[] = [];
const properties: Node.ObjectPatternProperty[] = [];

this.expect('{');
while (!this.match('}')) {
properties.push(this.parsePropertyPattern(params, kind));
properties.push(this.match('...') ? this.parseRestProperty(params, kind) : this.parsePropertyPattern(params, kind));
if (!this.match('}')) {
this.expect(',');
}
Expand Down
2 changes: 2 additions & 0 deletions src/syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ export const Syntax = {
Program: 'Program',
Property: 'Property',
RestElement: 'RestElement',
RestProperty: 'RestProperty',
ReturnStatement: 'ReturnStatement',
SequenceExpression: 'SequenceExpression',
SpreadElement: 'SpreadElement',
SpreadProperty: 'SpreadProperty',
Super: 'Super',
SwitchCase: 'SwitchCase',
SwitchStatement: 'SwitchStatement',
Expand Down
2 changes: 2 additions & 0 deletions test/api-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ describe('esprima.Syntax', function () {
Program: 'Program',
Property: 'Property',
RestElement: 'RestElement',
RestProperty: 'RestProperty',
ReturnStatement: 'ReturnStatement',
SequenceExpression: 'SequenceExpression',
SpreadElement: 'SpreadElement',
SpreadProperty: 'SpreadProperty',
Super: 'Super',
SwitchCase: 'SwitchCase',
SwitchStatement: 'SwitchStatement',
Expand Down

This file was deleted.

This file was deleted.

1 change: 1 addition & 0 deletions test/fixtures/es2017/rest-property/destructuring-mirror.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
({x, ...y} = {x, ...y})
Loading

0 comments on commit dec2b98

Please sign in to comment.