Make CFXA_FMSimpleExpression a subclass of CFXA_FMExpression.

Having a tree with two distinct base classes seems dubious.

-- add const along the way
-- move some constructor implementations to .cpp file.

Change-Id: I37caf46569a857048a745bf00092e946e710c0ee
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/73570
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/xfa/fxfa/fm2js/BUILD.gn b/xfa/fxfa/fm2js/BUILD.gn
index a6b2540..3e151b4 100644
--- a/xfa/fxfa/fm2js/BUILD.gn
+++ b/xfa/fxfa/fm2js/BUILD.gn
@@ -15,8 +15,6 @@
     "cxfa_fmlexer.h",
     "cxfa_fmparser.cpp",
     "cxfa_fmparser.h",
-    "cxfa_fmsimpleexpression.cpp",
-    "cxfa_fmsimpleexpression.h",
     "cxfa_fmtojavascriptdepth.cpp",
     "cxfa_fmtojavascriptdepth.h",
   ]
@@ -33,7 +31,6 @@
     "cxfa_fmexpression_unittest.cpp",
     "cxfa_fmlexer_unittest.cpp",
     "cxfa_fmparser_unittest.cpp",
-    "cxfa_fmsimpleexpression_unittest.cpp",
   ]
   deps = [ ":fm2js" ]
   pdfium_root_dir = "../../../"
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
index 98be02b..0a0fd7b 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.cpp
@@ -6,10 +6,13 @@
 
 #include "xfa/fxfa/fm2js/cxfa_fmexpression.h"
 
+#include <algorithm>
 #include <utility>
 
+#include "core/fxcrt/autorestorer.h"
 #include "core/fxcrt/cfx_widetextbuf.h"
