HOME


Mini Shell 1.0
Redirecting to https://devs.lapieza.net/iniciar-sesion Redirecting to https://devs.lapieza.net/iniciar-sesion.
DIR: /proc/self/root/usr/share/nodejs/esprima/src/
Upload File :
Current File : //proc/self/root/usr/share/nodejs/esprima/src/parser.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
var assert_1 = require("./assert");
var error_handler_1 = require("./error-handler");
var messages_1 = require("./messages");
var Node = require("./nodes");
var scanner_1 = require("./scanner");
var syntax_1 = require("./syntax");
var token_1 = require("./token");
var ArrowParameterPlaceHolder = 'ArrowParameterPlaceHolder';
var Parser = /** @class */ (function () {
    function Parser(code, options, delegate) {
        if (options === void 0) { options = {}; }
        this.config = {
            range: (typeof options.range === 'boolean') && options.range,
            loc: (typeof options.loc === 'boolean') && options.loc,
            source: null,
            tokens: (typeof options.tokens === 'boolean') && options.tokens,
            comment: (typeof options.comment === 'boolean') && options.comment,
            tolerant: (typeof options.tolerant === 'boolean') && options.tolerant
        };
        if (this.config.loc && options.source && options.source !== null) {
            this.config.source = String(options.source);
        }
        this.delegate = delegate;
        this.errorHandler = new error_handler_1.ErrorHandler();
        this.errorHandler.tolerant = this.config.tolerant;
        this.scanner = new scanner_1.Scanner(code, this.errorHandler);
        this.scanner.trackComment = this.config.comment;
        this.operatorPrecedence = {
            ')': 0,
            ';': 0,
            ',': 0,
            '=': 0,
            ']': 0,
            '||': 1,
            '&&': 2,
            '|': 3,
            '^': 4,
            '&': 5,
            '==': 6,
            '!=': 6,
            '===': 6,
            '!==': 6,
            '<': 7,
            '>': 7,
            '<=': 7,
            '>=': 7,
            '<<': 8,
            '>>': 8,
            '>>>': 8,
            '+': 9,
            '-': 9,
            '*': 11,
            '/': 11,
            '%': 11
        };
        this.lookahead = {
            type: 2 /* EOF */,
            value: '',
            lineNumber: this.scanner.lineNumber,
            lineStart: 0,
            start: 0,
            end: 0
        };
        this.hasLineTerminator = false;
        this.context = {
            isModule: false,
            await: false,
            allowIn: true,
            allowStrictDirective: true,
            allowYield: true,
            firstCoverInitializedNameError: null,
            isAssignmentTarget: false,
            isBindingElement: false,
            inFunctionBody: false,
            inIteration: false,
            inSwitch: false,
            labelSet: {},
            strict: false
        };
        this.tokens = [];
        this.startMarker = {
            index: 0,
            line: this.scanner.lineNumber,
            column: 0
        };
        this.lastMarker = {
            index: 0,
            line: this.scanner.lineNumber,
            column: 0
        };
        this.nextToken();
        this.lastMarker = {
            index: this.scanner.index,
            line: this.scanner.lineNumber,
            column: this.scanner.index - this.scanner.lineStart
        };
    }
    Parser.prototype.throwError = function (messageFormat) {
        var values = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            values[_i - 1] = arguments[_i];
        }
        var args = Array.prototype.slice.call(arguments, 1);
        var msg = messageFormat.replace(/%(\d)/g, function (whole, idx) {
            (0, assert_1.assert)(idx < args.length, 'Message reference must be in range');
            return args[idx];
        });
        var index = this.lastMarker.index;
        var line = this.lastMarker.line;
        var column = this.lastMarker.column + 1;
        throw this.errorHandler.createError(index, line, column, msg);
    };
    Parser.prototype.tolerateError = function (messageFormat) {
        var values = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            values[_i - 1] = arguments[_i];
        }
        var args = Array.prototype.slice.call(arguments, 1);
        var msg = messageFormat.replace(/%(\d)/g, function (whole, idx) {
            (0, assert_1.assert)(idx < args.length, 'Message reference must be in range');
            return args[idx];
        });
        var index = this.lastMarker.index;
        var line = this.scanner.lineNumber;
        var column = this.lastMarker.column + 1;
        this.errorHandler.tolerateError(index, line, column, msg);
    };
    // Throw an exception because of the token.
    Parser.prototype.unexpectedTokenError = function (token, message) {
        var msg = message || messages_1.Messages.UnexpectedToken;
        var value;
        if (token) {
            if (!message) {
                msg = (token.type === 2 /* EOF */) ? messages_1.Messages.UnexpectedEOS :
                    (token.type === 3 /* Identifier */) ? messages_1.Messages.UnexpectedIdentifier :
                        (token.type === 6 /* NumericLiteral */) ? messages_1.Messages.UnexpectedNumber :
                            (token.type === 8 /* StringLiteral */) ? messages_1.Messages.UnexpectedString :
                                (token.type === 10 /* Template */) ? messages_1.Messages.UnexpectedTemplate :
                                    messages_1.Messages.UnexpectedToken;
                if (token.type === 4 /* Keyword */) {
                    if (this.scanner.isFutureReservedWord(token.value)) {
                        msg = messages_1.Messages.UnexpectedReserved;
                    }
                    else if (this.context.strict && this.scanner.isStrictModeReservedWord(token.value)) {
                        msg = messages_1.Messages.StrictReservedWord;
                    }
                }
            }
            value = token.value;
        }
        else {
            value = 'ILLEGAL';
        }
        msg = msg.replace('%0', value);
        if (token && typeof token.lineNumber === 'number') {
            var index = token.start;
            var line = token.lineNumber;
            var lastMarkerLineStart = this.lastMarker.index - this.lastMarker.column;
            var column = token.start - lastMarkerLineStart + 1;
            return this.errorHandler.createError(index, line, column, msg);
        }
        else {
            var index = this.lastMarker.index;
            var line = this.lastMarker.line;
            var column = this.lastMarker.column + 1;
            return this.errorHandler.createError(index, line, column, msg);
        }
    };
    Parser.prototype.throwUnexpectedToken = function (token, message) {
        throw this.unexpectedTokenError(token, message);
    };
    Parser.prototype.tolerateUnexpectedToken = function (token, message) {
        this.errorHandler.tolerate(this.unexpectedTokenError(token, message));
    };
    Parser.prototype.collectComments = function () {
        if (!this.config.comment) {
            this.scanner.scanComments();
        }
        else {
            var comments = this.scanner.scanComments();
            if (comments.length > 0 && this.delegate) {
                for (var i = 0; i < comments.length; ++i) {
                    var e = comments[i];
                    var node = void 0;
                    node = {
                        type: e.multiLine ? 'BlockComment' : 'LineComment',
                        value: this.scanner.source.slice(e.slice[0], e.slice[1])
                    };
                    if (this.config.range) {
                        node.range = e.range;
                    }
                    if (this.config.loc) {
                        node.loc = e.loc;
                    }
                    var metadata = {
                        start: {
                            line: e.loc.start.line,
                            column: e.loc.start.column,
                            offset: e.range[0]
                        },
                        end: {
                            line: e.loc.end.line,
                            column: e.loc.end.column,
                            offset: e.range[1]
                        }
                    };
                    this.delegate(node, metadata);
                }
            }
        }
    };
    // From internal representation to an external structure
    Parser.prototype.getTokenRaw = function (token) {
        return this.scanner.source.slice(token.start, token.end);
    };
    Parser.prototype.convertToken = function (token) {
        var t = {
            type: token_1.TokenName[token.type],
            value: this.getTokenRaw(token)
        };
        if (this.config.range) {
            t.range = [token.start, token.end];
        }
        if (this.config.loc) {
            t.loc = {
                start: {
                    line: this.startMarker.line,
                    column: this.startMarker.column
                },
                end: {
                    line: this.scanner.lineNumber,
                    column: this.scanner.index - this.scanner.lineStart
                }
            };
        }
        if (token.type === 9 /* RegularExpression */) {
            var pattern = token.pattern;
            var flags = token.flags;
            t.regex = { pattern: pattern, flags: flags };
        }
        return t;
    };
    Parser.prototype.nextToken = function () {
        var token = this.lookahead;
        this.lastMarker.index = this.scanner.index;
        this.lastMarker.line = this.scanner.lineNumber;
        this.lastMarker.column = this.scanner.index - this.scanner.lineStart;
        this.collectComments();
        if (this.scanner.index !== this.startMarker.index) {
            this.startMarker.index = this.scanner.index;
            this.startMarker.line = this.scanner.lineNumber;
            this.startMarker.column = this.scanner.index - this.scanner.lineStart;
        }
        var next = this.scanner.lex();
        this.hasLineTerminator = (token.lineNumber !== next.lineNumber);
        if (next && this.context.strict && next.type === 3 /* Identifier */) {
            if (this.scanner.isStrictModeReservedWord(next.value)) {
                next.type = 4 /* Keyword */;
            }
        }
        this.lookahead = next;
        if (this.config.tokens && next.type !== 2 /* EOF */) {
            this.tokens.push(this.convertToken(next));
        }
        return token;
    };
    Parser.prototype.nextRegexToken = function () {
        this.collectComments();
        var token = this.scanner.scanRegExp();
        if (this.config.tokens) {
            // Pop the previous token, '/' or '/='
            // This is added from the lookahead token.
            this.tokens.pop();
            this.tokens.push(this.convertToken(token));
        }
        // Prime the next lookahead.
        this.lookahead = token;
        this.nextToken();
        return token;
    };
    Parser.prototype.createNode = function () {
        return {
            index: this.startMarker.index,
            line: this.startMarker.line,
            column: this.startMarker.column
        };
    };
    Parser.prototype.startNode = function (token, lastLineStart) {
        if (lastLineStart === void 0) { lastLineStart = 0; }
        var column = token.start - token.lineStart;
        var line = token.lineNumber;
        if (column < 0) {
            column += lastLineStart;
            line--;
        }
        return {
            index: token.start,
            line: line,
            column: column
        };
    };
    Parser.prototype.finalize = function (marker, node) {
        if (this.config.range) {
            node.range = [marker.index, this.lastMarker.index];
        }
        if (this.config.loc) {
            node.loc = {
                start: {
                    line: marker.line,
                    column: marker.column,
                },
                end: {
                    line: this.lastMarker.line,
                    column: this.lastMarker.column
                }
            };
            if (this.config.source) {
                node.loc.source = this.config.source;
            }
        }
        if (this.delegate) {
            var metadata = {
                start: {
                    line: marker.line,
                    column: marker.column,
                    offset: marker.index
                },
                end: {
                    line: this.lastMarker.line,
                    column: this.lastMarker.column,
                    offset: this.lastMarker.index
                }
            };
            this.delegate(node, metadata);
        }
        return node;
    };
    // Expect the next token to match the specified punctuator.
    // If not, an exception will be thrown.
    Parser.prototype.expect = function (value) {
        var token = this.nextToken();
        if (token.type !== 7 /* Punctuator */ || token.value !== value) {
            this.throwUnexpectedToken(token);
        }
    };
    // Quietly expect a comma when in tolerant mode, otherwise delegates to expect().
    Parser.prototype.expectCommaSeparator = function () {
        if (this.config.tolerant) {
            var token = this.lookahead;
            if (token.type === 7 /* Punctuator */ && token.value === ',') {
                this.nextToken();
            }
            else if (token.type === 7 /* Punctuator */ && token.value === ';') {
                this.nextToken();
                this.tolerateUnexpectedToken(token);
            }
            else {
                this.tolerateUnexpectedToken(token, messages_1.Messages.UnexpectedToken);
            }
        }
        else {
            this.expect(',');
        }
    };
    // Expect the next token to match the specified keyword.
    // If not, an exception will be thrown.
    Parser.prototype.expectKeyword = function (keyword) {
        var token = this.nextToken();
        if (token.type !== 4 /* Keyword */ || token.value !== keyword) {
            this.throwUnexpectedToken(token);
        }
    };
    // Return true if the next token matches the specified punctuator.
    Parser.prototype.match = function (value) {
        return this.lookahead.type === 7 /* Punctuator */ && this.lookahead.value === value;
    };
    // Return true if the next token matches the specified keyword
    Parser.prototype.matchKeyword = function (keyword) {
        return this.lookahead.type === 4 /* Keyword */ && this.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)
    Parser.prototype.matchContextualKeyword = function (keyword) {
        return this.lookahead.type === 3 /* Identifier */ && this.lookahead.value === keyword;
    };
    // Return true if the next token is an assignment operator
    Parser.prototype.matchAssign = function () {
        if (this.lookahead.type !== 7 /* Punctuator */) {
            return false;
        }
        var op = this.lookahead.value;
        return op === '=' ||
            op === '*=' ||
            op === '**=' ||
            op === '/=' ||
            op === '%=' ||
            op === '+=' ||
            op === '-=' ||
            op === '<<=' ||
            op === '>>=' ||
            op === '>>>=' ||
            op === '&=' ||
            op === '^=' ||
            op === '|=';
    };
    // 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.
    Parser.prototype.isolateCoverGrammar = function (parseFunction) {
        var previousIsBindingElement = this.context.isBindingElement;
        var previousIsAssignmentTarget = this.context.isAssignmentTarget;
        var previousFirstCoverInitializedNameError = this.context.firstCoverInitializedNameError;
        this.context.isBindingElement = true;
        this.context.isAssignmentTarget = true;
        this.context.firstCoverInitializedNameError = null;
        var result = parseFunction.call(this);
        if (this.context.firstCoverInitializedNameError !== null) {
            this.throwUnexpectedToken(this.context.firstCoverInitializedNameError);
        }
        this.context.isBindingElement = previousIsBindingElement;
        this.context.isAssignmentTarget = previousIsAssignmentTarget;
        this.context.firstCoverInitializedNameError = previousFirstCoverInitializedNameError;
        return result;
    };
    Parser.prototype.inheritCoverGrammar = function (parseFunction) {
        var previousIsBindingElement = this.context.isBindingElement;
        var previousIsAssignmentTarget = this.context.isAssignmentTarget;
        var previousFirstCoverInitializedNameError = this.context.firstCoverInitializedNameError;
        this.context.isBindingElement = true;
        this.context.isAssignmentTarget = true;
        this.context.firstCoverInitializedNameError = null;
        var result = parseFunction.call(this);
        this.context.isBindingElement = this.context.isBindingElement && previousIsBindingElement;
        this.context.isAssignmentTarget = this.context.isAssignmentTarget && previousIsAssignmentTarget;
        this.context.firstCoverInitializedNameError = previousFirstCoverInitializedNameError || this.context.firstCoverInitializedNameError;
        return result;
    };
    Parser.prototype.consumeSemicolon = function () {
        if (this.match(';')) {
            this.nextToken();
        }
        else if (!this.hasLineTerminator) {
            if (this.lookahead.type !== 2 /* EOF */ && !this.match('}')) {
                this.throwUnexpectedToken(this.lookahead);
            }
            this.lastMarker.index = this.startMarker.index;
            this.lastMarker.line = this.startMarker.line;
            this.lastMarker.column = this.startMarker.column;
        }
    };
    // https://tc39.github.io/ecma262/#sec-primary-expression
    Parser.prototype.parsePrimaryExpression = function () {
        var node = this.createNode();
        var expr;
        var token, raw;
        switch (this.lookahead.type) {
            case 3 /* Identifier */:
                if ((this.context.isModule || this.context.await) && this.lookahead.value === 'await') {
                    this.tolerateUnexpectedToken(this.lookahead);
                }
                expr = this.matchAsyncFunction() ? this.parseFunctionExpression() : this.finalize(node, new Node.Identifier(this.nextToken().value));
                break;
            case 6 /* NumericLiteral */:
            case 8 /* StringLiteral */:
                if (this.context.strict && this.lookahead.octal) {
                    this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.StrictOctalLiteral);
                }
                this.context.isAssignmentTarget = false;
                this.context.isBindingElement = false;
                token = this.nextToken();
                raw = this.getTokenRaw(token);
                expr = this.finalize(node, new Node.Literal(token.value, raw));
                break;
            case 1 /* BooleanLiteral */:
                this.context.isAssignmentTarget = false;
                this.context.isBindingElement = false;
                token = this.nextToken();
                raw = this.getTokenRaw(token);
                expr = this.finalize(node, new Node.Literal(token.value === 'true', raw));
                break;
            case 5 /* NullLiteral */:
                this.context.isAssignmentTarget = false;
                this.context.isBindingElement = false;
                token = this.nextToken();
                raw = this.getTokenRaw(token);
                expr = this.finalize(node, new Node.Literal(null, raw));
                break;
            case 10 /* Template */:
                expr = this.parseTemplateLiteral();
                break;
            case 7 /* Punctuator */:
                switch (this.lookahead.value) {
                    case '(':
                        this.context.isBindingElement = false;
                        expr = this.inheritCoverGrammar(this.parseGroupExpression);
                        break;
                    case '[':
                        expr = this.inheritCoverGrammar(this.parseArrayInitializer);
                        break;
                    case '{':
                        expr = this.inheritCoverGrammar(this.parseObjectInitializer);
                        break;
                    case '/':
                    case '/=':
                        this.context.isAssignmentTarget = false;
                        this.context.isBindingElement = false;
                        this.scanner.index = this.startMarker.index;
                        token = this.nextRegexToken();
                        raw = this.getTokenRaw(token);
                        expr = this.finalize(node, new Node.RegexLiteral(token.regex, raw, token.pattern, token.flags));
                        break;
                    default:
                        expr = this.throwUnexpectedToken(this.nextToken());
                }
                break;
            case 4 /* Keyword */:
                if (!this.context.strict && this.context.allowYield && this.matchKeyword('yield')) {
                    expr = this.parseIdentifierName();
                }
                else if (!this.context.strict && this.matchKeyword('let')) {
                    expr = this.finalize(node, new Node.Identifier(this.nextToken().value));
                }
                else {
                    this.context.isAssignmentTarget = false;
                    this.context.isBindingElement = false;
                    if (this.matchKeyword('function')) {
                        expr = this.parseFunctionExpression();
                    }
                    else if (this.matchKeyword('this')) {
                        this.nextToken();
                        expr = this.finalize(node, new Node.ThisExpression());
                    }
                    else if (this.matchKeyword('class')) {
                        expr = this.parseClassExpression();
                    }
                    else {
                        expr = this.throwUnexpectedToken(this.nextToken());
                    }
                }
                break;
            default:
                expr = this.throwUnexpectedToken(this.nextToken());
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-array-initializer
    Parser.prototype.parseSpreadElement = function () {
        var node = this.createNode();
        this.expect('...');
        var arg = this.inheritCoverGrammar(this.parseAssignmentExpression);
        return this.finalize(node, new Node.SpreadElement(arg));
    };
    Parser.prototype.parseArrayInitializer = function () {
        var node = this.createNode();
        var elements = [];
        this.expect('[');
        while (!this.match(']')) {
            if (this.match(',')) {
                this.nextToken();
                elements.push(null);
            }
            else if (this.match('...')) {
                var element = this.parseSpreadElement();
                if (!this.match(']')) {
                    this.context.isAssignmentTarget = false;
                    this.context.isBindingElement = false;
                    this.expect(',');
                }
                elements.push(element);
            }
            else {
                elements.push(this.inheritCoverGrammar(this.parseAssignmentExpression));
                if (!this.match(']')) {
                    this.expect(',');
                }
            }
        }
        this.expect(']');
        return this.finalize(node, new Node.ArrayExpression(elements));
    };
    // https://tc39.github.io/ecma262/#sec-object-initializer
    Parser.prototype.parsePropertyMethod = function (params) {
        this.context.isAssignmentTarget = false;
        this.context.isBindingElement = false;
        var previousStrict = this.context.strict;
        var previousAllowStrictDirective = this.context.allowStrictDirective;
        this.context.allowStrictDirective = params.simple;
        var body = this.isolateCoverGrammar(this.parseFunctionSourceElements);
        if (this.context.strict && params.firstRestricted) {
            this.tolerateUnexpectedToken(params.firstRestricted, params.message);
        }
        if (this.context.strict && params.stricted) {
            this.tolerateUnexpectedToken(params.stricted, params.message);
        }
        this.context.strict = previousStrict;
        this.context.allowStrictDirective = previousAllowStrictDirective;
        return body;
    };
    Parser.prototype.parsePropertyMethodFunction = function () {
        var isGenerator = false;
        var node = this.createNode();
        var previousAllowYield = this.context.allowYield;
        this.context.allowYield = true;
        var params = this.parseFormalParameters();
        var method = this.parsePropertyMethod(params);
        this.context.allowYield = previousAllowYield;
        return this.finalize(node, new Node.FunctionExpression(null, params.params, method, isGenerator));
    };
    Parser.prototype.parsePropertyMethodAsyncFunction = function () {
        var node = this.createNode();
        var previousAllowYield = this.context.allowYield;
        var previousAwait = this.context.await;
        this.context.allowYield = false;
        this.context.await = true;
        var params = this.parseFormalParameters();
        var method = this.parsePropertyMethod(params);
        this.context.allowYield = previousAllowYield;
        this.context.await = previousAwait;
        return this.finalize(node, new Node.AsyncFunctionExpression(null, params.params, method));
    };
    Parser.prototype.parseObjectPropertyKey = function () {
        var node = this.createNode();
        var token = this.nextToken();
        var key;
        switch (token.type) {
            case 8 /* StringLiteral */:
            case 6 /* NumericLiteral */:
                if (this.context.strict && token.octal) {
                    this.tolerateUnexpectedToken(token, messages_1.Messages.StrictOctalLiteral);
                }
                var raw = this.getTokenRaw(token);
                key = this.finalize(node, new Node.Literal(token.value, raw));
                break;
            case 3 /* Identifier */:
            case 1 /* BooleanLiteral */:
            case 5 /* NullLiteral */:
            case 4 /* Keyword */:
                key = this.finalize(node, new Node.Identifier(token.value));
                break;
            case 7 /* Punctuator */:
                if (token.value === '[') {
                    key = this.isolateCoverGrammar(this.parseAssignmentExpression);
                    this.expect(']');
                }
                else {
                    key = this.throwUnexpectedToken(token);
                }
                break;
            default:
                key = this.throwUnexpectedToken(token);
        }
        return key;
    };
    Parser.prototype.isPropertyKey = function (key, value) {
        return (key.type === syntax_1.Syntax.Identifier && key.name === value) ||
            (key.type === syntax_1.Syntax.Literal && key.value === value);
    };
    Parser.prototype.parseObjectProperty = function (hasProto) {
        var node = this.createNode();
        var token = this.lookahead;
        var kind;
        var key = null;
        var value = null;
        var computed = false;
        var method = false;
        var shorthand = false;
        var isAsync = false;
        if (token.type === 3 /* Identifier */) {
            var id = token.value;
            this.nextToken();
            computed = this.match('[');
            isAsync = !this.hasLineTerminator && (id === 'async') &&
                !this.match(':') && !this.match('(') && !this.match('*') && !this.match(',');
            key = isAsync ? this.parseObjectPropertyKey() : this.finalize(node, new Node.Identifier(id));
        }
        else if (this.match('*')) {
            this.nextToken();
        }
        else {
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
        }
        var lookaheadPropertyKey = this.qualifiedPropertyName(this.lookahead);
        if (token.type === 3 /* Identifier */ && !isAsync && token.value === 'get' && lookaheadPropertyKey) {
            kind = 'get';
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
            this.context.allowYield = false;
            value = this.parseGetterMethod();
        }
        else if (token.type === 3 /* Identifier */ && !isAsync && token.value === 'set' && lookaheadPropertyKey) {
            kind = 'set';
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
            value = this.parseSetterMethod();
        }
        else if (token.type === 7 /* Punctuator */ && token.value === '*' && lookaheadPropertyKey) {
            kind = 'init';
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
            value = this.parseGeneratorMethod();
            method = true;
        }
        else {
            if (!key) {
                this.throwUnexpectedToken(this.lookahead);
            }
            kind = 'init';
            if (this.match(':') && !isAsync) {
                if (!computed && this.isPropertyKey(key, '__proto__')) {
                    if (hasProto.value) {
                        this.tolerateError(messages_1.Messages.DuplicateProtoProperty);
                    }
                    hasProto.value = true;
                }
                this.nextToken();
                value = this.inheritCoverGrammar(this.parseAssignmentExpression);
            }
            else if (this.match('(')) {
                value = isAsync ? this.parsePropertyMethodAsyncFunction() : this.parsePropertyMethodFunction();
                method = true;
            }
            else if (token.type === 3 /* Identifier */) {
                var id = this.finalize(node, new Node.Identifier(token.value));
                if (this.match('=')) {
                    this.context.firstCoverInitializedNameError = this.lookahead;
                    this.nextToken();
                    shorthand = true;
                    var init = this.isolateCoverGrammar(this.parseAssignmentExpression);
                    value = this.finalize(node, new Node.AssignmentPattern(id, init));
                }
                else {
                    shorthand = true;
                    value = id;
                }
            }
            else {
                this.throwUnexpectedToken(this.nextToken());
            }
        }
        return this.finalize(node, new Node.Property(kind, key, computed, value, method, shorthand));
    };
    Parser.prototype.parseObjectInitializer = function () {
        var node = this.createNode();
        this.expect('{');
        var properties = [];
        var hasProto = { value: false };
        while (!this.match('}')) {
            properties.push(this.parseObjectProperty(hasProto));
            if (!this.match('}')) {
                this.expectCommaSeparator();
            }
        }
        this.expect('}');
        return this.finalize(node, new Node.ObjectExpression(properties));
    };
    // https://tc39.github.io/ecma262/#sec-template-literals
    Parser.prototype.parseTemplateHead = function () {
        (0, assert_1.assert)(this.lookahead.head, 'Template literal must start with a template head');
        var node = this.createNode();
        var token = this.nextToken();
        var raw = token.value;
        var cooked = token.cooked;
        return this.finalize(node, new Node.TemplateElement({ raw: raw, cooked: cooked }, token.tail));
    };
    Parser.prototype.parseTemplateElement = function () {
        if (this.lookahead.type !== 10 /* Template */) {
            this.throwUnexpectedToken();
        }
        var node = this.createNode();
        var token = this.nextToken();
        var raw = token.value;
        var cooked = token.cooked;
        return this.finalize(node, new Node.TemplateElement({ raw: raw, cooked: cooked }, token.tail));
    };
    Parser.prototype.parseTemplateLiteral = function () {
        var node = this.createNode();
        var expressions = [];
        var quasis = [];
        var quasi = this.parseTemplateHead();
        quasis.push(quasi);
        while (!quasi.tail) {
            expressions.push(this.parseExpression());
            quasi = this.parseTemplateElement();
            quasis.push(quasi);
        }
        return this.finalize(node, new Node.TemplateLiteral(quasis, expressions));
    };
    // https://tc39.github.io/ecma262/#sec-grouping-operator
    Parser.prototype.reinterpretExpressionAsPattern = function (expr) {
        switch (expr.type) {
            case syntax_1.Syntax.Identifier:
            case syntax_1.Syntax.MemberExpression:
            case syntax_1.Syntax.RestElement:
            case syntax_1.Syntax.AssignmentPattern:
                break;
            case syntax_1.Syntax.SpreadElement:
                expr.type = syntax_1.Syntax.RestElement;
                this.reinterpretExpressionAsPattern(expr.argument);
                break;
            case syntax_1.Syntax.ArrayExpression:
                expr.type = syntax_1.Syntax.ArrayPattern;
                for (var i = 0; i < expr.elements.length; i++) {
                    if (expr.elements[i] !== null) {
                        this.reinterpretExpressionAsPattern(expr.elements[i]);
                    }
                }
                break;
            case syntax_1.Syntax.ObjectExpression:
                expr.type = syntax_1.Syntax.ObjectPattern;
                for (var i = 0; i < expr.properties.length; i++) {
                    this.reinterpretExpressionAsPattern(expr.properties[i].value);
                }
                break;
            case syntax_1.Syntax.AssignmentExpression:
                expr.type = syntax_1.Syntax.AssignmentPattern;
                delete expr.operator;
                this.reinterpretExpressionAsPattern(expr.left);
                break;
            default:
                // Allow other node type for tolerant parsing.
                break;
        }
    };
    Parser.prototype.parseGroupExpression = function () {
        var expr;
        this.expect('(');
        if (this.match(')')) {
            this.nextToken();
            if (!this.match('=>')) {
                this.expect('=>');
            }
            expr = {
                type: ArrowParameterPlaceHolder,
                params: [],
                async: false
            };
        }
        else {
            var startToken = this.lookahead;
            var params = [];
            if (this.match('...')) {
                expr = this.parseRestElement(params);
                this.expect(')');
                if (!this.match('=>')) {
                    this.expect('=>');
                }
                expr = {
                    type: ArrowParameterPlaceHolder,
                    params: [expr],
                    async: false
                };
            }
            else {
                var arrow = false;
                this.context.isBindingElement = true;
                expr = this.inheritCoverGrammar(this.parseAssignmentExpression);
                if (this.match(',')) {
                    var expressions = [];
                    this.context.isAssignmentTarget = false;
                    expressions.push(expr);
                    while (this.lookahead.type !== 2 /* EOF */) {
                        if (!this.match(',')) {
                            break;
                        }
                        this.nextToken();
                        if (this.match(')')) {
                            this.nextToken();
                            for (var i = 0; i < expressions.length; i++) {
                                this.reinterpretExpressionAsPattern(expressions[i]);
                            }
                            arrow = true;
                            expr = {
                                type: ArrowParameterPlaceHolder,
                                params: expressions,
                                async: false
                            };
                        }
                        else if (this.match('...')) {
                            if (!this.context.isBindingElement) {
                                this.throwUnexpectedToken(this.lookahead);
                            }
                            expressions.push(this.parseRestElement(params));
                            this.expect(')');
                            if (!this.match('=>')) {
                                this.expect('=>');
                            }
                            this.context.isBindingElement = false;
                            for (var i = 0; i < expressions.length; i++) {
                                this.reinterpretExpressionAsPattern(expressions[i]);
                            }
                            arrow = true;
                            expr = {
                                type: ArrowParameterPlaceHolder,
                                params: expressions,
                                async: false
                            };
                        }
                        else {
                            expressions.push(this.inheritCoverGrammar(this.parseAssignmentExpression));
                        }
                        if (arrow) {
                            break;
                        }
                    }
                    if (!arrow) {
                        expr = this.finalize(this.startNode(startToken), new Node.SequenceExpression(expressions));
                    }
                }
                if (!arrow) {
                    this.expect(')');
                    if (this.match('=>')) {
                        if (expr.type === syntax_1.Syntax.Identifier && expr.name === 'yield') {
                            arrow = true;
                            expr = {
                                type: ArrowParameterPlaceHolder,
                                params: [expr],
                                async: false
                            };
                        }
                        if (!arrow) {
                            if (!this.context.isBindingElement) {
                                this.throwUnexpectedToken(this.lookahead);
                            }
                            if (expr.type === syntax_1.Syntax.SequenceExpression) {
                                for (var i = 0; i < expr.expressions.length; i++) {
                                    this.reinterpretExpressionAsPattern(expr.expressions[i]);
                                }
                            }
                            else {
                                this.reinterpretExpressionAsPattern(expr);
                            }
                            var parameters = (expr.type === syntax_1.Syntax.SequenceExpression ? expr.expressions : [expr]);
                            expr = {
                                type: ArrowParameterPlaceHolder,
                                params: parameters,
                                async: false
                            };
                        }
                    }
                    this.context.isBindingElement = false;
                }
            }
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-left-hand-side-expressions
    Parser.prototype.parseArguments = function () {
        this.expect('(');
        var args = [];
        if (!this.match(')')) {
            while (true) {
                var expr = this.match('...') ? this.parseSpreadElement() :
                    this.isolateCoverGrammar(this.parseAssignmentExpression);
                args.push(expr);
                if (this.match(')')) {
                    break;
                }
                this.expectCommaSeparator();
                if (this.match(')')) {
                    break;
                }
            }
        }
        this.expect(')');
        return args;
    };
    Parser.prototype.isIdentifierName = function (token) {
        return token.type === 3 /* Identifier */ ||
            token.type === 4 /* Keyword */ ||
            token.type === 1 /* BooleanLiteral */ ||
            token.type === 5 /* NullLiteral */;
    };
    Parser.prototype.parseIdentifierName = function () {
        var node = this.createNode();
        var token = this.nextToken();
        if (!this.isIdentifierName(token)) {
            this.throwUnexpectedToken(token);
        }
        return this.finalize(node, new Node.Identifier(token.value));
    };
    Parser.prototype.parseNewExpression = function () {
        var node = this.createNode();
        var id = this.parseIdentifierName();
        (0, assert_1.assert)(id.name === 'new', 'New expression must start with `new`');
        var expr;
        if (this.match('.')) {
            this.nextToken();
            if (this.lookahead.type === 3 /* Identifier */ && this.context.inFunctionBody && this.lookahead.value === 'target') {
                var property = this.parseIdentifierName();
                expr = new Node.MetaProperty(id, property);
            }
            else {
                this.throwUnexpectedToken(this.lookahead);
            }
        }
        else {
            var callee = this.isolateCoverGrammar(this.parseLeftHandSideExpression);
            var args = this.match('(') ? this.parseArguments() : [];
            expr = new Node.NewExpression(callee, args);
            this.context.isAssignmentTarget = false;
            this.context.isBindingElement = false;
        }
        return this.finalize(node, expr);
    };
    Parser.prototype.parseAsyncArgument = function () {
        var arg = this.parseAssignmentExpression();
        this.context.firstCoverInitializedNameError = null;
        return arg;
    };
    Parser.prototype.parseAsyncArguments = function () {
        this.expect('(');
        var args = [];
        if (!this.match(')')) {
            while (true) {
                var expr = this.match('...') ? this.parseSpreadElement() :
                    this.isolateCoverGrammar(this.parseAsyncArgument);
                args.push(expr);
                if (this.match(')')) {
                    break;
                }
                this.expectCommaSeparator();
                if (this.match(')')) {
                    break;
                }
            }
        }
        this.expect(')');
        return args;
    };
    Parser.prototype.parseLeftHandSideExpressionAllowCall = function () {
        var startToken = this.lookahead;
        var maybeAsync = this.matchContextualKeyword('async');
        var previousAllowIn = this.context.allowIn;
        this.context.allowIn = true;
        var expr;
        if (this.matchKeyword('super') && this.context.inFunctionBody) {
            expr = this.createNode();
            this.nextToken();
            expr = this.finalize(expr, new Node.Super());
            if (!this.match('(') && !this.match('.') && !this.match('[')) {
                this.throwUnexpectedToken(this.lookahead);
            }
        }
        else {
            expr = this.inheritCoverGrammar(this.matchKeyword('new') ? this.parseNewExpression : this.parsePrimaryExpression);
        }
        while (true) {
            if (this.match('.')) {
                this.context.isBindingElement = false;
                this.context.isAssignmentTarget = true;
                this.expect('.');
                var property = this.parseIdentifierName();
                expr = this.finalize(this.startNode(startToken), new Node.StaticMemberExpression(expr, property));
            }
            else if (this.match('(')) {
                var asyncArrow = maybeAsync && (startToken.lineNumber === this.lookahead.lineNumber);
                this.context.isBindingElement = false;
                this.context.isAssignmentTarget = false;
                var args = asyncArrow ? this.parseAsyncArguments() : this.parseArguments();
                expr = this.finalize(this.startNode(startToken), new Node.CallExpression(expr, args));
                if (asyncArrow && this.match('=>')) {
                    for (var i = 0; i < args.length; ++i) {
                        this.reinterpretExpressionAsPattern(args[i]);
                    }
                    expr = {
                        type: ArrowParameterPlaceHolder,
                        params: args,
                        async: true
                    };
                }
            }
            else if (this.match('[')) {
                this.context.isBindingElement = false;
                this.context.isAssignmentTarget = true;
                this.expect('[');
                var property = this.isolateCoverGrammar(this.parseExpression);
                this.expect(']');
                expr = this.finalize(this.startNode(startToken), new Node.ComputedMemberExpression(expr, property));
            }
            else if (this.lookahead.type === 10 /* Template */ && this.lookahead.head) {
                var quasi = this.parseTemplateLiteral();
                expr = this.finalize(this.startNode(startToken), new Node.TaggedTemplateExpression(expr, quasi));
            }
            else {
                break;
            }
        }
        this.context.allowIn = previousAllowIn;
        return expr;
    };
    Parser.prototype.parseSuper = function () {
        var node = this.createNode();
        this.expectKeyword('super');
        if (!this.match('[') && !this.match('.')) {
            this.throwUnexpectedToken(this.lookahead);
        }
        return this.finalize(node, new Node.Super());
    };
    Parser.prototype.parseLeftHandSideExpression = function () {
        (0, assert_1.assert)(this.context.allowIn, 'callee of new expression always allow in keyword.');
        var node = this.startNode(this.lookahead);
        var expr = (this.matchKeyword('super') && this.context.inFunctionBody) ? this.parseSuper() :
            this.inheritCoverGrammar(this.matchKeyword('new') ? this.parseNewExpression : this.parsePrimaryExpression);
        while (true) {
            if (this.match('[')) {
                this.context.isBindingElement = false;
                this.context.isAssignmentTarget = true;
                this.expect('[');
                var property = this.isolateCoverGrammar(this.parseExpression);
                this.expect(']');
                expr = this.finalize(node, new Node.ComputedMemberExpression(expr, property));
            }
            else if (this.match('.')) {
                this.context.isBindingElement = false;
                this.context.isAssignmentTarget = true;
                this.expect('.');
                var property = this.parseIdentifierName();
                expr = this.finalize(node, new Node.StaticMemberExpression(expr, property));
            }
            else if (this.lookahead.type === 10 /* Template */ && this.lookahead.head) {
                var quasi = this.parseTemplateLiteral();
                expr = this.finalize(node, new Node.TaggedTemplateExpression(expr, quasi));
            }
            else {
                break;
            }
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-update-expressions
    Parser.prototype.parseUpdateExpression = function () {
        var expr;
        var startToken = this.lookahead;
        if (this.match('++') || this.match('--')) {
            var node = this.startNode(startToken);
            var token = this.nextToken();
            expr = this.inheritCoverGrammar(this.parseUnaryExpression);
            if (this.context.strict && expr.type === syntax_1.Syntax.Identifier && this.scanner.isRestrictedWord(expr.name)) {
                this.tolerateError(messages_1.Messages.StrictLHSPrefix);
            }
            if (!this.context.isAssignmentTarget) {
                this.tolerateError(messages_1.Messages.InvalidLHSInAssignment);
            }
            var prefix = true;
            expr = this.finalize(node, new Node.UpdateExpression(token.value, expr, prefix));
            this.context.isAssignmentTarget = false;
            this.context.isBindingElement = false;
        }
        else {
            expr = this.inheritCoverGrammar(this.parseLeftHandSideExpressionAllowCall);
            if (!this.hasLineTerminator && this.lookahead.type === 7 /* Punctuator */) {
                if (this.match('++') || this.match('--')) {
                    if (this.context.strict && expr.type === syntax_1.Syntax.Identifier && this.scanner.isRestrictedWord(expr.name)) {
                        this.tolerateError(messages_1.Messages.StrictLHSPostfix);
                    }
                    if (!this.context.isAssignmentTarget) {
                        this.tolerateError(messages_1.Messages.InvalidLHSInAssignment);
                    }
                    this.context.isAssignmentTarget = false;
                    this.context.isBindingElement = false;
                    var operator = this.nextToken().value;
                    var prefix = false;
                    expr = this.finalize(this.startNode(startToken), new Node.UpdateExpression(operator, expr, prefix));
                }
            }
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-unary-operators
    Parser.prototype.parseAwaitExpression = function () {
        var node = this.createNode();
        this.nextToken();
        var argument = this.parseUnaryExpression();
        return this.finalize(node, new Node.AwaitExpression(argument));
    };
    Parser.prototype.parseUnaryExpression = function () {
        var expr;
        if (this.match('+') || this.match('-') || this.match('~') || this.match('!') ||
            this.matchKeyword('delete') || this.matchKeyword('void') || this.matchKeyword('typeof')) {
            var node = this.startNode(this.lookahead);
            var token = this.nextToken();
            expr = this.inheritCoverGrammar(this.parseUnaryExpression);
            expr = this.finalize(node, new Node.UnaryExpression(token.value, expr));
            if (this.context.strict && expr.operator === 'delete' && expr.argument.type === syntax_1.Syntax.Identifier) {
                this.tolerateError(messages_1.Messages.StrictDelete);
            }
            this.context.isAssignmentTarget = false;
            this.context.isBindingElement = false;
        }
        else if (this.context.await && this.matchContextualKeyword('await')) {
            expr = this.parseAwaitExpression();
        }
        else {
            expr = this.parseUpdateExpression();
        }
        return expr;
    };
    Parser.prototype.parseExponentiationExpression = function () {
        var startToken = this.lookahead;
        var expr = this.inheritCoverGrammar(this.parseUnaryExpression);
        if (expr.type !== syntax_1.Syntax.UnaryExpression && this.match('**')) {
            this.nextToken();
            this.context.isAssignmentTarget = false;
            this.context.isBindingElement = false;
            var left = expr;
            var right = this.isolateCoverGrammar(this.parseExponentiationExpression);
            expr = this.finalize(this.startNode(startToken), new Node.BinaryExpression('**', left, right));
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-exp-operator
    // https://tc39.github.io/ecma262/#sec-multiplicative-operators
    // https://tc39.github.io/ecma262/#sec-additive-operators
    // https://tc39.github.io/ecma262/#sec-bitwise-shift-operators
    // https://tc39.github.io/ecma262/#sec-relational-operators
    // https://tc39.github.io/ecma262/#sec-equality-operators
    // https://tc39.github.io/ecma262/#sec-binary-bitwise-operators
    // https://tc39.github.io/ecma262/#sec-binary-logical-operators
    Parser.prototype.binaryPrecedence = function (token) {
        var op = token.value;
        var precedence;
        if (token.type === 7 /* Punctuator */) {
            precedence = this.operatorPrecedence[op] || 0;
        }
        else if (token.type === 4 /* Keyword */) {
            precedence = (op === 'instanceof' || (this.context.allowIn && op === 'in')) ? 7 : 0;
        }
        else {
            precedence = 0;
        }
        return precedence;
    };
    Parser.prototype.parseBinaryExpression = function () {
        var startToken = this.lookahead;
        var expr = this.inheritCoverGrammar(this.parseExponentiationExpression);
        var token = this.lookahead;
        var prec = this.binaryPrecedence(token);
        if (prec > 0) {
            this.nextToken();
            this.context.isAssignmentTarget = false;
            this.context.isBindingElement = false;
            var markers = [startToken, this.lookahead];
            var left = expr;
            var right = this.isolateCoverGrammar(this.parseExponentiationExpression);
            var stack = [left, token.value, right];
            var precedences = [prec];
            while (true) {
                prec = this.binaryPrecedence(this.lookahead);
                if (prec <= 0) {
                    break;
                }
                // Reduce: make a binary expression from the three topmost entries.
                while ((stack.length > 2) && (prec <= precedences[precedences.length - 1])) {
                    right = stack.pop();
                    var operator = stack.pop();
                    precedences.pop();
                    left = stack.pop();
                    markers.pop();
                    var node = this.startNode(markers[markers.length - 1]);
                    stack.push(this.finalize(node, new Node.BinaryExpression(operator, left, right)));
                }
                // Shift.
                stack.push(this.nextToken().value);
                precedences.push(prec);
                markers.push(this.lookahead);
                stack.push(this.isolateCoverGrammar(this.parseExponentiationExpression));
            }
            // Final reduce to clean-up the stack.
            var i = stack.length - 1;
            expr = stack[i];
            var lastMarker = markers.pop();
            while (i > 1) {
                var marker = markers.pop();
                var lastLineStart = lastMarker && lastMarker.lineStart;
                var node = this.startNode(marker, lastLineStart);
                var operator = stack[i - 1];
                expr = this.finalize(node, new Node.BinaryExpression(operator, stack[i - 2], expr));
                i -= 2;
                lastMarker = marker;
            }
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-conditional-operator
    Parser.prototype.parseConditionalExpression = function () {
        var startToken = this.lookahead;
        var expr = this.inheritCoverGrammar(this.parseBinaryExpression);
        if (this.match('?')) {
            this.nextToken();
            var previousAllowIn = this.context.allowIn;
            this.context.allowIn = true;
            var consequent = this.isolateCoverGrammar(this.parseAssignmentExpression);
            this.context.allowIn = previousAllowIn;
            this.expect(':');
            var alternate = this.isolateCoverGrammar(this.parseAssignmentExpression);
            expr = this.finalize(this.startNode(startToken), new Node.ConditionalExpression(expr, consequent, alternate));
            this.context.isAssignmentTarget = false;
            this.context.isBindingElement = false;
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-assignment-operators
    Parser.prototype.checkPatternParam = function (options, param) {
        switch (param.type) {
            case syntax_1.Syntax.Identifier:
                this.validateParam(options, param, param.name);
                break;
            case syntax_1.Syntax.RestElement:
                this.checkPatternParam(options, param.argument);
                break;
            case syntax_1.Syntax.AssignmentPattern:
                this.checkPatternParam(options, param.left);
                break;
            case syntax_1.Syntax.ArrayPattern:
                for (var i = 0; i < param.elements.length; i++) {
                    if (param.elements[i] !== null) {
                        this.checkPatternParam(options, param.elements[i]);
                    }
                }
                break;
            case syntax_1.Syntax.ObjectPattern:
                for (var i = 0; i < param.properties.length; i++) {
                    this.checkPatternParam(options, param.properties[i].value);
                }
                break;
            default:
                break;
        }
        options.simple = options.simple && (param instanceof Node.Identifier);
    };
    Parser.prototype.reinterpretAsCoverFormalsList = function (expr) {
        var params = [expr];
        var options;
        var asyncArrow = false;
        switch (expr.type) {
            case syntax_1.Syntax.Identifier:
                break;
            case ArrowParameterPlaceHolder:
                params = expr.params;
                asyncArrow = expr.async;
                break;
            default:
                return null;
        }
        options = {
            simple: true,
            paramSet: {}
        };
        for (var i = 0; i < params.length; ++i) {
            var param = params[i];
            if (param.type === syntax_1.Syntax.AssignmentPattern) {
                if (param.right.type === syntax_1.Syntax.YieldExpression) {
                    if (param.right.argument) {
                        this.throwUnexpectedToken(this.lookahead);
                    }
                    param.right.type = syntax_1.Syntax.Identifier;
                    param.right.name = 'yield';
                    delete param.right.argument;
                    delete param.right.delegate;
                }
            }
            else if (asyncArrow && param.type === syntax_1.Syntax.Identifier && param.name === 'await') {
                this.throwUnexpectedToken(this.lookahead);
            }
            this.checkPatternParam(options, param);
            params[i] = param;
        }
        if (this.context.strict || !this.context.allowYield) {
            for (var i = 0; i < params.length; ++i) {
                var param = params[i];
                if (param.type === syntax_1.Syntax.YieldExpression) {
                    this.throwUnexpectedToken(this.lookahead);
                }
            }
        }
        if (options.message === messages_1.Messages.StrictParamDupe) {
            var token = this.context.strict ? options.stricted : options.firstRestricted;
            this.throwUnexpectedToken(token, options.message);
        }
        return {
            simple: options.simple,
            params: params,
            stricted: options.stricted,
            firstRestricted: options.firstRestricted,
            message: options.message
        };
    };
    Parser.prototype.parseAssignmentExpression = function () {
        var expr;
        if (!this.context.allowYield && this.matchKeyword('yield')) {
            expr = this.parseYieldExpression();
        }
        else {
            var startToken = this.lookahead;
            var token = startToken;
            expr = this.parseConditionalExpression();
            if (token.type === 3 /* Identifier */ && (token.lineNumber === this.lookahead.lineNumber) && token.value === 'async') {
                if (this.lookahead.type === 3 /* Identifier */ || this.matchKeyword('yield')) {
                    var arg = this.parsePrimaryExpression();
                    this.reinterpretExpressionAsPattern(arg);
                    expr = {
                        type: ArrowParameterPlaceHolder,
                        params: [arg],
                        async: true
                    };
                }
            }
            if (expr.type === ArrowParameterPlaceHolder || this.match('=>')) {
                // https://tc39.github.io/ecma262/#sec-arrow-function-definitions
                this.context.isAssignmentTarget = false;
                this.context.isBindingElement = false;
                var isAsync = expr.async;
                var list = this.reinterpretAsCoverFormalsList(expr);
                if (list) {
                    if (this.hasLineTerminator) {
                        this.tolerateUnexpectedToken(this.lookahead);
                    }
                    this.context.firstCoverInitializedNameError = null;
                    var previousStrict = this.context.strict;
                    var previousAllowStrictDirective = this.context.allowStrictDirective;
                    this.context.allowStrictDirective = list.simple;
                    var previousAllowYield = this.context.allowYield;
                    var previousAwait = this.context.await;
                    this.context.allowYield = true;
                    this.context.await = isAsync;
                    var node = this.startNode(startToken);
                    this.expect('=>');
                    var body = void 0;
                    if (this.match('{')) {
                        var previousAllowIn = this.context.allowIn;
                        this.context.allowIn = true;
                        body = this.parseFunctionSourceElements();
                        this.context.allowIn = previousAllowIn;
                    }
                    else {
                        body = this.isolateCoverGrammar(this.parseAssignmentExpression);
                    }
                    var expression = body.type !== syntax_1.Syntax.BlockStatement;
                    if (this.context.strict && list.firstRestricted) {
                        this.throwUnexpectedToken(list.firstRestricted, list.message);
                    }
                    if (this.context.strict && list.stricted) {
                        this.tolerateUnexpectedToken(list.stricted, list.message);
                    }
                    expr = isAsync ? this.finalize(node, new Node.AsyncArrowFunctionExpression(list.params, body, expression)) :
                        this.finalize(node, new Node.ArrowFunctionExpression(list.params, body, expression));
                    this.context.strict = previousStrict;
                    this.context.allowStrictDirective = previousAllowStrictDirective;
                    this.context.allowYield = previousAllowYield;
                    this.context.await = previousAwait;
                }
            }
            else {
                if (this.matchAssign()) {
                    if (!this.context.isAssignmentTarget) {
                        this.tolerateError(messages_1.Messages.InvalidLHSInAssignment);
                    }
                    if (this.context.strict && expr.type === syntax_1.Syntax.Identifier) {
                        var id = expr;
                        if (this.scanner.isRestrictedWord(id.name)) {
                            this.tolerateUnexpectedToken(token, messages_1.Messages.StrictLHSAssignment);
                        }
                        if (this.scanner.isStrictModeReservedWord(id.name)) {
                            this.tolerateUnexpectedToken(token, messages_1.Messages.StrictReservedWord);
                        }
                    }
                    if (!this.match('=')) {
                        this.context.isAssignmentTarget = false;
                        this.context.isBindingElement = false;
                    }
                    else {
                        this.reinterpretExpressionAsPattern(expr);
                    }
                    token = this.nextToken();
                    var operator = token.value;
                    var right = this.isolateCoverGrammar(this.parseAssignmentExpression);
                    expr = this.finalize(this.startNode(startToken), new Node.AssignmentExpression(operator, expr, right));
                    this.context.firstCoverInitializedNameError = null;
                }
            }
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-comma-operator
    Parser.prototype.parseExpression = function () {
        var startToken = this.lookahead;
        var expr = this.isolateCoverGrammar(this.parseAssignmentExpression);
        if (this.match(',')) {
            var expressions = [];
            expressions.push(expr);
            while (this.lookahead.type !== 2 /* EOF */) {
                if (!this.match(',')) {
                    break;
                }
                this.nextToken();
                expressions.push(this.isolateCoverGrammar(this.parseAssignmentExpression));
            }
            expr = this.finalize(this.startNode(startToken), new Node.SequenceExpression(expressions));
        }
        return expr;
    };
    // https://tc39.github.io/ecma262/#sec-block
    Parser.prototype.parseStatementListItem = function () {
        var statement;
        this.context.isAssignmentTarget = true;
        this.context.isBindingElement = true;
        if (this.lookahead.type === 4 /* Keyword */) {
            switch (this.lookahead.value) {
                case 'export':
                    if (!this.context.isModule) {
                        this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.IllegalExportDeclaration);
                    }
                    statement = this.parseExportDeclaration();
                    break;
                case 'import':
                    if (!this.context.isModule) {
                        this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.IllegalImportDeclaration);
                    }
                    statement = this.parseImportDeclaration();
                    break;
                case 'const':
                    statement = this.parseLexicalDeclaration({ inFor: false });
                    break;
                case 'function':
                    statement = this.parseFunctionDeclaration();
                    break;
                case 'class':
                    statement = this.parseClassDeclaration();
                    break;
                case 'let':
                    statement = this.isLexicalDeclaration() ? this.parseLexicalDeclaration({ inFor: false }) : this.parseStatement();
                    break;
                default:
                    statement = this.parseStatement();
                    break;
            }
        }
        else {
            statement = this.parseStatement();
        }
        return statement;
    };
    Parser.prototype.parseBlock = function () {
        var node = this.createNode();
        this.expect('{');
        var block = [];
        while (true) {
            if (this.match('}')) {
                break;
            }
            block.push(this.parseStatementListItem());
        }
        this.expect('}');
        return this.finalize(node, new Node.BlockStatement(block));
    };
    // https://tc39.github.io/ecma262/#sec-let-and-const-declarations
    Parser.prototype.parseLexicalBinding = function (kind, options) {
        var node = this.createNode();
        var params = [];
        var id = this.parsePattern(params, kind);
        if (this.context.strict && id.type === syntax_1.Syntax.Identifier) {
            if (this.scanner.isRestrictedWord(id.name)) {
                this.tolerateError(messages_1.Messages.StrictVarName);
            }
        }
        var init = null;
        if (kind === 'const') {
            if (!this.matchKeyword('in') && !this.matchContextualKeyword('of')) {
                if (this.match('=')) {
                    this.nextToken();
                    init = this.isolateCoverGrammar(this.parseAssignmentExpression);
                }
                else {
                    this.throwError(messages_1.Messages.DeclarationMissingInitializer, 'const');
                }
            }
        }
        else if ((!options.inFor && id.type !== syntax_1.Syntax.Identifier) || this.match('=')) {
            this.expect('=');
            init = this.isolateCoverGrammar(this.parseAssignmentExpression);
        }
        return this.finalize(node, new Node.VariableDeclarator(id, init));
    };
    Parser.prototype.parseBindingList = function (kind, options) {
        var list = [this.parseLexicalBinding(kind, options)];
        while (this.match(',')) {
            this.nextToken();
            list.push(this.parseLexicalBinding(kind, options));
        }
        return list;
    };
    Parser.prototype.isLexicalDeclaration = function () {
        var state = this.scanner.saveState();
        this.scanner.scanComments();
        var next = this.scanner.lex();
        this.scanner.restoreState(state);
        return (next.type === 3 /* Identifier */) ||
            (next.type === 7 /* Punctuator */ && next.value === '[') ||
            (next.type === 7 /* Punctuator */ && next.value === '{') ||
            (next.type === 4 /* Keyword */ && next.value === 'let') ||
            (next.type === 4 /* Keyword */ && next.value === 'yield');
    };
    Parser.prototype.parseLexicalDeclaration = function (options) {
        var node = this.createNode();
        var kind = this.nextToken().value;
        (0, assert_1.assert)(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');
        var declarations = this.parseBindingList(kind, options);
        this.consumeSemicolon();
        return this.finalize(node, new Node.VariableDeclaration(declarations, kind));
    };
    // https://tc39.github.io/ecma262/#sec-destructuring-binding-patterns
    Parser.prototype.parseBindingRestElement = function (params, kind) {
        var node = this.createNode();
        this.expect('...');
        var arg = this.parsePattern(params, kind);
        return this.finalize(node, new Node.RestElement(arg));
    };
    Parser.prototype.parseArrayPattern = function (params, kind) {
        var node = this.createNode();
        this.expect('[');
        var elements = [];
        while (!this.match(']')) {
            if (this.match(',')) {
                this.nextToken();
                elements.push(null);
            }
            else {
                if (this.match('...')) {
                    elements.push(this.parseBindingRestElement(params, kind));
                    break;
                }
                else {
                    elements.push(this.parsePatternWithDefault(params, kind));
                }
                if (!this.match(']')) {
                    this.expect(',');
                }
            }
        }
        this.expect(']');
        return this.finalize(node, new Node.ArrayPattern(elements));
    };
    Parser.prototype.parsePropertyPattern = function (params, kind) {
        var node = this.createNode();
        var computed = false;
        var shorthand = false;
        var method = false;
        var key;
        var value;
        if (this.lookahead.type === 3 /* Identifier */) {
            var keyToken = this.lookahead;
            key = this.parseVariableIdentifier();
            var init = this.finalize(node, new Node.Identifier(keyToken.value));
            if (this.match('=')) {
                params.push(keyToken);
                shorthand = true;
                this.nextToken();
                var expr = this.parseAssignmentExpression();
                value = this.finalize(this.startNode(keyToken), new Node.AssignmentPattern(init, expr));
            }
            else if (!this.match(':')) {
                params.push(keyToken);
                shorthand = true;
                value = init;
            }
            else {
                this.expect(':');
                value = this.parsePatternWithDefault(params, kind);
            }
        }
        else {
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
            this.expect(':');
            value = this.parsePatternWithDefault(params, kind);
        }
        return this.finalize(node, new Node.Property('init', key, computed, value, method, shorthand));
    };
    Parser.prototype.parseObjectPattern = function (params, kind) {
        var node = this.createNode();
        var properties = [];
        this.expect('{');
        while (!this.match('}')) {
            properties.push(this.parsePropertyPattern(params, kind));
            if (!this.match('}')) {
                this.expect(',');
            }
        }
        this.expect('}');
        return this.finalize(node, new Node.ObjectPattern(properties));
    };
    Parser.prototype.parsePattern = function (params, kind) {
        var pattern;
        if (this.match('[')) {
            pattern = this.parseArrayPattern(params, kind);
        }
        else if (this.match('{')) {
            pattern = this.parseObjectPattern(params, kind);
        }
        else {
            if (this.matchKeyword('let') && (kind === 'const' || kind === 'let')) {
                this.tolerateUnexpectedToken(this.lookahead, messages_1.Messages.LetInLexicalBinding);
            }
            params.push(this.lookahead);
            pattern = this.parseVariableIdentifier(kind);
        }
        return pattern;
    };
    Parser.prototype.parsePatternWithDefault = function (params, kind) {
        var startToken = this.lookahead;
        var pattern = this.parsePattern(params, kind);
        if (this.match('=')) {
            this.nextToken();
            var previousAllowYield = this.context.allowYield;
            this.context.allowYield = true;
            var right = this.isolateCoverGrammar(this.parseAssignmentExpression);
            this.context.allowYield = previousAllowYield;
            pattern = this.finalize(this.startNode(startToken), new Node.AssignmentPattern(pattern, right));
        }
        return pattern;
    };
    // https://tc39.github.io/ecma262/#sec-variable-statement
    Parser.prototype.parseVariableIdentifier = function (kind) {
        var node = this.createNode();
        var token = this.nextToken();
        if (token.type === 4 /* Keyword */ && token.value === 'yield') {
            if (this.context.strict) {
                this.tolerateUnexpectedToken(token, messages_1.Messages.StrictReservedWord);
            }
            else if (!this.context.allowYield) {
                this.throwUnexpectedToken(token);
            }
        }
        else if (token.type !== 3 /* Identifier */) {
            if (this.context.strict && token.type === 4 /* Keyword */ && this.scanner.isStrictModeReservedWord(token.value)) {
                this.tolerateUnexpectedToken(token, messages_1.Messages.StrictReservedWord);
            }
            else {
                if (this.context.strict || token.value !== 'let' || kind !== 'var') {
                    this.throwUnexpectedToken(token);
                }
            }
        }
        else if ((this.context.isModule || this.context.await) && token.type === 3 /* Identifier */ && token.value === 'await') {
            this.tolerateUnexpectedToken(token);
        }
        return this.finalize(node, new Node.Identifier(token.value));
    };
    Parser.prototype.parseVariableDeclaration = function (options) {
        var node = this.createNode();
        var params = [];
        var id = this.parsePattern(params, 'var');
        if (this.context.strict && id.type === syntax_1.Syntax.Identifier) {
            if (this.scanner.isRestrictedWord(id.name)) {
                this.tolerateError(messages_1.Messages.StrictVarName);
            }
        }
        var init = null;
        if (this.match('=')) {
            this.nextToken();
            init = this.isolateCoverGrammar(this.parseAssignmentExpression);
        }
        else if (id.type !== syntax_1.Syntax.Identifier && !options.inFor) {
            this.expect('=');
        }
        return this.finalize(node, new Node.VariableDeclarator(id, init));
    };
    Parser.prototype.parseVariableDeclarationList = function (options) {
        var opt = { inFor: options.inFor };
        var list = [];
        list.push(this.parseVariableDeclaration(opt));
        while (this.match(',')) {
            this.nextToken();
            list.push(this.parseVariableDeclaration(opt));
        }
        return list;
    };
    Parser.prototype.parseVariableStatement = function () {
        var node = this.createNode();
        this.expectKeyword('var');
        var declarations = this.parseVariableDeclarationList({ inFor: false });
        this.consumeSemicolon();
        return this.finalize(node, new Node.VariableDeclaration(declarations, 'var'));
    };
    // https://tc39.github.io/ecma262/#sec-empty-statement
    Parser.prototype.parseEmptyStatement = function () {
        var node = this.createNode();
        this.expect(';');
        return this.finalize(node, new Node.EmptyStatement());
    };
    // https://tc39.github.io/ecma262/#sec-expression-statement
    Parser.prototype.parseExpressionStatement = function () {
        var node = this.createNode();
        var expr = this.parseExpression();
        this.consumeSemicolon();
        return this.finalize(node, new Node.ExpressionStatement(expr));
    };
    // https://tc39.github.io/ecma262/#sec-if-statement
    Parser.prototype.parseIfClause = function () {
        if (this.context.strict && this.matchKeyword('function')) {
            this.tolerateError(messages_1.Messages.StrictFunction);
        }
        return this.parseStatement();
    };
    Parser.prototype.parseIfStatement = function () {
        var node = this.createNode();
        var consequent;
        var alternate = null;
        this.expectKeyword('if');
        this.expect('(');
        var test = this.parseExpression();
        if (!this.match(')') && this.config.tolerant) {
            this.tolerateUnexpectedToken(this.nextToken());
            consequent = this.finalize(this.createNode(), new Node.EmptyStatement());
        }
        else {
            this.expect(')');
            consequent = this.parseIfClause();
            if (this.matchKeyword('else')) {
                this.nextToken();
                alternate = this.parseIfClause();
            }
        }
        return this.finalize(node, new Node.IfStatement(test, consequent, alternate));
    };
    // https://tc39.github.io/ecma262/#sec-do-while-statement
    Parser.prototype.parseDoWhileStatement = function () {
        var node = this.createNode();
        this.expectKeyword('do');
        var previousInIteration = this.context.inIteration;
        this.context.inIteration = true;
        var body = this.parseStatement();
        this.context.inIteration = previousInIteration;
        this.expectKeyword('while');
        this.expect('(');
        var test = this.parseExpression();
        if (!this.match(')') && this.config.tolerant) {
            this.tolerateUnexpectedToken(this.nextToken());
        }
        else {
            this.expect(')');
            if (this.match(';')) {
                this.nextToken();
            }
        }
        return this.finalize(node, new Node.DoWhileStatement(body, test));
    };
    // https://tc39.github.io/ecma262/#sec-while-statement
    Parser.prototype.parseWhileStatement = function () {
        var node = this.createNode();
        var body;
        this.expectKeyword('while');
        this.expect('(');
        var test = this.parseExpression();
        if (!this.match(')') && this.config.tolerant) {
            this.tolerateUnexpectedToken(this.nextToken());
            body = this.finalize(this.createNode(), new Node.EmptyStatement());
        }
        else {
            this.expect(')');
            var previousInIteration = this.context.inIteration;
            this.context.inIteration = true;
            body = this.parseStatement();
            this.context.inIteration = previousInIteration;
        }
        return this.finalize(node, new Node.WhileStatement(test, body));
    };
    // https://tc39.github.io/ecma262/#sec-for-statement
    // https://tc39.github.io/ecma262/#sec-for-in-and-for-of-statements
    Parser.prototype.parseForStatement = function () {
        var init = null;
        var test = null;
        var update = null;
        var forIn = true;
        var left, right;
        var node = this.createNode();
        this.expectKeyword('for');
        this.expect('(');
        if (this.match(';')) {
            this.nextToken();
        }
        else {
            if (this.matchKeyword('var')) {
                init = this.createNode();
                this.nextToken();
                var previousAllowIn = this.context.allowIn;
                this.context.allowIn = false;
                var declarations = this.parseVariableDeclarationList({ inFor: true });
                this.context.allowIn = previousAllowIn;
                if (declarations.length === 1 && this.matchKeyword('in')) {
                    var decl = declarations[0];
                    if (decl.init && (decl.id.type === syntax_1.Syntax.ArrayPattern || decl.id.type === syntax_1.Syntax.ObjectPattern || this.context.strict)) {
                        this.tolerateError(messages_1.Messages.ForInOfLoopInitializer, 'for-in');
                    }
                    init = this.finalize(init, new Node.VariableDeclaration(declarations, 'var'));
                    this.nextToken();
                    left = init;
                    right = this.parseExpression();
                    init = null;
                }
                else if (declarations.length === 1 && declarations[0].init === null && this.matchContextualKeyword('of')) {
                    init = this.finalize(init, new Node.VariableDeclaration(declarations, 'var'));
                    this.nextToken();
                    left = init;
                    right = this.parseAssignmentExpression();
                    init = null;
                    forIn = false;
                }
                else {
                    init = this.finalize(init, new Node.VariableDeclaration(declarations, 'var'));
                    this.expect(';');
                }
            }
            else if (this.matchKeyword('const') || this.matchKeyword('let')) {
                init = this.createNode();
                var kind = this.nextToken().value;
                if (!this.context.strict && this.lookahead.value === 'in') {
                    init = this.finalize(init, new Node.Identifier(kind));
                    this.nextToken();
                    left = init;
                    right = this.parseExpression();
                    init = null;
                }
                else {
                    var previousAllowIn = this.context.allowIn;
                    this.context.allowIn = false;
                    var declarations = this.parseBindingList(kind, { inFor: true });
                    this.context.allowIn = previousAllowIn;
                    if (declarations.length === 1 && declarations[0].init === null && this.matchKeyword('in')) {
                        init = this.finalize(init, new Node.VariableDeclaration(declarations, kind));
                        this.nextToken();
                        left = init;
                        right = this.parseExpression();
                        init = null;
                    }
                    else if (declarations.length === 1 && declarations[0].init === null && this.matchContextualKeyword('of')) {
                        init = this.finalize(init, new Node.VariableDeclaration(declarations, kind));
                        this.nextToken();
                        left = init;
                        right = this.parseAssignmentExpression();
                        init = null;
                        forIn = false;
                    }
                    else {
                        this.consumeSemicolon();
                        init = this.finalize(init, new Node.VariableDeclaration(declarations, kind));
                    }
                }
            }
            else {
                var initStartToken = this.lookahead;
                var previousAllowIn = this.context.allowIn;
                this.context.allowIn = false;
                init = this.inheritCoverGrammar(this.parseAssignmentExpression);
                this.context.allowIn = previousAllowIn;
                if (this.matchKeyword('in')) {
                    if (!this.context.isAssignmentTarget || init.type === syntax_1.Syntax.AssignmentExpression) {
                        this.tolerateError(messages_1.Messages.InvalidLHSInForIn);
                    }
                    this.nextToken();
                    this.reinterpretExpressionAsPattern(init);
                    left = init;
                    right = this.parseExpression();
                    init = null;
                }
                else if (this.matchContextualKeyword('of')) {
                    if (!this.context.isAssignmentTarget || init.type === syntax_1.Syntax.AssignmentExpression) {
                        this.tolerateError(messages_1.Messages.InvalidLHSInForLoop);
                    }
                    this.nextToken();
                    this.reinterpretExpressionAsPattern(init);
                    left = init;
                    right = this.parseAssignmentExpression();
                    init = null;
                    forIn = false;
                }
                else {
                    if (this.match(',')) {
                        var initSeq = [init];
                        while (this.match(',')) {
                            this.nextToken();
                            initSeq.push(this.isolateCoverGrammar(this.parseAssignmentExpression));
                        }
                        init = this.finalize(this.startNode(initStartToken), new Node.SequenceExpression(initSeq));
                    }
                    this.expect(';');
                }
            }
        }
        if (typeof left === 'undefined') {
            if (!this.match(';')) {
                test = this.parseExpression();
            }
            this.expect(';');
            if (!this.match(')')) {
                update = this.parseExpression();
            }
        }
        var body;
        if (!this.match(')') && this.config.tolerant) {
            this.tolerateUnexpectedToken(this.nextToken());
            body = this.finalize(this.createNode(), new Node.EmptyStatement());
        }
        else {
            this.expect(')');
            var previousInIteration = this.context.inIteration;
            this.context.inIteration = true;
            body = this.isolateCoverGrammar(this.parseStatement);
            this.context.inIteration = previousInIteration;
        }
        return (typeof left === 'undefined') ?
            this.finalize(node, new Node.ForStatement(init, test, update, body)) :
            forIn ? this.finalize(node, new Node.ForInStatement(left, right, body)) :
                this.finalize(node, new Node.ForOfStatement(left, right, body));
    };
    // https://tc39.github.io/ecma262/#sec-continue-statement
    Parser.prototype.parseContinueStatement = function () {
        var node = this.createNode();
        this.expectKeyword('continue');
        var label = null;
        if (this.lookahead.type === 3 /* Identifier */ && !this.hasLineTerminator) {
            var id = this.parseVariableIdentifier();
            label = id;
            var key = '$' + id.name;
            if (!Object.prototype.hasOwnProperty.call(this.context.labelSet, key)) {
                this.throwError(messages_1.Messages.UnknownLabel, id.name);
            }
        }
        this.consumeSemicolon();
        if (label === null && !this.context.inIteration) {
            this.throwError(messages_1.Messages.IllegalContinue);
        }
        return this.finalize(node, new Node.ContinueStatement(label));
    };
    // https://tc39.github.io/ecma262/#sec-break-statement
    Parser.prototype.parseBreakStatement = function () {
        var node = this.createNode();
        this.expectKeyword('break');
        var label = null;
        if (this.lookahead.type === 3 /* Identifier */ && !this.hasLineTerminator) {
            var id = this.parseVariableIdentifier();
            var key = '$' + id.name;
            if (!Object.prototype.hasOwnProperty.call(this.context.labelSet, key)) {
                this.throwError(messages_1.Messages.UnknownLabel, id.name);
            }
            label = id;
        }
        this.consumeSemicolon();
        if (label === null && !this.context.inIteration && !this.context.inSwitch) {
            this.throwError(messages_1.Messages.IllegalBreak);
        }
        return this.finalize(node, new Node.BreakStatement(label));
    };
    // https://tc39.github.io/ecma262/#sec-return-statement
    Parser.prototype.parseReturnStatement = function () {
        if (!this.context.inFunctionBody) {
            this.tolerateError(messages_1.Messages.IllegalReturn);
        }
        var node = this.createNode();
        this.expectKeyword('return');
        var hasArgument = (!this.match(';') && !this.match('}') &&
            !this.hasLineTerminator && this.lookahead.type !== 2 /* EOF */) ||
            this.lookahead.type === 8 /* StringLiteral */ ||
            this.lookahead.type === 10 /* Template */;
        var argument = hasArgument ? this.parseExpression() : null;
        this.consumeSemicolon();
        return this.finalize(node, new Node.ReturnStatement(argument));
    };
    // https://tc39.github.io/ecma262/#sec-with-statement
    Parser.prototype.parseWithStatement = function () {
        if (this.context.strict) {
            this.tolerateError(messages_1.Messages.StrictModeWith);
        }
        var node = this.createNode();
        var body;
        this.expectKeyword('with');
        this.expect('(');
        var object = this.parseExpression();
        if (!this.match(')') && this.config.tolerant) {
            this.tolerateUnexpectedToken(this.nextToken());
            body = this.finalize(this.createNode(), new Node.EmptyStatement());
        }
        else {
            this.expect(')');
            body = this.parseStatement();
        }
        return this.finalize(node, new Node.WithStatement(object, body));
    };
    // https://tc39.github.io/ecma262/#sec-switch-statement
    Parser.prototype.parseSwitchCase = function () {
        var node = this.createNode();
        var test;
        if (this.matchKeyword('default')) {
            this.nextToken();
            test = null;
        }
        else {
            this.expectKeyword('case');
            test = this.parseExpression();
        }
        this.expect(':');
        var consequent = [];
        while (true) {
            if (this.match('}') || this.matchKeyword('default') || this.matchKeyword('case')) {
                break;
            }
            consequent.push(this.parseStatementListItem());
        }
        return this.finalize(node, new Node.SwitchCase(test, consequent));
    };
    Parser.prototype.parseSwitchStatement = function () {
        var node = this.createNode();
        this.expectKeyword('switch');
        this.expect('(');
        var discriminant = this.parseExpression();
        this.expect(')');
        var previousInSwitch = this.context.inSwitch;
        this.context.inSwitch = true;
        var cases = [];
        var defaultFound = false;
        this.expect('{');
        while (true) {
            if (this.match('}')) {
                break;
            }
            var clause = this.parseSwitchCase();
            if (clause.test === null) {
                if (defaultFound) {
                    this.throwError(messages_1.Messages.MultipleDefaultsInSwitch);
                }
                defaultFound = true;
            }
            cases.push(clause);
        }
        this.expect('}');
        this.context.inSwitch = previousInSwitch;
        return this.finalize(node, new Node.SwitchStatement(discriminant, cases));
    };
    // https://tc39.github.io/ecma262/#sec-labelled-statements
    Parser.prototype.parseLabelledStatement = function () {
        var node = this.createNode();
        var expr = this.parseExpression();
        var statement;
        if ((expr.type === syntax_1.Syntax.Identifier) && this.match(':')) {
            this.nextToken();
            var id = expr;
            var key = '$' + id.name;
            if (Object.prototype.hasOwnProperty.call(this.context.labelSet, key)) {
                this.throwError(messages_1.Messages.Redeclaration, 'Label', id.name);
            }
            this.context.labelSet[key] = true;
            var body = void 0;
            if (this.matchKeyword('class')) {
                this.tolerateUnexpectedToken(this.lookahead);
                body = this.parseClassDeclaration();
            }
            else if (this.matchKeyword('function')) {
                var token = this.lookahead;
                var declaration = this.parseFunctionDeclaration();
                if (this.context.strict) {
                    this.tolerateUnexpectedToken(token, messages_1.Messages.StrictFunction);
                }
                else if (declaration.generator) {
                    this.tolerateUnexpectedToken(token, messages_1.Messages.GeneratorInLegacyContext);
                }
                body = declaration;
            }
            else {
                body = this.parseStatement();
            }
            delete this.context.labelSet[key];
            statement = new Node.LabeledStatement(id, body);
        }
        else {
            this.consumeSemicolon();
            statement = new Node.ExpressionStatement(expr);
        }
        return this.finalize(node, statement);
    };
    // https://tc39.github.io/ecma262/#sec-throw-statement
    Parser.prototype.parseThrowStatement = function () {
        var node = this.createNode();
        this.expectKeyword('throw');
        if (this.hasLineTerminator) {
            this.throwError(messages_1.Messages.NewlineAfterThrow);
        }
        var argument = this.parseExpression();
        this.consumeSemicolon();
        return this.finalize(node, new Node.ThrowStatement(argument));
    };
    // https://tc39.github.io/ecma262/#sec-try-statement
    Parser.prototype.parseCatchClause = function () {
        var node = this.createNode();
        this.expectKeyword('catch');
        this.expect('(');
        if (this.match(')')) {
            this.throwUnexpectedToken(this.lookahead);
        }
        var params = [];
        var param = this.parsePattern(params);
        var paramMap = {};
        for (var i = 0; i < params.length; i++) {
            var key = '$' + params[i].value;
            if (Object.prototype.hasOwnProperty.call(paramMap, key)) {
                this.tolerateError(messages_1.Messages.DuplicateBinding, params[i].value);
            }
            paramMap[key] = true;
        }
        if (this.context.strict && param.type === syntax_1.Syntax.Identifier) {
            if (this.scanner.isRestrictedWord(param.name)) {
                this.tolerateError(messages_1.Messages.StrictCatchVariable);
            }
        }
        this.expect(')');
        var body = this.parseBlock();
        return this.finalize(node, new Node.CatchClause(param, body));
    };
    Parser.prototype.parseFinallyClause = function () {
        this.expectKeyword('finally');
        return this.parseBlock();
    };
    Parser.prototype.parseTryStatement = function () {
        var node = this.createNode();
        this.expectKeyword('try');
        var block = this.parseBlock();
        var handler = this.matchKeyword('catch') ? this.parseCatchClause() : null;
        var finalizer = this.matchKeyword('finally') ? this.parseFinallyClause() : null;
        if (!handler && !finalizer) {
            this.throwError(messages_1.Messages.NoCatchOrFinally);
        }
        return this.finalize(node, new Node.TryStatement(block, handler, finalizer));
    };
    // https://tc39.github.io/ecma262/#sec-debugger-statement
    Parser.prototype.parseDebuggerStatement = function () {
        var node = this.createNode();
        this.expectKeyword('debugger');
        this.consumeSemicolon();
        return this.finalize(node, new Node.DebuggerStatement());
    };
    // https://tc39.github.io/ecma262/#sec-ecmascript-language-statements-and-declarations
    Parser.prototype.parseStatement = function () {
        var statement;
        switch (this.lookahead.type) {
            case 1 /* BooleanLiteral */:
            case 5 /* NullLiteral */:
            case 6 /* NumericLiteral */:
            case 8 /* StringLiteral */:
            case 10 /* Template */:
            case 9 /* RegularExpression */:
                statement = this.parseExpressionStatement();
                break;
            case 7 /* Punctuator */:
                var value = this.lookahead.value;
                if (value === '{') {
                    statement = this.parseBlock();
                }
                else if (value === '(') {
                    statement = this.parseExpressionStatement();
                }
                else if (value === ';') {
                    statement = this.parseEmptyStatement();
                }
                else {
                    statement = this.parseExpressionStatement();
                }
                break;
            case 3 /* Identifier */:
                statement = this.matchAsyncFunction() ? this.parseFunctionDeclaration() : this.parseLabelledStatement();
                break;
            case 4 /* Keyword */:
                switch (this.lookahead.value) {
                    case 'break':
                        statement = this.parseBreakStatement();
                        break;
                    case 'continue':
                        statement = this.parseContinueStatement();
                        break;
                    case 'debugger':
                        statement = this.parseDebuggerStatement();
                        break;
                    case 'do':
                        statement = this.parseDoWhileStatement();
                        break;
                    case 'for':
                        statement = this.parseForStatement();
                        break;
                    case 'function':
                        statement = this.parseFunctionDeclaration();
                        break;
                    case 'if':
                        statement = this.parseIfStatement();
                        break;
                    case 'return':
                        statement = this.parseReturnStatement();
                        break;
                    case 'switch':
                        statement = this.parseSwitchStatement();
                        break;
                    case 'throw':
                        statement = this.parseThrowStatement();
                        break;
                    case 'try':
                        statement = this.parseTryStatement();
                        break;
                    case 'var':
                        statement = this.parseVariableStatement();
                        break;
                    case 'while':
                        statement = this.parseWhileStatement();
                        break;
                    case 'with':
                        statement = this.parseWithStatement();
                        break;
                    default:
                        statement = this.parseExpressionStatement();
                        break;
                }
                break;
            default:
                statement = this.throwUnexpectedToken(this.lookahead);
        }
        return statement;
    };
    // https://tc39.github.io/ecma262/#sec-function-definitions
    Parser.prototype.parseFunctionSourceElements = function () {
        var node = this.createNode();
        this.expect('{');
        var body = this.parseDirectivePrologues();
        var previousLabelSet = this.context.labelSet;
        var previousInIteration = this.context.inIteration;
        var previousInSwitch = this.context.inSwitch;
        var previousInFunctionBody = this.context.inFunctionBody;
        this.context.labelSet = {};
        this.context.inIteration = false;
        this.context.inSwitch = false;
        this.context.inFunctionBody = true;
        while (this.lookahead.type !== 2 /* EOF */) {
            if (this.match('}')) {
                break;
            }
            body.push(this.parseStatementListItem());
        }
        this.expect('}');
        this.context.labelSet = previousLabelSet;
        this.context.inIteration = previousInIteration;
        this.context.inSwitch = previousInSwitch;
        this.context.inFunctionBody = previousInFunctionBody;
        return this.finalize(node, new Node.BlockStatement(body));
    };
    Parser.prototype.validateParam = function (options, param, name) {
        var key = '$' + name;
        if (this.context.strict) {
            if (this.scanner.isRestrictedWord(name)) {
                options.stricted = param;
                options.message = messages_1.Messages.StrictParamName;
            }
            if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
                options.stricted = param;
                options.message = messages_1.Messages.StrictParamDupe;
            }
        }
        else if (!options.firstRestricted) {
            if (this.scanner.isRestrictedWord(name)) {
                options.firstRestricted = param;
                options.message = messages_1.Messages.StrictParamName;
            }
            else if (this.scanner.isStrictModeReservedWord(name)) {
                options.firstRestricted = param;
                options.message = messages_1.Messages.StrictReservedWord;
            }
            else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
                options.stricted = param;
                options.message = messages_1.Messages.StrictParamDupe;
            }
        }
        /* istanbul ignore next */
        if (typeof Object.defineProperty === 'function') {
            Object.defineProperty(options.paramSet, key, { value: true, enumerable: true, writable: true, configurable: true });
        }
        else {
            options.paramSet[key] = true;
        }
    };
    Parser.prototype.parseRestElement = function (params) {
        var node = this.createNode();
        this.expect('...');
        var arg = this.parsePattern(params);
        if (this.match('=')) {
            this.throwError(messages_1.Messages.DefaultRestParameter);
        }
        if (!this.match(')')) {
            this.throwError(messages_1.Messages.ParameterAfterRestParameter);
        }
        return this.finalize(node, new Node.RestElement(arg));
    };
    Parser.prototype.parseFormalParameter = function (options) {
        var params = [];
        var param = this.match('...') ? this.parseRestElement(params) : this.parsePatternWithDefault(params);
        for (var i = 0; i < params.length; i++) {
            this.validateParam(options, params[i], params[i].value);
        }
        options.simple = options.simple && (param instanceof Node.Identifier);
        options.params.push(param);
    };
    Parser.prototype.parseFormalParameters = function (firstRestricted) {
        var options;
        options = {
            simple: true,
            params: [],
            firstRestricted: firstRestricted
        };
        this.expect('(');
        if (!this.match(')')) {
            options.paramSet = {};
            while (this.lookahead.type !== 2 /* EOF */) {
                this.parseFormalParameter(options);
                if (this.match(')')) {
                    break;
                }
                this.expect(',');
                if (this.match(')')) {
                    break;
                }
            }
        }
        this.expect(')');
        return {
            simple: options.simple,
            params: options.params,
            stricted: options.stricted,
            firstRestricted: options.firstRestricted,
            message: options.message
        };
    };
    Parser.prototype.matchAsyncFunction = function () {
        var match = this.matchContextualKeyword('async');
        if (match) {
            var state = this.scanner.saveState();
            this.scanner.scanComments();
            var next = this.scanner.lex();
            this.scanner.restoreState(state);
            match = (state.lineNumber === next.lineNumber) && (next.type === 4 /* Keyword */) && (next.value === 'function');
        }
        return match;
    };
    Parser.prototype.parseFunctionDeclaration = function (identifierIsOptional) {
        var node = this.createNode();
        var isAsync = this.matchContextualKeyword('async');
        if (isAsync) {
            this.nextToken();
        }
        this.expectKeyword('function');
        var isGenerator = isAsync ? false : this.match('*');
        if (isGenerator) {
            this.nextToken();
        }
        var message;
        var id = null;
        var firstRestricted = null;
        if (!identifierIsOptional || !this.match('(')) {
            var token = this.lookahead;
            id = this.parseVariableIdentifier();
            if (this.context.strict) {
                if (this.scanner.isRestrictedWord(token.value)) {
                    this.tolerateUnexpectedToken(token, messages_1.Messages.StrictFunctionName);
                }
            }
            else {
                if (this.scanner.isRestrictedWord(token.value)) {
                    firstRestricted = token;
                    message = messages_1.Messages.StrictFunctionName;
                }
                else if (this.scanner.isStrictModeReservedWord(token.value)) {
                    firstRestricted = token;
                    message = messages_1.Messages.StrictReservedWord;
                }
            }
        }
        var previousAllowAwait = this.context.await;
        var previousAllowYield = this.context.allowYield;
        this.context.await = isAsync;
        this.context.allowYield = !isGenerator;
        var formalParameters = this.parseFormalParameters(firstRestricted);
        var params = formalParameters.params;
        var stricted = formalParameters.stricted;
        firstRestricted = formalParameters.firstRestricted;
        if (formalParameters.message) {
            message = formalParameters.message;
        }
        var previousStrict = this.context.strict;
        var previousAllowStrictDirective = this.context.allowStrictDirective;
        this.context.allowStrictDirective = formalParameters.simple;
        var body = this.parseFunctionSourceElements();
        if (this.context.strict && firstRestricted) {
            this.throwUnexpectedToken(firstRestricted, message);
        }
        if (this.context.strict && stricted) {
            this.tolerateUnexpectedToken(stricted, message);
        }
        this.context.strict = previousStrict;
        this.context.allowStrictDirective = previousAllowStrictDirective;
        this.context.await = previousAllowAwait;
        this.context.allowYield = previousAllowYield;
        return isAsync ? this.finalize(node, new Node.AsyncFunctionDeclaration(id, params, body)) :
            this.finalize(node, new Node.FunctionDeclaration(id, params, body, isGenerator));
    };
    Parser.prototype.parseFunctionExpression = function () {
        var node = this.createNode();
        var isAsync = this.matchContextualKeyword('async');
        if (isAsync) {
            this.nextToken();
        }
        this.expectKeyword('function');
        var isGenerator = isAsync ? false : this.match('*');
        if (isGenerator) {
            this.nextToken();
        }
        var message;
        var id = null;
        var firstRestricted;
        var previousAllowAwait = this.context.await;
        var previousAllowYield = this.context.allowYield;
        this.context.await = isAsync;
        this.context.allowYield = !isGenerator;
        if (!this.match('(')) {
            var token = this.lookahead;
            id = (!this.context.strict && !isGenerator && this.matchKeyword('yield')) ? this.parseIdentifierName() : this.parseVariableIdentifier();
            if (this.context.strict) {
                if (this.scanner.isRestrictedWord(token.value)) {
                    this.tolerateUnexpectedToken(token, messages_1.Messages.StrictFunctionName);
                }
            }
            else {
                if (this.scanner.isRestrictedWord(token.value)) {
                    firstRestricted = token;
                    message = messages_1.Messages.StrictFunctionName;
                }
                else if (this.scanner.isStrictModeReservedWord(token.value)) {
                    firstRestricted = token;
                    message = messages_1.Messages.StrictReservedWord;
                }
            }
        }
        var formalParameters = this.parseFormalParameters(firstRestricted);
        var params = formalParameters.params;
        var stricted = formalParameters.stricted;
        firstRestricted = formalParameters.firstRestricted;
        if (formalParameters.message) {
            message = formalParameters.message;
        }
        var previousStrict = this.context.strict;
        var previousAllowStrictDirective = this.context.allowStrictDirective;
        this.context.allowStrictDirective = formalParameters.simple;
        var body = this.parseFunctionSourceElements();
        if (this.context.strict && firstRestricted) {
            this.throwUnexpectedToken(firstRestricted, message);
        }
        if (this.context.strict && stricted) {
            this.tolerateUnexpectedToken(stricted, message);
        }
        this.context.strict = previousStrict;
        this.context.allowStrictDirective = previousAllowStrictDirective;
        this.context.await = previousAllowAwait;
        this.context.allowYield = previousAllowYield;
        return isAsync ? this.finalize(node, new Node.AsyncFunctionExpression(id, params, body)) :
            this.finalize(node, new Node.FunctionExpression(id, params, body, isGenerator));
    };
    // https://tc39.github.io/ecma262/#sec-directive-prologues-and-the-use-strict-directive
    Parser.prototype.parseDirective = function () {
        var token = this.lookahead;
        var node = this.createNode();
        var expr = this.parseExpression();
        var directive = (expr.type === syntax_1.Syntax.Literal) ? this.getTokenRaw(token).slice(1, -1) : null;
        this.consumeSemicolon();
        return this.finalize(node, directive ? new Node.Directive(expr, directive) : new Node.ExpressionStatement(expr));
    };
    Parser.prototype.parseDirectivePrologues = function () {
        var firstRestricted = null;
        var body = [];
        while (true) {
            var token = this.lookahead;
            if (token.type !== 8 /* StringLiteral */) {
                break;
            }
            var statement = this.parseDirective();
            body.push(statement);
            var directive = statement.directive;
            if (typeof directive !== 'string') {
                break;
            }
            if (directive === 'use strict') {
                this.context.strict = true;
                if (firstRestricted) {
                    this.tolerateUnexpectedToken(firstRestricted, messages_1.Messages.StrictOctalLiteral);
                }
                if (!this.context.allowStrictDirective) {
                    this.tolerateUnexpectedToken(token, messages_1.Messages.IllegalLanguageModeDirective);
                }
            }
            else {
                if (!firstRestricted && token.octal) {
                    firstRestricted = token;
                }
            }
        }
        return body;
    };
    // https://tc39.github.io/ecma262/#sec-method-definitions
    Parser.prototype.qualifiedPropertyName = function (token) {
        switch (token.type) {
            case 3 /* Identifier */:
            case 8 /* StringLiteral */:
            case 1 /* BooleanLiteral */:
            case 5 /* NullLiteral */:
            case 6 /* NumericLiteral */:
            case 4 /* Keyword */:
                return true;
            case 7 /* Punctuator */:
                return token.value === '[';
            default:
                break;
        }
        return false;
    };
    Parser.prototype.parseGetterMethod = function () {
        var node = this.createNode();
        var isGenerator = false;
        var previousAllowYield = this.context.allowYield;
        this.context.allowYield = !isGenerator;
        var formalParameters = this.parseFormalParameters();
        if (formalParameters.params.length > 0) {
            this.tolerateError(messages_1.Messages.BadGetterArity);
        }
        var method = this.parsePropertyMethod(formalParameters);
        this.context.allowYield = previousAllowYield;
        return this.finalize(node, new Node.FunctionExpression(null, formalParameters.params, method, isGenerator));
    };
    Parser.prototype.parseSetterMethod = function () {
        var node = this.createNode();
        var isGenerator = false;
        var previousAllowYield = this.context.allowYield;
        this.context.allowYield = !isGenerator;
        var formalParameters = this.parseFormalParameters();
        if (formalParameters.params.length !== 1) {
            this.tolerateError(messages_1.Messages.BadSetterArity);
        }
        else if (formalParameters.params[0] instanceof Node.RestElement) {
            this.tolerateError(messages_1.Messages.BadSetterRestParameter);
        }
        var method = this.parsePropertyMethod(formalParameters);
        this.context.allowYield = previousAllowYield;
        return this.finalize(node, new Node.FunctionExpression(null, formalParameters.params, method, isGenerator));
    };
    Parser.prototype.parseGeneratorMethod = function () {
        var node = this.createNode();
        var isGenerator = true;
        var previousAllowYield = this.context.allowYield;
        this.context.allowYield = true;
        var params = this.parseFormalParameters();
        this.context.allowYield = false;
        var method = this.parsePropertyMethod(params);
        this.context.allowYield = previousAllowYield;
        return this.finalize(node, new Node.FunctionExpression(null, params.params, method, isGenerator));
    };
    // https://tc39.github.io/ecma262/#sec-generator-function-definitions
    Parser.prototype.isStartOfExpression = function () {
        var start = true;
        var value = this.lookahead.value;
        switch (this.lookahead.type) {
            case 7 /* Punctuator */:
                start = (value === '[') || (value === '(') || (value === '{') ||
                    (value === '+') || (value === '-') ||
                    (value === '!') || (value === '~') ||
                    (value === '++') || (value === '--') ||
                    (value === '/') || (value === '/='); // regular expression literal
                break;
            case 4 /* Keyword */:
                start = (value === 'class') || (value === 'delete') ||
                    (value === 'function') || (value === 'let') || (value === 'new') ||
                    (value === 'super') || (value === 'this') || (value === 'typeof') ||
                    (value === 'void') || (value === 'yield');
                break;
            default:
                break;
        }
        return start;
    };
    Parser.prototype.parseYieldExpression = function () {
        var node = this.createNode();
        this.expectKeyword('yield');
        var argument = null;
        var delegate = false;
        if (!this.hasLineTerminator) {
            var previousAllowYield = this.context.allowYield;
            this.context.allowYield = false;
            delegate = this.match('*');
            if (delegate) {
                this.nextToken();
                argument = this.parseAssignmentExpression();
            }
            else if (this.isStartOfExpression()) {
                argument = this.parseAssignmentExpression();
            }
            this.context.allowYield = previousAllowYield;
        }
        return this.finalize(node, new Node.YieldExpression(argument, delegate));
    };
    // https://tc39.github.io/ecma262/#sec-class-definitions
    Parser.prototype.parseClassElement = function (hasConstructor) {
        var token = this.lookahead;
        var node = this.createNode();
        var kind = '';
        var key = null;
        var value = null;
        var computed = false;
        var method = false;
        var isStatic = false;
        var isAsync = false;
        if (this.match('*')) {
            this.nextToken();
        }
        else {
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
            var id = key;
            if (id.name === 'static' && (this.qualifiedPropertyName(this.lookahead) || this.match('*'))) {
                token = this.lookahead;
                isStatic = true;
                computed = this.match('[');
                if (this.match('*')) {
                    this.nextToken();
                }
                else {
                    key = this.parseObjectPropertyKey();
                }
            }
            if ((token.type === 3 /* Identifier */) && !this.hasLineTerminator && (token.value === 'async')) {
                var punctuator = this.lookahead.value;
                if (punctuator !== ':' && punctuator !== '(' && punctuator !== '*') {
                    isAsync = true;
                    token = this.lookahead;
                    key = this.parseObjectPropertyKey();
                    if (token.type === 3 /* Identifier */ && token.value === 'constructor') {
                        this.tolerateUnexpectedToken(token, messages_1.Messages.ConstructorIsAsync);
                    }
                }
            }
        }
        var lookaheadPropertyKey = this.qualifiedPropertyName(this.lookahead);
        if (token.type === 3 /* Identifier */) {
            if (token.value === 'get' && lookaheadPropertyKey) {
                kind = 'get';
                computed = this.match('[');
                key = this.parseObjectPropertyKey();
                this.context.allowYield = false;
                value = this.parseGetterMethod();
            }
            else if (token.value === 'set' && lookaheadPropertyKey) {
                kind = 'set';
                computed = this.match('[');
                key = this.parseObjectPropertyKey();
                value = this.parseSetterMethod();
            }
        }
        else if (token.type === 7 /* Punctuator */ && token.value === '*' && lookaheadPropertyKey) {
            kind = 'init';
            computed = this.match('[');
            key = this.parseObjectPropertyKey();
            value = this.parseGeneratorMethod();
            method = true;
        }
        if (!kind && key && this.match('(')) {
            kind = 'init';
            value = isAsync ? this.parsePropertyMethodAsyncFunction() : this.parsePropertyMethodFunction();
            method = true;
        }
        if (!kind) {
            this.throwUnexpectedToken(this.lookahead);
        }
        if (kind === 'init') {
            kind = 'method';
        }
        if (!computed) {
            if (isStatic && this.isPropertyKey(key, 'prototype')) {
                this.throwUnexpectedToken(token, messages_1.Messages.StaticPrototype);
            }
            if (!isStatic && this.isPropertyKey(key, 'constructor')) {
                if (kind !== 'method' || !method || (value && value.generator)) {
                    this.throwUnexpectedToken(token, messages_1.Messages.ConstructorSpecialMethod);
                }
                if (hasConstructor.value) {
                    this.throwUnexpectedToken(token, messages_1.Messages.DuplicateConstructor);
                }
                else {
                    hasConstructor.value = true;
                }
                kind = 'constructor';
            }
        }
        return this.finalize(node, new Node.MethodDefinition(key, computed, value, kind, isStatic));
    };
    Parser.prototype.parseClassElementList = function () {
        var body = [];
        var hasConstructor = { value: false };
        this.expect('{');
        while (!this.match('}')) {
            if (this.match(';')) {
                this.nextToken();
            }
            else {
                body.push(this.parseClassElement(hasConstructor));
            }
        }
        this.expect('}');
        return body;
    };
    Parser.prototype.parseClassBody = function () {
        var node = this.createNode();
        var elementList = this.parseClassElementList();
        return this.finalize(node, new Node.ClassBody(elementList));
    };
    Parser.prototype.parseClassDeclaration = function (identifierIsOptional) {
        var node = this.createNode();
        var previousStrict = this.context.strict;
        this.context.strict = true;
        this.expectKeyword('class');
        var id = (identifierIsOptional && (this.lookahead.type !== 3 /* Identifier */)) ? null : this.parseVariableIdentifier();
        var superClass = null;
        if (this.matchKeyword('extends')) {
            this.nextToken();
            superClass = this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall);
        }
        var classBody = this.parseClassBody();
        this.context.strict = previousStrict;
        return this.finalize(node, new Node.ClassDeclaration(id, superClass, classBody));
    };
    Parser.prototype.parseClassExpression = function () {
        var node = this.createNode();
        var previousStrict = this.context.strict;
        this.context.strict = true;
        this.expectKeyword('class');
        var id = (this.lookahead.type === 3 /* Identifier */) ? this.parseVariableIdentifier() : null;
        var superClass = null;
        if (this.matchKeyword('extends')) {
            this.nextToken();
            superClass = this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall);
        }
        var classBody = this.parseClassBody();
        this.context.strict = previousStrict;
        return this.finalize(node, new Node.ClassExpression(id, superClass, classBody));
    };
    // https://tc39.github.io/ecma262/#sec-scripts
    // https://tc39.github.io/ecma262/#sec-modules
    Parser.prototype.parseModule = function () {
        this.context.strict = true;
        this.context.isModule = true;
        this.scanner.isModule = true;
        var node = this.createNode();
        var body = this.parseDirectivePrologues();
        while (this.lookahead.type !== 2 /* EOF */) {
            body.push(this.parseStatementListItem());
        }
        return this.finalize(node, new Node.Module(body));
    };
    Parser.prototype.parseScript = function () {
        var node = this.createNode();
        var body = this.parseDirectivePrologues();
        while (this.lookahead.type !== 2 /* EOF */) {
            body.push(this.parseStatementListItem());
        }
        return this.finalize(node, new Node.Script(body));
    };
    // https://tc39.github.io/ecma262/#sec-imports
    Parser.prototype.parseModuleSpecifier = function () {
        var node = this.createNode();
        if (this.lookahead.type !== 8 /* StringLiteral */) {
            this.throwError(messages_1.Messages.InvalidModuleSpecifier);
        }
        var token = this.nextToken();
        var raw = this.getTokenRaw(token);
        return this.finalize(node, new Node.Literal(token.value, raw));
    };
    // import {<foo as bar>} ...;
    Parser.prototype.parseImportSpecifier = function () {
        var node = this.createNode();
        var imported;
        var local;
        if (this.lookahead.type === 3 /* Identifier */) {
            imported = this.parseVariableIdentifier();
            local = imported;
            if (this.matchContextualKeyword('as')) {
                this.nextToken();
                local = this.parseVariableIdentifier();
            }
        }
        else {
            imported = this.parseIdentifierName();
            local = imported;
            if (this.matchContextualKeyword('as')) {
                this.nextToken();
                local = this.parseVariableIdentifier();
            }
            else {
                this.throwUnexpectedToken(this.nextToken());
            }
        }
        return this.finalize(node, new Node.ImportSpecifier(local, imported));
    };
    // {foo, bar as bas}
    Parser.prototype.parseNamedImports = function () {
        this.expect('{');
        var specifiers = [];
        while (!this.match('}')) {
            specifiers.push(this.parseImportSpecifier());
            if (!this.match('}')) {
                this.expect(',');
            }
        }
        this.expect('}');
        return specifiers;
    };
    // import <foo> ...;
    Parser.prototype.parseImportDefaultSpecifier = function () {
        var node = this.createNode();
        var local = this.parseIdentifierName();
        return this.finalize(node, new Node.ImportDefaultSpecifier(local));
    };
    // import <* as foo> ...;
    Parser.prototype.parseImportNamespaceSpecifier = function () {
        var node = this.createNode();
        this.expect('*');
        if (!this.matchContextualKeyword('as')) {
            this.throwError(messages_1.Messages.NoAsAfterImportNamespace);
        }
        this.nextToken();
        var local = this.parseIdentifierName();
        return this.finalize(node, new Node.ImportNamespaceSpecifier(local));
    };
    Parser.prototype.parseImportDeclaration = function () {
        if (this.context.inFunctionBody) {
            this.throwError(messages_1.Messages.IllegalImportDeclaration);
        }
        var node = this.createNode();
        this.expectKeyword('import');
        var src;
        var specifiers = [];
        if (this.lookahead.type === 8 /* StringLiteral */) {
            // import 'foo';
            src = this.parseModuleSpecifier();
        }
        else {
            if (this.match('{')) {
                // import {bar}
                specifiers = specifiers.concat(this.parseNamedImports());
            }
            else if (this.match('*')) {
                // import * as foo
                specifiers.push(this.parseImportNamespaceSpecifier());
            }
            else if (this.isIdentifierName(this.lookahead) && !this.matchKeyword('default')) {
                // import foo
                specifiers.push(this.parseImportDefaultSpecifier());
                if (this.match(',')) {
                    this.nextToken();
                    if (this.match('*')) {
                        // import foo, * as foo
                        specifiers.push(this.parseImportNamespaceSpecifier());
                    }
                    else if (this.match('{')) {
                        // import foo, {bar}
                        specifiers = specifiers.concat(this.parseNamedImports());
                    }
                    else {
                        this.throwUnexpectedToken(this.lookahead);
                    }
                }
            }
            else {
                this.throwUnexpectedToken(this.nextToken());
            }
            if (!this.matchContextualKeyword('from')) {
                var message = this.lookahead.value ? messages_1.Messages.UnexpectedToken : messages_1.Messages.MissingFromClause;
                this.throwError(message, this.lookahead.value);
            }
            this.nextToken();
            src = this.parseModuleSpecifier();
        }
        this.consumeSemicolon();
        return this.finalize(node, new Node.ImportDeclaration(specifiers, src));
    };
    // https://tc39.github.io/ecma262/#sec-exports
    Parser.prototype.parseExportSpecifier = function () {
        var node = this.createNode();
        var local = this.parseIdentifierName();
        var exported = local;
        if (this.matchContextualKeyword('as')) {
            this.nextToken();
            exported = this.parseIdentifierName();
        }
        return this.finalize(node, new Node.ExportSpecifier(local, exported));
    };
    Parser.prototype.parseExportDeclaration = function () {
        if (this.context.inFunctionBody) {
            this.throwError(messages_1.Messages.IllegalExportDeclaration);
        }
        var node = this.createNode();
        this.expectKeyword('export');
        var exportDeclaration;
        if (this.matchKeyword('default')) {
            // export default ...
            this.nextToken();
            if (this.matchKeyword('function')) {
                // export default function foo () {}
                // export default function () {}
                var declaration = this.parseFunctionDeclaration(true);
                exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration));
            }
            else if (this.matchKeyword('class')) {
                // export default class foo {}
                var declaration = this.parseClassDeclaration(true);
                exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration));
            }
            else if (this.matchContextualKeyword('async')) {
                // export default async function f () {}
                // export default async function () {}
                // export default async x => x
                var declaration = this.matchAsyncFunction() ? this.parseFunctionDeclaration(true) : this.parseAssignmentExpression();
                exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration));
            }
            else {
                if (this.matchContextualKeyword('from')) {
                    this.throwError(messages_1.Messages.UnexpectedToken, this.lookahead.value);
                }
                // export default {};
                // export default [];
                // export default (1 + 2);
                var declaration = this.match('{') ? this.parseObjectInitializer() :
                    this.match('[') ? this.parseArrayInitializer() : this.parseAssignmentExpression();
                this.consumeSemicolon();
                exportDeclaration = this.finalize(node, new Node.ExportDefaultDeclaration(declaration));
            }
        }
        else if (this.match('*')) {
            // export * from 'foo';
            this.nextToken();
            if (!this.matchContextualKeyword('from')) {
                var message = this.lookahead.value ? messages_1.Messages.UnexpectedToken : messages_1.Messages.MissingFromClause;
                this.throwError(message, this.lookahead.value);
            }
            this.nextToken();
            var src = this.parseModuleSpecifier();
            this.consumeSemicolon();
            exportDeclaration = this.finalize(node, new Node.ExportAllDeclaration(src));
        }
        else if (this.lookahead.type === 4 /* Keyword */) {
            // export var f = 1;
            var declaration = void 0;
            switch (this.lookahead.value) {
                case 'let':
                case 'const':
                    declaration = this.parseLexicalDeclaration({ inFor: false });
                    break;
                case 'var':
                case 'class':
                case 'function':
                    declaration = this.parseStatementListItem();
                    break;
                default:
                    this.throwUnexpectedToken(this.lookahead);
            }
            exportDeclaration = this.finalize(node, new Node.ExportNamedDeclaration(declaration, [], null));
        }
        else if (this.matchAsyncFunction()) {
            var declaration = this.parseFunctionDeclaration();
            exportDeclaration = this.finalize(node, new Node.ExportNamedDeclaration(declaration, [], null));
        }
        else {
            var specifiers = [];
            var source = null;
            var isExportFromIdentifier = false;
            this.expect('{');
            while (!this.match('}')) {
                isExportFromIdentifier = isExportFromIdentifier || this.matchKeyword('default');
                specifiers.push(this.parseExportSpecifier());
                if (!this.match('}')) {
                    this.expect(',');
                }
            }
            this.expect('}');
            if (this.matchContextualKeyword('from')) {
                // export {default} from 'foo';
                // export {foo} from 'foo';
                this.nextToken();
                source = this.parseModuleSpecifier();
                this.consumeSemicolon();
            }
            else if (isExportFromIdentifier) {
                // export {default}; // missing fromClause
                var message = this.lookahead.value ? messages_1.Messages.UnexpectedToken : messages_1.Messages.MissingFromClause;
                this.throwError(message, this.lookahead.value);
            }
            else {
                // export {foo};
                this.consumeSemicolon();
            }
            exportDeclaration = this.finalize(node, new Node.ExportNamedDeclaration(null, specifiers, source));
        }
        return exportDeclaration;
    };
    return Parser;
}());
exports.Parser = Parser;