text: // Copyright 2014 PDFium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
  
  #include "xfa/fxfa/fm2js/cxfa_fmparser.h"
  
  #include <memory>
  #include <utility>
  #include <vector>
  
  #include "core/fxcrt/autorestorer.h"
  #include "third_party/base/ptr_util.h"
  
  namespace {
  
  constexpr unsigned int kMaxParseDepth = 1250;
  constexpr unsigned int kMaxPostExpressions = 256;
  
  }  // namespace
  
  CXFA_FMParser::CXFA_FMParser(const WideStringView& wsFormcalc)
      : m_lexer(pdfium::MakeUnique<CXFA_FMLexer>(wsFormcalc)),
        m_error(false),
        m_parse_depth(0),
        m_max_parse_depth(kMaxParseDepth) {}
  
  CXFA_FMParser::~CXFA_FMParser() = default;
  
  std::unique_ptr<CXFA_FMAST> CXFA_FMParser::Parse() {
    m_token = m_lexer->NextToken();
    if (HasError())
      return nullptr;
  
    auto expressions = ParseExpressionList();
    if (HasError())
      return nullptr;
  
    // We failed to parse all of the input so something has gone wrong.
    if (!m_lexer->IsComplete())
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMAST>(std::move(expressions));
  }
  
  bool CXFA_FMParser::NextToken() {
    if (HasError())
      return false;
  
    m_token = m_lexer->NextToken();
    while (!HasError() && m_token.m_type == TOKreserver)
      m_token = m_lexer->NextToken();
    return !HasError();
  }
  
  bool CXFA_FMParser::CheckThenNext(XFA_FM_TOKEN op) {
    if (HasError())
      return false;
  
    if (m_token.m_type != op) {
      m_error = true;
      return false;
    }
    return NextToken();
  }
  
  bool CXFA_FMParser::IncrementParseDepthAndCheck() {
    return ++m_parse_depth < m_max_parse_depth;
  }
  
  std::vector<std::unique_ptr<CXFA_FMExpression>>
  CXFA_FMParser::ParseExpressionList() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return std::vector<std::unique_ptr<CXFA_FMExpression>>();
  
    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
    while (!HasError()) {
      if (m_token.m_type == TOKeof || m_token.m_type == TOKendfunc ||
          m_token.m_type == TOKendif || m_token.m_type == TOKelseif ||
          m_token.m_type == TOKelse || m_token.m_type == TOKendwhile ||
          m_token.m_type == TOKendfor || m_token.m_type == TOKend ||
          m_token.m_type == TOKendfunc || m_token.m_type == TOKreserver) {
        break;
      }
  
      std::unique_ptr<CXFA_FMExpression> expr =
          m_token.m_type == TOKfunc ? ParseFunction() : ParseExpression();
      if (!expr) {
        m_error = true;
        return std::vector<std::unique_ptr<CXFA_FMExpression>>();
      }
      expressions.push_back(std::move(expr));
    }
    return expressions;
  }
  
  // Func := 'func' Identifier '(' ParameterList ')' do ExpressionList 'endfunc'
  // ParamterList := (Not actually defined in the grammar) .....
  //                 (Identifier (',' Identifier)*)?
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseFunction() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
    if (!CheckThenNext(TOKfunc))
      return nullptr;
    if (m_token.m_type != TOKidentifier)
      return nullptr;
  
    WideStringView ident = m_token.m_string;
    if (!NextToken())
      return nullptr;
    if (!CheckThenNext(TOKlparen))
      return nullptr;
  
    std::vector<WideStringView> arguments;
    bool last_was_comma = false;
    while (1) {
      if (m_token.m_type == TOKrparen)
        break;
      if (m_token.m_type != TOKidentifier)
        return nullptr;
  
      last_was_comma = false;
  
      arguments.push_back(m_token.m_string);
      if (!NextToken())
        return nullptr;
      if (m_token.m_type != TOKcomma)
        continue;
  
      last_was_comma = true;
      if (!NextToken())
        return nullptr;
    }
    if (last_was_comma || !CheckThenNext(TOKrparen))
      return nullptr;
    if (!CheckThenNext(TOKdo))
      return nullptr;
  
    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
    if (m_token.m_type != TOKendfunc)
      expressions = ParseExpressionList();
  
    if (!CheckThenNext(TOKendfunc))
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
        ident, std::move(arguments), std::move(expressions));
  }
  
  // Expression := IfExpression | WhileExpression | ForExpression |
  //               ForEachExpression | AssignmentExpression |
  //               DeclarationExpression | SimpleExpression
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMExpression> expr;
    switch (m_token.m_type) {
      case TOKvar:
        expr = ParseDeclarationExpression();
        break;
      case TOKnull:
      case TOKnumber:
      case TOKstring:
      case TOKplus:
      case TOKminus:
      case TOKksnot:
      case TOKidentifier:
      case TOKlparen:
        expr = ParseExpExpression();
        break;
      case TOKif:
        expr = ParseIfExpression();
        break;
      case TOKwhile:
        expr = ParseWhileExpression();
        break;
      case TOKfor:
        expr = ParseForExpression();
        break;
      case TOKforeach:
        expr = ParseForeachExpression();
        break;
      case TOKdo:
        expr = ParseDoExpression();
        break;
      case TOKbreak:
        expr = pdfium::MakeUnique<CXFA_FMBreakExpression>();
        if (!NextToken())
          return nullptr;
        break;
      case TOKcontinue:
        expr = pdfium::MakeUnique<CXFA_FMContinueExpression>();
        if (!NextToken())
          return nullptr;
        break;
      default:
        return nullptr;
    }
    return expr;
  }
  
  // Declaration := 'var' Variable | 'var' Variable '=' SimpleExpression |
  //           'Func' Identifier '(' ParameterList ')' do ExpressionList 'EndFunc'
  // TODO(dsinclair): We appear to be handling the 'func' case elsewhere.
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDeclarationExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    WideStringView ident;
    if (!NextToken())
      return nullptr;
    if (m_token.m_type != TOKidentifier)
      return nullptr;
  
    ident = m_token.m_string;
    if (!NextToken())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> expr;
    if (m_token.m_type == TOKassign) {
      if (!NextToken())
        return nullptr;
  
      expr = ParseSimpleExpression();
      if (!expr)
        return nullptr;
    }
  
    return pdfium::MakeUnique<CXFA_FMVarExpression>(ident, std::move(expr));
  }
  
  // SimpleExpression := LogicalOrExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseSimpleExpression() {
    if (HasError())
      return nullptr;
  
    return ParseLogicalOrExpression();
  }
  
  // Exp := SimpleExpression ( '=' SimpleExpression )?
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
    if (!pExp1)
      return nullptr;
  
    if (m_token.m_type == TOKassign) {
      if (!NextToken())
        return nullptr;
  
      std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseSimpleExpression();
      if (!pExp2)
        return nullptr;
  
      pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
          TOKassign, std::move(pExp1), std::move(pExp2));
    }
    return pdfium::MakeUnique<CXFA_FMExpExpression>(std::move(pExp1));
  }
  
  // LogicalOr := LogicalAndExpression |
  //              LogicalOrExpression LogicalOrOperator LogicalAndExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseLogicalOrExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseLogicalAndExpression();
    if (!e1)
      return nullptr;
  
    // TODO(dsinclair): Is this for() needed?
    for (;;) {
      if (!IncrementParseDepthAndCheck())
        return nullptr;
  
      switch (m_token.m_type) {
        case TOKor:
        case TOKksor: {
          if (!NextToken())
            return nullptr;
  
          std::unique_ptr<CXFA_FMSimpleExpression> e2(
              ParseLogicalAndExpression());
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMLogicalOrExpression>(
              TOKor, std::move(e1), std::move(e2));
          continue;
        }
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  // LogicalAnd := EqualityExpression |
  //               LogicalAndExpression LogicalAndOperator EqualityExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseLogicalAndExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseEqualityExpression();
    if (!e1)
      return nullptr;
  
    // TODO(dsinclair): Is this for() needed?
    for (;;) {
      if (!IncrementParseDepthAndCheck())
        return nullptr;
  
      switch (m_token.m_type) {
        case TOKand:
        case TOKksand: {
          if (!NextToken())
            return nullptr;
  
          std::unique_ptr<CXFA_FMSimpleExpression> e2 = ParseEqualityExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMLogicalAndExpression>(
              TOKand, std::move(e1), std::move(e2));
          continue;
        }
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  // Equality := RelationExpression |
  //             EqualityExpression EqulaityOperator RelationalExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseEqualityExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseRelationalExpression();
    if (!e1)
      return nullptr;
  
    // TODO(dsinclair): Is this for() needed?
    for (;;) {
      if (!IncrementParseDepthAndCheck())
        return nullptr;
  
      switch (m_token.m_type) {
        case TOKeq:
        case TOKkseq: {
          if (!NextToken())
            return nullptr;
  
          std::unique_ptr<CXFA_FMSimpleExpression> e2 =
              ParseRelationalExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMEqualExpression>(TOKeq, std::move(e1),
                                                          std::move(e2));
          continue;
        }
        case TOKne:
        case TOKksne: {
          if (!NextToken())
            return nullptr;
  
          std::unique_ptr<CXFA_FMSimpleExpression> e2 =
              ParseRelationalExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMNotEqualExpression>(TOKne, std::move(e1),
                                                             std::move(e2));
          continue;
        }
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  // Relational := AdditiveExpression |
  //               RelationalExpression RelationalOperator AdditiveExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseRelationalExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseAdditiveExpression();
    if (!e1)
      return nullptr;
  
    // TODO(dsinclair): Is this for() needed?
    for (;;) {
      if (!IncrementParseDepthAndCheck())
        return nullptr;
  
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_token.m_type) {
        case TOKlt:
        case TOKkslt:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseAdditiveExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMLtExpression>(TOKlt, std::move(e1),
                                                       std::move(e2));
          continue;
        case TOKgt:
        case TOKksgt:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseAdditiveExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMGtExpression>(TOKgt, std::move(e1),
                                                       std::move(e2));
          continue;
        case TOKle:
        case TOKksle:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseAdditiveExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMLeExpression>(TOKle, std::move(e1),
                                                       std::move(e2));
          continue;
        case TOKge:
        case TOKksge:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseAdditiveExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMGeExpression>(TOKge, std::move(e1),
                                                       std::move(e2));
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  // Additive := MultiplicativeExpression |
  //             AdditiveExpression AdditiveOperator MultiplicativeExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseAdditiveExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseMultiplicativeExpression();
    if (!e1)
      return nullptr;
  
    // TODO(dsinclair): Is this for() needed?
    for (;;) {
      if (!IncrementParseDepthAndCheck())
        return nullptr;
  
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_token.m_type) {
        case TOKplus:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseMultiplicativeExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMPlusExpression>(TOKplus, std::move(e1),
                                                         std::move(e2));
          continue;
        case TOKminus:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseMultiplicativeExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMMinusExpression>(TOKminus, std::move(e1),
                                                          std::move(e2));
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  // Multiplicative := UnaryExpression |
  //                 MultiplicateExpression MultiplicativeOperator UnaryExpression
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParseMultiplicativeExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseUnaryExpression();
    if (!e1)
      return nullptr;
  
    // TODO(dsinclair): Is this for() needed?
    for (;;) {
      if (!IncrementParseDepthAndCheck())
        return nullptr;
  
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_token.m_type) {
        case TOKmul:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseUnaryExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMMulExpression>(TOKmul, std::move(e1),
                                                        std::move(e2));
          continue;
        case TOKdiv:
          if (!NextToken())
            return nullptr;
  
          e2 = ParseUnaryExpression();
          if (!e2)
            return nullptr;
  
          e1 = pdfium::MakeUnique<CXFA_FMDivExpression>(TOKdiv, std::move(e1),
                                                        std::move(e2));
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  // Unary := PrimaryExpression | UnaryOperator UnaryExpression
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseUnaryExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> expr;
    switch (m_token.m_type) {
      case TOKplus:
        if (!NextToken())
          return nullptr;
  
        expr = ParseUnaryExpression();
        if (!expr)
          return nullptr;
  
        expr = pdfium::MakeUnique<CXFA_FMPosExpression>(std::move(expr));
        break;
      case TOKminus:
        if (!NextToken())
          return nullptr;
  
        expr = ParseUnaryExpression();
        if (!expr)
          return nullptr;
  
        expr = pdfium::MakeUnique<CXFA_FMNegExpression>(std::move(expr));
        break;
      case TOKksnot:
        if (!NextToken())
          return nullptr;
  
        expr = ParseUnaryExpression();
        if (!expr)
          return nullptr;
  
        expr = pdfium::MakeUnique<CXFA_FMNotExpression>(std::move(expr));
        break;
      default:
        return ParsePrimaryExpression();
    }
    return expr;
  }
  
  // Primary := Literal | FunctionCall | Accessor ('.*' )? |
  //           '(' SimpleExpression ')'
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParser::ParsePrimaryExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> expr = ParseLiteral();
    if (expr)
      return NextToken() ? std::move(expr) : nullptr;
  
    switch (m_token.m_type) {
      case TOKidentifier: {
        WideStringView wsIdentifier(m_token.m_string);
        if (!NextToken())
          return nullptr;
        if (m_token.m_type == TOKlbracket) {
          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
          if (!s)
            return nullptr;
  
          expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
              nullptr, TOKdot, wsIdentifier, std::move(s));
          if (!expr)
            return nullptr;
          if (!NextToken())
            return nullptr;
        } else {
          expr = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(wsIdentifier);
        }
        break;
      }
      case TOKlparen:
        expr = ParseParenExpression();
        if (!expr)
          return nullptr;
        break;
      default:
        return nullptr;
    }
    return ParsePostExpression(std::move(expr));
  }
  
  // Literal := String | Number | Null
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseLiteral() {
    switch (m_token.m_type) {
      case TOKnumber:
        return pdfium::MakeUnique<CXFA_FMNumberExpression>(m_token.m_string);
      case TOKstring:
        return pdfium::MakeUnique<CXFA_FMStringExpression>(m_token.m_string);
      case TOKnull:
        return pdfium::MakeUnique<CXFA_FMNullExpression>();
      default:
        return nullptr;
    }
  }
  
  // TODO(dsinclair): Make this match up to the grammar
  // I believe this is parsing the accessor ( '.' | '..' | '.#' )
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParsePostExpression(
      std::unique_ptr<CXFA_FMSimpleExpression> expr) {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    size_t expr_count = 0;
    while (1) {
      ++expr_count;
      // Limit the number of expressions allowed in the post expression statement.
      // If we don't do this then its possible to generate a stack overflow
      // by having a very large number of things like .. expressions.
      if (expr_count > kMaxPostExpressions)
        return nullptr;
  
      switch (m_token.m_type) {
        case TOKlparen: {
          if (!NextToken())
            return nullptr;
  
          std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
          if (m_token.m_type != TOKrparen) {
            while (m_token.m_type != TOKrparen) {
              std::unique_ptr<CXFA_FMSimpleExpression> simple_expr =
                  ParseSimpleExpression();
              if (!simple_expr)
                return nullptr;
  
              expressions.push_back(std::move(simple_expr));
              if (m_token.m_type == TOKcomma) {
                if (!NextToken())
                  return nullptr;
              } else if (m_token.m_type == TOKeof ||
                         m_token.m_type == TOKreserver) {
                break;
              }
            }
            if (m_token.m_type != TOKrparen)
              return nullptr;
          }
          expr = pdfium::MakeUnique<CXFA_FMCallExpression>(
              std::move(expr), std::move(expressions), false);
          if (!NextToken())
            return nullptr;
          if (m_token.m_type != TOKlbracket)
            continue;
  
          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
          if (!s)
            return nullptr;
  
          expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
              std::move(expr), TOKcall, L"", std::move(s));
          break;
        }
        case TOKdot: {
          if (!NextToken())
            return nullptr;
          if (m_token.m_type != TOKidentifier)
            return nullptr;
  
          WideStringView tempStr = m_token.m_string;
          if (!NextToken())
            return nullptr;
          if (m_token.m_type == TOKlparen) {
            std::unique_ptr<CXFA_FMSimpleExpression> pExpCall;
            if (!NextToken())
              return nullptr;
  
            std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
            if (m_token.m_type != TOKrparen) {
              while (m_token.m_type != TOKrparen) {
                std::unique_ptr<CXFA_FMSimpleExpression> exp =
                    ParseSimpleExpression();
                if (!exp)
                  return nullptr;
  
                expressions.push_back(std::move(exp));
                if (m_token.m_type == TOKcomma) {
                  if (!NextToken())
                    return nullptr;
                } else if (m_token.m_type == TOKeof ||
                           m_token.m_type == TOKreserver) {
                  break;
                }
              }
              if (m_token.m_type != TOKrparen)
                return nullptr;
            }
            std::unique_ptr<CXFA_FMSimpleExpression> pIdentifier =
                pdfium::MakeUnique<CXFA_FMIdentifierExpression>(tempStr);
            pExpCall = pdfium::MakeUnique<CXFA_FMCallExpression>(
                std::move(pIdentifier), std::move(expressions), true);
            expr = pdfium::MakeUnique<CXFA_FMMethodCallExpression>(
                std::move(expr), std::move(pExpCall));
            if (!NextToken())
              return nullptr;
            if (m_token.m_type != TOKlbracket)
              continue;
  
            std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
            if (!s)
              return nullptr;
  
            expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                std::move(expr), TOKcall, L"", std::move(s));
          } else if (m_token.m_type == TOKlbracket) {
            std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
            if (!s)
              return nullptr;
  
            expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                std::move(expr), TOKdot, tempStr, std::move(s));
          } else {
            std::unique_ptr<CXFA_FMSimpleExpression> s =
                pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
                                                           nullptr, false);
            expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                std::move(expr), TOKdot, tempStr, std::move(s));
            continue;
          }
          break;
        }
        case TOKdotdot: {
          if (!NextToken())
            return nullptr;
          if (m_token.m_type != TOKidentifier)
            return nullptr;
  
          WideStringView tempStr = m_token.m_string;
          if (!NextToken())
            return nullptr;
          if (m_token.m_type == TOKlbracket) {
            std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
            if (!s)
              return nullptr;
  
            expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
                std::move(expr), TOKdotdot, tempStr, std::move(s));
          } else {
            std::unique_ptr<CXFA_FMSimpleExpression> s =
                pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
                                                           nullptr, false);
            expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
                std::move(expr), TOKdotdot, tempStr, std::move(s));
            continue;
          }
          break;
        }
        case TOKdotscream: {
          if (!NextToken())
            return nullptr;
          if (m_token.m_type != TOKidentifier)
            return nullptr;
  
          WideStringView tempStr = m_token.m_string;
          if (!NextToken())
            return nullptr;
  
          if (m_token.m_type != TOKlbracket) {
            std::unique_ptr<CXFA_FMSimpleExpression> s =
                pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
                                                           nullptr, false);
            expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                std::move(expr), TOKdotscream, tempStr, std::move(s));
            continue;
          }
  
          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
          if (!s)
            return nullptr;
  
          expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
              std::move(expr), TOKdotscream, tempStr, std::move(s));
          break;
        }
        case TOKdotstar: {
          std::unique_ptr<CXFA_FMSimpleExpression> s =
              pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
                                                         nullptr, false);
          expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
              std::move(expr), TOKdotstar, L"*", std::move(s));
          break;
        }
        default:
          return expr;
      }
      if (!NextToken())
        return nullptr;
    }
    return expr;
  }
  
  // Index := '[' ('*' | '+' SimpleExpression | '-' SimpleExpression) ']'
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseIndexExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
    if (!CheckThenNext(TOKlbracket))
      return nullptr;
  
    if (m_token.m_type == TOKmul) {
      auto pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>(
          ACCESSOR_NO_RELATIVEINDEX, nullptr, true);
      if (!pExp || !NextToken())
        return nullptr;
  
      // TODO(dsinclair): This should CheckThenNext(TOKrbracket) but need to clean
      // up the callsites.
      if (m_token.m_type != TOKrbracket)
        return nullptr;
      return pExp;
    }
  
    XFA_FM_AccessorIndex accessorIndex = ACCESSOR_NO_RELATIVEINDEX;
    if (m_token.m_type == TOKplus) {
      accessorIndex = ACCESSOR_POSITIVE_INDEX;
      if (!NextToken())
        return nullptr;
    } else if (m_token.m_type == TOKminus) {
      accessorIndex = ACCESSOR_NEGATIVE_INDEX;
      if (!NextToken())
        return nullptr;
    }
  
    std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
    if (!s)
      return nullptr;
    if (m_token.m_type != TOKrbracket)
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMIndexExpression>(accessorIndex, std::move(s),
                                                      false);
  }
  
  // Paren := '(' SimpleExpression ')'
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseParenExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    if (!CheckThenNext(TOKlparen))
      return nullptr;
    if (m_token.m_type == TOKrparen)
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
    if (!pExp1)
      return nullptr;
  
    if (!CheckThenNext(TOKrparen))
      return nullptr;
    return pExp1;
  }
  
  // If := 'if' '(' SimpleExpression ')' 'then' ExpressionList
  //       ('elseif' '(' SimpleExpression ')' 'then' ExpressionList)*
  //       ('else' ExpressionList)?
  //       'endif'
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseIfExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
  
    if (!CheckThenNext(TOKif))
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
    if (!pCondition)
      return nullptr;
    if (!CheckThenNext(TOKthen))
      return nullptr;
  
    auto pIfExpressions =
        pdfium::MakeUnique<CXFA_FMBlockExpression>(ParseExpressionList());
  
    std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions;
    while (m_token.m_type == TOKelseif) {
      if (!NextToken())
        return nullptr;
  
      auto elseIfCondition = ParseParenExpression();
      if (!elseIfCondition)
        return nullptr;
      if (!CheckThenNext(TOKthen))
        return nullptr;
  
      auto elseIfExprs = ParseExpressionList();
      pElseIfExpressions.push_back(pdfium::MakeUnique<CXFA_FMIfExpression>(
          std::move(elseIfCondition),
          pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(elseIfExprs)),
          std::vector<std::unique_ptr<CXFA_FMIfExpression>>(), nullptr));
    }
  
    std::unique_ptr<CXFA_FMExpression> pElseExpression;
    if (m_token.m_type == TOKelse) {
      if (!NextToken())
        return nullptr;
  
      pElseExpression =
          pdfium::MakeUnique<CXFA_FMBlockExpression>(ParseExpressionList());
    }
    if (!CheckThenNext(TOKendif))
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMIfExpression>(
        std::move(pCondition), std::move(pIfExpressions),
        std::move(pElseIfExpressions), std::move(pElseExpression));
  }
  
  // While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile'
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseWhileExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
    if (!CheckThenNext(TOKwhile))
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
    if (!pCondition || !CheckThenNext(TOKdo))
      return nullptr;
  
    auto exprs = ParseExpressionList();
    if (!CheckThenNext(TOKendwhile))
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMWhileExpression>(
        std::move(pCondition),
        pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
  }
  
  // For := 'for' Assignment 'upto' Accessor ('step' SimpleExpression)?
  //            'do' ExpressionList 'endfor' |
  //         'for' Assignment 'downto' Accessor ('step' SimpleExpression)?
  //            'do' ExpressionList 'endfor'
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForExpression() {
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
    if (!CheckThenNext(TOKfor))
      return nullptr;
    if (m_token.m_type != TOKidentifier)
      return nullptr;
  
    WideStringView wsVariant = m_token.m_string;
    if (!NextToken())
      return nullptr;
    if (!CheckThenNext(TOKassign))
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pAssignment =
        ParseSimpleExpression();
    if (!pAssignment)
      return nullptr;
  
    int32_t iDirection = 0;
    if (m_token.m_type == TOKupto)
      iDirection = 1;
    else if (m_token.m_type == TOKdownto)
      iDirection = -1;
    else
      return nullptr;
  
    if (!NextToken())
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor = ParseSimpleExpression();
    if (!pAccessor)
      return nullptr;
  
    std::unique_ptr<CXFA_FMSimpleExpression> pStep;
    if (m_token.m_type == TOKstep) {
      if (!NextToken())
        return nullptr;
      pStep = ParseSimpleExpression();
      if (!pStep)
        return nullptr;
    }
    if (!CheckThenNext(TOKdo))
      return nullptr;
  
    auto exprs = ParseExpressionList();
    if (!CheckThenNext(TOKendfor))
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMForExpression>(
        wsVariant, std::move(pAssignment), std::move(pAccessor), iDirection,
        std::move(pStep),
        pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
  }
  
  // Foreach := 'foreach' Identifier 'in' '(' ArgumentList ')'
  //            'do' ExpressionList 'endfor'
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForeachExpression() {
    if (m_token.m_type != TOKforeach)
      return nullptr;
  
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
    if (!CheckThenNext(TOKforeach))
      return nullptr;
    if (m_token.m_type != TOKidentifier)
      return nullptr;
  
    WideStringView wsIdentifier = m_token.m_string;
    if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen))
      return nullptr;
  
    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> pArgumentList;
    while (m_token.m_type != TOKrparen) {
      std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
      if (!s)
        return nullptr;
  
      pArgumentList.push_back(std::move(s));
      if (m_token.m_type != TOKcomma)
        break;
      if (!NextToken())
        return nullptr;
    }
    // We must have arguments.
    if (pArgumentList.empty())
      return nullptr;
    if (!CheckThenNext(TOKrparen))
      return nullptr;
  
    auto exprs = ParseExpressionList();
    if (!CheckThenNext(TOKendfor))
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMForeachExpression>(
        wsIdentifier, std::move(pArgumentList),
        pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
  }
  
  // Block := 'do' ExpressionList 'end'
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDoExpression() {
    if (m_token.m_type != TOKdo)
      return nullptr;
  
    AutoRestorer<unsigned long> restorer(&m_parse_depth);
    if (HasError() || !IncrementParseDepthAndCheck())
      return nullptr;
    if (!CheckThenNext(TOKdo))
      return nullptr;
  
    auto exprs = ParseExpressionList();
    if (!CheckThenNext(TOKend))
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMDoExpression>(
        pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
  }
  
  bool CXFA_FMParser::HasError() const {
    return m_error || m_token.m_type == TOKreserver;
  }
  