-#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
+#include "core/fxcrt/fx_extension.h"
+#include "third_party/base/logging.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
 namespace {
@@ -19,6 +22,57 @@
 const wchar_t kPlusEqual[] = L" += ";
 const wchar_t kMinusEqual[] = L" -= ";
 
+const wchar_t* const g_BuiltInFuncs[] = {
+    L"Abs",          L"Apr",       L"At",       L"Avg",
+    L"Ceil",         L"Choose",    L"Concat",   L"Count",
+    L"Cterm",        L"Date",      L"Date2Num", L"DateFmt",
+    L"Decode",       L"Encode",    L"Eval",     L"Exists",
+    L"Floor",        L"Format",    L"FV",       L"Get",
+    L"HasValue",     L"If",        L"Ipmt",     L"IsoDate2Num",
+    L"IsoTime2Num",  L"Left",      L"Len",      L"LocalDateFmt",
+    L"LocalTimeFmt", L"Lower",     L"Ltrim",    L"Max",
+    L"Min",          L"Mod",       L"NPV",      L"Num2Date",
+    L"Num2GMTime",   L"Num2Time",  L"Oneof",    L"Parse",
+    L"Pmt",          L"Post",      L"PPmt",     L"Put",
+    L"PV",           L"Rate",      L"Ref",      L"Replace",
+    L"Right",        L"Round",     L"Rtrim",    L"Space",
+    L"Str",          L"Stuff",     L"Substr",   L"Sum",
+    L"Term",         L"Time",      L"Time2Num", L"TimeFmt",
+    L"UnitType",     L"UnitValue", L"Upper",    L"Uuid",
+    L"Within",       L"WordNum",
+};
+
+const size_t g_BuiltInFuncsMaxLen = 12;
+
+struct XFA_FMSOMMethod {
+  const wchar_t* m_wsSomMethodName;
+  uint32_t m_dParameters;
+};
+
+const XFA_FMSOMMethod gs_FMSomMethods[] = {
+    {L"absPage", 0x01},
+    {L"absPageInBatch", 0x01},
+    {L"absPageSpan", 0x01},
+    {L"append", 0x01},
+    {L"clear", 0x01},
+    {L"formNodes", 0x01},
+    {L"h", 0x01},
+    {L"insert", 0x03},
+    {L"isRecordGroup", 0x01},
+    {L"page", 0x01},
+    {L"pageSpan", 0x01},
+    {L"remove", 0x01},
+    {L"saveFilteredXML", 0x01},
+    {L"setElement", 0x01},
+    {L"sheet", 0x01},
+    {L"sheetInBatch", 0x01},
+    {L"sign", 0x61},
+    {L"verify", 0x0d},
+    {L"w", 0x01},
+    {L"x", 0x01},
+    {L"y", 0x01},
+};
+
 WideString IdentifierToName(WideStringView ident) {
   if (ident.IsEmpty())
     return WideString();
@@ -31,6 +85,668 @@
 
 CXFA_FMExpression::CXFA_FMExpression() = default;
 
+CXFA_FMExpression::~CXFA_FMExpression() = default;
+
+CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op)
+    : m_op(op), m_bChainable(false) {}
+
+CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op,
+                                                 bool chainable)
+    : m_op(op), m_bChainable(chainable) {}
+
+CXFA_FMSimpleExpression::~CXFA_FMSimpleExpression() = default;
+
+CXFA_FMChainableExpression::CXFA_FMChainableExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMSimpleExpression(op, /*chainable=*/true),
+      m_pExp1(std::move(pExp1)),
+      m_pExp2(std::move(pExp2)) {}
+
+CXFA_FMChainableExpression::~CXFA_FMChainableExpression() {
+  DeleteChain(std::move(m_pExp1));
+  DeleteChain(std::move(m_pExp2));
+}
+
+CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetFirstExpression()
+    const {
+  return m_pExp1.get();
+}
+
+CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetSecondExpression()
+    const {
+  return m_pExp2.get();
+}
+
+// static
+void CXFA_FMChainableExpression::DeleteChain(
+    std::unique_ptr<CXFA_FMSimpleExpression> pRoot) {
+  while (pRoot && pRoot->chainable()) {
+    auto* pRootChain = static_cast<CXFA_FMChainableExpression*>(pRoot.get());
+
+    // If either child is not a chainable expression (i.e. a leaf node), simply
+    // delete it.
+    if (pRootChain->m_pExp1 && !pRootChain->m_pExp1->chainable())
+      pRootChain->m_pExp1.reset();
+    if (pRootChain->m_pExp2 && !pRootChain->m_pExp2->chainable())
+      pRootChain->m_pExp2.reset();
+
+    // If the root is missing either child, delete the root and promote the only
+    // child to the root.
+    if (!pRootChain->m_pExp1) {
+      pRoot = std::move(pRootChain->m_pExp2);
+      continue;
+    }
+    if (!pRootChain->m_pExp2) {
+      pRoot = std::move(pRootChain->m_pExp1);
+      continue;
+    }
+
+    // Otherwise, perform a right tree rotation.
+    std::unique_ptr<CXFA_FMSimpleExpression> pPivot(
+        std::move(pRootChain->m_pExp1));
+    auto* pPivotChain = static_cast<CXFA_FMChainableExpression*>(pPivot.get());
+    pRootChain->m_pExp1 = std::move(pPivotChain->m_pExp2);
+    pPivotChain->m_pExp2 = std::move(pRoot);
+    pRoot = std::move(pPivot);
+  }
+}
+
+CXFA_FMNullExpression::CXFA_FMNullExpression()
+    : CXFA_FMSimpleExpression(TOKnull) {}
+
+bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                         ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  *js << "null";
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber)
+    : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {}
+
+CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default;
+
+bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                           ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  *js << m_wsNumber;
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString)
+    : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {}
+
+CXFA_FMStringExpression::~CXFA_FMStringExpression() = default;
+
+bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                           ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  WideString tempStr(m_wsString);
+  if (tempStr.GetLength() <= 2) {
+    *js << tempStr;
+    return !CXFA_IsTooBig(*js);
+  }
+
+  *js << "\"";
+  for (size_t i = 1; i < tempStr.GetLength() - 1; i++) {
+    wchar_t oneChar = tempStr[i];
+    switch (oneChar) {
+      case L'\"':
+        ++i;
+        *js << "\\\"";
+        break;
+      case 0x0d:
+        break;
+      case 0x0a:
+        *js << "\\n";
+        break;
+      default:
+        js->AppendChar(oneChar);
+        break;
+    }
+  }
+  *js << "\"";
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
+    WideStringView wsIdentifier)
+    : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {}
+
+CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default;
+
+bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                               ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  if (m_wsIdentifier.EqualsASCII("$"))
+    *js << "this";
+  else if (m_wsIdentifier.EqualsASCII("!"))
+    *js << "xfa.datasets";
+  else if (m_wsIdentifier.EqualsASCII("$data"))
+    *js << "xfa.datasets.data";
+  else if (m_wsIdentifier.EqualsASCII("$event"))
+    *js << "xfa.event";
+  else if (m_wsIdentifier.EqualsASCII("$form"))
+    *js << "xfa.form";
+  else if (m_wsIdentifier.EqualsASCII("$host"))
+    *js << "xfa.host";
+  else if (m_wsIdentifier.EqualsASCII("$layout"))
+    *js << "xfa.layout";
+  else if (m_wsIdentifier.EqualsASCII("$template"))
+    *js << "xfa.template";
+  else if (m_wsIdentifier[0] == L'!')
+    *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1);
+  else
+    *js << m_wsIdentifier;
+
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMAssignExpression::CXFA_FMAssignExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default;
+
+bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                           ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  CFX_WideTextBuf tempExp1;
+  const CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
+  if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
+    return false;
+
+  *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n";
+  if (type == ReturnType::kImplied)
+    *js << "pfm_ret = ";
+
+  CFX_WideTextBuf tempExp2;
+  const CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
+  if (!exp2->ToJavaScript(&tempExp2, ReturnType::kInfered))
+    return false;
+
+  *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n";
+
+  if (exp1->GetOperatorToken() == TOKidentifier &&
+      !tempExp1.AsStringView().EqualsASCII("this")) {
+    *js << "else\n{\n";
+    if (type == ReturnType::kImplied)
+      *js << "pfm_ret = ";
+
+    *js << tempExp1 << " = pfm_rt.asgn_val_op";
+    *js << "(" << tempExp1 << ", " << tempExp2 << ");\n";
+    *js << "}\n";
+  }
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMBinExpression::CXFA_FMBinExpression(
+    const WideString& opName,
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)),
+      m_OpName(opName) {}
+
+CXFA_FMBinExpression::~CXFA_FMBinExpression() = default;
+
+bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                        ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  *js << "pfm_rt." << m_OpName << "(";
+  if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << ", ";
+  if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << ")";
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"log_or_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"log_and_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMEqualExpression::CXFA_FMEqualExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"eq_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"neq_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMGtExpression::CXFA_FMGtExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"gt_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMGeExpression::CXFA_FMGeExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"ge_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMLtExpression::CXFA_FMLtExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"lt_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMLeExpression::CXFA_FMLeExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"le_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMPlusExpression::CXFA_FMPlusExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"plus_op", op, std::move(pExp1), std::move(pExp2)) {
+}
+
+CXFA_FMMinusExpression::CXFA_FMMinusExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"minus_op",
+                           op,
+                           std::move(pExp1),
+                           std::move(pExp2)) {}
+
+CXFA_FMMulExpression::CXFA_FMMulExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"mul_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMDivExpression::CXFA_FMDivExpression(
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
+    : CXFA_FMBinExpression(L"div_op", op, std::move(pExp1), std::move(pExp2)) {}
+
+CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
+    const WideString& opName,
+    XFA_FM_TOKEN op,
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
+    : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {}
+
+CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default;
+
+bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  *js << "pfm_rt." << m_OpName.c_str() << "(";
+  if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << ")";
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMPosExpression::CXFA_FMPosExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
+    : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {}
+
+CXFA_FMNegExpression::CXFA_FMNegExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
+    : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {}
+
+CXFA_FMNotExpression::CXFA_FMNotExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
+    : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {}
+
+CXFA_FMCallExpression::CXFA_FMCallExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pExp,
+    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
+    bool bIsSomMethod)
+    : CXFA_FMSimpleExpression(TOKcall),
+      m_pExp(std::move(pExp)),
+      m_bIsSomMethod(bIsSomMethod),
+      m_Arguments(std::move(pArguments)) {}
+
+CXFA_FMCallExpression::~CXFA_FMCallExpression() = default;
+
+bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) const {
+  if (funcName->GetLength() > g_BuiltInFuncsMaxLen)
+    return false;
+
+  WideString str = funcName->MakeString();
+  const wchar_t* const* pMatchResult = std::lower_bound(
+      std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str,
+      [](const wchar_t* iter, const WideString& val) -> bool {
+        return val.CompareNoCase(iter) > 0;
+      });
+  if (pMatchResult != std::end(g_BuiltInFuncs) &&
+      !str.CompareNoCase(*pMatchResult)) {
+    funcName->Clear();
+    *funcName << *pMatchResult;
+    return true;
+  }
+  return false;
+}
+
+uint32_t CXFA_FMCallExpression::IsMethodWithObjParam(
+    const WideString& methodName) const {
+  const XFA_FMSOMMethod* result = std::lower_bound(
+      std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods), methodName,
+      [](const XFA_FMSOMMethod iter, const WideString& val) {
+        return val.Compare(iter.m_wsSomMethodName) > 0;
+      });
+  if (result != std::end(gs_FMSomMethods) &&
+      !methodName.Compare(result->m_wsSomMethodName)) {
+    return result->m_dParameters;
+  }
+  return 0;
+}
+
+bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                         ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  CFX_WideTextBuf funcName;
+  if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInfered))
+    return false;
+
+  if (m_bIsSomMethod) {
+    *js << funcName << "(";
+    uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString());
+    if (methodPara > 0) {
+      for (size_t i = 0; i < m_Arguments.size(); ++i) {
+        // Currently none of our expressions use objects for a parameter over
+        // the 6th. Make sure we don't overflow the shift when doing this
+        // check. If we ever need more the 32 object params we can revisit.
+        *js << "pfm_rt.get_";
+        if (i < 32 && (methodPara & (0x01 << i)) > 0)
+          *js << "jsobj";
+        else
+          *js << "val";
+
+        *js << "(";
+        if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInfered))
+          return false;
+        *js << ")";
+        if (i + 1 < m_Arguments.size())
+          *js << ", ";
+      }
+    } else {
+      for (const auto& expr : m_Arguments) {
+        *js << "pfm_rt.get_val(";
+        if (!expr->ToJavaScript(js, ReturnType::kInfered))
+          return false;
+        *js << ")";
+        if (expr != m_Arguments.back())
+          *js << ", ";
+      }
+    }
+    *js << ")";
+    return !CXFA_IsTooBig(*js);
+  }
+
+  bool isEvalFunc = false;
+  bool isExistsFunc = false;
+  if (!IsBuiltInFunc(&funcName)) {
+    // If a function is not a SomMethod or a built-in then the input was
+    // invalid, so failing. The scanner/lexer should catch this, but currently
+    // doesn't. This failure will bubble up to the top-level and cause the
+    // transpile to fail.
+    return false;
+  }
+
+  if (funcName.AsStringView().EqualsASCII("Eval")) {
+    isEvalFunc = true;
+    *js << "eval.call(this, pfm_rt.Translate";
+  } else {
+    if (funcName.AsStringView().EqualsASCII("Exists"))
+      isExistsFunc = true;
+
+    *js << "pfm_rt." << funcName;
+  }
+
+  *js << "(";
+  if (isExistsFunc) {
+    *js << "\n(\nfunction ()\n{\ntry\n{\n";
+    if (!m_Arguments.empty()) {
+      *js << "return ";
+      if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInfered))
+        return false;
+      *js << ";\n}\n";
+    } else {
+      *js << "return 0;\n}\n";
+    }
+    *js << "catch(accessExceptions)\n";
+    *js << "{\nreturn 0;\n}\n}\n).call(this)\n";
+  } else {
+    for (const auto& expr : m_Arguments) {
+      if (!expr->ToJavaScript(js, ReturnType::kInfered))
+        return false;
+      if (expr != m_Arguments.back())
+        *js << ", ";
+    }
+  }
+  *js << ")";
+  if (isEvalFunc)
+    *js << ")";
+
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
+    XFA_FM_TOKEN op,
+    WideStringView wsIdentifier,
+    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
+    : CXFA_FMChainableExpression(op,
+                                 std::move(pAccessor),
+                                 std::move(pIndexExp)),
+      m_wsIdentifier(wsIdentifier) {}
+
+CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default;
+
+bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                                ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  *js << "pfm_rt.dot_acc(";
+
+  CFX_WideTextBuf tempExp1;
+  CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
+  if (exp1) {
+    if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
+      return false;
+
+    *js << tempExp1;
+  } else {
+    *js << "null";
+  }
+  *js << ", \"";
+
+  if (exp1 && exp1->GetOperatorToken() == TOKidentifier)
+    *js << tempExp1;
+
+  *js << "\", ";
+  if (GetOperatorToken() == TOKdotscream)
+    *js << "\"#" << m_wsIdentifier << "\", ";
+  else if (GetOperatorToken() == TOKdotstar)
+    *js << "\"*\", ";
+  else if (GetOperatorToken() == TOKcall)
+    *js << "\"\", ";
+  else
+    *js << "\"" << m_wsIdentifier << "\", ";
+
+  CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
+  if (!exp2->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+
+  *js << ")";
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMIndexExpression::CXFA_FMIndexExpression(
+    XFA_FM_AccessorIndex accessorIndex,
+    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
+    bool bIsStarIndex)
+    : CXFA_FMSimpleExpression(TOKlbracket),
+      m_pExp(std::move(pIndexExp)),
+      m_accessorIndex(accessorIndex),
+      m_bIsStarIndex(bIsStarIndex) {}
+
+CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default;
+
+bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                          ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  switch (m_accessorIndex) {
+    case ACCESSOR_NO_INDEX:
+      *js << "0";
+      break;
+    case ACCESSOR_NO_RELATIVEINDEX:
+      *js << "1";
+      break;
+    case ACCESSOR_POSITIVE_INDEX:
+      *js << "2";
+      break;
+    case ACCESSOR_NEGATIVE_INDEX:
+      *js << "3";
+      break;
+    default:
+      *js << "0";
+  }
+  if (m_bIsStarIndex)
+    return !CXFA_IsTooBig(*js);
+
+  *js << ", ";
+  if (m_pExp) {
+    if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
+      return false;
+  } else {
+    *js << "0";
+  }
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
+    XFA_FM_TOKEN op,
+    WideStringView wsIdentifier,
+    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
+    : CXFA_FMChainableExpression(op,
+                                 std::move(pAccessor),
+                                 std::move(pIndexExp)),
+      m_wsIdentifier(wsIdentifier) {}
+
+CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default;
+
+bool CXFA_FMDotDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                                   ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
+  *js << "pfm_rt.dotdot_acc(";
+  if (!exp1->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << ", "
+      << "\"";
+  if (exp1->GetOperatorToken() == TOKidentifier) {
+    if (!exp1->ToJavaScript(js, ReturnType::kInfered))
+      return false;
+  }
+
+  CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
+  *js << "\", \"" << m_wsIdentifier << "\", ";
+  if (!exp2->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << ")";
+  return !CXFA_IsTooBig(*js);
+}
+
+CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
+    std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
+    std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)
+    : CXFA_FMChainableExpression(TOKdot,
+                                 std::move(pAccessorExp1),
+                                 std::move(pCallExp)) {}
+
+CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default;
+
+bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf* js,
+                                               ReturnType type) const {
+  CXFA_FMToJavaScriptDepth depthManager;
+  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
+    return false;
+
+  CFX_WideTextBuf buf;
+  if (!GetFirstExpression()->ToJavaScript(&buf, ReturnType::kInfered))
+    return false;
+
+  *js << "(function() {\n";
+  *js << "  return pfm_method_runner(" << buf << ", function(obj) {\n";
+  *js << "    return obj.";
+  if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered))
+    return false;
+  *js << ";\n";
+  *js << "  });\n";
+  *js << "}).call(this)";
+  return !CXFA_IsTooBig(*js);
+}
+
+bool CXFA_IsTooBig(const CFX_WideTextBuf& js) {
+  return js.GetSize() >= 256 * 1024 * 1024;
+}
+
 CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
     WideStringView wsName,
     std::vector<WideStringView>&& arguments,
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression.h b/xfa/fxfa/fm2js/cxfa_fmexpression.h
index f8f54b8..1a33eff 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression.h
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression.h
@@ -11,19 +11,339 @@
 #include <vector>
 
 #include "third_party/base/optional.h"
