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/xfa_fmparse.h"
  
  #include <memory>
  #include <utility>
  #include <vector>
  
  #include "third_party/base/ptr_util.h"
  
  CXFA_FMParse::CXFA_FMParse(const CFX_WideStringC& wsFormcalc,
                             CXFA_FMErrorInfo* pErrorInfo)
      : m_pToken(nullptr), m_pErrorInfo(pErrorInfo) {
    m_lexer = pdfium::MakeUnique<CXFA_FMLexer>(wsFormcalc, m_pErrorInfo);
  }
  
  CXFA_FMParse::~CXFA_FMParse() {}
  
  void CXFA_FMParse::NextToken() {
    m_pToken = m_lexer->NextToken();
    while (m_pToken->m_type == TOKreserver) {
      if (m_lexer->HasError()) {
        break;
      }
      m_pToken = m_lexer->NextToken();
    }
  }
  
  void CXFA_FMParse::Check(XFA_FM_TOKEN op) {
    if (m_pToken->m_type != op) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedToken, XFA_FM_KeywordToString(op),
            ws_TempString.c_str());
    }
    NextToken();
  }
  
  void CXFA_FMParse::Error(uint32_t lineNum, const FX_WCHAR* msg, ...) {
    m_pErrorInfo->linenum = lineNum;
    va_list ap;
    va_start(ap, msg);
    m_pErrorInfo->message.FormatV(msg, ap);
    va_end(ap);
  }
  
  std::vector<std::unique_ptr<CXFA_FMExpression>>
  CXFA_FMParse::ParseTopExpression() {
    std::unique_ptr<CXFA_FMExpression> expr;
    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
    while (1) {
      if (m_pToken->m_type == TOKeof || m_pToken->m_type == TOKendfunc ||
          m_pToken->m_type == TOKendif || m_pToken->m_type == TOKelseif ||
          m_pToken->m_type == TOKelse || m_pToken->m_type == TOKreserver) {
        return expressions;
      }
  
      if (m_pToken->m_type == TOKfunc) {
        expr = ParseFunction();
        if (expr) {
          expressions.push_back(std::move(expr));
        } else {
          break;
        }
      } else {
        expr = ParseExpression();
        if (expr) {
          expressions.push_back(std::move(expr));
        } else {
          break;
        }
      }
    }
    return expressions;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseFunction() {
    CFX_WideStringC ident;
    std::vector<CFX_WideStringC> arguments;
    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    if (m_pToken->m_type != TOKidentifier) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedIdentifier,
            ws_TempString.c_str());
    } else {
      ident = m_pToken->m_wstring;
      NextToken();
    }
    Check(TOKlparen);
    if (m_pToken->m_type == TOKrparen) {
      NextToken();
    } else {
      while (1) {
        if (m_pToken->m_type == TOKidentifier) {
          arguments.push_back(m_pToken->m_wstring);
          NextToken();
          if (m_pToken->m_type == TOKcomma) {
            NextToken();
            continue;
          } else if (m_pToken->m_type == TOKrparen) {
            NextToken();
            break;
          } else {
            Check(TOKrparen);
            break;
          }
        } else {
          CFX_WideString ws_TempString(m_pToken->m_wstring);
          Error(m_pToken->m_uLinenum, kFMErrExpectedIdentifier,
                ws_TempString.c_str());
          NextToken();
          break;
        }
      }
    }
    Check(TOKdo);
    if (m_pToken->m_type == TOKendfunc) {
      NextToken();
    } else {
      expressions = ParseTopExpression();
      Check(TOKendfunc);
    }
    if (!m_pErrorInfo->message.IsEmpty())
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
        line, false, ident, std::move(arguments), std::move(expressions));
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseExpression() {
    std::unique_ptr<CXFA_FMExpression> expr;
    uint32_t line = m_pToken->m_uLinenum;
    switch (m_pToken->m_type) {
      case TOKvar:
        expr = ParseVarExpression();
        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>(line);
        NextToken();
        break;
      case TOKcontinue:
        expr = pdfium::MakeUnique<CXFA_FMContinueExpression>(line);
        NextToken();
        break;
      default:
        CFX_WideString ws_TempString(m_pToken->m_wstring);
        Error(m_pToken->m_uLinenum, kFMErrUnexpectedExpression,
              ws_TempString.c_str());
        NextToken();
        break;
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseVarExpression() {
    CFX_WideStringC ident;
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    if (m_pToken->m_type != TOKidentifier) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedIdentifier,
            ws_TempString.c_str());
    } else {
      ident = m_pToken->m_wstring;
      NextToken();
    }
    std::unique_ptr<CXFA_FMExpression> expr;
    if (m_pToken->m_type == TOKassign) {
      NextToken();
      expr = ParseExpExpression();
    }
    if (!m_pErrorInfo->message.IsEmpty())
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMVarExpression>(line, ident, std::move(expr));
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParse::ParseSimpleExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseLogicalOrExpression();
    while (m_pToken->m_type == TOKassign) {
      NextToken();
      std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseLogicalOrExpression();
      if (m_pErrorInfo->message.IsEmpty()) {
        pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
            line, TOKassign, std::move(pExp1), std::move(pExp2));
      } else {
        pExp1.reset();
      }
    }
    return pExp1;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseExpExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
    if (!m_pErrorInfo->message.IsEmpty())
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMExpExpression>(line, std::move(pExp1));
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseLogicalOrExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseLogicalAndExpression();
    for (;;) {
      switch (m_pToken->m_type) {
        case TOKor:
        case TOKksor: {
          NextToken();
          std::unique_ptr<CXFA_FMSimpleExpression> e2(
              ParseLogicalAndExpression());
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMLogicalOrExpression>(
                line, TOKor, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        }
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseLogicalAndExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseEqualityExpression();
    for (;;) {
      switch (m_pToken->m_type) {
        case TOKand:
        case TOKksand: {
          NextToken();
          std::unique_ptr<CXFA_FMSimpleExpression> e2 = ParseEqualityExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMLogicalAndExpression>(
                line, TOKand, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        }
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseEqualityExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseRelationalExpression();
    for (;;) {
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_pToken->m_type) {
        case TOKeq:
        case TOKkseq:
          NextToken();
          e2 = ParseRelationalExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMEqualityExpression>(
                line, TOKeq, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        case TOKne:
        case TOKksne:
          NextToken();
          e2 = ParseRelationalExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMEqualityExpression>(
                line, TOKne, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseRelationalExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseAddtiveExpression();
    for (;;) {
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_pToken->m_type) {
        case TOKlt:
        case TOKkslt:
          NextToken();
          e2 = ParseAddtiveExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
                line, TOKlt, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        case TOKgt:
        case TOKksgt:
          NextToken();
          e2 = ParseAddtiveExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
                line, TOKgt, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        case TOKle:
        case TOKksle:
          NextToken();
          e2 = ParseAddtiveExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
                line, TOKle, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        case TOKge:
        case TOKksge:
          NextToken();
          e2 = ParseAddtiveExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMRelationalExpression>(
                line, TOKge, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseAddtiveExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseMultiplicativeExpression();
    for (;;) {
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_pToken->m_type) {
        case TOKplus:
          NextToken();
          e2 = ParseMultiplicativeExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMAdditiveExpression>(
                line, TOKplus, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        case TOKminus:
          NextToken();
          e2 = ParseMultiplicativeExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMAdditiveExpression>(
                line, TOKminus, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseMultiplicativeExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseUnaryExpression();
    for (;;) {
      std::unique_ptr<CXFA_FMSimpleExpression> e2;
      switch (m_pToken->m_type) {
        case TOKmul:
          NextToken();
          e2 = ParseUnaryExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMMultiplicativeExpression>(
                line, TOKmul, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        case TOKdiv:
          NextToken();
          e2 = ParseUnaryExpression();
          if (m_pErrorInfo->message.IsEmpty()) {
            e1 = pdfium::MakeUnique<CXFA_FMMultiplicativeExpression>(
                line, TOKdiv, std::move(e1), std::move(e2));
          } else {
            e1.reset();
          }
          continue;
        default:
          break;
      }
      break;
    }
    return e1;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParse::ParseUnaryExpression() {
    std::unique_ptr<CXFA_FMSimpleExpression> expr;
    uint32_t line = m_pToken->m_uLinenum;
    switch (m_pToken->m_type) {
      case TOKplus:
        NextToken();
        expr = ParseUnaryExpression();
        if (m_pErrorInfo->message.IsEmpty())
          expr = pdfium::MakeUnique<CXFA_FMPosExpression>(line, std::move(expr));
        else
          expr.reset();
        break;
      case TOKminus:
        NextToken();
        expr = ParseUnaryExpression();
        if (m_pErrorInfo->message.IsEmpty())
          expr = pdfium::MakeUnique<CXFA_FMNegExpression>(line, std::move(expr));
        else
          expr.reset();
        break;
      case TOKksnot:
        NextToken();
        expr = ParseUnaryExpression();
        if (m_pErrorInfo->message.IsEmpty())
          expr = pdfium::MakeUnique<CXFA_FMNotExpression>(line, std::move(expr));
        else
          expr.reset();
        break;
      default:
        expr = ParsePrimaryExpression();
        break;
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParsePrimaryExpression() {
    std::unique_ptr<CXFA_FMSimpleExpression> expr;
    uint32_t line = m_pToken->m_uLinenum;
    switch (m_pToken->m_type) {
      case TOKnumber:
        expr = pdfium::MakeUnique<CXFA_FMNumberExpression>(line,
                                                           m_pToken->m_wstring);
        NextToken();
        break;
      case TOKstring:
        expr = pdfium::MakeUnique<CXFA_FMStringExpression>(line,
                                                           m_pToken->m_wstring);
        NextToken();
        break;
      case TOKidentifier: {
        CFX_WideStringC wsIdentifier(m_pToken->m_wstring);
        NextToken();
        if (m_pToken->m_type == TOKlbracket) {
          std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
          if (s) {
            expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                line, nullptr, TOKdot, wsIdentifier, std::move(s));
          }
          NextToken();
        } else {
          expr =
              pdfium::MakeUnique<CXFA_FMIdentifierExpression>(line, wsIdentifier);
        }
      } break;
      case TOKif:
        expr = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(
            line, m_pToken->m_wstring);
        NextToken();
        break;
      case TOKnull:
        expr = pdfium::MakeUnique<CXFA_FMNullExpression>(line);
        NextToken();
        break;
      case TOKlparen:
        expr = ParseParenExpression();
        break;
      default:
        CFX_WideString ws_TempString(m_pToken->m_wstring);
        Error(m_pToken->m_uLinenum, kFMErrUnexpectedExpression,
              ws_TempString.c_str());
        NextToken();
        break;
    }
    expr = ParsePostExpression(std::move(expr));
    if (!m_pErrorInfo->message.IsEmpty())
      expr.reset();
    return expr;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParse::ParsePostExpression(
      std::unique_ptr<CXFA_FMSimpleExpression> expr) {
    uint32_t line = m_pToken->m_uLinenum;
    while (1) {
      switch (m_pToken->m_type) {
        case TOKlparen: {
          NextToken();
          std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
          if (m_pToken->m_type != TOKrparen) {
            while (m_pToken->m_type != TOKrparen) {
              if (std::unique_ptr<CXFA_FMSimpleExpression> expr =
                      ParseSimpleExpression())
                expressions.push_back(std::move(expr));
              if (m_pToken->m_type == TOKcomma) {
                NextToken();
              } else if (m_pToken->m_type == TOKeof ||
                         m_pToken->m_type == TOKreserver) {
                break;
              }
            }
            if (m_pToken->m_type != TOKrparen) {
              CFX_WideString ws_TempString(m_pToken->m_wstring);
              Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
                    XFA_FM_KeywordToString(TOKrparen), ws_TempString.c_str());
            }
          }
          if (m_pErrorInfo->message.IsEmpty()) {
            expr = pdfium::MakeUnique<CXFA_FMCallExpression>(
                line, std::move(expr), std::move(expressions), false);
            NextToken();
            if (m_pToken->m_type != TOKlbracket)
              continue;
  
            std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
            if (s) {
              expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                  line, std::move(expr), TOKcall, L"", std::move(s));
            } else {
              expr.reset();
            }
          } else {
            expr.reset();
          }
        } break;
        case TOKdot:
          NextToken();
          if (m_pToken->m_type == TOKidentifier) {
            CFX_WideStringC tempStr = m_pToken->m_wstring;
            uint32_t tempLine = m_pToken->m_uLinenum;
            NextToken();
            if (m_pToken->m_type == TOKlparen) {
              std::unique_ptr<CXFA_FMSimpleExpression> pExpCall;
              NextToken();
              std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
              if (m_pToken->m_type != TOKrparen) {
                while (m_pToken->m_type != TOKrparen) {
                  std::unique_ptr<CXFA_FMSimpleExpression> exp =
                      ParseSimpleExpression();
                  expressions.push_back(std::move(exp));
                  if (m_pToken->m_type == TOKcomma) {
                    NextToken();
                  } else if (m_pToken->m_type == TOKeof ||
                             m_pToken->m_type == TOKreserver) {
                    break;
                  }
                }
                if (m_pToken->m_type != TOKrparen) {
                  CFX_WideString ws_TempString(m_pToken->m_wstring);
                  Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
                        XFA_FM_KeywordToString(TOKrparen), ws_TempString.c_str());
                }
              }
              if (m_pErrorInfo->message.IsEmpty()) {
                std::unique_ptr<CXFA_FMSimpleExpression> pIdentifier =
                    pdfium::MakeUnique<CXFA_FMIdentifierExpression>(tempLine,
                                                                    tempStr);
                pExpCall = pdfium::MakeUnique<CXFA_FMCallExpression>(
                    line, std::move(pIdentifier), std::move(expressions), true);
                expr = pdfium::MakeUnique<CXFA_FMMethodCallExpression>(
                    line, std::move(expr), std::move(pExpCall));
                NextToken();
                if (m_pToken->m_type != TOKlbracket)
                  continue;
  
                std::unique_ptr<CXFA_FMSimpleExpression> s =
                    ParseIndexExpression();
                if (s) {
                  expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                      line, std::move(expr), TOKcall, L"", std::move(s));
                } else {
                  expr.reset();
                }
              } else {
                expr.reset();
              }
            } else if (m_pToken->m_type == TOKlbracket) {
              std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
              if (!(m_pErrorInfo->message.IsEmpty()))
                return nullptr;
  
              expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                  tempLine, std::move(expr), TOKdot, tempStr, std::move(s));
            } else {
              std::unique_ptr<CXFA_FMSimpleExpression> s =
                  pdfium::MakeUnique<CXFA_FMIndexExpression>(
                      tempLine, ACCESSOR_NO_INDEX, nullptr, false);
              expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                  line, std::move(expr), TOKdot, tempStr, std::move(s));
              continue;
            }
          } else {
            CFX_WideString ws_TempString(m_pToken->m_wstring);
            Error(m_pToken->m_uLinenum, kFMErrExpectedIdentifier,
                  ws_TempString.c_str());
            return expr;
          }
          break;
        case TOKdotdot:
          NextToken();
          if (m_pToken->m_type == TOKidentifier) {
            CFX_WideStringC tempStr = m_pToken->m_wstring;
            uint32_t tempLine = m_pToken->m_uLinenum;
            NextToken();
            if (m_pToken->m_type == TOKlbracket) {
              std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
              if (!(m_pErrorInfo->message.IsEmpty())) {
                return nullptr;
              }
              expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
                  tempLine, std::move(expr), TOKdotdot, tempStr, std::move(s));
            } else {
              std::unique_ptr<CXFA_FMSimpleExpression> s =
                  pdfium::MakeUnique<CXFA_FMIndexExpression>(
                      tempLine, ACCESSOR_NO_INDEX, nullptr, false);
              expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
                  line, std::move(expr), TOKdotdot, tempStr, std::move(s));
              continue;
            }
          } else {
            CFX_WideString ws_TempString(m_pToken->m_wstring);
            Error(m_pToken->m_uLinenum, kFMErrExpectedIdentifier,
                  ws_TempString.c_str());
            return expr;
          }
          break;
        case TOKdotscream:
          NextToken();
          if (m_pToken->m_type == TOKidentifier) {
            CFX_WideStringC tempStr = m_pToken->m_wstring;
            uint32_t tempLine = m_pToken->m_uLinenum;
            NextToken();
            if (m_pToken->m_type == TOKlbracket) {
              std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
              if (!(m_pErrorInfo->message.IsEmpty()))
                return nullptr;
  
              expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                  tempLine, std::move(expr), TOKdotscream, tempStr, std::move(s));
            } else {
              std::unique_ptr<CXFA_FMSimpleExpression> s =
                  pdfium::MakeUnique<CXFA_FMIndexExpression>(
                      tempLine, ACCESSOR_NO_INDEX, nullptr, false);
              expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
                  line, std::move(expr), TOKdotscream, tempStr, std::move(s));
              continue;
            }
          } else {
            CFX_WideString ws_TempString(m_pToken->m_wstring);
            Error(m_pToken->m_uLinenum, kFMErrExpectedIdentifier,
                  ws_TempString.c_str());
            return expr;
          }
          break;
        case TOKdotstar: {
          std::unique_ptr<CXFA_FMSimpleExpression> s =
              pdfium::MakeUnique<CXFA_FMIndexExpression>(line, ACCESSOR_NO_INDEX,
                                                         nullptr, false);
          expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
              line, std::move(expr), TOKdotstar, L"*", std::move(s));
        } break;
        default:
          return expr;
      }
      NextToken();
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParse::ParseIndexExpression() {
    std::unique_ptr<CXFA_FMSimpleExpression> pExp;
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    std::unique_ptr<CXFA_FMSimpleExpression> s;
    XFA_FM_AccessorIndex accessorIndex = ACCESSOR_NO_RELATIVEINDEX;
    if (m_pToken->m_type == TOKmul) {
      pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>(line, accessorIndex,
                                                        std::move(s), true);
      NextToken();
      if (m_pToken->m_type != TOKrbracket) {
        CFX_WideString ws_TempString(m_pToken->m_wstring);
        Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
              XFA_FM_KeywordToString(TOKrparen), ws_TempString.c_str());
        pExp.reset();
      }
      return pExp;
    }
    if (m_pToken->m_type == TOKplus) {
      accessorIndex = ACCESSOR_POSITIVE_INDEX;
      NextToken();
    } else if (m_pToken->m_type == TOKminus) {
      accessorIndex = ACCESSOR_NEGATIVE_INDEX;
      NextToken();
    }
    s = ParseSimpleExpression();
    if (m_pToken->m_type != TOKrbracket) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
            XFA_FM_KeywordToString(TOKrparen), ws_TempString.c_str());
    } else {
      pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>(line, accessorIndex,
                                                        std::move(s), false);
    }
    return pExp;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParse::ParseParenExpression() {
    Check(TOKlparen);
  
    if (m_pToken->m_type == TOKrparen) {
      Error(m_pToken->m_uLinenum, kFMErrExpectedNonEmptyExpression);
      NextToken();
      return nullptr;
    }
  
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseLogicalOrExpression();
  
    while (m_pToken->m_type == TOKassign) {
      NextToken();
      std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseLogicalOrExpression();
      if (m_pErrorInfo->message.IsEmpty()) {
        pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
            line, TOKassign, std::move(pExp1), std::move(pExp2));
      } else {
        pExp1.reset();
      }
    }
    Check(TOKrparen);
    return pExp1;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseBlockExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    std::unique_ptr<CXFA_FMExpression> expr;
    std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
  
    while (1) {
      switch (m_pToken->m_type) {
        case TOKeof:
        case TOKendif:
        case TOKelseif:
        case TOKelse:
        case TOKendwhile:
        case TOKendfor:
        case TOKend:
        case TOKendfunc:
        case TOKreserver:
          break;
        case TOKfunc:
          expr = ParseFunction();
          if (expr) {
            expressions.push_back(std::move(expr));
          }
          continue;
        default:
          expr = ParseExpression();
          if (expr) {
            expressions.push_back(std::move(expr));
          }
          continue;
      }
      break;
    }
    std::unique_ptr<CXFA_FMBlockExpression> pExp;
    if (m_pErrorInfo->message.IsEmpty()) {
      pExp = pdfium::MakeUnique<CXFA_FMBlockExpression>(line,
                                                        std::move(expressions));
    }
    return pExp;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseIfExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    const FX_WCHAR* pStartPos = m_lexer->SavePos();
    NextToken();
    Check(TOKlparen);
    std::unique_ptr<CXFA_FMSimpleExpression> pExpression;
    while (m_pToken->m_type != TOKrparen) {
      pExpression = ParseSimpleExpression();
      if (m_pToken->m_type != TOKcomma)
        break;
      NextToken();
    }
    Check(TOKrparen);
    if (m_pToken->m_type != TOKthen) {
      m_lexer->SetCurrentLine(line);
      m_pToken = new CXFA_FMToken(line);
      m_pToken->m_type = TOKidentifier;
      m_pToken->m_wstring = FX_WSTRC(L"if");
      m_lexer->SetToken(m_pToken);
      m_lexer->RestorePos(pStartPos);
      return ParseExpExpression();
    }
    Check(TOKthen);
    std::unique_ptr<CXFA_FMExpression> pIfExpression = ParseBlockExpression();
    std::unique_ptr<CXFA_FMExpression> pElseExpression;
    switch (m_pToken->m_type) {
      case TOKeof:
      case TOKendif:
        Check(TOKendif);
        break;
      case TOKif:
        pElseExpression = ParseIfExpression();
        Check(TOKendif);
        break;
      case TOKelseif:
        pElseExpression = ParseIfExpression();
        break;
      case TOKelse:
        NextToken();
        pElseExpression = ParseBlockExpression();
        Check(TOKendif);
        break;
      default:
        CFX_WideString ws_TempString(m_pToken->m_wstring);
        Error(m_pToken->m_uLinenum, kFMErrExpectedEndIf, ws_TempString.c_str());
        NextToken();
        break;
    }
    std::unique_ptr<CXFA_FMIfExpression> pExp;
    if (m_pErrorInfo->message.IsEmpty()) {
      pExp = pdfium::MakeUnique<CXFA_FMIfExpression>(line, std::move(pExpression),
                                                     std::move(pIfExpression),
                                                     std::move(pElseExpression));
    }
    return pExp;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseWhileExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
    Check(TOKdo);
    std::unique_ptr<CXFA_FMExpression> pExpression = ParseBlockExpression();
    Check(TOKendwhile);
    std::unique_ptr<CXFA_FMExpression> expr;
    if (m_pErrorInfo->message.IsEmpty()) {
      expr = pdfium::MakeUnique<CXFA_FMWhileExpression>(
          line, std::move(pCondition), std::move(pExpression));
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMSimpleExpression>
  CXFA_FMParse::ParseSubassignmentInForExpression() {
    std::unique_ptr<CXFA_FMSimpleExpression> expr;
    switch (m_pToken->m_type) {
      case TOKidentifier:
        expr = ParseSimpleExpression();
        break;
      default:
        CFX_WideString ws_TempString(m_pToken->m_wstring);
        Error(m_pToken->m_uLinenum, kFMErrUnexpectedExpression,
              ws_TempString.c_str());
        NextToken();
        break;
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseForExpression() {
    CFX_WideStringC wsVariant;
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    if (m_pToken->m_type != TOKidentifier) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
            XFA_FM_KeywordToString(m_pToken->m_type), ws_TempString.c_str());
    }
    wsVariant = m_pToken->m_wstring;
    NextToken();
    std::unique_ptr<CXFA_FMSimpleExpression> pAssignment;
    if (m_pToken->m_type == TOKassign) {
      NextToken();
      pAssignment = ParseSimpleExpression();
    } else {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
            XFA_FM_KeywordToString(m_pToken->m_type), ws_TempString.c_str());
    }
    int32_t iDirection = 0;
    if (m_pToken->m_type == TOKupto) {
      iDirection = 1;
    } else if (m_pToken->m_type == TOKdownto) {
      iDirection = -1;
    } else {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedToken, L"upto or downto",
            ws_TempString.c_str());
    }
    NextToken();
    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor = ParseSimpleExpression();
    std::unique_ptr<CXFA_FMSimpleExpression> pStep;
    if (m_pToken->m_type == TOKstep) {
      NextToken();
      pStep = ParseSimpleExpression();
    }
    Check(TOKdo);
    std::unique_ptr<CXFA_FMExpression> pList = ParseBlockExpression();
    Check(TOKendfor);
    std::unique_ptr<CXFA_FMExpression> expr;
    if (m_pErrorInfo->message.IsEmpty()) {
      expr = pdfium::MakeUnique<CXFA_FMForExpression>(
          line, wsVariant, std::move(pAssignment), std::move(pAccessor),
          iDirection, std::move(pStep), std::move(pList));
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseForeachExpression() {
    std::unique_ptr<CXFA_FMExpression> expr;
    CFX_WideStringC wsIdentifier;
    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> pAccessors;
    std::unique_ptr<CXFA_FMExpression> pList;
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    if (m_pToken->m_type != TOKidentifier) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrExpectedToken,
            XFA_FM_KeywordToString(m_pToken->m_type), ws_TempString.c_str());
    }
    wsIdentifier = m_pToken->m_wstring;
    NextToken();
    Check(TOKin);
    Check(TOKlparen);
    if (m_pToken->m_type == TOKrparen) {
      CFX_WideString ws_TempString(m_pToken->m_wstring);
      Error(m_pToken->m_uLinenum, kFMErrUnexpectedExpression,
            ws_TempString.c_str());
      NextToken();
    } else {
      while (m_pToken->m_type != TOKrparen) {
        std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
        if (s)
          pAccessors.push_back(std::move(s));
        if (m_pToken->m_type != TOKcomma)
          break;
        NextToken();
      }
      Check(TOKrparen);
    }
    Check(TOKdo);
    pList = ParseBlockExpression();
    Check(TOKendfor);
    if (m_pErrorInfo->message.IsEmpty()) {
      expr = pdfium::MakeUnique<CXFA_FMForeachExpression>(
          line, wsIdentifier, std::move(pAccessors), std::move(pList));
    }
    return expr;
  }
  
  std::unique_ptr<CXFA_FMExpression> CXFA_FMParse::ParseDoExpression() {
    uint32_t line = m_pToken->m_uLinenum;
    NextToken();
    std::unique_ptr<CXFA_FMExpression> expr = ParseBlockExpression();
    Check(TOKend);
    if (!m_pErrorInfo->message.IsEmpty())
      return nullptr;
  
    return pdfium::MakeUnique<CXFA_FMDoExpression>(line, std::move(expr));
  }
  