Skip to content

Commit

Permalink
fixes jquery#1001: ES6 classes support
Browse files Browse the repository at this point in the history
  • Loading branch information
ikarienator committed Feb 15, 2015
1 parent 663d048 commit 58d726e
Show file tree
Hide file tree
Showing 2 changed files with 1,996 additions and 21 deletions.
119 changes: 111 additions & 8 deletions esprima.js
Expand Up @@ -116,6 +116,9 @@
BreakStatement: 'BreakStatement',
CallExpression: 'CallExpression',
CatchClause: 'CatchClause',
ClassBody: 'ClassBody',
ClassDeclaration: 'ClassDeclaration',
ClassExpression: 'ClassExpression',
ConditionalExpression: 'ConditionalExpression',
ContinueStatement: 'ContinueStatement',
DoWhileStatement: 'DoWhileStatement',
Expand All @@ -132,6 +135,7 @@
LabeledStatement: 'LabeledStatement',
LogicalExpression: 'LogicalExpression',
MemberExpression: 'MemberExpression',
MethodDefinition: 'MethodDefinition',
NewExpression: 'NewExpression',
ObjectExpression: 'ObjectExpression',
Program: 'Program',
Expand Down Expand Up @@ -189,7 +193,10 @@
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
StrictReservedWord: 'Use of future reserved word in strict mode',
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals'
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
ConstructorSpecialMethod: 'Class constructor may not be an accessor',
DuplicateConstructor: 'A class may only have one constructor',
StaticPrototype: 'Classes may not have static property named prototype'
};

// See also tools/generate-unicode-regex.py.
Expand Down Expand Up @@ -259,10 +266,8 @@

function isFutureReservedWord(id) {
switch (id) {
case 'class':
case 'enum':
case 'export':
case 'extends':
case 'import':
case 'super':
return true;
Expand All @@ -279,7 +284,6 @@
case 'private':
case 'protected':
case 'public':
case 'static':
case 'yield':
case 'let':
return true;
Expand Down Expand Up @@ -318,7 +322,8 @@
(id === 'class') || (id === 'super');
case 6:
return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
(id === 'switch') || (id === 'export') || (id === 'import');
(id === 'switch') || (id === 'export') || (id === 'import') ||
(id === 'static');
case 7:
return (id === 'default') || (id === 'finally') || (id === 'extends');
case 8:
Expand Down Expand Up @@ -1721,6 +1726,31 @@
return this;
},

finishClassBody: function (body) {
this.type = Syntax.ClassBody;
this.body = body;
this.finish();
return this;
},

finishClassDeclaration: function (name, superClass, body) {
this.type = Syntax.ClassDeclaration;
this.name = name;
this.superClass = superClass;
this.body = body;
this.finish();
return this;
},

finishClassExpression: function (name, superClass, body) {
this.type = Syntax.ClassExpression;
this.name = name;
this.superClass = superClass;
this.body = body;
this.finish();
return this;
},

finishConditionalExpression: function (test, consequent, alternate) {
this.type = Syntax.ConditionalExpression;
this.test = test;
Expand Down Expand Up @@ -2442,10 +2472,12 @@
}
if (matchKeyword('this')) {
lex();
expr = node.finishThisExpression();
} else {
throwUnexpectedToken(lex());
return node.finishThisExpression();
}
if (matchKeyword('class')) {
return parseClass(true);
}
throwUnexpectedToken(lex());
} else if (type === Token.BooleanLiteral) {
token = lex();
token.value = (token.value === 'true');
Expand Down Expand Up @@ -3845,6 +3877,75 @@
return node.finishFunctionExpression(id, params, defaults, body);
}

function convertPropertyToMethodDefinition(isStatic, property) {
property.type = Syntax.MethodDefinition;
property.static = isStatic;
delete property.kind;
delete property.method;
delete property.shorthand;
return property;
}

function parseClass(isExpr) {
var id = null, superClass = null, body, hasConstructor = false, isStatic = false, method, token, computed, key,
classNode = new Node(), classBody;
expectKeyword('class');

if (!isExpr || lookahead.type === Token.Identifier) {
id = parseVariableIdentifier();
}

if (matchKeyword('extends')) {
lex();
superClass = parseLeftHandSideExpressionAllowCall();
}

classBody = new Node();

expect('{');
body = [];
while (!match('}')) {
if (match(';')) {
lex();
} else {
method = new Node();
isStatic = matchKeyword('static');
if (isStatic) {
lex();
}
token = lookahead;
computed = match('[');
key = parseObjectPropertyKey();
method = tryParseMethodDefinition(token, key, computed, method);
if (method) {
if (!isStatic) {
if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') {
if (method.kind !== 'init' || !method.method || method.value.generator) {
throwError(Messages.ConstructorSpecialMethod);
}
if (hasConstructor) {
throwError(Messages.DuplicateConstructor);
} else {
hasConstructor = true;
}
}
} else {
if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') {
throwError(Messages.StaticPrototype);
}
}
body.push(convertPropertyToMethodDefinition(isStatic, method));
} else {
throwUnexpectedToken(lookahead);
}
}
}
lex();
classBody = classBody.finishClassBody(body);

return classNode[isExpr ? 'finishClassExpression' : 'finishClassDeclaration'](id, superClass, classBody);
}

// 14 Program

function parseSourceElement() {
Expand All @@ -3855,6 +3956,8 @@
return parseConstLetDeclaration(lookahead.value);
case 'function':
return parseFunctionDeclaration();
case 'class':
return parseClass(false);
}
}

Expand Down

0 comments on commit 58d726e

Please sign in to comment.