-#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
+#include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 
 class CFX_WideTextBuf;
 
+enum XFA_FM_AccessorIndex {
+  ACCESSOR_NO_INDEX,
+  ACCESSOR_NO_RELATIVEINDEX,
+  ACCESSOR_POSITIVE_INDEX,
+  ACCESSOR_NEGATIVE_INDEX
+};
+
+enum class ReturnType { kImplied, kInfered };
+
 class CXFA_FMExpression {
  public:
-  virtual ~CXFA_FMExpression() = default;
+  virtual ~CXFA_FMExpression();
   virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const = 0;
 
  protected:
   CXFA_FMExpression();
 };
 
+class CXFA_FMSimpleExpression : public CXFA_FMExpression {
+ public:
+  ~CXFA_FMSimpleExpression() override;
+
+  XFA_FM_TOKEN GetOperatorToken() const { return m_op; }
+  bool chainable() const { return m_bChainable; }
+
+ protected:
+  explicit CXFA_FMSimpleExpression(XFA_FM_TOKEN op);
+  CXFA_FMSimpleExpression(XFA_FM_TOKEN op, bool chainable);
+
+ private:
+  const XFA_FM_TOKEN m_op;
+  const bool m_bChainable;
+};
+
+class CXFA_FMChainableExpression : public CXFA_FMSimpleExpression {
+ public:
+  ~CXFA_FMChainableExpression() override;
+
+ protected:
+  CXFA_FMChainableExpression(XFA_FM_TOKEN op,
+                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+
+  CXFA_FMSimpleExpression* GetFirstExpression() const;
+  CXFA_FMSimpleExpression* GetSecondExpression() const;
+
+ private:
+  // Iteratively delete a chainable expression tree in linear time and constant
+  // space.
+  static void DeleteChain(std::unique_ptr<CXFA_FMSimpleExpression> pRoot);
+
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
+};
+
+class CXFA_FMNullExpression final : public CXFA_FMSimpleExpression {
+ public:
+  CXFA_FMNullExpression();
+  ~CXFA_FMNullExpression() override = default;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+};
+
+class CXFA_FMNumberExpression final : public CXFA_FMSimpleExpression {
+ public:
+  explicit CXFA_FMNumberExpression(WideStringView wsNumber);
+  ~CXFA_FMNumberExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  WideStringView m_wsNumber;
+};
+
+class CXFA_FMStringExpression final : public CXFA_FMSimpleExpression {
+ public:
+  explicit CXFA_FMStringExpression(WideStringView wsString);
+  ~CXFA_FMStringExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  WideStringView m_wsString;
+};
+
+class CXFA_FMIdentifierExpression final : public CXFA_FMSimpleExpression {
+ public:
+  explicit CXFA_FMIdentifierExpression(WideStringView wsIdentifier);
+  ~CXFA_FMIdentifierExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  WideStringView m_wsIdentifier;
+};
+
+class CXFA_FMAssignExpression final : public CXFA_FMChainableExpression {
+ public:
+  CXFA_FMAssignExpression(XFA_FM_TOKEN op,
+                          std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                          std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMAssignExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+};
+
+class CXFA_FMBinExpression : public CXFA_FMChainableExpression {
+ public:
+  ~CXFA_FMBinExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ protected:
+  CXFA_FMBinExpression(const WideString& opName,
+                       XFA_FM_TOKEN op,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+
+ private:
+  WideString m_OpName;
+};
+
+class CXFA_FMLogicalOrExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op,
+                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMLogicalOrExpression() override = default;
+};
+
+class CXFA_FMLogicalAndExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op,
+                              std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                              std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMLogicalAndExpression() override = default;
+};
+
+class CXFA_FMEqualExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMEqualExpression(XFA_FM_TOKEN op,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMEqualExpression() override = default;
+};
+
+class CXFA_FMNotEqualExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMNotEqualExpression(XFA_FM_TOKEN op,
+                            std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                            std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMNotEqualExpression() override = default;
+};
+
+class CXFA_FMGtExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMGtExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMGtExpression() override = default;
+};
+
+class CXFA_FMGeExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMGeExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMGeExpression() override = default;
+};
+
+class CXFA_FMLtExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMLtExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMLtExpression() override = default;
+};
+
+class CXFA_FMLeExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMLeExpression(XFA_FM_TOKEN op,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMLeExpression() override = default;
+};
+
+class CXFA_FMPlusExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMPlusExpression(XFA_FM_TOKEN op,
+                        std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                        std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMPlusExpression() override = default;
+};
+
+class CXFA_FMMinusExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMMinusExpression(XFA_FM_TOKEN op,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMMinusExpression() override = default;
+};
+
+class CXFA_FMMulExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMMulExpression(XFA_FM_TOKEN op,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMMulExpression() override = default;
+};
+
+class CXFA_FMDivExpression final : public CXFA_FMBinExpression {
+ public:
+  CXFA_FMDivExpression(XFA_FM_TOKEN op,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
+                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
+  ~CXFA_FMDivExpression() override = default;
+};
+
+class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression {
+ public:
+  ~CXFA_FMUnaryExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ protected:
+  CXFA_FMUnaryExpression(const WideString& opName,
+                         XFA_FM_TOKEN op,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+
+ private:
+  WideString m_OpName;
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+};
+
+class CXFA_FMPosExpression final : public CXFA_FMUnaryExpression {
+ public:
+  explicit CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+  ~CXFA_FMPosExpression() override = default;
+};
+
+class CXFA_FMNegExpression final : public CXFA_FMUnaryExpression {
+ public:
+  explicit CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+  ~CXFA_FMNegExpression() override = default;
+};
+
+class CXFA_FMNotExpression final : public CXFA_FMUnaryExpression {
+ public:
+  explicit CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
+  ~CXFA_FMNotExpression() override = default;
+};
+
+class CXFA_FMCallExpression final : public CXFA_FMSimpleExpression {
+ public:
+  CXFA_FMCallExpression(
+      std::unique_ptr<CXFA_FMSimpleExpression> pExp,
+      std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
+      bool bIsSomMethod);
+  ~CXFA_FMCallExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+  bool IsBuiltInFunc(CFX_WideTextBuf* funcName) const;
+  uint32_t IsMethodWithObjParam(const WideString& methodName) const;
+
+ private:
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+  bool m_bIsSomMethod;
+  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> m_Arguments;
+};
+
+class CXFA_FMDotAccessorExpression final : public CXFA_FMChainableExpression {
+ public:
+  CXFA_FMDotAccessorExpression(
+      std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
+      XFA_FM_TOKEN op,
+      WideStringView wsIdentifier,
+      std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
+  ~CXFA_FMDotAccessorExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  WideStringView m_wsIdentifier;
+};
+
+class CXFA_FMIndexExpression final : public CXFA_FMSimpleExpression {
+ public:
+  CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex,
+                         std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
+                         bool bIsStarIndex);
+  ~CXFA_FMIndexExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
+  XFA_FM_AccessorIndex m_accessorIndex;
+  bool m_bIsStarIndex;
+};
+
+class CXFA_FMDotDotAccessorExpression final
+    : public CXFA_FMChainableExpression {
+ public:
+  CXFA_FMDotDotAccessorExpression(
+      std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
+      XFA_FM_TOKEN op,
+      WideStringView wsIdentifier,
+      std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
+  ~CXFA_FMDotDotAccessorExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+
+ private:
+  WideStringView m_wsIdentifier;
+};
+
+class CXFA_FMMethodCallExpression final : public CXFA_FMChainableExpression {
+ public:
+  CXFA_FMMethodCallExpression(
+      std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
+      std::unique_ptr<CXFA_FMSimpleExpression> pCallExp);
+  ~CXFA_FMMethodCallExpression() override;
+
+  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) const override;
+};
+
+bool CXFA_IsTooBig(const CFX_WideTextBuf& js);
+
 class CXFA_FMFunctionDefinition final : public CXFA_FMExpression {
  public:
   CXFA_FMFunctionDefinition(
diff --git a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
index 70e87b1..6903a0f 100644
--- a/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmexpression_unittest.cpp
@@ -10,8 +10,81 @@
 #include "core/fxcrt/cfx_widetextbuf.h"
 #include "core/fxcrt/fx_string.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
 #include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
 
+TEST(FMCallExpressionTest, more_than_32_arguments) {
+  // Use sign as it has 3 object parameters at positions 0, 5, and 6.
+  auto exp = std::make_unique<CXFA_FMIdentifierExpression>(L"sign");
+
+  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> args;
+  for (size_t i = 0; i < 50; i++)
+    args.push_back(std::make_unique<CXFA_FMNullExpression>());
+
+  CXFA_FMToJavaScriptDepth::Reset();
+  CXFA_FMCallExpression callExp(std::move(exp), std::move(args), true);
+
+  CFX_WideTextBuf js;
+  callExp.ToJavaScript(&js, ReturnType::kInfered);
+
+  // Generate the result javascript string.
+  WideString result = L"sign(";
+  for (size_t i = 0; i < 50; i++) {
+    if (i > 0)
+      result += L", ";
+
+    result += L"pfm_rt.get_";
+    // Object positions for sign() method.
+    if (i == 0 || i == 5 || i == 6)
+      result += L"jsobj(null)";
+    else
+      result += L"val(null)";
+  }
+  result += L")";
+
+  EXPECT_EQ(result.AsStringView(), js.AsStringView());
+}
+
+TEST(FMStringExpressionTest, Empty) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+  CXFA_FMStringExpression(L"").ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_EQ(L"", accumulator.AsStringView());
+}
+
+TEST(FMStringExpressionTest, Short) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+  CXFA_FMStringExpression(L"a").ToJavaScript(&accumulator,
+                                             ReturnType::kInfered);
+  EXPECT_EQ(L"a", accumulator.AsStringView());
+}
+
+TEST(FMStringExpressionTest, Medium) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+  CXFA_FMStringExpression(L".abcd.").ToJavaScript(&accumulator,
+                                                  ReturnType::kInfered);
+  EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView());
+}
+
+TEST(FMStringExpressionTest, Long) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+  std::vector<WideStringView::UnsignedType> vec(140000, L'A');
+  CXFA_FMStringExpression(WideStringView(vec))
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_EQ(140000u, accumulator.GetLength());
+}
+
+TEST(FMStringExpressionTest, Quoted) {
+  CXFA_FMToJavaScriptDepth::Reset();
+  CFX_WideTextBuf accumulator;
+  CXFA_FMStringExpression(L".Simon says \"\"run\"\".")
+      .ToJavaScript(&accumulator, ReturnType::kInfered);
+  EXPECT_EQ(L"\"Simon says \\\"run\\\"\"", accumulator.AsStringView());
+}
+
 TEST(CXFA_FMExpressionTest, VarExpressionInitNull) {
   CXFA_FMToJavaScriptDepth::Reset();
   CFX_WideTextBuf accumulator;
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
deleted file mode 100644
index 2371c44..0000000
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.cpp
+++ /dev/null
@@ -1,728 +0,0 @@
-// 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_fmsimpleexpression.h"
-
-#include <algorithm>
-#include <utility>
-
-#include "core/fxcrt/autorestorer.h"
-#include "core/fxcrt/cfx_widetextbuf.h"
-#include "core/fxcrt/fx_extension.h"
-#include "third_party/base/logging.h"
-#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
-
-namespace {
-
-const wchar_t* const g_BuiltInFuncs[] = {
-    L"Abs",          L"Apr",       L"At",       L"Avg",
-    L"Ceil",         L"Choose",    L"Concat",   L"Count",
-    L"Cterm",        L"Date",      L"Date2Num", L"DateFmt",
-    L"Decode",       L"Encode",    L"Eval",     L"Exists",
-    L"Floor",        L"Format",    L"FV",       L"Get",
-    L"HasValue",     L"If",        L"Ipmt",     L"IsoDate2Num",
-    L"IsoTime2Num",  L"Left",      L"Len",      L"LocalDateFmt",
-    L"LocalTimeFmt", L"Lower",     L"Ltrim",    L"Max",
-    L"Min",          L"Mod",       L"NPV",      L"Num2Date",
-    L"Num2GMTime",   L"Num2Time",  L"Oneof",    L"Parse",
-    L"Pmt",          L"Post",      L"PPmt",     L"Put",
-    L"PV",           L"Rate",      L"Ref",      L"Replace",
-    L"Right",        L"Round",     L"Rtrim",    L"Space",
-    L"Str",          L"Stuff",     L"Substr",   L"Sum",
-    L"Term",         L"Time",      L"Time2Num", L"TimeFmt",
-    L"UnitType",     L"UnitValue", L"Upper",    L"Uuid",
-    L"Within",       L"WordNum",
-};
-
-const size_t g_BuiltInFuncsMaxLen = 12;
-
-struct XFA_FMSOMMethod {
-  const wchar_t* m_wsSomMethodName;
-  uint32_t m_dParameters;
-};
-
-const XFA_FMSOMMethod gs_FMSomMethods[] = {
-    {L"absPage", 0x01},
-    {L"absPageInBatch", 0x01},
-    {L"absPageSpan", 0x01},
-    {L"append", 0x01},
-    {L"clear", 0x01},
-    {L"formNodes", 0x01},
-    {L"h", 0x01},
-    {L"insert", 0x03},
-    {L"isRecordGroup", 0x01},
-    {L"page", 0x01},
-    {L"pageSpan", 0x01},
-    {L"remove", 0x01},
-    {L"saveFilteredXML", 0x01},
-    {L"setElement", 0x01},
-    {L"sheet", 0x01},
-    {L"sheetInBatch", 0x01},
-    {L"sign", 0x61},
-    {L"verify", 0x0d},
-    {L"w", 0x01},
-    {L"x", 0x01},
-    {L"y", 0x01},
-};
-
-}  // namespace
-
-CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op)
-    : m_op(op), m_bChainable(false) {}
-
-CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op,
-                                                 bool chainable)
-    : m_op(op), m_bChainable(chainable) {}
-
-XFA_FM_TOKEN CXFA_FMSimpleExpression::GetOperatorToken() const {
-  return m_op;
-}
-
-CXFA_FMChainableExpression::CXFA_FMChainableExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMSimpleExpression(op, /*chainable=*/true),
-      m_pExp1(std::move(pExp1)),
-      m_pExp2(std::move(pExp2)) {}
-
-CXFA_FMChainableExpression::~CXFA_FMChainableExpression() {
-  DeleteChain(std::move(m_pExp1));
-  DeleteChain(std::move(m_pExp2));
-}
-
-CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetFirstExpression() {
-  return m_pExp1.get();
-}
-
-CXFA_FMSimpleExpression* CXFA_FMChainableExpression::GetSecondExpression() {
-  return m_pExp2.get();
-}
-
-// static
-void CXFA_FMChainableExpression::DeleteChain(
-    std::unique_ptr<CXFA_FMSimpleExpression> pRoot) {
-  while (pRoot && pRoot->chainable()) {
-    auto* pRootChain = static_cast<CXFA_FMChainableExpression*>(pRoot.get());
-
-    // If either child is not a chainable expression (i.e. a leaf node), simply
-    // delete it.
-    if (pRootChain->m_pExp1 && !pRootChain->m_pExp1->chainable())
-      pRootChain->m_pExp1.reset();
-    if (pRootChain->m_pExp2 && !pRootChain->m_pExp2->chainable())
-      pRootChain->m_pExp2.reset();
-
-    // If the root is missing either child, delete the root and promote the only
-    // child to the root.
-    if (!pRootChain->m_pExp1) {
-      pRoot = std::move(pRootChain->m_pExp2);
-      continue;
-    }
-    if (!pRootChain->m_pExp2) {
-      pRoot = std::move(pRootChain->m_pExp1);
-      continue;
-    }
-
-    // Otherwise, perform a right tree rotation.
-    std::unique_ptr<CXFA_FMSimpleExpression> pPivot(
-        std::move(pRootChain->m_pExp1));
-    auto* pPivotChain = static_cast<CXFA_FMChainableExpression*>(pPivot.get());
-    pRootChain->m_pExp1 = std::move(pPivotChain->m_pExp2);
-    pPivotChain->m_pExp2 = std::move(pRoot);
-    pRoot = std::move(pPivot);
-  }
-}
-
-CXFA_FMNullExpression::CXFA_FMNullExpression()
-    : CXFA_FMSimpleExpression(TOKnull) {}
-
-bool CXFA_FMNullExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  *js << "null";
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMNumberExpression::CXFA_FMNumberExpression(WideStringView wsNumber)
-    : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(wsNumber) {}
-
-CXFA_FMNumberExpression::~CXFA_FMNumberExpression() = default;
-
-bool CXFA_FMNumberExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                           ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  *js << m_wsNumber;
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMStringExpression::CXFA_FMStringExpression(WideStringView wsString)
-    : CXFA_FMSimpleExpression(TOKstring), m_wsString(wsString) {}
-
-CXFA_FMStringExpression::~CXFA_FMStringExpression() = default;
-
-bool CXFA_FMStringExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                           ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  WideString tempStr(m_wsString);
-  if (tempStr.GetLength() <= 2) {
-    *js << tempStr;
-    return !CXFA_IsTooBig(*js);
-  }
-
-  *js << "\"";
-  for (size_t i = 1; i < tempStr.GetLength() - 1; i++) {
-    wchar_t oneChar = tempStr[i];
-    switch (oneChar) {
-      case L'\"':
-        ++i;
-        *js << "\\\"";
-        break;
-      case 0x0d:
-        break;
-      case 0x0a:
-        *js << "\\n";
-        break;
-      default:
-        js->AppendChar(oneChar);
-        break;
-    }
-  }
-  *js << "\"";
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMIdentifierExpression::CXFA_FMIdentifierExpression(
-    WideStringView wsIdentifier)
-    : CXFA_FMSimpleExpression(TOKidentifier), m_wsIdentifier(wsIdentifier) {}
-
-CXFA_FMIdentifierExpression::~CXFA_FMIdentifierExpression() = default;
-
-bool CXFA_FMIdentifierExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                               ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  if (m_wsIdentifier.EqualsASCII("$"))
-    *js << "this";
-  else if (m_wsIdentifier.EqualsASCII("!"))
-    *js << "xfa.datasets";
-  else if (m_wsIdentifier.EqualsASCII("$data"))
-    *js << "xfa.datasets.data";
-  else if (m_wsIdentifier.EqualsASCII("$event"))
-    *js << "xfa.event";
-  else if (m_wsIdentifier.EqualsASCII("$form"))
-    *js << "xfa.form";
-  else if (m_wsIdentifier.EqualsASCII("$host"))
-    *js << "xfa.host";
-  else if (m_wsIdentifier.EqualsASCII("$layout"))
-    *js << "xfa.layout";
-  else if (m_wsIdentifier.EqualsASCII("$template"))
-    *js << "xfa.template";
-  else if (m_wsIdentifier[0] == L'!')
-    *js << "pfm__excl__" << m_wsIdentifier.Last(m_wsIdentifier.GetLength() - 1);
-  else
-    *js << m_wsIdentifier;
-
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMAssignExpression::CXFA_FMAssignExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMAssignExpression::~CXFA_FMAssignExpression() = default;
-
-bool CXFA_FMAssignExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                           ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  CFX_WideTextBuf tempExp1;
-  CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
-  if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
-    return false;
-
-  *js << "if (pfm_rt.is_obj(" << tempExp1 << "))\n{\n";
-  if (type == ReturnType::kImplied)
-    *js << "pfm_ret = ";
-
-  CFX_WideTextBuf tempExp2;
-  CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
-  if (!exp2->ToJavaScript(&tempExp2, ReturnType::kInfered))
-    return false;
-
-  *js << "pfm_rt.asgn_val_op(" << tempExp1 << ", " << tempExp2 << ");\n}\n";
-
-  if (exp1->GetOperatorToken() == TOKidentifier &&
-      !tempExp1.AsStringView().EqualsASCII("this")) {
-    *js << "else\n{\n";
-    if (type == ReturnType::kImplied)
-      *js << "pfm_ret = ";
-
-    *js << tempExp1 << " = pfm_rt.asgn_val_op";
-    *js << "(" << tempExp1 << ", " << tempExp2 << ");\n";
-    *js << "}\n";
-  }
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMBinExpression::CXFA_FMBinExpression(
-    const WideString& opName,
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMChainableExpression(op, std::move(pExp1), std::move(pExp2)),
-      m_OpName(opName) {}
-
-CXFA_FMBinExpression::~CXFA_FMBinExpression() = default;
-
-bool CXFA_FMBinExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  *js << "pfm_rt." << m_OpName << "(";
-  if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-  *js << ", ";
-  if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-  *js << ")";
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"log_or_op",
-                           op,
-                           std::move(pExp1),
-                           std::move(pExp2)) {}
-
-CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"log_and_op",
-                           op,
-                           std::move(pExp1),
-                           std::move(pExp2)) {}
-
-CXFA_FMEqualExpression::CXFA_FMEqualExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"eq_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"neq_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMGtExpression::CXFA_FMGtExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"gt_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMGeExpression::CXFA_FMGeExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"ge_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMLtExpression::CXFA_FMLtExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"lt_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMLeExpression::CXFA_FMLeExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"le_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMPlusExpression::CXFA_FMPlusExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"plus_op", op, std::move(pExp1), std::move(pExp2)) {
-}
-
-CXFA_FMMinusExpression::CXFA_FMMinusExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"minus_op",
-                           op,
-                           std::move(pExp1),
-                           std::move(pExp2)) {}
-
-CXFA_FMMulExpression::CXFA_FMMulExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"mul_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMDivExpression::CXFA_FMDivExpression(
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp2)
-    : CXFA_FMBinExpression(L"div_op", op, std::move(pExp1), std::move(pExp2)) {}
-
-CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(
-    const WideString& opName,
-    XFA_FM_TOKEN op,
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(std::move(pExp)) {}
-
-CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default;
-
-bool CXFA_FMUnaryExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                          ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  *js << "pfm_rt." << m_OpName.c_str() << "(";
-  if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-  *js << ")";
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMPosExpression::CXFA_FMPosExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(L"pos_op", TOKplus, std::move(pExp)) {}
-
-CXFA_FMNegExpression::CXFA_FMNegExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(L"neg_op", TOKminus, std::move(pExp)) {}
-
-CXFA_FMNotExpression::CXFA_FMNotExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp)
-    : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, std::move(pExp)) {}
-
-CXFA_FMCallExpression::CXFA_FMCallExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pExp,
-    std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
-    bool bIsSomMethod)
-    : CXFA_FMSimpleExpression(TOKcall),
-      m_pExp(std::move(pExp)),
-      m_bIsSomMethod(bIsSomMethod),
-      m_Arguments(std::move(pArguments)) {}
-
-CXFA_FMCallExpression::~CXFA_FMCallExpression() = default;
-
-bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) {
-  if (funcName->GetLength() > g_BuiltInFuncsMaxLen)
-    return false;
-
-  WideString str = funcName->MakeString();
-  const wchar_t* const* pMatchResult = std::lower_bound(
-      std::begin(g_BuiltInFuncs), std::end(g_BuiltInFuncs), str,
-      [](const wchar_t* iter, const WideString& val) -> bool {
-        return val.CompareNoCase(iter) > 0;
-      });
-  if (pMatchResult != std::end(g_BuiltInFuncs) &&
-      !str.CompareNoCase(*pMatchResult)) {
-    funcName->Clear();
-    *funcName << *pMatchResult;
-    return true;
-  }
-  return false;
-}
-
-uint32_t CXFA_FMCallExpression::IsMethodWithObjParam(
-    const WideString& methodName) {
-  const XFA_FMSOMMethod* result = std::lower_bound(
-      std::begin(gs_FMSomMethods), std::end(gs_FMSomMethods), methodName,
-      [](const XFA_FMSOMMethod iter, const WideString& val) {
-        return val.Compare(iter.m_wsSomMethodName) > 0;
-      });
-  if (result != std::end(gs_FMSomMethods) &&
-      !methodName.Compare(result->m_wsSomMethodName)) {
-    return result->m_dParameters;
-  }
-  return 0;
-}
-
-bool CXFA_FMCallExpression::ToJavaScript(CFX_WideTextBuf* js, ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  CFX_WideTextBuf funcName;
-  if (!m_pExp->ToJavaScript(&funcName, ReturnType::kInfered))
-    return false;
-
-  if (m_bIsSomMethod) {
-    *js << funcName << "(";
-    uint32_t methodPara = IsMethodWithObjParam(funcName.MakeString());
-    if (methodPara > 0) {
-      for (size_t i = 0; i < m_Arguments.size(); ++i) {
-        // Currently none of our expressions use objects for a parameter over
-        // the 6th. Make sure we don't overflow the shift when doing this
-        // check. If we ever need more the 32 object params we can revisit.
-        *js << "pfm_rt.get_";
-        if (i < 32 && (methodPara & (0x01 << i)) > 0)
-          *js << "jsobj";
-        else
-          *js << "val";
-
-        *js << "(";
-        if (!m_Arguments[i]->ToJavaScript(js, ReturnType::kInfered))
-          return false;
-        *js << ")";
-        if (i + 1 < m_Arguments.size())
-          *js << ", ";
-      }
-    } else {
-      for (const auto& expr : m_Arguments) {
-        *js << "pfm_rt.get_val(";
-        if (!expr->ToJavaScript(js, ReturnType::kInfered))
-          return false;
-        *js << ")";
-        if (expr != m_Arguments.back())
-          *js << ", ";
-      }
-    }
-    *js << ")";
-    return !CXFA_IsTooBig(*js);
-  }
-
-  bool isEvalFunc = false;
-  bool isExistsFunc = false;
-  if (!IsBuiltInFunc(&funcName)) {
-    // If a function is not a SomMethod or a built-in then the input was
-    // invalid, so failing. The scanner/lexer should catch this, but currently
-    // doesn't. This failure will bubble up to the top-level and cause the
-    // transpile to fail.
-    return false;
-  }
-
-  if (funcName.AsStringView().EqualsASCII("Eval")) {
-    isEvalFunc = true;
-    *js << "eval.call(this, pfm_rt.Translate";
-  } else {
-    if (funcName.AsStringView().EqualsASCII("Exists"))
-      isExistsFunc = true;
-
-    *js << "pfm_rt." << funcName;
-  }
-
-  *js << "(";
-  if (isExistsFunc) {
-    *js << "\n(\nfunction ()\n{\ntry\n{\n";
-    if (!m_Arguments.empty()) {
-      *js << "return ";
-      if (!m_Arguments[0]->ToJavaScript(js, ReturnType::kInfered))
-        return false;
-      *js << ";\n}\n";
-    } else {
-      *js << "return 0;\n}\n";
-    }
-    *js << "catch(accessExceptions)\n";
-    *js << "{\nreturn 0;\n}\n}\n).call(this)\n";
-  } else {
-    for (const auto& expr : m_Arguments) {
-      if (!expr->ToJavaScript(js, ReturnType::kInfered))
-        return false;
-      if (expr != m_Arguments.back())
-        *js << ", ";
-    }
-  }
-  *js << ")";
-  if (isEvalFunc)
-    *js << ")";
-
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-    XFA_FM_TOKEN op,
-    WideStringView wsIdentifier,
-    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
-    : CXFA_FMChainableExpression(op,
-                                 std::move(pAccessor),
-                                 std::move(pIndexExp)),
-      m_wsIdentifier(wsIdentifier) {}
-
-CXFA_FMDotAccessorExpression::~CXFA_FMDotAccessorExpression() = default;
-
-bool CXFA_FMDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                                ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  *js << "pfm_rt.dot_acc(";
-
-  CFX_WideTextBuf tempExp1;
-  CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
-  if (exp1) {
-    if (!exp1->ToJavaScript(&tempExp1, ReturnType::kInfered))
-      return false;
-
-    *js << tempExp1;
-  } else {
-    *js << "null";
-  }
-  *js << ", \"";
-
-  if (exp1 && exp1->GetOperatorToken() == TOKidentifier)
-    *js << tempExp1;
-
-  *js << "\", ";
-  if (m_op == TOKdotscream)
-    *js << "\"#" << m_wsIdentifier << "\", ";
-  else if (m_op == TOKdotstar)
-    *js << "\"*\", ";
-  else if (m_op == TOKcall)
-    *js << "\"\", ";
-  else
-    *js << "\"" << m_wsIdentifier << "\", ";
-
-  CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
-  if (!exp2->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-
-  *js << ")";
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMIndexExpression::CXFA_FMIndexExpression(
-    XFA_FM_AccessorIndex accessorIndex,
-    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
-    bool bIsStarIndex)
-    : CXFA_FMSimpleExpression(TOKlbracket),
-      m_pExp(std::move(pIndexExp)),
-      m_accessorIndex(accessorIndex),
-      m_bIsStarIndex(bIsStarIndex) {}
-
-CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default;
-
-bool CXFA_FMIndexExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                          ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  switch (m_accessorIndex) {
-    case ACCESSOR_NO_INDEX:
-      *js << "0";
-      break;
-    case ACCESSOR_NO_RELATIVEINDEX:
-      *js << "1";
-      break;
-    case ACCESSOR_POSITIVE_INDEX:
-      *js << "2";
-      break;
-    case ACCESSOR_NEGATIVE_INDEX:
-      *js << "3";
-      break;
-    default:
-      *js << "0";
-  }
-  if (m_bIsStarIndex)
-    return !CXFA_IsTooBig(*js);
-
-  *js << ", ";
-  if (m_pExp) {
-    if (!m_pExp->ToJavaScript(js, ReturnType::kInfered))
-      return false;
-  } else {
-    *js << "0";
-  }
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-    XFA_FM_TOKEN op,
-    WideStringView wsIdentifier,
-    std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp)
-    : CXFA_FMChainableExpression(op,
-                                 std::move(pAccessor),
-                                 std::move(pIndexExp)),
-      m_wsIdentifier(wsIdentifier) {}
-
-CXFA_FMDotDotAccessorExpression::~CXFA_FMDotDotAccessorExpression() = default;
-
-bool CXFA_FMDotDotAccessorExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                                   ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  CXFA_FMSimpleExpression* exp1 = GetFirstExpression();
-  *js << "pfm_rt.dotdot_acc(";
-  if (!exp1->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-  *js << ", "
-      << "\"";
-  if (exp1->GetOperatorToken() == TOKidentifier) {
-    if (!exp1->ToJavaScript(js, ReturnType::kInfered))
-      return false;
-  }
-
-  CXFA_FMSimpleExpression* exp2 = GetSecondExpression();
-  *js << "\", \"" << m_wsIdentifier << "\", ";
-  if (!exp2->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-  *js << ")";
-  return !CXFA_IsTooBig(*js);
-}
-
-CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression(
-    std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
-    std::unique_ptr<CXFA_FMSimpleExpression> pCallExp)
-    : CXFA_FMChainableExpression(TOKdot,
-                                 std::move(pAccessorExp1),
-                                 std::move(pCallExp)) {}
-
-CXFA_FMMethodCallExpression::~CXFA_FMMethodCallExpression() = default;
-
-bool CXFA_FMMethodCallExpression::ToJavaScript(CFX_WideTextBuf* js,
-                                               ReturnType type) {
-  CXFA_FMToJavaScriptDepth depthManager;
-  if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth())
-    return false;
-
-  CFX_WideTextBuf buf;
-  if (!GetFirstExpression()->ToJavaScript(&buf, ReturnType::kInfered))
-    return false;
-
-  *js << "(function() {\n";
-  *js << "  return pfm_method_runner(" << buf << ", function(obj) {\n";
-  *js << "    return obj.";
-  if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInfered))
-    return false;
-  *js << ";\n";
-  *js << "  });\n";
-  *js << "}).call(this)";
-  return !CXFA_IsTooBig(*js);
-}
-
-bool CXFA_IsTooBig(const CFX_WideTextBuf& js) {
-  return js.GetSize() >= 256 * 1024 * 1024;
-}
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h
deleted file mode 100644
index 81c341c..0000000
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h
+++ /dev/null
@@ -1,338 +0,0 @@
-// 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
-
-#ifndef XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_
-#define XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_
-
-#include <memory>
-#include <vector>
-
-#include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
-
-enum XFA_FM_AccessorIndex {
-  ACCESSOR_NO_INDEX,
-  ACCESSOR_NO_RELATIVEINDEX,
-  ACCESSOR_POSITIVE_INDEX,
-  ACCESSOR_NEGATIVE_INDEX
-};
-
-enum class ReturnType { kImplied, kInfered };
-
-class CFX_WideTextBuf;
-
-class CXFA_FMSimpleExpression {
- public:
-  virtual ~CXFA_FMSimpleExpression() = default;
-  virtual bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) = 0;
-
-  XFA_FM_TOKEN GetOperatorToken() const;
-  bool chainable() const { return m_bChainable; }
-
- protected:
-  explicit CXFA_FMSimpleExpression(XFA_FM_TOKEN op);
-  CXFA_FMSimpleExpression(XFA_FM_TOKEN op, bool chainable);
-
-  const XFA_FM_TOKEN m_op;
-
- private:
-  const bool m_bChainable;
-};
-
-class CXFA_FMChainableExpression : public CXFA_FMSimpleExpression {
- public:
-  ~CXFA_FMChainableExpression() override;
-
- protected:
-  CXFA_FMChainableExpression(XFA_FM_TOKEN op,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-
-  CXFA_FMSimpleExpression* GetFirstExpression();
-  CXFA_FMSimpleExpression* GetSecondExpression();
-
- private:
-  // Iteratively delete a chainable expression tree in linear time and constant
-  // space.
-  static void DeleteChain(std::unique_ptr<CXFA_FMSimpleExpression> pRoot);
-
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp1;
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp2;
-};
-
-class CXFA_FMNullExpression final : public CXFA_FMSimpleExpression {
- public:
-  CXFA_FMNullExpression();
-  ~CXFA_FMNullExpression() override = default;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-};
-
-class CXFA_FMNumberExpression final : public CXFA_FMSimpleExpression {
- public:
-  explicit CXFA_FMNumberExpression(WideStringView wsNumber);
-  ~CXFA_FMNumberExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  WideStringView m_wsNumber;
-};
-
-class CXFA_FMStringExpression final : public CXFA_FMSimpleExpression {
- public:
-  explicit CXFA_FMStringExpression(WideStringView wsString);
-  ~CXFA_FMStringExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  WideStringView m_wsString;
-};
-
-class CXFA_FMIdentifierExpression final : public CXFA_FMSimpleExpression {
- public:
-  explicit CXFA_FMIdentifierExpression(WideStringView wsIdentifier);
-  ~CXFA_FMIdentifierExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  WideStringView m_wsIdentifier;
-};
-
-class CXFA_FMAssignExpression final : public CXFA_FMChainableExpression {
- public:
-  CXFA_FMAssignExpression(XFA_FM_TOKEN op,
-                          std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                          std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMAssignExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-};
-
-class CXFA_FMBinExpression : public CXFA_FMChainableExpression {
- public:
-  ~CXFA_FMBinExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- protected:
-  CXFA_FMBinExpression(const WideString& opName,
-                       XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-
- private:
-  WideString m_OpName;
-};
-
-class CXFA_FMLogicalOrExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMLogicalOrExpression(XFA_FM_TOKEN op,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                             std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLogicalOrExpression() override = default;
-};
-
-class CXFA_FMLogicalAndExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMLogicalAndExpression(XFA_FM_TOKEN op,
-                              std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                              std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLogicalAndExpression() override = default;
-};
-
-class CXFA_FMEqualExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMEqualExpression(XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMEqualExpression() override = default;
-};
-
-class CXFA_FMNotEqualExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMNotEqualExpression(XFA_FM_TOKEN op,
-                            std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                            std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMNotEqualExpression() override = default;
-};
-
-class CXFA_FMGtExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMGtExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMGtExpression() override = default;
-};
-
-class CXFA_FMGeExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMGeExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMGeExpression() override = default;
-};
-
-class CXFA_FMLtExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMLtExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLtExpression() override = default;
-};
-
-class CXFA_FMLeExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMLeExpression(XFA_FM_TOKEN op,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                      std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMLeExpression() override = default;
-};
-
-class CXFA_FMPlusExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMPlusExpression(XFA_FM_TOKEN op,
-                        std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                        std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMPlusExpression() override = default;
-};
-
-class CXFA_FMMinusExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMMinusExpression(XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMMinusExpression() override = default;
-};
-
-class CXFA_FMMulExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMMulExpression(XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMMulExpression() override = default;
-};
-
-class CXFA_FMDivExpression final : public CXFA_FMBinExpression {
- public:
-  CXFA_FMDivExpression(XFA_FM_TOKEN op,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp1,
-                       std::unique_ptr<CXFA_FMSimpleExpression> pExp2);
-  ~CXFA_FMDivExpression() override = default;
-};
-
-class CXFA_FMUnaryExpression : public CXFA_FMSimpleExpression {
- public:
-  ~CXFA_FMUnaryExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- protected:
-  CXFA_FMUnaryExpression(const WideString& opName,
-                         XFA_FM_TOKEN op,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-
- private:
-  WideString m_OpName;
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
-};
-
-class CXFA_FMPosExpression final : public CXFA_FMUnaryExpression {
- public:
-  explicit CXFA_FMPosExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMPosExpression() override = default;
-};
-
-class CXFA_FMNegExpression final : public CXFA_FMUnaryExpression {
- public:
-  explicit CXFA_FMNegExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMNegExpression() override = default;
-};
-
-class CXFA_FMNotExpression final : public CXFA_FMUnaryExpression {
- public:
-  explicit CXFA_FMNotExpression(std::unique_ptr<CXFA_FMSimpleExpression> pExp);
-  ~CXFA_FMNotExpression() override = default;
-};
-
-class CXFA_FMCallExpression final : public CXFA_FMSimpleExpression {
- public:
-  CXFA_FMCallExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pExp,
-      std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pArguments,
-      bool bIsSomMethod);
-  ~CXFA_FMCallExpression() override;
-
-  bool IsBuiltInFunc(CFX_WideTextBuf* funcName);
-  uint32_t IsMethodWithObjParam(const WideString& methodName);
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
-  bool m_bIsSomMethod;
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> m_Arguments;
-};
-
-class CXFA_FMDotAccessorExpression final : public CXFA_FMChainableExpression {
- public:
-  CXFA_FMDotAccessorExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-      XFA_FM_TOKEN op,
-      WideStringView wsIdentifier,
-      std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
-  ~CXFA_FMDotAccessorExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  WideStringView m_wsIdentifier;
-};
-
-class CXFA_FMIndexExpression final : public CXFA_FMSimpleExpression {
- public:
-  CXFA_FMIndexExpression(XFA_FM_AccessorIndex accessorIndex,
-                         std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp,
-                         bool bIsStarIndex);
-  ~CXFA_FMIndexExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  std::unique_ptr<CXFA_FMSimpleExpression> m_pExp;
-  XFA_FM_AccessorIndex m_accessorIndex;
-  bool m_bIsStarIndex;
-};
-
-class CXFA_FMDotDotAccessorExpression final
-    : public CXFA_FMChainableExpression {
- public:
-  CXFA_FMDotDotAccessorExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
-      XFA_FM_TOKEN op,
-      WideStringView wsIdentifier,
-      std::unique_ptr<CXFA_FMSimpleExpression> pIndexExp);
-  ~CXFA_FMDotDotAccessorExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-
- private:
-  WideStringView m_wsIdentifier;
-};
-
-class CXFA_FMMethodCallExpression final : public CXFA_FMChainableExpression {
- public:
-  CXFA_FMMethodCallExpression(
-      std::unique_ptr<CXFA_FMSimpleExpression> pAccessorExp1,
-      std::unique_ptr<CXFA_FMSimpleExpression> pCallExp);
-  ~CXFA_FMMethodCallExpression() override;
-
-  bool ToJavaScript(CFX_WideTextBuf* js, ReturnType type) override;
-};
-
-bool CXFA_IsTooBig(const CFX_WideTextBuf& js);
-
-#endif  // XFA_FXFA_FM2JS_CXFA_FMSIMPLEEXPRESSION_H_
diff --git a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp
deleted file mode 100644
index 8831e05..0000000
--- a/xfa/fxfa/fm2js/cxfa_fmsimpleexpression_unittest.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 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.
-
-#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
-
-#include <memory>
-#include <utility>
-
-#include "core/fxcrt/cfx_widetextbuf.h"
-#include "core/fxcrt/fx_string.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "xfa/fxfa/fm2js/cxfa_fmlexer.h"
-#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
-
-TEST(FMCallExpressionTest, more_than_32_arguments) {
-  // Use sign as it has 3 object parameters at positions 0, 5, and 6.
-  auto exp = std::make_unique<CXFA_FMIdentifierExpression>(L"sign");
-
-  std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> args;
-  for (size_t i = 0; i < 50; i++)
-    args.push_back(std::make_unique<CXFA_FMNullExpression>());
-
-  CXFA_FMToJavaScriptDepth::Reset();
-  CXFA_FMCallExpression callExp(std::move(exp), std::move(args), true);
-
-  CFX_WideTextBuf js;
-  callExp.ToJavaScript(&js, ReturnType::kInfered);
-
-  // Generate the result javascript string.
-  WideString result = L"sign(";
-  for (size_t i = 0; i < 50; i++) {
-    if (i > 0)
-      result += L", ";
-
-    result += L"pfm_rt.get_";
-    // Object positions for sign() method.
-    if (i == 0 || i == 5 || i == 6)
-      result += L"jsobj(null)";
-    else
-      result += L"val(null)";
-  }
-  result += L")";
-
-  EXPECT_EQ(result.AsStringView(), js.AsStringView());
-}
-
-TEST(FMStringExpressionTest, Empty) {
-  CXFA_FMToJavaScriptDepth::Reset();
-  CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L"").ToJavaScript(&accumulator, ReturnType::kInfered);
-  EXPECT_EQ(L"", accumulator.AsStringView());
-}
-
-TEST(FMStringExpressionTest, Short) {
-  CXFA_FMToJavaScriptDepth::Reset();
-  CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L"a").ToJavaScript(&accumulator,
-                                             ReturnType::kInfered);
-  EXPECT_EQ(L"a", accumulator.AsStringView());
-}
-
-TEST(FMStringExpressionTest, Medium) {
-  CXFA_FMToJavaScriptDepth::Reset();
-  CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L".abcd.").ToJavaScript(&accumulator,
-                                                  ReturnType::kInfered);
-  EXPECT_EQ(L"\"abcd\"", accumulator.AsStringView());
-}
-
-TEST(FMStringExpressionTest, Long) {
-  CXFA_FMToJavaScriptDepth::Reset();
-  CFX_WideTextBuf accumulator;
-  std::vector<WideStringView::UnsignedType> vec(140000, L'A');
-  CXFA_FMStringExpression(WideStringView(vec))
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
-  EXPECT_EQ(140000u, accumulator.GetLength());
-}
-
-TEST(FMStringExpressionTest, Quoted) {
-  CXFA_FMToJavaScriptDepth::Reset();
-  CFX_WideTextBuf accumulator;
-  CXFA_FMStringExpression(L".Simon says \"\"run\"\".")
-      .ToJavaScript(&accumulator, ReturnType::kInfered);
-  EXPECT_EQ(L"\"Simon says \\\"run\\\"\"", accumulator.AsStringView());
-}