Skip to content

Commit

Permalink
ES6: Add support for generators
Browse files Browse the repository at this point in the history
  • Loading branch information
David He authored and ariya committed Jun 3, 2015
1 parent b2c153e commit 8ff3239
Show file tree
Hide file tree
Showing 68 changed files with 2,977 additions and 24 deletions.
166 changes: 143 additions & 23 deletions esprima.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@
VariableDeclaration: 'VariableDeclaration',
VariableDeclarator: 'VariableDeclarator',
WhileStatement: 'WhileStatement',
WithStatement: 'WithStatement'
WithStatement: 'WithStatement',
YieldExpression: 'YieldExpression'
};

PlaceHolders = {
Expand Down Expand Up @@ -194,6 +195,7 @@
IllegalContinue: 'Illegal continue statement',
IllegalBreak: 'Illegal break statement',
IllegalReturn: 'Illegal return statement',
IllegalYield: 'Illegal yield expression',
StrictModeWith: 'Strict mode code may not include a with statement',
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
Expand Down Expand Up @@ -1955,25 +1957,25 @@
return this;
},

finishFunctionDeclaration: function (id, params, defaults, body) {
finishFunctionDeclaration: function (id, params, defaults, body, generator) {
this.type = Syntax.FunctionDeclaration;
this.id = id;
this.params = params;
this.defaults = defaults;
this.body = body;
this.generator = false;
this.generator = generator;
this.expression = false;
this.finish();
return this;
},

finishFunctionExpression: function (id, params, defaults, body) {
finishFunctionExpression: function (id, params, defaults, body, generator) {
this.type = Syntax.FunctionExpression;
this.id = id;
this.params = params;
this.defaults = defaults;
this.body = body;
this.generator = false;
this.generator = generator;
this.expression = false;
this.finish();
return this;
Expand Down Expand Up @@ -2283,6 +2285,14 @@
this.source = src;
this.finish();
return this;
},

finishYieldExpression: function (argument, delegate) {
this.type = Syntax.YieldExpression;
this.arguments = argument;
this.delegate = delegate;
this.finish();
return this;
}
};

Expand Down Expand Up @@ -2603,6 +2613,7 @@
if (match('=')) {
lex();
init = parseAssignmentExpression();

return node.finishProperty(
'init', key, false,
new WrappingNode(key).finishAssignmentPattern(key, init), false, false);
Expand Down Expand Up @@ -2693,7 +2704,7 @@

// 11.1.5 Object Initialiser

function parsePropertyFunction(node, paramInfo) {
function parsePropertyFunction(node, paramInfo, isGenerator) {
var previousStrict, body;

isAssignmentTarget = isBindingElement = false;
Expand All @@ -2709,14 +2720,20 @@
}

strict = previousStrict;
return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body);
return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body, isGenerator);
}

function parsePropertyMethodFunction() {
var params, method, node = new Node();
var params, method, node = new Node(),
previousAllowYield = state.allowYield;

state.allowYield = false;
params = parseParams();
method = parsePropertyFunction(node, params);
state.allowYield = previousAllowYield;

state.allowYield = false;
method = parsePropertyFunction(node, params, false);
state.allowYield = previousAllowYield;

return method;
}
Expand Down Expand Up @@ -2774,7 +2791,8 @@
// In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
// is responsible to visit other options.
function tryParseMethodDefinition(token, key, computed, node) {
var value, options, methodNode;
var value, options, methodNode, params,
previousAllowYield = state.allowYield;

if (token.type === Token.Identifier) {
// check for `get` and `set`;
Expand All @@ -2785,13 +2803,17 @@
methodNode = new Node();
expect('(');
expect(')');

state.allowYield = false;
value = parsePropertyFunction(methodNode, {
params: [],
defaults: [],
stricted: null,
firstRestricted: null,
message: null
});
}, false);
state.allowYield = previousAllowYield;

return node.finishProperty('get', key, computed, value, false, false);
} else if (token.value === 'set' && lookaheadPropertyName()) {
computed = match('[');
Expand All @@ -2809,19 +2831,38 @@
if (match(')')) {
tolerateUnexpectedToken(lookahead);
} else {
state.allowYield = false;
parseParam(options);
state.allowYield = previousAllowYield;
if (options.defaultCount === 0) {
options.defaults = [];
}
}
expect(')');

value = parsePropertyFunction(methodNode, options);
state.allowYield = false;
value = parsePropertyFunction(methodNode, options, false);
state.allowYield = previousAllowYield;

return node.finishProperty('set', key, computed, value, false, false);
}
} else if (token.type === Token.Punctuator && token.value === '*' && lookaheadPropertyName()) {
computed = match('[');
key = parseObjectPropertyKey();
methodNode = new Node();

state.allowYield = false;
params = parseParams();
state.allowYield = previousAllowYield;

state.allowYield = true;
value = parsePropertyFunction(methodNode, params, true);
state.allowYield = previousAllowYield;

return node.finishProperty('init', key, computed, value, true, false);
}

