parseStmt method

  1. @override
ASTNode? parseStmt({
  1. required ParseStyle style,
})
override

Implementation

@override
ASTNode? parseStmt({required ParseStyle style}) {
  handlePrecedings();

  // if (_handlePrecedingCommentsOrEmptyLines()) {
  //   return null;
  // }

  // handle emtpy statement is a must because automatic semicolon insertion.
  if (curTok.type == lexicon.endOfStatementMark) {
    advance();
    return null;
  }

  if (curTok.type == Semantic.endOfFile) {
    return null;
  }

  // save preceding comments because those might change during expression parsing.
  final savedPrecedings = savePrecedings();

  // if (curTok is TokenEmptyLine) {
  //   final empty = advance();
  //   final emptyStmt = ASTEmptyLine(
  //       line: empty.line, column: empty.column, offset: empty.offset);
  //   emptyStmt.precedingComments = precedingComments;
  //   return emptyStmt;
  // }

  ASTNode stmt;

  switch (style) {
    case ParseStyle.script:
      if (curTok.lexeme == lexicon.kImport) {
        stmt = _parseImportDecl();
      } else if (curTok.lexeme == lexicon.kExport) {
        stmt = _parseExportStmt();
      } else if (curTok.lexeme == lexicon.kType) {
        stmt = _parseTypeAliasDecl(isTopLevel: true);
      } else if (curTok.lexeme == lexicon.kNamespace) {
        stmt = _parseNamespaceDecl(isTopLevel: true);
      } else if (curTok.type == lexicon.kExternal) {
        advance();
        if (curTok.type == lexicon.kAbstract) {
          advance();
          stmt = _parseClassDecl(
              isAbstract: true, isExternal: true, isTopLevel: true);
        } else if (curTok.type == lexicon.kClass) {
          stmt = _parseClassDecl(isExternal: true, isTopLevel: true);
        } else if (curTok.type == lexicon.kEnum) {
          stmt = _parseEnumDecl(isExternal: true, isTopLevel: true);
        } else if (lexicon.variableDeclarationKeywords
            .contains(curTok.type)) {
          final err = HTError.externalVar(
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        } else if (curTok.type == lexicon.kFun) {
          stmt = _parseFunction(isExternal: true, isTopLevel: true);
        } else {
          final err = HTError.unexpected(
              lexicon.kExternal, Semantic.declStmt, curTok.lexeme,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        }
      } else if (curTok.type == lexicon.kAbstract) {
        advance();
        stmt = _parseClassDecl(
            isAbstract: true, isTopLevel: true, lateResolve: false);
      } else if (curTok.type == lexicon.kClass) {
        stmt = _parseClassDecl(isTopLevel: true, lateResolve: false);
      } else if (curTok.type == lexicon.kEnum) {
        stmt = _parseEnumDecl(isTopLevel: true);
      } else if (curTok.type == lexicon.kVar) {
        if (lexicon.destructuringDeclarationMark.contains(peek(1).type)) {
          stmt = _parseDestructuringDecl(isTopLevel: true, isMutable: true);
        } else {
          stmt = _parseVarDecl(isMutable: true, isTopLevel: true);
        }
      } else if (curTok.type == lexicon.kFinal) {
        if (lexicon.destructuringDeclarationMark.contains(peek(1).type)) {
          stmt = _parseDestructuringDecl(isTopLevel: true);
        } else {
          stmt = _parseVarDecl(isTopLevel: true);
        }
      } else if (curTok.type == lexicon.kLate) {
        stmt = _parseVarDecl(lateFinalize: true, isTopLevel: true);
      } else if (curTok.type == lexicon.kConst) {
        stmt = _parseVarDecl(isConst: true, isTopLevel: true);
      } else if (curTok.type == lexicon.kFun) {
        if (expect([lexicon.kFun, Semantic.identifier]) ||
            expect([
              lexicon.kFun,
              lexicon.externalFunctionTypeDefStart,
              Semantic.identifier,
              lexicon.externalFunctionTypeDefEnd,
              Semantic.identifier
            ])) {
          stmt = _parseFunction(isTopLevel: true);
        } else {
          stmt = _parseFunction(
              category: FunctionCategory.literal, isTopLevel: true);
        }
      }
      // else if (curTok.type == lexicon.kAsync) {
      //   if (expect([lexicon.kAsync, Semantic.identifier]) ||
      //       expect([
      //         lexicon.kFun,
      //         lexicon.externalFunctionTypeDefStart,
      //         Semantic.identifier,
      //         lexicon.externalFunctionTypeDefEnd,
      //         Semantic.identifier
      //       ])) {
      //     stmt = _parseFunction(isAsync: true, isTopLevel: true);
      //   } else {
      //     stmt = _parseFunction(
      //         category: FunctionCategory.literal,
      //         isAsync: true,
      //         isTopLevel: true);
      //   }
      // }
      else if (curTok.type == lexicon.kStruct) {
        stmt =
            _parseStructDecl(isTopLevel: true); // , lateInitialize: false);
      } else if (curTok.type == lexicon.kDelete) {
        stmt = _parseDeleteStmt();
      } else if (curTok.type == lexicon.kIf) {
        stmt = _parseIf();
      } else if (curTok.type == lexicon.kWhile) {
        stmt = _parseWhileStmt();
      } else if (curTok.type == lexicon.kDo) {
        stmt = _parseDoStmt();
      } else if (curTok.type == lexicon.kFor) {
        stmt = _parseForStmt();
      } else if (curTok.type == lexicon.kWhen) {
        stmt = _parseWhen();
      } else if (curTok.type == lexicon.kAssert) {
        stmt = _parseAssertStmt();
      } else if (curTok.type == lexicon.kThrow) {
        stmt = _parseThrowStmt();
      } else {
        stmt = _parseExprStmt();
      }
      break;
    case ParseStyle.module:
      if (curTok.lexeme == lexicon.kImport) {
        stmt = _parseImportDecl();
      } else if (curTok.lexeme == lexicon.kExport) {
        stmt = _parseExportStmt();
      } else if (curTok.lexeme == lexicon.kType) {
        stmt = _parseTypeAliasDecl(isTopLevel: true);
      } else if (curTok.lexeme == lexicon.kNamespace) {
        stmt = _parseNamespaceDecl(isTopLevel: true);
      } else if (curTok.type == lexicon.kExternal) {
        advance();
        if (curTok.type == lexicon.kAbstract) {
          advance();
          if (curTok.type != lexicon.kClass) {
            final err = HTError.unexpected(
                lexicon.kAbstract, Semantic.classDeclaration, curTok.lexeme,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          } else {
            stmt = _parseClassDecl(
                isAbstract: true, isExternal: true, isTopLevel: true);
          }
        } else if (curTok.type == lexicon.kClass) {
          stmt = _parseClassDecl(isExternal: true, isTopLevel: true);
        } else if (curTok.type == lexicon.kEnum) {
          stmt = _parseEnumDecl(isExternal: true, isTopLevel: true);
        } else if (curTok.type == lexicon.kFun) {
          stmt = _parseFunction(isExternal: true, isTopLevel: true);
        } else if (lexicon.variableDeclarationKeywords
            .contains(curTok.type)) {
          final err = HTError.externalVar(
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        } else {
          final err = HTError.unexpected(
              lexicon.kExternal, Semantic.declStmt, curTok.lexeme,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        }
      } else if (curTok.type == lexicon.kAbstract) {
        advance();
        stmt = _parseClassDecl(isAbstract: true, isTopLevel: true);
      } else if (curTok.type == lexicon.kClass) {
        stmt = _parseClassDecl(isTopLevel: true);
      } else if (curTok.type == lexicon.kEnum) {
        stmt = _parseEnumDecl(isTopLevel: true);
      } else if (curTok.type == lexicon.kVar) {
        stmt = _parseVarDecl(
            isMutable: true, isTopLevel: true, lateInitialize: true);
      } else if (curTok.type == lexicon.kFinal) {
        stmt = _parseVarDecl(lateInitialize: true, isTopLevel: true);
      } else if (curTok.type == lexicon.kLate) {
        stmt = _parseVarDecl(lateFinalize: true, isTopLevel: true);
      } else if (curTok.type == lexicon.kConst) {
        stmt = _parseVarDecl(isConst: true, isTopLevel: true);
      } else if (curTok.type == lexicon.kFun) {
        stmt = _parseFunction(isTopLevel: true);
      } else if (curTok.type == lexicon.kStruct) {
        stmt = _parseStructDecl(isTopLevel: true);
      } else {
        final err = HTError.unexpected(
            Semantic.declStmt, Semantic.declStmt, curTok.lexeme,
            filename: currrentFileName,
            line: curTok.line,
            column: curTok.column,
            offset: curTok.offset,
            length: curTok.length);
        errors.add(err);
        final errToken = advance();
        stmt = ASTEmptyLine(
            source: currentSource,
            line: errToken.line,
            column: errToken.column,
            offset: errToken.offset);
      }
      break;
    case ParseStyle.namespace:
      if (curTok.lexeme == lexicon.kType) {
        stmt = _parseTypeAliasDecl();
      } else if (curTok.lexeme == lexicon.kNamespace) {
        stmt = _parseNamespaceDecl();
      } else if (curTok.type == lexicon.kExternal) {
        advance();
        if (curTok.type == lexicon.kAbstract) {
          advance();
          if (curTok.type != lexicon.kClass) {
            final err = HTError.unexpected(
                lexicon.kAbstract, Semantic.classDeclaration, curTok.lexeme,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          } else {
            stmt = _parseClassDecl(isAbstract: true, isExternal: true);
          }
        } else if (curTok.type == lexicon.kClass) {
          stmt = _parseClassDecl(isExternal: true);
        } else if (curTok.type == lexicon.kEnum) {
          stmt = _parseEnumDecl(isExternal: true);
        } else if (curTok.type == lexicon.kFun) {
          stmt = _parseFunction(isExternal: true);
        } else if (lexicon.variableDeclarationKeywords
            .contains(curTok.type)) {
          final err = HTError.externalVar(
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        } else {
          final err = HTError.unexpected(
              lexicon.kExternal, Semantic.declStmt, curTok.lexeme,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        }
      } else if (curTok.type == lexicon.kAbstract) {
        advance();
        stmt = _parseClassDecl(
            isAbstract: true, lateResolve: _isWithinModuleNamespace);
      } else if (curTok.type == lexicon.kClass) {
        stmt = _parseClassDecl(lateResolve: _isWithinModuleNamespace);
      } else if (curTok.type == lexicon.kEnum) {
        stmt = _parseEnumDecl();
      } else if (curTok.type == lexicon.kVar) {
        stmt = _parseVarDecl(
            isMutable: true, lateInitialize: _isWithinModuleNamespace);
      } else if (curTok.type == lexicon.kFinal) {
        stmt = _parseVarDecl(lateInitialize: _isWithinModuleNamespace);
      } else if (curTok.type == lexicon.kConst) {
        stmt = _parseVarDecl(isConst: true);
      } else if (curTok.type == lexicon.kFun) {
        stmt = _parseFunction();
      } else if (curTok.type == lexicon.kStruct) {
        stmt = _parseStructDecl();
      } else {
        final err = HTError.unexpected(
            Semantic.declStmt, Semantic.declStmt, curTok.lexeme,
            filename: currrentFileName,
            line: curTok.line,
            column: curTok.column,
            offset: curTok.offset,
            length: curTok.length);
        errors.add(err);
        final errToken = advance();
        stmt = ASTEmptyLine(
            source: currentSource,
            line: errToken.line,
            column: errToken.column,
            offset: errToken.offset);
      }
      break;
    case ParseStyle.classDefinition:
      final isOverrided = expect([lexicon.kOverride], consume: true);
      final isExternal = expect([lexicon.kExternal], consume: true) ||
          (_currentClassDeclaration?.isExternal ?? false);
      final isStatic = expect([lexicon.kStatic], consume: true);
      if (curTok.lexeme == lexicon.kType) {
        if (isExternal) {
          final err = HTError.external(Semantic.typeAliasDeclaration,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        } else {
          stmt = _parseTypeAliasDecl();
        }
      } else {
        if (curTok.type == lexicon.kVar) {
          stmt = _parseVarDecl(
              classId: _currentClassDeclaration?.id,
              isOverrided: isOverrided,
              isExternal: isExternal,
              isMutable: true,
              isStatic: isStatic,
              lateInitialize: true);
        } else if (curTok.type == lexicon.kFinal) {
          stmt = _parseVarDecl(
              classId: _currentClassDeclaration?.id,
              isOverrided: isOverrided,
              isExternal: isExternal,
              isStatic: isStatic,
              lateInitialize: true);
        } else if (curTok.type == lexicon.kLate) {
          stmt = _parseVarDecl(
              classId: _currentClassDeclaration?.id,
              isOverrided: isOverrided,
              isExternal: isExternal,
              isStatic: isStatic,
              lateFinalize: true);
        } else if (curTok.type == lexicon.kConst) {
          if (isStatic) {
            stmt = _parseVarDecl(
                isConst: true, classId: _currentClassDeclaration?.id);
          } else {
            final err = HTError.external(Semantic.typeAliasDeclaration,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          }
        } else if (curTok.type == lexicon.kFun) {
          stmt = _parseFunction(
              category: FunctionCategory.method,
              classId: _currentClassDeclaration?.id,
              isOverrided: isOverrided,
              isExternal: isExternal,
              isStatic: isStatic);
        }
        // else if (curTok.type == lexicon.kAsync) {
        //   if (isExternal) {
        //     final err = HTError.external(Semantic.asyncFunction,
        //         filename: currrentFileName,
        //         line: curTok.line,
        //         column: curTok.column,
        //         offset: curTok.offset,
        //         length: curTok.length);
        //     errors.add(err);
        //     final errToken = advance();
        //     stmt = ASTEmptyLine(
        //         source: currentSource,
        //         line: errToken.line,
        //         column: errToken.column,
        //         offset: errToken.offset);
        //   } else {
        //     stmt = _parseFunction(
        //         category: FunctionCategory.method,
        //         classId: _currentClassDeclaration?.id,
        //         isAsync: true,
        //         isOverrided: isOverrided,
        //         isExternal: isExternal,
        //         isStatic: isStatic);
        //   }
        // }
        else if (curTok.type == lexicon.kGet) {
          stmt = _parseFunction(
              category: FunctionCategory.getter,
              classId: _currentClassDeclaration?.id,
              isOverrided: isOverrided,
              isExternal: isExternal,
              isStatic: isStatic);
        } else if (curTok.type == lexicon.kSet) {
          stmt = _parseFunction(
              category: FunctionCategory.setter,
              classId: _currentClassDeclaration?.id,
              isOverrided: isOverrided,
              isExternal: isExternal,
              isStatic: isStatic);
        } else if (curTok.type == lexicon.kConstruct) {
          if (isStatic) {
            final err = HTError.unexpected(
                lexicon.kStatic, Semantic.declStmt, lexicon.kConstruct,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          } else if (isExternal && !_currentClassDeclaration!.isExternal) {
            final err = HTError.external(Semantic.ctorFunction,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          } else {
            stmt = _parseFunction(
              category: FunctionCategory.constructor,
              classId: _currentClassDeclaration?.id,
              isExternal: isExternal,
            );
          }
        } else if (curTok.type == lexicon.kFactory) {
          if (isStatic) {
            final err = HTError.unexpected(
                lexicon.kStatic, Semantic.declStmt, lexicon.kConstruct,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          } else if (isExternal && !_currentClassDeclaration!.isExternal) {
            final err = HTError.external(Semantic.factory,
                filename: currrentFileName,
                line: curTok.line,
                column: curTok.column,
                offset: curTok.offset,
                length: curTok.length);
            errors.add(err);
            final errToken = advance();
            stmt = ASTEmptyLine(
                source: currentSource,
                line: errToken.line,
                column: errToken.column,
                offset: errToken.offset);
          } else {
            stmt = _parseFunction(
              category: FunctionCategory.factoryConstructor,
              classId: _currentClassDeclaration?.id,
              isExternal: isExternal,
              isStatic: true,
            );
          }
        } else {
          final err = HTError.unexpected(
              Semantic.classDefinition, Semantic.declStmt, curTok.lexeme,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        }
      }
      break;
    case ParseStyle.structDefinition:
      final isExternal = expect([lexicon.kExternal], consume: true);
      final isStatic = expect([lexicon.kStatic], consume: true);
      if (curTok.type == lexicon.kVar) {
        stmt = _parseVarDecl(
            classId: _currentStructId,
            isField: true,
            isExternal: isExternal,
            isMutable: true,
            isStatic: isStatic,
            lateInitialize: true);
      } else if (curTok.type == lexicon.kFinal) {
        stmt = _parseVarDecl(
            classId: _currentStructId,
            isField: true,
            isExternal: isExternal,
            isStatic: isStatic,
            lateInitialize: true);
      } else if (curTok.type == lexicon.kFun) {
        stmt = _parseFunction(
            category: FunctionCategory.method,
            classId: _currentStructId,
            isExternal: isExternal,
            isField: true,
            isStatic: isStatic);
      }
      // else if (curTok.type == lexicon.kAsync) {
      //   if (isExternal) {
      //     final err = HTError.external(Semantic.asyncFunction,
      //         filename: currrentFileName,
      //         line: curTok.line,
      //         column: curTok.column,
      //         offset: curTok.offset,
      //         length: curTok.length);
      //     errors.add(err);
      //     final errToken = advance();
      //     stmt = ASTEmptyLine(
      //         source: currentSource,
      //         line: errToken.line,
      //         column: errToken.column,
      //         offset: errToken.offset);
      //   } else {
      //     stmt = _parseFunction(
      //         category: FunctionCategory.method,
      //         classId: _currentStructId,
      //         isAsync: true,
      //         isField: true,
      //         isExternal: isExternal,
      //         isStatic: isStatic);
      //   }
      // }
      else if (curTok.type == lexicon.kGet) {
        stmt = _parseFunction(
            category: FunctionCategory.getter,
            classId: _currentStructId,
            isField: true,
            isExternal: isExternal,
            isStatic: isStatic);
      } else if (curTok.type == lexicon.kSet) {
        stmt = _parseFunction(
            category: FunctionCategory.setter,
            classId: _currentStructId,
            isField: true,
            isExternal: isExternal,
            isStatic: isStatic);
      } else if (curTok.type == lexicon.kConstruct) {
        if (isStatic) {
          final err = HTError.unexpected(
              lexicon.kStatic, Semantic.declStmt, lexicon.kConstruct,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        } else if (isExternal) {
          final err = HTError.external(Semantic.ctorFunction,
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
          final errToken = advance();
          stmt = ASTEmptyLine(
              source: currentSource,
              line: errToken.line,
              column: errToken.column,
              offset: errToken.offset);
        } else {
          stmt = _parseFunction(
              category: FunctionCategory.constructor,
              classId: _currentStructId,
              isExternal: isExternal,
              isField: true);
        }
      } else {
        final err = HTError.unexpected(
            Semantic.structDefinition, Semantic.declStmt, curTok.lexeme,
            filename: currrentFileName,
            line: curTok.line,
            column: curTok.column,
            offset: curTok.offset,
            length: curTok.length);
        errors.add(err);
        final errToken = advance();
        stmt = ASTEmptyLine(
            source: currentSource,
            line: errToken.line,
            column: errToken.column,
            offset: errToken.offset);
      }
      break;
    case ParseStyle.functionDefinition:
      if (curTok.lexeme == lexicon.kType) {
        stmt = _parseTypeAliasDecl();
      } else if (curTok.lexeme == lexicon.kNamespace) {
        stmt = _parseNamespaceDecl();
      } else if (curTok.type == lexicon.kAbstract) {
        advance();
        stmt = _parseClassDecl(isAbstract: true, lateResolve: false);
      } else if (curTok.type == lexicon.kClass) {
        stmt = _parseClassDecl(lateResolve: false);
      } else if (curTok.type == lexicon.kEnum) {
        stmt = _parseEnumDecl();
      } else if (curTok.type == lexicon.kVar) {
        if (lexicon.destructuringDeclarationMark.contains(peek(1).type)) {
          stmt = _parseDestructuringDecl(isMutable: true);
        } else {
          stmt = _parseVarDecl(isMutable: true);
        }
      } else if (curTok.type == lexicon.kFinal) {
        if (lexicon.destructuringDeclarationMark.contains(peek(1).type)) {
          stmt = _parseDestructuringDecl();
        } else {
          stmt = _parseVarDecl();
        }
      } else if (curTok.type == lexicon.kLate) {
        stmt = _parseVarDecl(lateFinalize: true);
      } else if (curTok.type == lexicon.kConst) {
        stmt = _parseVarDecl(isConst: true);
      } else if (curTok.type == lexicon.kFun) {
        if (expect([lexicon.kFun, Semantic.identifier]) ||
            expect([
              lexicon.kFun,
              lexicon.externalFunctionTypeDefStart,
              Semantic.identifier,
              lexicon.externalFunctionTypeDefEnd,
              Semantic.identifier
            ])) {
          stmt = _parseFunction();
        } else {
          stmt = _parseFunction(category: FunctionCategory.literal);
        }
      }
      // else if (curTok.type == lexicon.kAsync) {
      //   if (expect([lexicon.kAsync, Semantic.identifier]) ||
      //       expect([
      //         lexicon.kFun,
      //         lexicon.externalFunctionTypeDefStart,
      //         Semantic.identifier,
      //         lexicon.externalFunctionTypeDefEnd,
      //         Semantic.identifier
      //       ])) {
      //     stmt = _parseFunction(isAsync: true);
      //   } else {
      //     stmt = _parseFunction(
      //         category: FunctionCategory.literal, isAsync: true);
      //   }
      // }
      else if (curTok.type == lexicon.kStruct) {
        stmt = _parseStructDecl(); // (lateInitialize: false);
      } else if (curTok.type == lexicon.kDelete) {
        stmt = _parseDeleteStmt();
      } else if (curTok.type == lexicon.kIf) {
        stmt = _parseIf();
      } else if (curTok.type == lexicon.kWhile) {
        stmt = _parseWhileStmt();
      } else if (curTok.type == lexicon.kDo) {
        stmt = _parseDoStmt();
      } else if (curTok.type == lexicon.kFor) {
        stmt = _parseForStmt();
      } else if (curTok.type == lexicon.kWhen) {
        stmt = _parseWhen();
      } else if (curTok.type == lexicon.kAssert) {
        stmt = _parseAssertStmt();
      } else if (curTok.type == lexicon.kThrow) {
        stmt = _parseThrowStmt();
      } else if (curTok.type == lexicon.kBreak) {
        if (!_isInLoop) {
          final err = HTError.misplacedBreak(
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
        }
        final keyword = advance();
        final hasEndOfStmtMark =
            expect([lexicon.endOfStatementMark], consume: true);
        stmt = BreakStmt(keyword,
            hasEndOfStmtMark: hasEndOfStmtMark,
            source: currentSource,
            line: keyword.line,
            column: keyword.column,
            offset: keyword.offset,
            length: keyword.length);
      } else if (curTok.type == lexicon.kContinue) {
        if (!_isInLoop) {
          final err = HTError.misplacedContinue(
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
        }
        final keyword = advance();
        final hasEndOfStmtMark =
            expect([lexicon.endOfStatementMark], consume: true);
        stmt = ContinueStmt(keyword,
            hasEndOfStmtMark: hasEndOfStmtMark,
            source: currentSource,
            line: keyword.line,
            column: keyword.column,
            offset: keyword.offset,
            length: keyword.length);
      } else if (curTok.type == lexicon.kReturn) {
        if (_currentFunctionCategory == null ||
            _currentFunctionCategory == FunctionCategory.constructor) {
          final err = HTError.misplacedReturn(
              filename: currrentFileName,
              line: curTok.line,
              column: curTok.column,
              offset: curTok.offset,
              length: curTok.length);
          errors.add(err);
        }
        stmt = _parseReturnStmt();
      } else {
        stmt = _parseExprStmt();
      }
      break;
    case ParseStyle.expression:
      stmt = parseExpr();
  }

  currentPrecedings = savedPrecedings;
  setPrecedings(stmt);
  // it's possible that there's trailing comment after end of stmt mark (;).
  handleTrailing(stmt);

  return stmt;
}