diff --git a/dist/swagger-ui.js b/dist/swagger-ui.js index 8ab3d6d0..f8c2bebd 100644 --- a/dist/swagger-ui.js +++ b/dist/swagger-ui.js @@ -414,19 +414,26 @@ this["Handlebars"]["templates"]["operation"] = Handlebars.template({"1":function },"14":function(depth0,helpers,partials,data) { return "
\n
\n
| Parameter | \nValue | \nDescription | \nParameter Type | \nData Type | \n
|---|
| HTTP Status Code | \nReason | \nResponse Model | \nHeaders | \n
|---|
| HTTP Status Code | \nReason | \nResponse Model | \nHeaders | \n
|---|
| ' + type + ' |
|---|
expect(value)
+ * @since 2.0
+ */
+ function expectCommaSeparator() {
+ var token;
+
+ if (extra.errors) {
+ token = lookahead;
+ if (token.type === Token.Punctuator && token.value === ',') {
+ lex();
+ } else if (token.type === Token.Punctuator && token.value === ';') {
+ lex();
+ tolerateUnexpectedToken(token);
+ } else {
+ tolerateUnexpectedToken(token, Messages.UnexpectedToken);
+ }
+ } else {
+ expect(',');
+ }
+ }
+
+ // Expect the next token to match the specified keyword.
+ // If not, an exception will be thrown.
+
+ function expectKeyword(keyword) {
+ var token = lex();
+ if (token.type !== Token.Keyword || token.value !== keyword) {
+ throwUnexpectedToken(token);
+ }
+ }
+
+ // Return true if the next token matches the specified punctuator.
+
+ function match(value) {
+ return lookahead.type === Token.Punctuator && lookahead.value === value;
+ }
+
+ // Return true if the next token matches the specified keyword
+
+ function matchKeyword(keyword) {
+ return lookahead.type === Token.Keyword && lookahead.value === keyword;
+ }
+
+ // Return true if the next token matches the specified contextual keyword
+ // (where an identifier is sometimes a keyword depending on the context)
+
+ function matchContextualKeyword(keyword) {
+ return lookahead.type === Token.Identifier && lookahead.value === keyword;
+ }
+
+ // Return true if the next token is an assignment operator
+
+ function matchAssign() {
+ var op;
+
+ if (lookahead.type !== Token.Punctuator) {
+ return false;
+ }
+ op = lookahead.value;
+ return op === '=' ||
+ op === '*=' ||
+ op === '/=' ||
+ op === '%=' ||
+ op === '+=' ||
+ op === '-=' ||
+ op === '<<=' ||
+ op === '>>=' ||
+ op === '>>>=' ||
+ op === '&=' ||
+ op === '^=' ||
+ op === '|=';
+ }
+
+ function consumeSemicolon() {
+ // Catch the very common case first: immediately a semicolon (U+003B).
+ if (source.charCodeAt(startIndex) === 0x3B || match(';')) {
+ lex();
+ return;
+ }
+
+ if (hasLineTerminator) {
+ return;
+ }
+
+ // FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
+ lastIndex = startIndex;
+ lastLineNumber = startLineNumber;
+ lastLineStart = startLineStart;
+
+ if (lookahead.type !== Token.EOF && !match('}')) {
+ throwUnexpectedToken(lookahead);
+ }
+ }
+
+ // Cover grammar support.
+ //
+ // When an assignment expression position starts with an left parenthesis, the determination of the type
+ // of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
+ // or the first comma. This situation also defers the determination of all the expressions nested in the pair.
+ //
+ // There are three productions that can be parsed in a parentheses pair that needs to be determined
+ // after the outermost pair is closed. They are:
+ //
+ // 1. AssignmentExpression
+ // 2. BindingElements
+ // 3. AssignmentTargets
+ //
+ // In order to avoid exponential backtracking, we use two flags to denote if the production can be
+ // binding element or assignment target.
+ //
+ // The three productions have the relationship:
+ //
+ // BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression
+ //
+ // with a single exception that CoverInitializedName when used directly in an Expression, generates
+ // an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
+ // first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
+ //
+ // isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
+ // effect the current flags. This means the production the parser parses is only used as an expression. Therefore
+ // the CoverInitializedName check is conducted.
+ //
+ // inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
+ // the flags outside of the parser. This means the production the parser parses is used as a part of a potential
+ // pattern. The CoverInitializedName check is deferred.
+ function isolateCoverGrammar(parser) {
+ var oldIsBindingElement = isBindingElement,
+ oldIsAssignmentTarget = isAssignmentTarget,
+ oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
+ result;
+ isBindingElement = true;
+ isAssignmentTarget = true;
+ firstCoverInitializedNameError = null;
+ result = parser();
+ if (firstCoverInitializedNameError !== null) {
+ throwUnexpectedToken(firstCoverInitializedNameError);
+ }
+ isBindingElement = oldIsBindingElement;
+ isAssignmentTarget = oldIsAssignmentTarget;
+ firstCoverInitializedNameError = oldFirstCoverInitializedNameError;
+ return result;
+ }
+
+ function inheritCoverGrammar(parser) {
+ var oldIsBindingElement = isBindingElement,
+ oldIsAssignmentTarget = isAssignmentTarget,
+ oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
+ result;
+ isBindingElement = true;
+ isAssignmentTarget = true;
+ firstCoverInitializedNameError = null;
+ result = parser();
+ isBindingElement = isBindingElement && oldIsBindingElement;
+ isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget;
+ firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError;
+ return result;
+ }
+
+ function parseArrayPattern() {
+ var node = new Node(), elements = [], rest, restNode;
+ expect('[');
+
+ while (!match(']')) {
+ if (match(',')) {
+ lex();
+ elements.push(null);
+ } else {
+ if (match('...')) {
+ restNode = new Node();
+ lex();
+ rest = parseVariableIdentifier();
+ elements.push(restNode.finishRestElement(rest));
+ break;
+ } else {
+ elements.push(parsePatternWithDefault());
+ }
+ if (!match(']')) {
+ expect(',');
+ }
+ }
+
+ }
+
+ expect(']');
+
+ return node.finishArrayPattern(elements);
+ }
+
+ function parsePropertyPattern() {
+ var node = new Node(), key, computed = match('['), init;
+ if (lookahead.type === Token.Identifier) {
+ key = parseVariableIdentifier();
+ if (match('=')) {
+ lex();
+ init = parseAssignmentExpression();
+ return node.finishProperty(
+ 'init', key, false,
+ new WrappingNode(key).finishAssignmentPattern(key, init), false, false);
+ } else if (!match(':')) {
+ return node.finishProperty('init', key, false, key, false, true);
+ }
+ } else {
+ key = parseObjectPropertyKey();
+ }
+ expect(':');
+ init = parsePatternWithDefault();
+ return node.finishProperty('init', key, computed, init, false, false);
+ }
+
+ function parseObjectPattern() {
+ var node = new Node(), properties = [];
+
+ expect('{');
+
+ while (!match('}')) {
+ properties.push(parsePropertyPattern());
+ if (!match('}')) {
+ expect(',');
+ }
+ }
+
+ lex();
+
+ return node.finishObjectPattern(properties);
+ }
+
+ function parsePattern() {
+ if (lookahead.type === Token.Identifier) {
+ return parseVariableIdentifier();
+ } else if (match('[')) {
+ return parseArrayPattern();
+ } else if (match('{')) {
+ return parseObjectPattern();
+ }
+ throwUnexpectedToken(lookahead);
+ }
+
+ function parsePatternWithDefault() {
+ var startToken = lookahead, pattern, right;
+ pattern = parsePattern();
+ if (match('=')) {
+ lex();
+ right = isolateCoverGrammar(parseAssignmentExpression);
+ pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right);
+ }
+ return pattern;
+ }
+
+ // 11.1.4 Array Initialiser
+
+ function parseArrayInitialiser() {
+ var elements = [], node = new Node(), restSpread;
+
+ expect('[');
+
+ while (!match(']')) {
+ if (match(',')) {
+ lex();
+ elements.push(null);
+ } else if (match('...')) {
+ restSpread = new Node();
+ lex();
+ restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression));
+
+ if (!match(']')) {
+ isAssignmentTarget = isBindingElement = false;
+ expect(',');
+ }
+ elements.push(restSpread);
+ } else {
+ elements.push(inheritCoverGrammar(parseAssignmentExpression));
+
+ if (!match(']')) {
+ expect(',');
+ }
+ }
+ }
+
+ lex();
+
+ return node.finishArrayExpression(elements);
+ }
+
+ // 11.1.5 Object Initialiser
+
+ function parsePropertyFunction(node, paramInfo) {
+ var previousStrict, body;
+
+ isAssignmentTarget = isBindingElement = false;
+
+ previousStrict = strict;
+ body = isolateCoverGrammar(parseFunctionSourceElements);
+
+ if (strict && paramInfo.firstRestricted) {
+ tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message);
+ }
+ if (strict && paramInfo.stricted) {
+ tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message);
+ }
+
+ strict = previousStrict;
+ return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body);
+ }
+
+ function parsePropertyMethodFunction() {
+ var params, method, node = new Node();
+
+ params = parseParams();
+ method = parsePropertyFunction(node, params);
+
+ return method;
+ }
+
+ function parseObjectPropertyKey() {
+ var token, node = new Node(), expr;
+
+ token = lex();
+
+ // Note: This function is called only from parseObjectProperty(), where
+ // EOF and Punctuator tokens are already filtered out.
+
+ switch (token.type) {
+ case Token.StringLiteral:
+ case Token.NumericLiteral:
+ if (strict && token.octal) {
+ tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
+ }
+ return node.finishLiteral(token);
+ case Token.Identifier:
+ case Token.BooleanLiteral:
+ case Token.NullLiteral:
+ case Token.Keyword:
+ return node.finishIdentifier(token.value);
+ case Token.Punctuator:
+ if (token.value === '[') {
+ expr = isolateCoverGrammar(parseAssignmentExpression);
+ expect(']');
+ return expr;
+ }
+ break;
+ }
+ throwUnexpectedToken(token);
+ }
+
+ function lookaheadPropertyName() {
+ switch (lookahead.type) {
+ case Token.Identifier:
+ case Token.StringLiteral:
+ case Token.BooleanLiteral:
+ case Token.NullLiteral:
+ case Token.NumericLiteral:
+ case Token.Keyword:
+ return true;
+ case Token.Punctuator:
+ return lookahead.value === '[';
+ }
+ return false;
+ }
+
+ // This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
+ // it might be called at a position where there is in fact a short hand identifier pattern or a data property.
+ // This can only be determined after we consumed up to the left parentheses.
+ //
+ // 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;
+
+ if (token.type === Token.Identifier) {
+ // check for `get` and `set`;
+
+ if (token.value === 'get' && lookaheadPropertyName()) {
+ computed = match('[');
+ key = parseObjectPropertyKey();
+ methodNode = new Node();
+ expect('(');
+ expect(')');
+ value = parsePropertyFunction(methodNode, {
+ params: [],
+ defaults: [],
+ stricted: null,
+ firstRestricted: null,
+ message: null
+ });
+ return node.finishProperty('get', key, computed, value, false, false);
+ } else if (token.value === 'set' && lookaheadPropertyName()) {
+ computed = match('[');
+ key = parseObjectPropertyKey();
+ methodNode = new Node();
+ expect('(');
+
+ options = {
+ params: [],
+ defaultCount: 0,
+ defaults: [],
+ firstRestricted: null,
+ paramSet: {}
+ };
+ if (match(')')) {
+ tolerateUnexpectedToken(lookahead);
+ } else {
+ parseParam(options);
+ if (options.defaultCount === 0) {
+ options.defaults = [];
+ }
+ }
+ expect(')');
+
+ value = parsePropertyFunction(methodNode, options);
+ return node.finishProperty('set', key, computed, value, false, false);
+ }
+ }
+
+ if (match('(')) {
+ value = parsePropertyMethodFunction();
+ return node.finishProperty('init', key, computed, value, true, false);
+ }
+
+ // Not a MethodDefinition.
+ return null;
+ }
+
+ function checkProto(key, computed, hasProto) {
+ if (computed === false && (key.type === Syntax.Identifier && key.name === '__proto__' ||
+ key.type === Syntax.Literal && key.value === '__proto__')) {
+ if (hasProto.value) {
+ tolerateError(Messages.DuplicateProtoProperty);
+ } else {
+ hasProto.value = true;
+ }
+ }
+ }
+
+ function parseObjectProperty(hasProto) {
+ var token = lookahead, node = new Node(), computed, key, maybeMethod, value;
+
+ computed = match('[');
+ key = parseObjectPropertyKey();
+ maybeMethod = tryParseMethodDefinition(token, key, computed, node);
+
+ if (maybeMethod) {
+ checkProto(maybeMethod.key, maybeMethod.computed, hasProto);
+ // finished
+ return maybeMethod;
+ }
+
+ // init property or short hand property.
+ checkProto(key, computed, hasProto);
+
+ if (match(':')) {
+ lex();
+ value = inheritCoverGrammar(parseAssignmentExpression);
+ return node.finishProperty('init', key, computed, value, false, false);
+ }
+
+ if (token.type === Token.Identifier) {
+ if (match('=')) {
+ firstCoverInitializedNameError = lookahead;
+ lex();
+ value = isolateCoverGrammar(parseAssignmentExpression);
+ return node.finishProperty('init', key, computed,
+ new WrappingNode(token).finishAssignmentPattern(key, value), false, true);
+ }
+ return node.finishProperty('init', key, computed, key, false, true);
+ }
+
+ throwUnexpectedToken(lookahead);
+ }
+
+ function parseObjectInitialiser() {
+ var properties = [], hasProto = {value: false}, node = new Node();
+
+ expect('{');
+
+ while (!match('}')) {
+ properties.push(parseObjectProperty(hasProto));
+
+ if (!match('}')) {
+ expectCommaSeparator();
+ }
+ }
+
+ expect('}');
+
+ return node.finishObjectExpression(properties);
+ }
+
+ function reinterpretExpressionAsPattern(expr) {
+ var i;
+ switch (expr.type) {
+ case Syntax.Identifier:
+ case Syntax.MemberExpression:
+ case Syntax.RestElement:
+ case Syntax.AssignmentPattern:
+ break;
+ case Syntax.SpreadElement:
+ expr.type = Syntax.RestElement;
+ reinterpretExpressionAsPattern(expr.argument);
+ break;
+ case Syntax.ArrayExpression:
+ expr.type = Syntax.ArrayPattern;
+ for (i = 0; i < expr.elements.length; i++) {
+ if (expr.elements[i] !== null) {
+ reinterpretExpressionAsPattern(expr.elements[i]);
+ }
+ }
+ break;
+ case Syntax.ObjectExpression:
+ expr.type = Syntax.ObjectPattern;
+ for (i = 0; i < expr.properties.length; i++) {
+ reinterpretExpressionAsPattern(expr.properties[i].value);
+ }
+ break;
+ case Syntax.AssignmentExpression:
+ expr.type = Syntax.AssignmentPattern;
+ reinterpretExpressionAsPattern(expr.left);
+ break;
+ default:
+ // Allow other node type for tolerant parsing.
+ break;
+ }
+ }
+
+ function parseTemplateElement(option) {
+ var node, token;
+
+ if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) {
+ throwUnexpectedToken();
+ }
+
+ node = new Node();
+ token = lex();
+
+ return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail);
+ }
+
+ function parseTemplateLiteral() {
+ var quasi, quasis, expressions, node = new Node();
+
+ quasi = parseTemplateElement({ head: true });
+ quasis = [ quasi ];
+ expressions = [];
+
+ while (!quasi.tail) {
+ expressions.push(parseExpression());
+ quasi = parseTemplateElement({ head: false });
+ quasis.push(quasi);
+ }
+
+ return node.finishTemplateLiteral(quasis, expressions);
+ }
+
+ // 11.1.6 The Grouping Operator
+
+ function parseGroupExpression() {
+ var expr, expressions, startToken, i;
+
+ expect('(');
+
+ if (match(')')) {
+ lex();
+ if (!match('=>')) {
+ expect('=>');
+ }
+ return {
+ type: PlaceHolders.ArrowParameterPlaceHolder,
+ params: []
+ };
+ }
+
+ startToken = lookahead;
+ if (match('...')) {
+ expr = parseRestElement();
+ expect(')');
+ if (!match('=>')) {
+ expect('=>');
+ }
+ return {
+ type: PlaceHolders.ArrowParameterPlaceHolder,
+ params: [expr]
+ };
+ }
+
+ isBindingElement = true;
+ expr = inheritCoverGrammar(parseAssignmentExpression);
+
+ if (match(',')) {
+ isAssignmentTarget = false;
+ expressions = [expr];
+
+ while (startIndex < length) {
+ if (!match(',')) {
+ break;
+ }
+ lex();
+
+ if (match('...')) {
+ if (!isBindingElement) {
+ throwUnexpectedToken(lookahead);
+ }
+ expressions.push(parseRestElement());
+ expect(')');
+ if (!match('=>')) {
+ expect('=>');
+ }
+ isBindingElement = false;
+ for (i = 0; i < expressions.length; i++) {
+ reinterpretExpressionAsPattern(expressions[i]);
+ }
+ return {
+ type: PlaceHolders.ArrowParameterPlaceHolder,
+ params: expressions
+ };
+ }
+
+ expressions.push(inheritCoverGrammar(parseAssignmentExpression));
+ }
+
+ expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
+ }
+
+
+ expect(')');
+
+ if (match('=>')) {
+ if (!isBindingElement) {
+ throwUnexpectedToken(lookahead);
+ }
+
+ if (expr.type === Syntax.SequenceExpression) {
+ for (i = 0; i < expr.expressions.length; i++) {
+ reinterpretExpressionAsPattern(expr.expressions[i]);
+ }
+ } else {
+ reinterpretExpressionAsPattern(expr);
+ }
+
+ expr = {
+ type: PlaceHolders.ArrowParameterPlaceHolder,
+ params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr]
+ };
+ }
+ isBindingElement = false;
+ return expr;
+ }
+
+
+ // 11.1 Primary Expressions
+
+ function parsePrimaryExpression() {
+ var type, token, expr, node;
+
+ if (match('(')) {
+ isBindingElement = false;
+ return inheritCoverGrammar(parseGroupExpression);
+ }
+
+ if (match('[')) {
+ return inheritCoverGrammar(parseArrayInitialiser);
+ }
+
+ if (match('{')) {
+ return inheritCoverGrammar(parseObjectInitialiser);
+ }
+
+ type = lookahead.type;
+ node = new Node();
+
+ if (type === Token.Identifier) {
+ expr = node.finishIdentifier(lex().value);
+ } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+ isAssignmentTarget = isBindingElement = false;
+ if (strict && lookahead.octal) {
+ tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral);
+ }
+ expr = node.finishLiteral(lex());
+ } else if (type === Token.Keyword) {
+ isAssignmentTarget = isBindingElement = false;
+ if (matchKeyword('function')) {
+ return parseFunctionExpression();
+ }
+ if (matchKeyword('this')) {
+ lex();
+ return node.finishThisExpression();
+ }
+ if (matchKeyword('class')) {
+ return parseClassExpression();
+ }
+ throwUnexpectedToken(lex());
+ } else if (type === Token.BooleanLiteral) {
+ isAssignmentTarget = isBindingElement = false;
+ token = lex();
+ token.value = (token.value === 'true');
+ expr = node.finishLiteral(token);
+ } else if (type === Token.NullLiteral) {
+ isAssignmentTarget = isBindingElement = false;
+ token = lex();
+ token.value = null;
+ expr = node.finishLiteral(token);
+ } else if (match('/') || match('/=')) {
+ isAssignmentTarget = isBindingElement = false;
+ index = startIndex;
+
+ if (typeof extra.tokens !== 'undefined') {
+ token = collectRegex();
+ } else {
+ token = scanRegExp();
+ }
+ lex();
+ expr = node.finishLiteral(token);
+ } else if (type === Token.Template) {
+ expr = parseTemplateLiteral();
+ } else {
+ throwUnexpectedToken(lex());
+ }
+
+ return expr;
+ }
+
+ // 11.2 Left-Hand-Side Expressions
+
+ function parseArguments() {
+ var args = [];
+
+ expect('(');
+
+ if (!match(')')) {
+ while (startIndex < length) {
+ args.push(isolateCoverGrammar(parseAssignmentExpression));
+ if (match(')')) {
+ break;
+ }
+ expectCommaSeparator();
+ }
+ }
+
+ expect(')');
+
+ return args;
+ }
+
+ function parseNonComputedProperty() {
+ var token, node = new Node();
+
+ token = lex();
+
+ if (!isIdentifierName(token)) {
+ throwUnexpectedToken(token);
+ }
+
+ return node.finishIdentifier(token.value);
+ }
+
+ function parseNonComputedMember() {
+ expect('.');
+
+ return parseNonComputedProperty();
+ }
+
+ function parseComputedMember() {
+ var expr;
+
+ expect('[');
+
+ expr = isolateCoverGrammar(parseExpression);
+
+ expect(']');
+
+ return expr;
+ }
+
+ function parseNewExpression() {
+ var callee, args, node = new Node();
+
+ expectKeyword('new');
+ callee = isolateCoverGrammar(parseLeftHandSideExpression);
+ args = match('(') ? parseArguments() : [];
+
+ isAssignmentTarget = isBindingElement = false;
+
+ return node.finishNewExpression(callee, args);
+ }
+
+ function parseLeftHandSideExpressionAllowCall() {
+ var quasi, expr, args, property, startToken, previousAllowIn = state.allowIn;
+
+ startToken = lookahead;
+ state.allowIn = true;
+
+ if (matchKeyword('super') && state.inFunctionBody) {
+ expr = new Node();
+ lex();
+ expr = expr.finishSuper();
+ if (!match('(') && !match('.') && !match('[')) {
+ throwUnexpectedToken(lookahead);
+ }
+ } else {
+ expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
+ }
+
+ for (;;) {
+ if (match('.')) {
+ isBindingElement = false;
+ isAssignmentTarget = true;
+ property = parseNonComputedMember();
+ expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
+ } else if (match('(')) {
+ isBindingElement = false;
+ isAssignmentTarget = false;
+ args = parseArguments();
+ expr = new WrappingNode(startToken).finishCallExpression(expr, args);
+ } else if (match('[')) {
+ isBindingElement = false;
+ isAssignmentTarget = true;
+ property = parseComputedMember();
+ expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
+ } else if (lookahead.type === Token.Template && lookahead.head) {
+ quasi = parseTemplateLiteral();
+ expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
+ } else {
+ break;
+ }
+ }
+ state.allowIn = previousAllowIn;
+
+ return expr;
+ }
+
+ function parseLeftHandSideExpression() {
+ var quasi, expr, property, startToken;
+ assert(state.allowIn, 'callee of new expression always allow in keyword.');
+
+ startToken = lookahead;
+
+ if (matchKeyword('super') && state.inFunctionBody) {
+ expr = new Node();
+ lex();
+ expr = expr.finishSuper();
+ if (!match('[') && !match('.')) {
+ throwUnexpectedToken(lookahead);
+ }
+ } else {
+ expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
+ }
+
+ for (;;) {
+ if (match('[')) {
+ isBindingElement = false;
+ isAssignmentTarget = true;
+ property = parseComputedMember();
+ expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
+ } else if (match('.')) {
+ isBindingElement = false;
+ isAssignmentTarget = true;
+ property = parseNonComputedMember();
+ expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
+ } else if (lookahead.type === Token.Template && lookahead.head) {
+ quasi = parseTemplateLiteral();
+ expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
+ } else {
+ break;
+ }
+ }
+ return expr;
+ }
+
+ // 11.3 Postfix Expressions
+
+ function parsePostfixExpression() {
+ var expr, token, startToken = lookahead;
+
+ expr = inheritCoverGrammar(parseLeftHandSideExpressionAllowCall);
+
+ if (!hasLineTerminator && lookahead.type === Token.Punctuator) {
+ if (match('++') || match('--')) {
+ // 11.3.1, 11.3.2
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ tolerateError(Messages.StrictLHSPostfix);
+ }
+
+ if (!isAssignmentTarget) {
+ tolerateError(Messages.InvalidLHSInAssignment);
+ }
+
+ isAssignmentTarget = isBindingElement = false;
+
+ token = lex();
+ expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr);
+ }
+ }
+
+ return expr;
+ }
+
+ // 11.4 Unary Operators
+
+ function parseUnaryExpression() {
+ var token, expr, startToken;
+
+ if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
+ expr = parsePostfixExpression();
+ } else if (match('++') || match('--')) {
+ startToken = lookahead;
+ token = lex();
+ expr = inheritCoverGrammar(parseUnaryExpression);
+ // 11.4.4, 11.4.5
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ tolerateError(Messages.StrictLHSPrefix);
+ }
+
+ if (!isAssignmentTarget) {
+ tolerateError(Messages.InvalidLHSInAssignment);
+ }
+ expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
+ isAssignmentTarget = isBindingElement = false;
+ } else if (match('+') || match('-') || match('~') || match('!')) {
+ startToken = lookahead;
+ token = lex();
+ expr = inheritCoverGrammar(parseUnaryExpression);
+ expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
+ isAssignmentTarget = isBindingElement = false;
+ } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
+ startToken = lookahead;
+ token = lex();
+ expr = inheritCoverGrammar(parseUnaryExpression);
+ expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
+ if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
+ tolerateError(Messages.StrictDelete);
+ }
+ isAssignmentTarget = isBindingElement = false;
+ } else {
+ expr = parsePostfixExpression();
+ }
+
+ return expr;
+ }
+
+ function binaryPrecedence(token, allowIn) {
+ var prec = 0;
+
+ if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
+ return 0;
+ }
+
+ switch (token.value) {
+ case '||':
+ prec = 1;
+ break;
+
+ case '&&':
+ prec = 2;
+ break;
+
+ case '|':
+ prec = 3;
+ break;
+
+ case '^':
+ prec = 4;
+ break;
+
+ case '&':
+ prec = 5;
+ break;
+
+ case '==':
+ case '!=':
+ case '===':
+ case '!==':
+ prec = 6;
+ break;
+
+ case '<':
+ case '>':
+ case '<=':
+ case '>=':
+ case 'instanceof':
+ prec = 7;
+ break;
+
+ case 'in':
+ prec = allowIn ? 7 : 0;
+ break;
+
+ case '<<':
+ case '>>':
+ case '>>>':
+ prec = 8;
+ break;
+
+ case '+':
+ case '-':
+ prec = 9;
+ break;
+
+ case '*':
+ case '/':
+ case '%':
+ prec = 11;
+ break;
+
+ default:
+ break;
+ }
+
+ return prec;
+ }
+
+ // 11.5 Multiplicative Operators
+ // 11.6 Additive Operators
+ // 11.7 Bitwise Shift Operators
+ // 11.8 Relational Operators
+ // 11.9 Equality Operators
+ // 11.10 Binary Bitwise Operators
+ // 11.11 Binary Logical Operators
+
+ function parseBinaryExpression() {
+ var marker, markers, expr, token, prec, stack, right, operator, left, i;
+
+ marker = lookahead;
+ left = inheritCoverGrammar(parseUnaryExpression);
+
+ token = lookahead;
+ prec = binaryPrecedence(token, state.allowIn);
+ if (prec === 0) {
+ return left;
+ }
+ isAssignmentTarget = isBindingElement = false;
+ token.prec = prec;
+ lex();
+
+ markers = [marker, lookahead];
+ right = isolateCoverGrammar(parseUnaryExpression);
+
+ stack = [left, token, right];
+
+ while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
+
+ // Reduce: make a binary expression from the three topmost entries.
+ while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
+ right = stack.pop();
+ operator = stack.pop().value;
+ left = stack.pop();
+ markers.pop();
+ expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right);
+ stack.push(expr);
+ }
+
+ // Shift.
+ token = lex();
+ token.prec = prec;
+ stack.push(token);
+ markers.push(lookahead);
+ expr = isolateCoverGrammar(parseUnaryExpression);
+ stack.push(expr);
+ }
+
+ // Final reduce to clean-up the stack.
+ i = stack.length - 1;
+ expr = stack[i];
+ markers.pop();
+ while (i > 1) {
+ expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
+ i -= 2;
+ }
+
+ return expr;
+ }
+
+
+ // 11.12 Conditional Operator
+
+ function parseConditionalExpression() {
+ var expr, previousAllowIn, consequent, alternate, startToken;
+
+ startToken = lookahead;
+
+ expr = inheritCoverGrammar(parseBinaryExpression);
+ if (match('?')) {
+ lex();
+ previousAllowIn = state.allowIn;
+ state.allowIn = true;
+ consequent = isolateCoverGrammar(parseAssignmentExpression);
+ state.allowIn = previousAllowIn;
+ expect(':');
+ alternate = isolateCoverGrammar(parseAssignmentExpression);
+
+ expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
+ isAssignmentTarget = isBindingElement = false;
+ }
+
+ return expr;
+ }
+
+ // [ES6] 14.2 Arrow Function
+
+ function parseConciseBody() {
+ if (match('{')) {
+ return parseFunctionSourceElements();
+ }
+ return isolateCoverGrammar(parseAssignmentExpression);
+ }
+
+ function checkPatternParam(options, param) {
+ var i;
+ switch (param.type) {
+ case Syntax.Identifier:
+ validateParam(options, param, param.name);
+ break;
+ case Syntax.RestElement:
+ checkPatternParam(options, param.argument);
+ break;
+ case Syntax.AssignmentPattern:
+ checkPatternParam(options, param.left);
+ break;
+ case Syntax.ArrayPattern:
+ for (i = 0; i < param.elements.length; i++) {
+ if (param.elements[i] !== null) {
+ checkPatternParam(options, param.elements[i]);
+ }
+ }
+ break;
+ default:
+ assert(param.type === Syntax.ObjectPattern, 'Invalid type');
+ for (i = 0; i < param.properties.length; i++) {
+ checkPatternParam(options, param.properties[i].value);
+ }
+ break;
+ }
+ }
+ function reinterpretAsCoverFormalsList(expr) {
+ var i, len, param, params, defaults, defaultCount, options, token;
+
+ defaults = [];
+ defaultCount = 0;
+ params = [expr];
+
+ switch (expr.type) {
+ case Syntax.Identifier:
+ break;
+ case PlaceHolders.ArrowParameterPlaceHolder:
+ params = expr.params;
+ break;
+ default:
+ return null;
+ }
+
+ options = {
+ paramSet: {}
+ };
+
+ for (i = 0, len = params.length; i < len; i += 1) {
+ param = params[i];
+ switch (param.type) {
+ case Syntax.AssignmentPattern:
+ params[i] = param.left;
+ defaults.push(param.right);
+ ++defaultCount;
+ checkPatternParam(options, param.left);
+ break;
+ default:
+ checkPatternParam(options, param);
+ params[i] = param;
+ defaults.push(null);
+ break;
+ }
+ }
+
+ if (options.message === Messages.StrictParamDupe) {
+ token = strict ? options.stricted : options.firstRestricted;
+ throwUnexpectedToken(token, options.message);
+ }
+
+ if (defaultCount === 0) {
+ defaults = [];
+ }
+
+ return {
+ params: params,
+ defaults: defaults,
+ stricted: options.stricted,
+ firstRestricted: options.firstRestricted,
+ message: options.message
+ };
+ }
+
+ function parseArrowFunctionExpression(options, node) {
+ var previousStrict, body;
+
+ if (hasLineTerminator) {
+ tolerateUnexpectedToken(lookahead);
+ }
+ expect('=>');
+ previousStrict = strict;
+
+ body = parseConciseBody();
+
+ if (strict && options.firstRestricted) {
+ throwUnexpectedToken(options.firstRestricted, options.message);
+ }
+ if (strict && options.stricted) {
+ tolerateUnexpectedToken(options.stricted, options.message);
+ }
+
+ strict = previousStrict;
+
+ return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement);
+ }
+
+ // 11.13 Assignment Operators
+
+ function parseAssignmentExpression() {
+ var token, expr, right, list, startToken;
+
+ startToken = lookahead;
+ token = lookahead;
+
+ expr = parseConditionalExpression();
+
+ if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) {
+ isAssignmentTarget = isBindingElement = false;
+ list = reinterpretAsCoverFormalsList(expr);
+
+ if (list) {
+ firstCoverInitializedNameError = null;
+ return parseArrowFunctionExpression(list, new WrappingNode(startToken));
+ }
+
+ return expr;
+ }
+
+ if (matchAssign()) {
+ if (!isAssignmentTarget) {
+ tolerateError(Messages.InvalidLHSInAssignment);
+ }
+
+ // 11.13.1
+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+ tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
+ }
+
+ if (!match('=')) {
+ isAssignmentTarget = isBindingElement = false;
+ } else {
+ reinterpretExpressionAsPattern(expr);
+ }
+
+ token = lex();
+ right = isolateCoverGrammar(parseAssignmentExpression);
+ expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right);
+ firstCoverInitializedNameError = null;
+ }
+
+ return expr;
+ }
+
+ // 11.14 Comma Operator
+
+ function parseExpression() {
+ var expr, startToken = lookahead, expressions;
+
+ expr = isolateCoverGrammar(parseAssignmentExpression);
+
+ if (match(',')) {
+ expressions = [expr];
+
+ while (startIndex < length) {
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ expressions.push(isolateCoverGrammar(parseAssignmentExpression));
+ }
+
+ expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
+ }
+
+ return expr;
+ }
+
+ // 12.1 Block
+
+ function parseStatementListItem() {
+ if (lookahead.type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'export':
+ if (sourceType !== 'module') {
+ tolerateUnexpectedToken(lookahead, Messages.IllegalExportDeclaration);
+ }
+ return parseExportDeclaration();
+ case 'import':
+ if (sourceType !== 'module') {
+ tolerateUnexpectedToken(lookahead, Messages.IllegalImportDeclaration);
+ }
+ return parseImportDeclaration();
+ case 'const':
+ case 'let':
+ return parseLexicalDeclaration({inFor: false});
+ case 'function':
+ return parseFunctionDeclaration(new Node());
+ case 'class':
+ return parseClassDeclaration();
+ }
+ }
+
+ return parseStatement();
+ }
+
+ function parseStatementList() {
+ var list = [];
+ while (startIndex < length) {
+ if (match('}')) {
+ break;
+ }
+ list.push(parseStatementListItem());
+ }
+
+ return list;
+ }
+
+ function parseBlock() {
+ var block, node = new Node();
+
+ expect('{');
+
+ block = parseStatementList();
+
+ expect('}');
+
+ return node.finishBlockStatement(block);
+ }
+
+ // 12.2 Variable Statement
+
+ function parseVariableIdentifier() {
+ var token, node = new Node();
+
+ token = lex();
+
+ if (token.type !== Token.Identifier) {
+ if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) {
+ tolerateUnexpectedToken(token, Messages.StrictReservedWord);
+ } else {
+ throwUnexpectedToken(token);
+ }
+ }
+
+ return node.finishIdentifier(token.value);
+ }
+
+ function parseVariableDeclaration() {
+ var init = null, id, node = new Node();
+
+ id = parsePattern();
+
+ // 12.2.1
+ if (strict && isRestrictedWord(id.name)) {
+ tolerateError(Messages.StrictVarName);
+ }
+
+ if (match('=')) {
+ lex();
+ init = isolateCoverGrammar(parseAssignmentExpression);
+ } else if (id.type !== Syntax.Identifier) {
+ expect('=');
+ }
+
+ return node.finishVariableDeclarator(id, init);
+ }
+
+ function parseVariableDeclarationList() {
+ var list = [];
+
+ do {
+ list.push(parseVariableDeclaration());
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ } while (startIndex < length);
+
+ return list;
+ }
+
+ function parseVariableStatement(node) {
+ var declarations;
+
+ expectKeyword('var');
+
+ declarations = parseVariableDeclarationList();
+
+ consumeSemicolon();
+
+ return node.finishVariableDeclaration(declarations);
+ }
+
+ function parseLexicalBinding(kind, options) {
+ var init = null, id, node = new Node();
+
+ id = parsePattern();
+
+ // 12.2.1
+ if (strict && id.type === Syntax.Identifier && isRestrictedWord(id.name)) {
+ tolerateError(Messages.StrictVarName);
+ }
+
+ if (kind === 'const') {
+ if (!matchKeyword('in')) {
+ expect('=');
+ init = isolateCoverGrammar(parseAssignmentExpression);
+ }
+ } else if ((!options.inFor && id.type !== Syntax.Identifier) || match('=')) {
+ expect('=');
+ init = isolateCoverGrammar(parseAssignmentExpression);
+ }
+
+ return node.finishVariableDeclarator(id, init);
+ }
+
+ function parseBindingList(kind, options) {
+ var list = [];
+
+ do {
+ list.push(parseLexicalBinding(kind, options));
+ if (!match(',')) {
+ break;
+ }
+ lex();
+ } while (startIndex < length);
+
+ return list;
+ }
+
+ function parseLexicalDeclaration(options) {
+ var kind, declarations, node = new Node();
+
+ kind = lex().value;
+ assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');
+
+ declarations = parseBindingList(kind, options);
+
+ consumeSemicolon();
+
+ return node.finishLexicalDeclaration(declarations, kind);
+ }
+
+ function parseRestElement() {
+ var param, node = new Node();
+
+ lex();
+
+ if (match('{')) {
+ throwError(Messages.ObjectPatternAsRestParameter);
+ }
+
+ param = parseVariableIdentifier();
+
+ if (match('=')) {
+ throwError(Messages.DefaultRestParameter);
+ }
+
+ if (!match(')')) {
+ throwError(Messages.ParameterAfterRestParameter);
+ }
+
+ return node.finishRestElement(param);
+ }
+
+ // 12.3 Empty Statement
+
+ function parseEmptyStatement(node) {
+ expect(';');
+ return node.finishEmptyStatement();
+ }
+
+ // 12.4 Expression Statement
+
+ function parseExpressionStatement(node) {
+ var expr = parseExpression();
+ consumeSemicolon();
+ return node.finishExpressionStatement(expr);
+ }
+
+ // 12.5 If statement
+
+ function parseIfStatement(node) {
+ var test, consequent, alternate;
+
+ expectKeyword('if');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ consequent = parseStatement();
+
+ if (matchKeyword('else')) {
+ lex();
+ alternate = parseStatement();
+ } else {
+ alternate = null;
+ }
+
+ return node.finishIfStatement(test, consequent, alternate);
+ }
+
+ // 12.6 Iteration Statements
+
+ function parseDoWhileStatement(node) {
+ var body, test, oldInIteration;
+
+ expectKeyword('do');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ expectKeyword('while');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ if (match(';')) {
+ lex();
+ }
+
+ return node.finishDoWhileStatement(body, test);
+ }
+
+ function parseWhileStatement(node) {
+ var test, body, oldInIteration;
+
+ expectKeyword('while');
+
+ expect('(');
+
+ test = parseExpression();
+
+ expect(')');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = parseStatement();
+
+ state.inIteration = oldInIteration;
+
+ return node.finishWhileStatement(test, body);
+ }
+
+ function parseForStatement(node) {
+ var init, initSeq, initStartToken, test, update, left, right, kind, declarations,
+ body, oldInIteration, previousAllowIn = state.allowIn;
+
+ init = test = update = null;
+
+ expectKeyword('for');
+
+ expect('(');
+
+ if (match(';')) {
+ lex();
+ } else {
+ if (matchKeyword('var')) {
+ init = new Node();
+ lex();
+
+ state.allowIn = false;
+ init = init.finishVariableDeclaration(parseVariableDeclarationList());
+ state.allowIn = previousAllowIn;
+
+ if (init.declarations.length === 1 && matchKeyword('in')) {
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ } else {
+ expect(';');
+ }
+ } else if (matchKeyword('const') || matchKeyword('let')) {
+ init = new Node();
+ kind = lex().value;
+
+ state.allowIn = false;
+ declarations = parseBindingList(kind, {inFor: true});
+ state.allowIn = previousAllowIn;
+
+ if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) {
+ init = init.finishLexicalDeclaration(declarations, kind);
+ lex();
+ left = init;
+ right = parseExpression();
+ init = null;
+ } else {
+ consumeSemicolon();
+ init = init.finishLexicalDeclaration(declarations, kind);
+ }
+ } else {
+ initStartToken = lookahead;
+ state.allowIn = false;
+ init = inheritCoverGrammar(parseAssignmentExpression);
+ state.allowIn = previousAllowIn;
+
+ if (matchKeyword('in')) {
+ if (!isAssignmentTarget) {
+ tolerateError(Messages.InvalidLHSInForIn);
+ }
+
+ lex();
+ reinterpretExpressionAsPattern(init);
+ left = init;
+ right = parseExpression();
+ init = null;
+ } else {
+ if (match(',')) {
+ initSeq = [init];
+ while (match(',')) {
+ lex();
+ initSeq.push(isolateCoverGrammar(parseAssignmentExpression));
+ }
+ init = new WrappingNode(initStartToken).finishSequenceExpression(initSeq);
+ }
+ expect(';');
+ }
+ }
+ }
+
+ if (typeof left === 'undefined') {
+
+ if (!match(';')) {
+ test = parseExpression();
+ }
+ expect(';');
+
+ if (!match(')')) {
+ update = parseExpression();
+ }
+ }
+
+ expect(')');
+
+ oldInIteration = state.inIteration;
+ state.inIteration = true;
+
+ body = isolateCoverGrammar(parseStatement);
+
+ state.inIteration = oldInIteration;
+
+ return (typeof left === 'undefined') ?
+ node.finishForStatement(init, test, update, body) :
+ node.finishForInStatement(left, right, body);
+ }
+
+ // 12.7 The continue statement
+
+ function parseContinueStatement(node) {
+ var label = null, key;
+
+ expectKeyword('continue');
+
+ // Optimize the most common form: 'continue;'.
+ if (source.charCodeAt(startIndex) === 0x3B) {
+ lex();
+
+ if (!state.inIteration) {
+ throwError(Messages.IllegalContinue);
+ }
+
+ return node.finishContinueStatement(null);
+ }
+
+ if (hasLineTerminator) {
+ if (!state.inIteration) {
+ throwError(Messages.IllegalContinue);
+ }
+
+ return node.finishContinueStatement(null);
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ label = parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError(Messages.UnknownLabel, label.name);
+ }
+ }
+
+ consumeSemicolon();
+
+ if (label === null && !state.inIteration) {
+ throwError(Messages.IllegalContinue);
+ }
+
+ return node.finishContinueStatement(label);
+ }
+
+ // 12.8 The break statement
+
+ function parseBreakStatement(node) {
+ var label = null, key;
+
+ expectKeyword('break');
+
+ // Catch the very common case first: immediately a semicolon (U+003B).
+ if (source.charCodeAt(lastIndex) === 0x3B) {
+ lex();
+
+ if (!(state.inIteration || state.inSwitch)) {
+ throwError(Messages.IllegalBreak);
+ }
+
+ return node.finishBreakStatement(null);
+ }
+
+ if (hasLineTerminator) {
+ if (!(state.inIteration || state.inSwitch)) {
+ throwError(Messages.IllegalBreak);
+ }
+
+ return node.finishBreakStatement(null);
+ }
+
+ if (lookahead.type === Token.Identifier) {
+ label = parseVariableIdentifier();
+
+ key = '$' + label.name;
+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError(Messages.UnknownLabel, label.name);
+ }
+ }
+
+ consumeSemicolon();
+
+ if (label === null && !(state.inIteration || state.inSwitch)) {
+ throwError(Messages.IllegalBreak);
+ }
+
+ return node.finishBreakStatement(label);
+ }
+
+ // 12.9 The return statement
+
+ function parseReturnStatement(node) {
+ var argument = null;
+
+ expectKeyword('return');
+
+ if (!state.inFunctionBody) {
+ tolerateError(Messages.IllegalReturn);
+ }
+
+ // 'return' followed by a space and an identifier is very common.
+ if (source.charCodeAt(lastIndex) === 0x20) {
+ if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) {
+ argument = parseExpression();
+ consumeSemicolon();
+ return node.finishReturnStatement(argument);
+ }
+ }
+
+ if (hasLineTerminator) {
+ // HACK
+ return node.finishReturnStatement(null);
+ }
+
+ if (!match(';')) {
+ if (!match('}') && lookahead.type !== Token.EOF) {
+ argument = parseExpression();
+ }
+ }
+
+ consumeSemicolon();
+
+ return node.finishReturnStatement(argument);
+ }
+
+ // 12.10 The with statement
+
+ function parseWithStatement(node) {
+ var object, body;
+
+ if (strict) {
+ tolerateError(Messages.StrictModeWith);
+ }
+
+ expectKeyword('with');
+
+ expect('(');
+
+ object = parseExpression();
+
+ expect(')');
+
+ body = parseStatement();
+
+ return node.finishWithStatement(object, body);
+ }
+
+ // 12.10 The swith statement
+
+ function parseSwitchCase() {
+ var test, consequent = [], statement, node = new Node();
+
+ if (matchKeyword('default')) {
+ lex();
+ test = null;
+ } else {
+ expectKeyword('case');
+ test = parseExpression();
+ }
+ expect(':');
+
+ while (startIndex < length) {
+ if (match('}') || matchKeyword('default') || matchKeyword('case')) {
+ break;
+ }
+ statement = parseStatementListItem();
+ consequent.push(statement);
+ }
+
+ return node.finishSwitchCase(test, consequent);
+ }
+
+ function parseSwitchStatement(node) {
+ var discriminant, cases, clause, oldInSwitch, defaultFound;
+
+ expectKeyword('switch');
+
+ expect('(');
+
+ discriminant = parseExpression();
+
+ expect(')');
+
+ expect('{');
+
+ cases = [];
+
+ if (match('}')) {
+ lex();
+ return node.finishSwitchStatement(discriminant, cases);
+ }
+
+ oldInSwitch = state.inSwitch;
+ state.inSwitch = true;
+ defaultFound = false;
+
+ while (startIndex < length) {
+ if (match('}')) {
+ break;
+ }
+ clause = parseSwitchCase();
+ if (clause.test === null) {
+ if (defaultFound) {
+ throwError(Messages.MultipleDefaultsInSwitch);
+ }
+ defaultFound = true;
+ }
+ cases.push(clause);
+ }
+
+ state.inSwitch = oldInSwitch;
+
+ expect('}');
+
+ return node.finishSwitchStatement(discriminant, cases);
+ }
+
+ // 12.13 The throw statement
+
+ function parseThrowStatement(node) {
+ var argument;
+
+ expectKeyword('throw');
+
+ if (hasLineTerminator) {
+ throwError(Messages.NewlineAfterThrow);
+ }
+
+ argument = parseExpression();
+
+ consumeSemicolon();
+
+ return node.finishThrowStatement(argument);
+ }
+
+ // 12.14 The try statement
+
+ function parseCatchClause() {
+ var param, body, node = new Node();
+
+ expectKeyword('catch');
+
+ expect('(');
+ if (match(')')) {
+ throwUnexpectedToken(lookahead);
+ }
+
+ param = parsePattern();
+
+ // 12.14.1
+ if (strict && isRestrictedWord(param.name)) {
+ tolerateError(Messages.StrictCatchVariable);
+ }
+
+ expect(')');
+ body = parseBlock();
+ return node.finishCatchClause(param, body);
+ }
+
+ function parseTryStatement(node) {
+ var block, handler = null, finalizer = null;
+
+ expectKeyword('try');
+
+ block = parseBlock();
+
+ if (matchKeyword('catch')) {
+ handler = parseCatchClause();
+ }
+
+ if (matchKeyword('finally')) {
+ lex();
+ finalizer = parseBlock();
+ }
+
+ if (!handler && !finalizer) {
+ throwError(Messages.NoCatchOrFinally);
+ }
+
+ return node.finishTryStatement(block, handler, finalizer);
+ }
+
+ // 12.15 The debugger statement
+
+ function parseDebuggerStatement(node) {
+ expectKeyword('debugger');
+
+ consumeSemicolon();
+
+ return node.finishDebuggerStatement();
+ }
+
+ // 12 Statements
+
+ function parseStatement() {
+ var type = lookahead.type,
+ expr,
+ labeledBody,
+ key,
+ node;
+
+ if (type === Token.EOF) {
+ throwUnexpectedToken(lookahead);
+ }
+
+ if (type === Token.Punctuator && lookahead.value === '{') {
+ return parseBlock();
+ }
+ isAssignmentTarget = isBindingElement = true;
+ node = new Node();
+
+ if (type === Token.Punctuator) {
+ switch (lookahead.value) {
+ case ';':
+ return parseEmptyStatement(node);
+ case '(':
+ return parseExpressionStatement(node);
+ default:
+ break;
+ }
+ } else if (type === Token.Keyword) {
+ switch (lookahead.value) {
+ case 'break':
+ return parseBreakStatement(node);
+ case 'continue':
+ return parseContinueStatement(node);
+ case 'debugger':
+ return parseDebuggerStatement(node);
+ case 'do':
+ return parseDoWhileStatement(node);
+ case 'for':
+ return parseForStatement(node);
+ case 'function':
+ return parseFunctionDeclaration(node);
+ case 'if':
+ return parseIfStatement(node);
+ case 'return':
+ return parseReturnStatement(node);
+ case 'switch':
+ return parseSwitchStatement(node);
+ case 'throw':
+ return parseThrowStatement(node);
+ case 'try':
+ return parseTryStatement(node);
+ case 'var':
+ return parseVariableStatement(node);
+ case 'while':
+ return parseWhileStatement(node);
+ case 'with':
+ return parseWithStatement(node);
+ default:
+ break;
+ }
+ }
+
+ expr = parseExpression();
+
+ // 12.12 Labelled Statements
+ if ((expr.type === Syntax.Identifier) && match(':')) {
+ lex();
+
+ key = '$' + expr.name;
+ if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
+ throwError(Messages.Redeclaration, 'Label', expr.name);
+ }
+
+ state.labelSet[key] = true;
+ labeledBody = parseStatement();
+ delete state.labelSet[key];
+ return node.finishLabeledStatement(expr, labeledBody);
+ }
+
+ consumeSemicolon();
+
+ return node.finishExpressionStatement(expr);
+ }
+
+ // 13 Function Definition
+
+ function parseFunctionSourceElements() {
+ var statement, body = [], token, directive, firstRestricted,
+ oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount,
+ node = new Node();
+
+ expect('{');
+
+ while (startIndex < length) {
+ if (lookahead.type !== Token.StringLiteral) {
+ break;
+ }
+ token = lookahead;
+
+ statement = parseStatementListItem();
+ body.push(statement);
+ if (statement.expression.type !== Syntax.Literal) {
+ // this is not directive
+ break;
+ }
+ directive = source.slice(token.start + 1, token.end - 1);
+ if (directive === 'use strict') {
+ strict = true;
+ if (firstRestricted) {
+ tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
+ }
+ } else {
+ if (!firstRestricted && token.octal) {
+ firstRestricted = token;
+ }
+ }
+ }
+
+ oldLabelSet = state.labelSet;
+ oldInIteration = state.inIteration;
+ oldInSwitch = state.inSwitch;
+ oldInFunctionBody = state.inFunctionBody;
+ oldParenthesisCount = state.parenthesizedCount;
+
+ state.labelSet = {};
+ state.inIteration = false;
+ state.inSwitch = false;
+ state.inFunctionBody = true;
+ state.parenthesizedCount = 0;
+
+ while (startIndex < length) {
+ if (match('}')) {
+ break;
+ }
+ body.push(parseStatementListItem());
+ }
+
+ expect('}');
+
+ state.labelSet = oldLabelSet;
+ state.inIteration = oldInIteration;
+ state.inSwitch = oldInSwitch;
+ state.inFunctionBody = oldInFunctionBody;
+ state.parenthesizedCount = oldParenthesisCount;
+
+ return node.finishBlockStatement(body);
+ }
+
+ function validateParam(options, param, name) {
+ var key = '$' + name;
+ if (strict) {
+ if (isRestrictedWord(name)) {
+ options.stricted = param;
+ options.message = Messages.StrictParamName;
+ }
+ if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
+ options.stricted = param;
+ options.message = Messages.StrictParamDupe;
+ }
+ } else if (!options.firstRestricted) {
+ if (isRestrictedWord(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictParamName;
+ } else if (isStrictModeReservedWord(name)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictReservedWord;
+ } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
+ options.firstRestricted = param;
+ options.message = Messages.StrictParamDupe;
+ }
+ }
+ options.paramSet[key] = true;
+ }
+
+ function parseParam(options) {
+ var token, param, def;
+
+ token = lookahead;
+ if (token.value === '...') {
+ param = parseRestElement();
+ validateParam(options, param.argument, param.argument.name);
+ options.params.push(param);
+ options.defaults.push(null);
+ return false;
+ }
+
+ param = parsePatternWithDefault();
+ validateParam(options, token, token.value);
+
+ if (param.type === Syntax.AssignmentPattern) {
+ def = param.right;
+ param = param.left;
+ ++options.defaultCount;
+ }
+
+ options.params.push(param);
+ options.defaults.push(def);
+
+ return !match(')');
+ }
+
+ function parseParams(firstRestricted) {
+ var options;
+
+ options = {
+ params: [],
+ defaultCount: 0,
+ defaults: [],
+ firstRestricted: firstRestricted
+ };
+
+ expect('(');
+
+ if (!match(')')) {
+ options.paramSet = {};
+ while (startIndex < length) {
+ if (!parseParam(options)) {
+ break;
+ }
+ expect(',');
+ }
+ }
+
+ expect(')');
+
+ if (options.defaultCount === 0) {
+ options.defaults = [];
+ }
+
+ return {
+ params: options.params,
+ defaults: options.defaults,
+ stricted: options.stricted,
+ firstRestricted: options.firstRestricted,
+ message: options.message
+ };
+ }
+
+ function parseFunctionDeclaration(node, identifierIsOptional) {
+ var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict;
+
+ expectKeyword('function');
+ if (!identifierIsOptional || !match('(')) {
+ token = lookahead;
+ id = parseVariableIdentifier();
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ tolerateUnexpectedToken(token, Messages.StrictFunctionName);
+ }
+ } else {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ }
+ }
+ }
+
+ tmp = parseParams(firstRestricted);
+ params = tmp.params;
+ defaults = tmp.defaults;
+ stricted = tmp.stricted;
+ firstRestricted = tmp.firstRestricted;
+ if (tmp.message) {
+ message = tmp.message;
+ }
+
+ previousStrict = strict;
+ body = parseFunctionSourceElements();
+ if (strict && firstRestricted) {
+ throwUnexpectedToken(firstRestricted, message);
+ }
+ if (strict && stricted) {
+ tolerateUnexpectedToken(stricted, message);
+ }
+ strict = previousStrict;
+
+ return node.finishFunctionDeclaration(id, params, defaults, body);
+ }
+
+ function parseFunctionExpression() {
+ var token, id = null, stricted, firstRestricted, message, tmp,
+ params = [], defaults = [], body, previousStrict, node = new Node();
+
+ expectKeyword('function');
+
+ if (!match('(')) {
+ token = lookahead;
+ id = parseVariableIdentifier();
+ if (strict) {
+ if (isRestrictedWord(token.value)) {
+ tolerateUnexpectedToken(token, Messages.StrictFunctionName);
+ }
+ } else {
+ if (isRestrictedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictFunctionName;
+ } else if (isStrictModeReservedWord(token.value)) {
+ firstRestricted = token;
+ message = Messages.StrictReservedWord;
+ }
+ }
+ }
+
+ tmp = parseParams(firstRestricted);
+ params = tmp.params;
+ defaults = tmp.defaults;
+ stricted = tmp.stricted;
+ firstRestricted = tmp.firstRestricted;
+ if (tmp.message) {
+ message = tmp.message;
+ }
+
+ previousStrict = strict;
+ body = parseFunctionSourceElements();
+ if (strict && firstRestricted) {
+ throwUnexpectedToken(firstRestricted, message);
+ }
+ if (strict && stricted) {
+ tolerateUnexpectedToken(stricted, message);
+ }
+ strict = previousStrict;
+
+ return node.finishFunctionExpression(id, params, defaults, body);
+ }
+
+
+ function parseClassBody() {
+ var classBody, token, isStatic, hasConstructor = false, body, method, computed, key;
+
+ classBody = new Node();
+
+ expect('{');
+ body = [];
+ while (!match('}')) {
+ if (match(';')) {
+ lex();
+ } else {
+ method = new Node();
+ token = lookahead;
+ isStatic = false;
+ computed = match('[');
+ key = parseObjectPropertyKey();
+ if (key.name === 'static' && lookaheadPropertyName()) {
+ token = lookahead;
+ isStatic = true;
+ computed = match('[');
+ key = parseObjectPropertyKey();
+ }
+ method = tryParseMethodDefinition(token, key, computed, method);
+ if (method) {
+ method['static'] = isStatic;
+ if (method.kind === 'init') {
+ method.kind = 'method';
+ }
+ if (!isStatic) {
+ if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') {
+ if (method.kind !== 'method' || !method.method || method.value.generator) {
+ throwUnexpectedToken(token, Messages.ConstructorSpecialMethod);
+ }
+ if (hasConstructor) {
+ throwUnexpectedToken(token, Messages.DuplicateConstructor);
+ } else {
+ hasConstructor = true;
+ }
+ method.kind = 'constructor';
+ }
+ } else {
+ if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') {
+ throwUnexpectedToken(token, Messages.StaticPrototype);
+ }
+ }
+ method.type = Syntax.MethodDefinition;
+ delete method.method;
+ delete method.shorthand;
+ body.push(method);
+ } else {
+ throwUnexpectedToken(lookahead);
+ }
+ }
+ }
+ lex();
+ return classBody.finishClassBody(body);
+ }
+
+ function parseClassDeclaration(identifierIsOptional) {
+ var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
+ strict = true;
+
+ expectKeyword('class');
+
+ if (!identifierIsOptional || lookahead.type === Token.Identifier) {
+ id = parseVariableIdentifier();
+ }
+
+ if (matchKeyword('extends')) {
+ lex();
+ superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
+ }
+ classBody = parseClassBody();
+ strict = previousStrict;
+
+ return classNode.finishClassDeclaration(id, superClass, classBody);
+ }
+
+ function parseClassExpression() {
+ var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
+ strict = true;
+
+ expectKeyword('class');
+
+ if (lookahead.type === Token.Identifier) {
+ id = parseVariableIdentifier();
+ }
+
+ if (matchKeyword('extends')) {
+ lex();
+ superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
+ }
+ classBody = parseClassBody();
+ strict = previousStrict;
+
+ return classNode.finishClassExpression(id, superClass, classBody);
+ }
+
+ // Modules grammar from:
+ // people.mozilla.org/~jorendorff/es6-draft.html
+
+ function parseModuleSpecifier() {
+ var node = new Node();
+
+ if (lookahead.type !== Token.StringLiteral) {
+ throwError(Messages.InvalidModuleSpecifier);
+ }
+ return node.finishLiteral(lex());
+ }
+
+ function parseExportSpecifier() {
+ var exported, local, node = new Node(), def;
+ if (matchKeyword('default')) {
+ // export {default} from 'something';
+ def = new Node();
+ lex();
+ local = def.finishIdentifier('default');
+ } else {
+ local = parseVariableIdentifier();
+ }
+ if (matchContextualKeyword('as')) {
+ lex();
+ exported = parseNonComputedProperty();
+ }
+ return node.finishExportSpecifier(local, exported);
+ }
+
+ function parseExportNamedDeclaration(node) {
+ var declaration = null,
+ isExportFromIdentifier,
+ src = null, specifiers = [];
+
+ // non-default export
+ if (lookahead.type === Token.Keyword) {
+ // covers:
+ // export var f = 1;
+ switch (lookahead.value) {
+ case 'let':
+ case 'const':
+ case 'var':
+ case 'class':
+ case 'function':
+ declaration = parseStatementListItem();
+ return node.finishExportNamedDeclaration(declaration, specifiers, null);
+ }
+ }
+
+ expect('{');
+ if (!match('}')) {
+ do {
+ isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default');
+ specifiers.push(parseExportSpecifier());
+ } while (match(',') && lex());
+ }
+ expect('}');
+
+ if (matchContextualKeyword('from')) {
+ // covering:
+ // export {default} from 'foo';
+ // export {foo} from 'foo';
+ lex();
+ src = parseModuleSpecifier();
+ consumeSemicolon();
+ } else if (isExportFromIdentifier) {
+ // covering:
+ // export {default}; // missing fromClause
+ throwError(lookahead.value ?
+ Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
+ } else {
+ // cover
+ // export {foo};
+ consumeSemicolon();
+ }
+ return node.finishExportNamedDeclaration(declaration, specifiers, src);
+ }
+
+ function parseExportDefaultDeclaration(node) {
+ var declaration = null,
+ expression = null;
+
+ // covers:
+ // export default ...
+ expectKeyword('default');
+
+ if (matchKeyword('function')) {
+ // covers:
+ // export default function foo () {}
+ // export default function () {}
+ declaration = parseFunctionDeclaration(new Node(), true);
+ return node.finishExportDefaultDeclaration(declaration);
+ }
+ if (matchKeyword('class')) {
+ declaration = parseClassDeclaration(true);
+ return node.finishExportDefaultDeclaration(declaration);
+ }
+
+ if (matchContextualKeyword('from')) {
+ throwError(Messages.UnexpectedToken, lookahead.value);
+ }
+
+ // covers:
+ // export default {};
+ // export default [];
+ // export default (1 + 2);
+ if (match('{')) {
+ expression = parseObjectInitialiser();
+ } else if (match('[')) {
+ expression = parseArrayInitialiser();
+ } else {
+ expression = parseAssignmentExpression();
+ }
+ consumeSemicolon();
+ return node.finishExportDefaultDeclaration(expression);
+ }
+
+ function parseExportAllDeclaration(node) {
+ var src;
+
+ // covers:
+ // export * from 'foo';
+ expect('*');
+ if (!matchContextualKeyword('from')) {
+ throwError(lookahead.value ?
+ Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
+ }
+ lex();
+ src = parseModuleSpecifier();
+ consumeSemicolon();
+
+ return node.finishExportAllDeclaration(src);
+ }
+
+ function parseExportDeclaration() {
+ var node = new Node();
+ if (state.inFunctionBody) {
+ throwError(Messages.IllegalExportDeclaration);
+ }
+
+ expectKeyword('export');
+
+ if (matchKeyword('default')) {
+ return parseExportDefaultDeclaration(node);
+ }
+ if (match('*')) {
+ return parseExportAllDeclaration(node);
+ }
+ return parseExportNamedDeclaration(node);
+ }
+
+ function parseImportSpecifier() {
+ // import {