if (match('(')) {
if (key && match('(')) {
value = parsePropertyMethodFunction();
return node.finishProperty('init', key, computed, value, true, false);
}
Expand All @@ -2845,7 +2886,11 @@
var token = lookahead, node = new Node(), computed, key, maybeMethod, value;

computed = match('[');
key = parseObjectPropertyKey();
if (match('*')) {
lex();
} else {
key = parseObjectPropertyKey();
}
maybeMethod = tryParseMethodDefinition(token, key, computed, node);

if (maybeMethod) {
Expand All @@ -2854,6 +2899,10 @@
return maybeMethod;
}

if (!key) {
throwUnexpectedToken(lookahead);
}

// init property or short hand property.
checkProto(key, computed, hasProto);

Expand Down Expand Up @@ -3617,6 +3666,33 @@
return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement);
}

// [ES6] 14.4 Yield expression

function parseYieldExpression() {
var argument, expr, delegate, node = lookahead;

expr = new Node();

expectKeyword('yield');

if (!state.allowYield) {
tolerateUnexpectedToken(node, Messages.IllegalYield);
}

if (!hasLineTerminator) {
delegate = match('*');
if (delegate) {
lex();
}

if (!match(';') && !match('}') && lookahead.type !== Token.EOF) {
argument = parseExpression();
}
}

return expr.finishYieldExpression(argument, delegate);
}

// 11.13 Assignment Operators

function parseAssignmentExpression() {
Expand All @@ -3625,6 +3701,10 @@
startToken = lookahead;
token = lookahead;

if (matchKeyword('yield')) {
return parseYieldExpression();
}

expr = parseConditionalExpression();

if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) {
Expand Down Expand Up @@ -4600,9 +4680,16 @@
}

function parseFunctionDeclaration(node, identifierIsOptional) {
var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict;
var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict,
isGenerator, previousAllowYield;

expectKeyword('function');

isGenerator = match('*');
if (isGenerator) {
lex();
}

if (!identifierIsOptional || !match('(')) {
token = lookahead;
id = parseVariableIdentifier();
Expand All @@ -4621,7 +4708,11 @@
}
}

previousAllowYield = state.allowYield;
state.allowYield = false;
tmp = parseParams(firstRestricted);
state.allowYield = previousAllowYield;

params = tmp.params;
defaults = tmp.defaults;
stricted = tmp.stricted;
Expand All @@ -4630,7 +4721,9 @@
message = tmp.message;
}

previousAllowYield = state.allowYield;
previousStrict = strict;
state.allowYield = isGenerator;
body = parseFunctionSourceElements();
if (strict && firstRestricted) {
throwUnexpectedToken(firstRestricted, message);
Expand All @@ -4639,16 +4732,23 @@
tolerateUnexpectedToken(stricted, message);
}
strict = previousStrict;
state.allowYield = previousAllowYield;

return node.finishFunctionDeclaration(id, params, defaults, body);
return node.finishFunctionDeclaration(id, params, defaults, body, isGenerator);
}

function parseFunctionExpression() {
var token, id = null, stricted, firstRestricted, message, tmp,
params = [], defaults = [], body, previousStrict, node = new Node();
params = [], defaults = [], body, previousStrict, node = new Node(),
isGenerator, previousAllowYield;

expectKeyword('function');

isGenerator = match('*');
if (isGenerator) {
lex();
}

if (!match('(')) {
token = lookahead;
id = parseVariableIdentifier();
Expand All @@ -4667,7 +4767,11 @@
}
}

previousAllowYield = state.allowYield;
state.allowYield = false;
tmp = parseParams(firstRestricted);
state.allowYield = previousAllowYield;

params = tmp.params;
defaults = tmp.defaults;
stricted = tmp.stricted;
Expand All @@ -4677,16 +4781,20 @@
}

previousStrict = strict;
previousAllowYield = state.allowYield;
state.allowYield = isGenerator;
body = parseFunctionSourceElements();

if (strict && firstRestricted) {
throwUnexpectedToken(firstRestricted, message);
}
if (strict && stricted) {
tolerateUnexpectedToken(stricted, message);
}
strict = previousStrict;
state.allowYield = previousAllowYield;

return node.finishFunctionExpression(id, params, defaults, body);
return node.finishFunctionExpression(id, params, defaults, body, isGenerator);
}


Expand All @@ -4705,12 +4813,20 @@
token = lookahead;
isStatic = false;
computed = match('[');
key = parseObjectPropertyKey();
if (key.name === 'static' && lookaheadPropertyName()) {
if (match('*')) {
lex();
} else {
key = parseObjectPropertyKey();
}
if (key && key.name === 'static' && (lookaheadPropertyName() || match('*'))) {
token = lookahead;
isStatic = true;
computed = match('[');
key = parseObjectPropertyKey();
if (match('*')) {
lex();
} else {
key = parseObjectPropertyKey();
}
}
method = tryParseMethodDefinition(token, key, computed, method);
if (method) {
Expand Down Expand Up @@ -5136,12 +5252,14 @@
lookahead = null;
state = {
allowIn: true,
allowYield: false,
labelSet: {},
inFunctionBody: false,
inIteration: false,
inSwitch: false,
lastCommentStart: -1,
curlyStack: []
curlyStack: [],
isGenerator: false
};

extra = {};
Expand Down Expand Up @@ -5224,12 +5342,14 @@
lookahead = null;
state = {
allowIn: true,
allowYield: false,
labelSet: {},
inFunctionBody: false,
inIteration: false,
inSwitch: false,
lastCommentStart: -1,
curlyStack: []
curlyStack: [],
isGenerator: false
};
sourceType = 'script';
strict = false;
Expand Down
Loading

0 comments on commit 8ff3239

Please sign in to comment.