js-ast-parser
Version:
把javascript代码字符串解析为AST对象
1,150 lines • 62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.JavascriptAstParsser = void 0;
const JavascriptAst_1 = require("./JavascriptAst");
const constants_1 = require("./constants");
const patterns_1 = require("./patterns");
const javasriptAstParserUtil_1 = require("./javasriptAstParserUtil");
const UnExpectStatement_1 = require("./lib/statement/UnExpectStatement");
const ImportStatement_1 = require("./lib/statement/ImportStatement");
const StringLiteralExpression_1 = require("./lib/expression/StringLiteralExpression");
const IdentifierLiteralExpression_1 = require("./lib/expression/IdentifierLiteralExpression");
const BinaryExpression_1 = require("./lib/expression/BinaryExpression");
const MemberExpression_1 = require("./lib/expression/MemberExpression");
const CallExpression_1 = require("./lib/expression/CallExpression");
const TernaryExpression_1 = require("./lib/expression/TernaryExpression");
const TemplateLiteralExppression_1 = require("./lib/expression/TemplateLiteralExppression");
const VariableDeclarationStatement_1 = require("./lib/statement/VariableDeclarationStatement");
const FunctionDeclarationStatement_1 = require("./lib/statement/FunctionDeclarationStatement");
const Block_1 = require("./Block");
const SwitchCaseStatement_1 = require("./lib/statement/SwitchCaseStatement");
const TryCatchStatement_1 = require("./lib/statement/TryCatchStatement");
const DoWhileStatement_1 = require("./lib/statement/DoWhileStatement");
const WhileStatement_1 = require("./lib/statement/WhileStatement");
const ForStatement_1 = require("./lib/statement/ForStatement");
const IfStatement_1 = require("./lib/statement/IfStatement");
const ObjectLiteralExpression_1 = require("./lib/expression/ObjectLiteralExpression");
const ArrayLiteralExpression_1 = require("./lib/expression/ArrayLiteralExpression");
const UnaryExpression_1 = require("./lib/expression/UnaryExpression");
const SwitchStatement_1 = require("./lib/statement/SwitchStatement");
const WithStatement_1 = require("./lib/statement/WithStatement");
const NewExpressioin_1 = require("./lib/expression/NewExpressioin");
const ExportDeclarationStatement_1 = require("./lib/statement/ExportDeclarationStatement");
const ClassDeclarationStatement_1 = require("./lib/statement/ClassDeclarationStatement");
const AssignmentExpression_1 = require("./lib/expression/AssignmentExpression");
const RegExpressioin_1 = require("./lib/expression/RegExpressioin");
const ParticularLiteralExpression_1 = require("./lib/expression/ParticularLiteralExpression");
const NumberLiteratalExpression_1 = require("./lib/expression/NumberLiteratalExpression");
const ReturnStatement_1 = require("./lib/statement/ReturnStatement");
const ThrowStatement_1 = require("./lib/statement/ThrowStatement");
const DeleteStatement_1 = require("./lib/statement/DeleteStatement");
const TypeOfExpression_1 = require("./lib/expression/TypeOfExpression");
const FuntionExpression_1 = require("./lib/expression/FuntionExpression");
const scope_analyzer_1 = require("./lib/scope-analyzer/scope-analyzer");
const BreakStatement_1 = require("./lib/statement/BreakStatement");
const ContinueStatement_1 = require("./lib/statement/ContinueStatement");
const VoidExpression_1 = require("./lib/expression/VoidExpression");
const BracketEnwrapedExpressioin_1 = require("./lib/expression/BracketEnwrapedExpressioin");
const DebuggerStatement_1 = require("./lib/statement/DebuggerStatement");
class JavascriptAstParsser {
constructor(input) {
this.input = input;
this.pos = 0;
this.currentToken = {};
this.excutionFlag = 0;
this.startTokens = [];
this.tokens = [];
this.currentLine = 1;
this.isParsingFunDeclaration = false;
this.isParsingLoop = false;
this.depth = 1;
this.isParsingVarDeclaration = false;
}
get curCharCode() {
return this.input.charCodeAt(this.pos);
}
get nextCharCode() {
return this.input.charCodeAt(this.pos + 1);
}
get curChar() {
return this.input.charAt(this.pos);
}
parse(analyze = true) {
this.ast = new JavascriptAst_1.JavascriptAst();
let topLevelBlock = this.ast.topLevelBlock;
this.ast.topLevelBlock.depth = this.depth;
while (!this.isReadAll()) {
let node = this.parseNode();
if (!node) {
if (this.currentToken.value === '{') {
const reset = this.markPos();
node = this.parseObjLiteralExp();
if (node.code === constants_1.NodeCode.ObjectLiteralExpression &&
!node.properties.length &&
node.unexpectedNodes.length) {
reset();
node = this.parseBlock();
}
}
else if (this.currentToken.value === '[') {
node = this.parseArrExp();
}
}
else if (node.isUnexpectEnd) {
node = new UnExpectStatement_1.UnExpectStatement(node, 'unexpect end value');
}
node && topLevelBlock.body.push(node);
}
debugger;
if (analyze) {
new scope_analyzer_1.JavascriptScopeAnalyzer().analyze(this.ast.topLevelBlock);
}
return this.ast;
}
isReadAll() {
return this.pos > this.input.length - 1;
}
isLineEnd() {
let pos = this.pos, line = this.currentLine;
this.skipSpace();
let curLine = this.currentLine;
let isLineEnd = curLine > line || this.isReadAll();
this.pos = pos;
this.currentLine = line;
return isLineEnd;
}
advance(offset) {
this.pos = this.pos + (offset || 1);
}
markPos() {
let pos = this.pos, token = this.currentToken, len = this.tokens.length, startTokens = this.startTokens.slice();
return () => {
this.pos = pos;
this.currentToken = token;
this.tokens.length = len;
this.startTokens = startTokens;
};
}
skipSpace() {
loop: while (!this.isReadAll()) {
let ch = this.input.charCodeAt(this.pos);
switch (ch) {
case 32:
case 160:
++this.pos;
break;
case 13:
if (this.input.charCodeAt(this.pos + 1) === 10) {
++this.pos;
}
case 10:
case 8232:
case 8233:
this.pos++;
this.currentLine++;
break;
case 47:
if (this.nextCharCode === 47) {
this.pos++;
this.skipLineComment();
break;
}
else if (this.nextCharCode === 42) {
this.pos++;
this.skipBlockComment();
break;
}
break loop;
default:
if (ch > 8 && ch < 14) {
++this.pos;
}
else {
break loop;
}
}
}
}
consumeNextWordIfMatch(expectedWord) {
let reset = this.markPos();
this.next();
if (this.currentToken.value === expectedWord) {
return true;
}
reset();
return false;
}
isNextWordIs(expectedWord) {
let reset = this.markPos();
this.next();
if (this.currentToken.value === expectedWord) {
reset();
return true;
}
reset();
return false;
}
startParse(node, excutionFlag) {
let prevParsingNode = this.parsingNode, prevIsParsingLoop = this.isParsingLoop, isParsingFunDeclaration = this.isParsingFunDeclaration;
this.parsingNode = node;
excutionFlag && (this.excutionFlag |= excutionFlag);
return (expectExpressionEnd = true) => {
if (expectExpressionEnd && !prevParsingNode) {
this.expectExpressionEnd();
}
node.loc.end = this.pos;
if (this.parsingNode.code === constants_1.NodeCode.FunctionDeclarationStatement) {
this.isParsingFunDeclaration = false;
}
else if ((constants_1.NodeCode.Loop & this.parsingNode.code) === this.parsingNode.code) {
this.isParsingLoop = false;
}
this.parsingNode = prevParsingNode;
this.isParsingLoop = prevIsParsingLoop;
this.isParsingFunDeclaration = isParsingFunDeclaration;
excutionFlag && (this.excutionFlag &= ~excutionFlag);
if (node.isUnexpectEnd && this.parsingNode) {
this.parsingNode.isUnexpectEnd = true;
}
return node;
};
}
expectToken(expectedToken) {
if (this.isReadAll()) {
this.parsingNode.isUnexpectEnd = true;
return false;
}
expectedToken = typeof expectedToken === 'string' ? [expectedToken] : expectedToken;
for (let value of expectedToken) {
this.next();
if (this.currentToken.value !== value) {
this.parsingNode.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(this.currentToken.value, `expect ${value}`, this.currentToken.loc));
return false;
}
}
return true;
}
expectExpressionEnd() {
this.isReadAll() ||
this.isLineEnd() ||
this.expectToken(';');
}
parseNode(context = {}) {
if (this.isReadAll())
return null;
this.next();
let node;
switch (this.currentToken.type) {
case 'Keyword':
return this.parseIsStartWithKeyword();
case 'ParticularLiteral':
return new ParticularLiteralExpression_1.ParticularLiteralExpression(this.currentToken);
case 'TemplateLiteralExpStart':
return this.parseTemplateLiteralExp();
case 'IdentifierLiteral':
node = new IdentifierLiteralExpression_1.IdentifierLiteralExpression(this.currentToken);
if (this.excutionFlag & constants_1.NEED_PURE_IDENTIFIER)
return node;
return this.tryParseAssign(node) || !this.isParsingVarDeclaration && this.tryParse(node) || node;
case 'StringLiteral':
return this.tryParse(new StringLiteralExpression_1.StringLiteralExpression(this.currentToken));
case 'UnclosedStringLiteral':
return new UnExpectStatement_1.UnExpectStatement(new StringLiteralExpression_1.StringLiteralExpression(this.currentToken), 'unclosed string', this.currentToken.loc);
case 'NumberLiteral':
node = new NumberLiteratalExpression_1.NumberLiteralExpression(this.currentToken);
return this.tryParse(node);
case 'Operator':
if (!context.expectOperator && patterns_1.Patterns.prefixUnary.test(this.currentToken.value)) {
return this.parseUnaryExpression();
}
return null;
case 'RegExpStart':
if (context.expectOperator) {
return null;
}
return this.parseRegStatement();
case 'IllegalToken':
return new UnExpectStatement_1.UnExpectStatement(this.currentToken.value, 'Illegal token', this.currentToken.loc);
}
if (!this.currentToken.value && this.isReadAll()) {
if (this.parsingNode)
this.parsingNode.isUnexpectEnd = true;
}
return null;
}
next() {
this.skipSpace();
this.currentToken = {
loc: { start: null, end: null }
};
this.currentToken.loc.start = this.pos;
this.readWord();
this.currentToken.loc.end = this.pos;
this.tokens.push(Object.assign(this.currentToken));
return this.currentToken;
}
readWord() {
if ((0, javasriptAstParserUtil_1.isIdentifierStart)(this.curCharCode)) {
this.currentToken.value = this.readIdentifier();
if (!(this.excutionFlag & constants_1.IS_PARSING_ACCESSPROP) &&
!(this.excutionFlag & constants_1.IS_PARSING_OBJECT_KEY) &&
(this.currentToken.value === 'instanceof' || this.currentToken.value === 'in')) {
this.currentToken.type = 'Operator';
}
else if (patterns_1.Patterns.keywords.test(this.currentToken.value) &&
!(this.excutionFlag & constants_1.IS_PARSING_ACCESSPROP) &&
!(this.excutionFlag & constants_1.IS_PARSING_OBJECT_KEY)) {
this.currentToken.type = 'Keyword';
}
else if (patterns_1.Patterns.ParticularLiteral.test(this.currentToken.value)) {
this.currentToken.type = 'ParticularLiteral';
}
else {
this.currentToken.type = 'IdentifierLiteral';
}
}
else if ((0, javasriptAstParserUtil_1.isNumberStart)(this.curCharCode)) {
this.currentToken.type = 'NumberLiteral';
this.currentToken.value = this.readNumber();
}
else if (this.curCharCode === 39 || this.curCharCode === 34) {
let value = this.readString();
if (this.curCharCode !== this.stringStartToken) {
this.currentToken.type = 'UnclosedStringLiteral';
}
else {
this.currentToken.type = 'StringLiteral';
this.advance();
}
this.currentToken.value = value;
}
else if (patterns_1.Patterns.operators.test(this.curChar)) {
this.currentToken.type = 'Operator';
this.currentToken.value = this.readOperator();
this.currentToken.isAssignOperator = patterns_1.Patterns.assign.test(this.currentToken.value);
}
else {
let start = this.pos;
this.advance();
this.currentToken.value = this.input.slice(start, this.pos);
if (patterns_1.Patterns.blockStart.test(this.currentToken.value)) {
this.currentToken.type = 'BlockStart';
}
else if (patterns_1.Patterns.blockClose.test(this.currentToken.value)) {
this.currentToken.type = 'BlockClose';
}
else if (this.currentToken.value === '`') {
this.currentToken.type = 'TemplateLiteralExpStart';
}
else if (this.currentToken.value && ';.,:'.indexOf(this.currentToken.value) < 0) {
this.currentToken.value += this.readIllegalToken();
this.currentToken.type = 'IllegalToken';
}
}
}
readIllegalToken() {
let start = this.pos;
while (!this.isLineEnd() && this.curChar !== ';') {
this.advance();
}
return this.input.slice(start, this.pos);
}
readNumber() {
let start = this.pos;
this.consumeNumber();
return this.input.slice(start, this.pos);
}
consumeNumber() {
if (this.curCharCode === 48) {
switch (this.nextCharCode) {
case 98:
this.advance(2);
this.consumeBinary();
break;
case 120:
this.advance(2);
this.consumeHex();
break;
default:
this.advance();
break;
}
}
else {
this.currentToken.type = 'NumberLiteral';
let isReadingDecimal = false;
while (((0, javasriptAstParserUtil_1.isNumberCharCode)(this.curCharCode) || this.curCharCode === 46) && !this.isReadAll()) {
if (this.curCharCode === 46) {
if (isReadingDecimal) {
this.consumeUnexpect([]);
return;
}
isReadingDecimal = true;
}
this.advance();
}
}
}
readString() {
this.stringStartToken = this.curCharCode;
this.advance();
let start = this.pos;
this.consumeString();
return this.input.slice(start, this.pos);
}
consumeString() {
while (this.curCharCode !== this.stringStartToken && this.curCharCode !== 10 && !this.isReadAll()) {
this.advance();
}
}
readIdentifier() {
let start = this.pos;
this.advance();
this.consumeIdentifier();
return this.input.slice(start, this.pos);
}
consumeIdentifier() {
while ((0, javasriptAstParserUtil_1.isIdentifierChar)(this.curCharCode)) {
this.advance();
if (this.isReadAll())
break;
}
}
readOperator() {
let start = this.pos;
if (patterns_1.Patterns.canReapeat.test(this.curChar) && this.nextCharCode === this.curCharCode ||
patterns_1.Patterns.canPrefixAssign.test(this.curChar) && this.nextCharCode === 61 ||
this.curCharCode === 33 && this.nextCharCode === 61) {
this.advance();
}
if (this.curCharCode === 61 && this.nextCharCode === 61) {
this.advance();
}
this.advance();
return this.input.slice(start, this.pos);
}
safelyParseNode() {
let node = this.parseNode();
if (!this.parsingNode) {
return node;
}
if ((0, javasriptAstParserUtil_1.assertUnexpect)(this.parsingNode, node))
return null;
return node;
}
getExpectedNode(expectedCode) {
let node = this.safelyParseNode();
if (node) {
if ((expectedCode & node.code) === node.code)
return node;
this.parsingNode.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(node, '应为表达式'));
}
else if (this.isReadAll()) {
this.parsingNode.isUnexpectEnd = true;
}
else {
if (this.parsingNode && this.parsingNode.unexpectedNodes.length)
return null;
if (this.currentToken.value === '(' && expectedCode === constants_1.NodeCode.Expression)
return this.parseBracketEnwrapedExpression();
if (this.currentToken.value === '{' && (expectedCode & constants_1.NodeCode.ObjectLiteralExpression) === constants_1.NodeCode.ObjectLiteralExpression)
return this.parseObjLiteralExp();
if (this.currentToken.value === '[' && (expectedCode & constants_1.NodeCode.ArrayLiteralExpression) === constants_1.NodeCode.ArrayLiteralExpression)
return this.parseArrExp();
if (this.currentToken.value === '/' && (expectedCode & constants_1.NodeCode.RegExpression) === constants_1.NodeCode.RegExpression)
return this.parseRegStatement();
this.parsingNode.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(this.currentToken.value, `字符 '${this.currentToken.value}' 不该出现在此处`, this.currentToken.loc));
}
return null;
}
expectExpression() {
return this.getExpectedNode(constants_1.NodeCode.Expression);
}
tryToGetExpectedNode(expectedCode) {
let reset = this.markPos();
let node = this.parseNode();
if (node &&
!node.unexpectedNodes.length &&
(node.code & expectedCode) === node.code)
return node;
reset();
return null;
}
parseBlock(terminationTest = (node) => !node && this.currentToken.value === '}') {
let prevDepth = this.depth;
this.depth++;
let block = new Block_1.Block(), prevContext = this.excutionFlag, prevParsingNode = this.parsingNode;
block.loc = { start: this.pos, end: null };
block.depth = this.depth;
this.excutionFlag = 0;
this.parsingNode = null;
while (true) {
if (this.isReadAll()) {
prevParsingNode.isUnexpectEnd = true;
break;
}
let node = this.parseNode();
if (!node) {
if (this.currentToken.value === '{') {
const reset = this.markPos();
node = this.parseObjLiteralExp();
if (node.code === constants_1.NodeCode.ObjectLiteralExpression &&
!node.properties.length &&
node.unexpectedNodes.length) {
reset();
node = this.parseBlock();
}
}
else if (this.currentToken.value === '[') {
node = this.parseArrExp();
}
}
if (node) {
if (node.isUnexpectEnd) {
block.body.push(new UnExpectStatement_1.UnExpectStatement(node, 'unexpect end value'));
}
else {
block.body.push(node);
}
}
if (terminationTest(node))
break;
}
this.excutionFlag = prevContext;
this.parsingNode = prevParsingNode;
this.depth = prevDepth;
let len = block.body.length;
if (len) {
block.loc.end = block.body[len - 1].loc.end;
}
else {
block.loc.end = block.loc.start;
}
return block;
}
parseUnaryExpression() {
let node = new UnaryExpression_1.UnaryExpression(this.currentToken);
let finishParse = this.startParse(node);
node.prefix = true;
node.operator = this.currentToken.value;
node.argument = this.expectExpression();
return finishParse();
}
parseImportStatement() {
let node = this.tryToParseCallExpression(new IdentifierLiteralExpression_1.IdentifierLiteralExpression(this.currentToken));
if (node) {
return node;
}
else {
node = new ImportStatement_1.ImportStatement(this.currentToken);
let finishParse = this.startParse(node, constants_1.IS_PARSING_IMPORT);
if (node.from = this.tryToGetExpectedNode(constants_1.NodeCode.StringLiteralExpression))
return finishParse();
if (this.consumeNextWordIfMatch('{')) {
node.specifiers = this.getImportedSpecifiers();
}
else if (node.imported = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) {
if (this.consumeNextWordIfMatch('as') &&
!(node.local = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression))) {
return finishParse();
}
}
if (node.unexpectedNodes.length ||
!this.expectToken('from'))
return finishParse();
node.from = this.getExpectedNode(constants_1.NodeCode.StringLiteralExpression);
return finishParse();
}
}
getImportedSpecifiers() {
let specifiers = [], expectComma = false;
while (!this.consumeNextWordIfMatch('}') && !this.isReadAll()) {
if (expectComma) {
if (!this.expectToken(',')) {
break;
}
}
else {
let node = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression);
if (!node)
break;
let specifier = {
imported: node,
local: null
};
if (this.consumeNextWordIfMatch(':') || this.consumeNextWordIfMatch('as')) {
if (!(specifier.local = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression))) {
break;
}
}
specifiers.push(specifier);
}
expectComma = !expectComma;
}
return specifiers;
}
parseVarDeclarationStatement() {
this.isParsingVarDeclaration = true;
let statement = new VariableDeclarationStatement_1.VariableDeclarationStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_VARDECLARATION);
let declaration;
while (declaration = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression | constants_1.NodeCode.AssignmentExpression)) {
statement.declarations.push(declaration);
if (!this.consumeNextWordIfMatch(',')) {
break;
}
}
this.isParsingVarDeclaration = false;
return finishParse();
}
parseFunDeclarationStatement() {
let isClassMethod = this.currentToken.value !== 'function';
let statement = new FunctionDeclarationStatement_1.FunctionDeclarationStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_FUNDECLARATION);
this.isParsingFunDeclaration = true;
if ((statement.identifier = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) &&
this.expectToken('(')) {
let params;
if (!this.consumeNextWordIfMatch(')')) {
while (params = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) {
statement.params.push(params);
if (this.consumeNextWordIfMatch(')')) {
break;
}
else if (this.expectToken(',')) {
continue;
}
}
}
}
if (isClassMethod && statement.identifier)
statement.loc.start = statement.identifier.loc.start;
if (statement.unexpectedNodes.length)
return finishParse();
if (this.expectToken('{')) {
statement.body = this.parseBlock();
statement.body.functionBlock = true;
}
return finishParse();
}
tryParseFunciotnExpress() {
let currentToken = this.currentToken;
if (this.consumeNextWordIfMatch('(')) {
this.isParsingFunDeclaration = true;
let expression = new FuntionExpression_1.FunctionExpression(currentToken);
let finishParse = this.startParse(expression);
let param;
if (!this.consumeNextWordIfMatch(')')) {
while (param = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) {
expression.params.push(param);
if (this.consumeNextWordIfMatch(')') || !this.expectToken(','))
break;
}
}
;
if (!expression.unexpectedNodes.length && this.expectToken('{')) {
expression.body = this.parseBlock();
expression.body.functionBlock = true;
}
return finishParse();
}
return null;
}
parseObjLiteralExp() {
let expression = new ObjectLiteralExpression_1.ObjectLiteralExpression(this.currentToken);
let finishParse = this.startParse(expression);
let key, value;
this.excutionFlag |= constants_1.IS_PARSING_OBJECT_KEY;
while (!this.consumeNextWordIfMatch('}') && (key = this.getExpectedNode(constants_1.NodeCode.ObjectKey))) {
this.excutionFlag &= ~constants_1.IS_PARSING_OBJECT_KEY;
if (this.expectToken(':') && (value = this.getExpectedNode(constants_1.NodeCode.Expression))) {
expression.properties.push({
key: key,
value: value
});
this.excutionFlag |= constants_1.IS_PARSING_OBJECT_KEY;
if (this.consumeNextWordIfMatch('}') || !this.expectToken(',')) {
break;
}
}
else {
break;
}
}
this.excutionFlag &= ~constants_1.IS_PARSING_OBJECT_KEY;
if (expression.unexpectedNodes.length) {
return finishParse();
}
else {
return this.tryParse(finishParse(false));
}
}
parseArrExp() {
let expression = new ArrayLiteralExpression_1.ArrayLiteralExpression(this.currentToken);
let finishParse = this.startParse(expression);
let value;
while (!this.consumeNextWordIfMatch(']') && (value = this.expectExpression())) {
expression.items.push(value);
if (this.consumeNextWordIfMatch(']') || !this.expectToken(',')) {
break;
}
}
if (expression.unexpectedNodes.length) {
return finishParse();
}
else {
return this.tryParse(finishParse(false));
}
}
parseTryCatchStatment() {
let statement = new TryCatchStatement_1.TryCathchStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_TRY);
if (!this.expectToken('{')) {
return finishParse();
}
statement.body = this.parseBlock();
if (this.consumeNextWordIfMatch('catch')) {
let catchHandler = this.parseCatchHandler();
if (catchHandler.unexpectedNodes.length) {
statement.unexpectedNodes.push(catchHandler);
return finishParse();
}
statement.catchHandler = catchHandler;
}
if (this.consumeNextWordIfMatch('finally') && this.expectToken('{')) {
statement.finalizer = this.parseBlock();
}
if (!statement.catchHandler && !statement.finalizer)
statement.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(this.currentToken.value, 'expect finally', this.currentToken.loc));
return finishParse();
}
parseCatchHandler() {
let statement = new FunctionDeclarationStatement_1.FunctionDeclarationStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_FUNDECLARATION);
this.isParsingFunDeclaration = true;
statement.identifier = new IdentifierLiteralExpression_1.IdentifierLiteralExpression(this.currentToken);
if (this.expectToken('(')) {
let params;
if (!this.consumeNextWordIfMatch(')')) {
while (params = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) {
statement.params.push(params);
if (this.consumeNextWordIfMatch(')')) {
break;
}
else if (this.expectToken(',')) {
continue;
}
}
}
}
if (statement.unexpectedNodes.length)
return finishParse();
if (this.expectToken('{')) {
statement.body = this.parseBlock();
statement.body.functionBlock = true;
}
return finishParse();
}
parseDoWihleStatement() {
let statement = new DoWhileStatement_1.DoWhileStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_DOWHILE);
this.isParsingLoop = true;
if (!this.expectToken('{'))
return finishParse();
statement.body = this.parseBlock();
this.expectToken('while') &&
this.expectToken('(') &&
(statement.test = this.expectExpression()) &&
this.expectToken(')');
return finishParse();
}
parseWhileStatment() {
let statement = new WhileStatement_1.WhileStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_SWITCH);
this.isParsingLoop = true;
if (this.expectToken('(') &&
(statement.test = this.expectExpression()) &&
this.expectToken(')') &&
this.expectToken('{')) {
statement.consequence = this.parseBlock();
}
return finishParse();
}
parseExpressions(endFlag) {
let exprs = [];
while (!this.isReadAll()) {
let expr = this.expectExpression();
exprs.push(expr);
if (this.isNextWordIs(endFlag) || !this.consumeNextWordIfMatch(','))
return exprs;
}
}
parseForStatement() {
let statement = new ForStatement_1.ForStatement(this.currentToken);
let finishParse = this.startParse(statement);
this.isParsingLoop = true;
if (!this.expectToken('('))
return finishParse();
if (!this.consumeNextWordIfMatch(';')) {
let init = this.getExpectedNode(constants_1.NodeCode.Expression | constants_1.NodeCode.VariableDeclarationStatement);
if (!init) {
return finishParse();
}
else if (init.code === constants_1.NodeCode.IdentifierLiteralExpression ||
init.code === constants_1.NodeCode.VariableDeclarationStatement &&
init.declarations.length === 1 &&
init.declarations[0].code !== constants_1.NodeCode.AssignmentExpression) {
if ((statement.forOf = this.consumeNextWordIfMatch('of')) ||
(statement.forIn = this.consumeNextWordIfMatch('in'))) {
statement.left = init;
if ((statement.forIn ? statement.right = this.expectExpression() :
statement.right = this.expectExpression()) &&
this.expectToken(')') &&
this.expectToken('{')) {
statement.body = this.parseBlock();
}
return finishParse();
}
}
statement.init = init;
if (!this.expectToken(';'))
return finishParse();
}
if (!this.consumeNextWordIfMatch(';') &&
!(statement.test = this.expectExpression()) &&
!this.expectToken(';')) {
return finishParse();
}
if (this.consumeNextWordIfMatch(')') ||
this.expectToken(';') &&
(statement.update = this.parseExpressions(')')) &&
this.expectToken(')')) {
if (this.expectToken('{'))
statement.body = this.parseBlock();
}
return finishParse();
}
parseRegStatement() {
let expression = new RegExpressioin_1.RegExpressioin(this.currentToken);
let finishParse = this.startParse(expression);
let pos = this.pos - 1, escape = false;
while (!this.isReadAll() && !(!escape && this.curChar === '/')) {
this.advance();
if (this.curChar === '\n') {
expression.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(this.input.slice(pos, this.pos), '未完成的正则表达式', {
start: pos,
end: this.pos
}));
return finishParse();
}
if (escape) {
escape = false;
}
else if (this.curChar === '\\') {
escape = true;
}
}
this.advance();
expression.pattern = this.input.slice(pos, this.pos);
if (this.curChar === 'i' || this.curChar === 'g') {
let reset = this.markPos();
this.next();
if (!/i|g|ig|gi/.test(this.currentToken.value)) {
reset();
}
else {
expression.flag = this.currentToken.value;
}
}
return finishParse();
}
parseIfStatement() {
let statement = new IfStatement_1.IfStatement(this.currentToken);
let finishParse = this.startParse(statement);
let expectLineEnd = false;
let parseConditionBlock = () => {
if (this.consumeNextWordIfMatch('{')) {
return this.parseBlock();
}
else {
expectLineEnd = true;
let currentLine = this.currentLine;
let reset = this.markPos();
let block = new Block_1.Block();
if (this.consumeNextWordIfMatch('else')) {
if (currentLine === this.currentLine) {
statement.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement('else', 'statement expect', this.currentToken.loc));
return null;
}
reset();
return block;
}
else if (this.consumeNextWordIfMatch(';')) {
reset();
return block;
}
let nextStatement = this.safelyParseNode();
if (nextStatement) {
block.body.push(nextStatement);
}
return block;
}
};
if (!this.expectToken('(') ||
!(statement.test = this.expectExpression()) ||
!this.expectToken(')')) {
return finishParse();
}
statement.consequent = parseConditionBlock();
if (statement.unexpectedNodes.length || expectLineEnd && !this.isLineEnd())
return finishParse();
expectLineEnd = false;
if (this.consumeNextWordIfMatch('else')) {
if (this.consumeNextWordIfMatch('if')) {
statement.alternate = this.parseIfStatement();
}
else if (this.expectToken('{')) {
statement.alternate = this.parseBlock();
}
}
return finishParse();
}
parseBreakStatement() {
let statement = new BreakStatement_1.BreakStatement(this.currentToken);
let finishParse = this.startParse(statement);
if (!this.isLineEnd() && !this.isNextWordIs(';')) {
statement.argument = this.expectExpression();
}
if (!this.isParsingLoop)
return new UnExpectStatement_1.UnExpectStatement(finishParse(), '"break" 语句只能在循环语句里使用');
return finishParse();
}
parseReturnStatement() {
let statement = new ReturnStatement_1.ReturnStatement(this.currentToken);
let finishParse = this.startParse(statement);
if (!this.isLineEnd() && !this.isNextWordIs(';')) {
statement.argument = this.expectExpression();
}
if (!this.isParsingFunDeclaration)
return new UnExpectStatement_1.UnExpectStatement(finishParse(), 'A "return" statement can only be used within a function body');
return finishParse();
}
parseContinueStatement() {
let statement = new ContinueStatement_1.ContinueStatement(this.currentToken);
let finishParse = this.startParse(statement);
if (!this.isLineEnd() && !this.isNextWordIs(';')) {
statement.argument = this.expectExpression();
}
if (!this.isParsingLoop)
return new UnExpectStatement_1.UnExpectStatement(finishParse(), '"continue" 语句只能用在循环语句内');
return finishParse();
}
parseSwitchStatement() {
let statement = new SwitchStatement_1.SwitchStatement(this.currentToken);
let finishParse = this.startParse(statement);
let caseStatement;
if (!(this.expectToken('(') &&
(statement.discriminant = this.expectExpression()) &&
this.expectToken([')', '{'])))
return finishParse();
while (!this.consumeNextWordIfMatch('}')) {
if (caseStatement = this.parseCaseStatement()) {
if (caseStatement.unexpectedNodes.length) {
break;
}
statement.cases.push(caseStatement);
}
else {
break;
}
}
return finishParse();
}
parseCaseStatement() {
if (!this.consumeNextWordIfMatch('case') &&
!this.consumeNextWordIfMatch('default')) {
this.next();
this.parsingNode.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(this.currentToken.value, 'expect "case" or "default"', this.currentToken.loc));
return null;
}
let statement = new SwitchCaseStatement_1.SwitchCaseStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_CASE);
this.isParsingLoop = true;
statement.isDefault = this.currentToken.value === 'default';
if (!statement.isDefault && !(statement.test = this.expectExpression())) {
return finishParse();
}
if (this.expectToken(':')) {
if (this.consumeNextWordIfMatch('{')) {
statement.consequent = this.parseBlock();
}
else {
let reset = this.markPos();
statement.consequent = this.parseBlock((statement) => {
if (!statement &&
['case', 'default', '}'].includes(this.currentToken.value)) {
reset();
return true;
}
else {
reset = this.markPos();
}
});
}
}
return finishParse();
}
parseThrowStatement() {
let statement = new ThrowStatement_1.ThrowStatement(this.currentToken);
let finishParse = this.startParse(statement);
statement.argument = this.expectExpression();
return finishParse();
}
parseWithStatement() {
let statement = new WithStatement_1.WithStatement(this.currentToken);
let finishParse = this.startParse(statement);
if (this.expectToken('(') &&
(statement.context = this.expectExpression()) &&
this.expectToken(')') &&
this.expectToken('{')) {
statement.body = this.parseBlock();
}
return finishParse();
}
parseDeleteStatement() {
let statement = new DeleteStatement_1.DeleteStatement(this.currentToken);
let finishParse = this.startParse(statement);
statement.argument = this.getExpectedNode(constants_1.NodeCode.MemberExpression);
return finishParse();
}
parseNewStatement() {
let expression = new NewExpressioin_1.NewExpressioin(this.currentToken);
let finishParse = this.startParse(expression);
expression.callee = this.getExpectedNode(constants_1.NodeCode.CallExpression | constants_1.NodeCode.IdentifierLiteralExpression);
return finishParse();
}
parseClassDeclarationStatement() {
let statement = new ClassDeclarationStatement_1.ClassDeclarationStatement(this.currentToken);
let finishParse = this.startParse(statement, constants_1.IS_PARSING_CLASSDECLARATION);
if (!(statement.className = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) ||
this.consumeNextWordIfMatch('extends') &&
!(statement.super = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) ||
!this.expectToken('{')) {
return finishParse();
}
while (!this.consumeNextWordIfMatch('}') && !this.isReadAll()) {
let method = this.parseClassMehod();
if (!method)
return finishParse();
statement.methods.push(method);
}
return finishParse();
}
parseClassMehod() {
let reset = this.markPos();
this.next();
if (this.currentToken.type !== 'IdentifierLiteral') {
this.parsingNode.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(this.currentToken.value, 'expect identifier', this.currentToken.loc));
return null;
}
reset();
let statement = this.parseFunDeclarationStatement();
if (statement.unexpectedNodes.length) {
this.parsingNode.unexpectedNodes.push(statement);
return null;
}
return statement;
}
parseExportStatement() {
let statement = new ExportDeclarationStatement_1.ExportDeclarationStatement(this.currentToken);
let finishParse = this.startParse(statement);
if (this.consumeNextWordIfMatch('{')) {
let identifier;
while (identifier = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) {
let exportSpecifier = {
exported: identifier,
local: null
};
if (this.consumeNextWordIfMatch('as')) {
if (exportSpecifier.local = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression)) {
statement.specifiers.push(exportSpecifier);
}
else {
return finishParse();
}
}
statement.specifiers.push(exportSpecifier);
if (this.consumeNextWordIfMatch('}'))
break;
if (!this.expectToken(','))
return finishParse();
}
}
else {
let identifier = this.getExpectedNode(constants_1.NodeCode.Declaration | constants_1.NodeCode.IdentifierLiteralExpression);
if (identifier) {
statement.exported = identifier;
if ((identifier.code & constants_1.NodeCode.Declaration) === identifier.code) {
return finishParse();
}
if (this.consumeNextWordIfMatch('as') && !(statement.local = this.getExpectedNode(constants_1.NodeCode.IdentifierLiteralExpression))) {
return finishParse();
}
}
else {
return finishParse();
}
}
this.expectToken('from') &&
(statement.from = this.getExpectedNode(constants_1.NodeCode.StringLiteralExpression));
return finishParse();
}
parseTypeOfExpression() {
let expression = new TypeOfExpression_1.TypeOfExpression(this.currentToken);
let finishParse = this.startParse(expression, constants_1.IS_PARSING_TYPEOF);
expression.argument = this.expectExpression();
if (expression.unexpectedNodes.length) {
return finishParse();
}
else {
return this.tryParse(finishParse(false));
}
}
parseVoidExpression() {
let expression = new VoidExpression_1.VoidExpression(this.currentToken);
let finishParse = this.startParse(expression, constants_1.IS_PARSING_VOID);
expression.argument = this.expectExpression();
if (expression.unexpectedNodes.length) {
return finishParse();
}
else {
return this.tryParse(finishParse(false));
}
}
parseTemplateLiteralExp() {
let node = new TemplateLiteralExppression_1.TemplateLiteralExppression(this.currentToken);
let finishParse = this.startParse(node);
let consumeString = () => {
while (this.curCharCode !== 96 && !this.isReadAll() && this.input.slice(this.pos, this.pos + 2) !== '${') {
this.advance();
}
};
while (this.curCharCode !== 96) {
let start = this.pos, str;
consumeString();
str = new StringLiteralExpression_1.StringLiteralExpression({
value: this.input.slice(start, this.pos),
loc: {
start: start,
end: this.pos
}
});
if (this.isReadAll()) {
str && node.unexpectedNodes.push(new UnExpectStatement_1.UnExpectStatement(str, '未闭合的模板字符串', {
start: node.loc.start,
end: this.pos
}));
return finishParse();
}
node.content.push(str);
if (t