Declare CXFA_FMLexer as stack-allocated

Even though it has nothing to do with cppgc, this allows removing
some make_unique<CXFA_*> anti-patterns.

-- Make XFA_KEYWORD private to the one .cpp file that uses it.

Change-Id: If868242ae3ec9639e0452654195300a4aeed944c
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/73930
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/fxjs/xfa/cfxjse_formcalc_context.cpp b/fxjs/xfa/cfxjse_formcalc_context.cpp
index 1606150..974344f 100644
--- a/fxjs/xfa/cfxjse_formcalc_context.cpp
+++ b/fxjs/xfa/cfxjse_formcalc_context.cpp
@@ -5653,7 +5653,8 @@
   if (wsFormcalc.IsEmpty())
     return CFX_WideTextBuf();
 
-  CXFA_FMParser parser(pHeap, wsFormcalc);
+  CXFA_FMLexer lexer(wsFormcalc);
+  CXFA_FMParser parser(pHeap, &lexer);
   CXFA_FMAST* ast = parser.Parse();
   if (!ast || parser.HasError())
     return pdfium::nullopt;
diff --git a/testing/fuzzers/pdf_formcalc_fuzzer.cc b/testing/fuzzers/pdf_formcalc_fuzzer.cc
index d116648..2771b04 100644
--- a/testing/fuzzers/pdf_formcalc_fuzzer.cc
+++ b/testing/fuzzers/pdf_formcalc_fuzzer.cc
@@ -12,7 +12,8 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   auto* state = static_cast<XFAProcessState*>(FPDF_GetFuzzerPerProcessState());
   WideString input = WideString::FromUTF8(ByteStringView(data, size));
-  CXFA_FMParser parser(state->GetHeap(), input.AsStringView());
+  CXFA_FMLexer lexer(input.AsStringView());
+  CXFA_FMParser parser(state->GetHeap(), &lexer);
   parser.Parse();
   state->MaybeForceGCAndPump();
   return 0;
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer.cpp b/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
index efb59f2..159910f 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer.cpp
@@ -35,6 +35,11 @@
          c == 0x0020;    // Space
 }
 
+struct XFA_FMKeyword {
+  XFA_FM_TOKEN m_type;
+  const char* m_keyword;  // Raw, POD struct.
+};
+
 const XFA_FMKeyword keyWords[] = {
     {TOKdo, "do"},
     {TOKkseq, "eq"},
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer.h b/xfa/fxfa/fm2js/cxfa_fmlexer.h
index 2d9e5fc..fe55a12 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer.h
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer.h
@@ -8,6 +8,7 @@
 #define XFA_FXFA_FM2JS_CXFA_FMLEXER_H_
 
 #include "core/fxcrt/fx_string.h"
+#include "v8/include/cppgc/macros.h"
 
 enum XFA_FM_TOKEN {
   TOKand,
@@ -80,11 +81,6 @@
   TOKreserver
 };
 
-struct XFA_FMKeyword {
-  XFA_FM_TOKEN m_type;
-  const char* m_keyword;  // Raw, POD struct.
-};
-
 class CXFA_FMToken {
  public:
   CXFA_FMToken();
@@ -101,6 +97,8 @@
 };
 
 class CXFA_FMLexer {
+  CPPGC_STACK_ALLOCATED();  // Raw pointers allowed.
+
  public:
   explicit CXFA_FMLexer(WideStringView wsFormcalc);
   ~CXFA_FMLexer();
diff --git a/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
index 0b3003d..3f5eacc 100644
--- a/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmlexer_unittest.cpp
@@ -26,83 +26,95 @@
 }
 
 TEST(CXFA_FMLexerTest, Numbers) {
-  auto lexer = std::make_unique<CXFA_FMLexer>(L"-12");
-  CXFA_FMToken token = lexer->NextToken();
-  // TODO(dsinclair): Should this return -12 instead of two tokens?
-  EXPECT_EQ(TOKminus, token.m_type);
-  token = lexer->NextToken();
-  EXPECT_EQ(L"12", token.m_string);
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"1.5362");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"1.5362", token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"0.875");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"0.875", token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"5.56e-2");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"5.56e-2", token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"1.234E10");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"1.234E10", token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"123456789.012345678");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  // TODO(dsinclair): This should round as per IEEE 64-bit values.
-  // EXPECT_EQ(L"123456789.01234567", token.m_string);
-  EXPECT_EQ(L"123456789.012345678", token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"99999999999999999");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  // TODO(dsinclair): This is spec'd as rounding when > 16 significant digits
-  // prior to the exponent.
-  // EXPECT_EQ(L"100000000000000000", token.m_string);
-  EXPECT_EQ(L"99999999999999999", token.m_string);
-  EXPECT_TRUE(lexer->IsComplete());
+  {
+    CXFA_FMLexer lexer(L"-12");
+    CXFA_FMToken token = lexer.NextToken();
+    // TODO(dsinclair): Should this return -12 instead of two tokens?
+    EXPECT_EQ(TOKminus, token.m_type);
+    token = lexer.NextToken();
+    EXPECT_EQ(L"12", token.m_string);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"1.5362");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"1.5362", token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(L"0.875");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"0.875", token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(L"5.56e-2");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"5.56e-2", token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(L"1.234E10");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"1.234E10", token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(L"123456789.012345678");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    // TODO(dsinclair): This should round as per IEEE 64-bit values.
+    // EXPECT_EQ(L"123456789.01234567", token.m_string);
+    EXPECT_EQ(L"123456789.012345678", token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(L"99999999999999999");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    // TODO(dsinclair): This is spec'd as rounding when > 16 significant digits
+    // prior to the exponent.
+    // EXPECT_EQ(L"100000000000000000", token.m_string);
+    EXPECT_EQ(L"99999999999999999", token.m_string);
+    EXPECT_TRUE(lexer.IsComplete());
+  }
 }
 
 // The quotes are stripped in CXFA_FMStringExpression::ToJavaScript.
 TEST(CXFA_FMLexerTest, Strings) {
-  auto lexer =
-      std::make_unique<CXFA_FMLexer>(L"\"The cat jumped over the fence.\"");
-  CXFA_FMToken token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token.m_type);
-  EXPECT_EQ(L"\"The cat jumped over the fence.\"", token.m_string);
+  {
+    CXFA_FMLexer lexer(L"\"The cat jumped over the fence.\"");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKstring, token.m_type);
+    EXPECT_EQ(L"\"The cat jumped over the fence.\"", token.m_string);
 
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"\"\"");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token.m_type);
-  EXPECT_EQ(L"\"\"", token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(
-      L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token.m_type);
-  EXPECT_EQ(L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"",
-            token.m_string);
-
-  lexer = std::make_unique<CXFA_FMLexer>(
-      L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token.m_type);
-  EXPECT_EQ(
-      L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"",
-      token.m_string);
-  EXPECT_TRUE(lexer->IsComplete());
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"\"\"");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKstring, token.m_type);
+    EXPECT_EQ(L"\"\"", token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(
+        L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKstring, token.m_type);
+    EXPECT_EQ(L"\"The message reads: \"\"Warning: Insufficient Memory\"\"\"",
+              token.m_string);
+  }
+  {
+    CXFA_FMLexer lexer(
+        L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKstring, token.m_type);
+    EXPECT_EQ(
+        L"\"\\u0047\\u006f\\u0066\\u0069\\u0073\\u0068\\u0021\\u000d\\u000a\"",
+        token.m_string);
+    EXPECT_TRUE(lexer.IsComplete());
+  }
 }
 
 // Note, 'this' is a keyword but is not matched by the lexer.
@@ -171,123 +183,137 @@
             {L".*", TOKdotstar}};
 
   for (size_t i = 0; i < pdfium::size(op); ++i) {
-    auto lexer = std::make_unique<CXFA_FMLexer>(op[i].op);
-    CXFA_FMToken token = lexer->NextToken();
+    CXFA_FMLexer lexer(op[i].op);
+    CXFA_FMToken token = lexer.NextToken();
     EXPECT_EQ(op[i].token, token.m_type);
-    EXPECT_TRUE(lexer->IsComplete());
+    EXPECT_TRUE(lexer.IsComplete());
   }
 }
 
 TEST(CXFA_FMLexerTest, Comments) {
-  auto lexer = std::make_unique<CXFA_FMLexer>(L"// Empty.");
-  CXFA_FMToken token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
+  {
+    CXFA_FMLexer lexer(L"// Empty.");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"//");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"123 // Empty.\n\"str\"");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"123", token.m_string);
 
-  lexer = std::make_unique<CXFA_FMLexer>(L"//");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKstring, token.m_type);
+    EXPECT_EQ(L"\"str\"", token.m_string);
 
-  lexer = std::make_unique<CXFA_FMLexer>(L"123 // Empty.\n\"str\"");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"123", token.m_string);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L";");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"; Empty.");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"123 ;Empty.\n\"str\"");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"123", token.m_string);
 
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token.m_type);
-  EXPECT_EQ(L"\"str\"", token.m_string);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKstring, token.m_type);
+    EXPECT_EQ(L"\"str\"", token.m_string);
 
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L";");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"; Empty.");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"123 ;Empty.\n\"str\"");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"123", token.m_string);
-
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKstring, token.m_type);
-  EXPECT_EQ(L"\"str\"", token.m_string);
-
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-  EXPECT_TRUE(lexer->IsComplete());
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+    EXPECT_TRUE(lexer.IsComplete());
+  }
 }
 
 TEST(CXFA_FMLexerTest, ValidIdentifiers) {
   std::vector<const wchar_t*> identifiers = {
       L"a", L"an_identifier", L"_ident", L"$ident", L"!ident", L"GetAddr"};
   for (const auto* ident : identifiers) {
-    auto lexer = std::make_unique<CXFA_FMLexer>(ident);
-    CXFA_FMToken token = lexer->NextToken();
+    CXFA_FMLexer lexer(ident);
+    CXFA_FMToken token = lexer.NextToken();
     EXPECT_EQ(TOKidentifier, token.m_type);
     EXPECT_EQ(ident, token.m_string);
-    EXPECT_TRUE(lexer->IsComplete());
+    EXPECT_TRUE(lexer.IsComplete());
   }
 }
 
 TEST(CXFA_FMLexerTest, InvalidIdentifiers) {
-  auto lexer = std::make_unique<CXFA_FMLexer>(L"#a");
-  auto token = lexer->NextToken();
-  EXPECT_EQ(TOKreserver, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"1a");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKreserver, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"an@identifier");
-  token = lexer->NextToken();
-  EXPECT_NE(TOKreserver, token.m_type);
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKreserver, token.m_type);
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKreserver, token.m_type);
-
-  lexer = std::make_unique<CXFA_FMLexer>(L"_ident@");
-  token = lexer->NextToken();
-  EXPECT_NE(TOKreserver, token.m_type);
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKreserver, token.m_type);
-  EXPECT_FALSE(lexer->IsComplete());
+  {
+    CXFA_FMLexer lexer(L"#a");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKreserver, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"1a");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKreserver, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"an@identifier");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_NE(TOKreserver, token.m_type);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKreserver, token.m_type);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKreserver, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"_ident@");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_NE(TOKreserver, token.m_type);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKreserver, token.m_type);
+    EXPECT_FALSE(lexer.IsComplete());
+  }
 }
 
 TEST(CXFA_FMLexerTest, Whitespace) {
-  auto lexer = std::make_unique<CXFA_FMLexer>(L" \t\xc\x9\xb");
-  CXFA_FMToken token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
+  {
+    CXFA_FMLexer lexer(L" \t\xc\x9\xb");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+  }
+  {
+    CXFA_FMLexer lexer(L"123 \t\xc\x9\xb 456");
+    CXFA_FMToken token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"123", token.m_string);
 
-  lexer = std::make_unique<CXFA_FMLexer>(L"123 \t\xc\x9\xb 456");
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"123", token.m_string);
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKnumber, token.m_type);
+    EXPECT_EQ(L"456", token.m_string);
 
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKnumber, token.m_type);
-  EXPECT_EQ(L"456", token.m_string);
-
-  token = lexer->NextToken();
-  EXPECT_EQ(TOKeof, token.m_type);
-  EXPECT_TRUE(lexer->IsComplete());
+    token = lexer.NextToken();
+    EXPECT_EQ(TOKeof, token.m_type);
+    EXPECT_TRUE(lexer.IsComplete());
+  }
 }
 
 TEST(CXFA_FMLexerTest, NullData) {
-  auto lexer = std::make_unique<CXFA_FMLexer>(
-      WideStringView(L"\x2d\x32\x00\x2d\x32", 5));
-  CXFA_FMToken token = lexer->NextToken();
+  CXFA_FMLexer lexer(WideStringView(L"\x2d\x32\x00\x2d\x32", 5));
+  CXFA_FMToken token = lexer.NextToken();
   EXPECT_EQ(TOKminus, token.m_type);
 
-  token = lexer->NextToken();
+  token = lexer.NextToken();
   EXPECT_EQ(TOKnumber, token.m_type);
   EXPECT_EQ(L"2", token.m_string);
 
-  token = lexer->NextToken();
+  token = lexer.NextToken();
   EXPECT_EQ(TOKeof, token.m_type);
-  EXPECT_FALSE(lexer->IsComplete());
+  EXPECT_FALSE(lexer.IsComplete());
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.cpp b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
index 24742b1..4d9f272 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
@@ -20,12 +20,8 @@
 
 }  // namespace
 
-CXFA_FMParser::CXFA_FMParser(cppgc::Heap* pHeap, WideStringView wsFormcalc)
-    : m_heap(pHeap),
-      m_lexer(std::make_unique<CXFA_FMLexer>(wsFormcalc)),
-      m_error(false),
-      m_parse_depth(0),
-      m_max_parse_depth(kMaxParseDepth) {}
+CXFA_FMParser::CXFA_FMParser(cppgc::Heap* pHeap, CXFA_FMLexer* pLexer)
+    : m_heap(pHeap), m_lexer(pLexer), m_max_parse_depth(kMaxParseDepth) {}
 
 CXFA_FMParser::~CXFA_FMParser() = default;
 
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.h b/xfa/fxfa/fm2js/cxfa_fmparser.h
index 007df6d..0e61abb 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.h
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.h
@@ -22,7 +22,7 @@
   CPPGC_STACK_ALLOCATED();  // Allow Raw/Unowned pointers.
 
  public:
-  CXFA_FMParser(cppgc::Heap* heap, WideStringView wsFormcalc);
+  CXFA_FMParser(cppgc::Heap* heap, CXFA_FMLexer* pLexer);
   ~CXFA_FMParser();
 
   // Returned object is owned by cppgc heap.
@@ -65,10 +65,10 @@
   ParseArgumentList();
 
   UnownedPtr<cppgc::Heap> const m_heap;
-  std::unique_ptr<CXFA_FMLexer> m_lexer;
+  UnownedPtr<CXFA_FMLexer> m_lexer;
   CXFA_FMToken m_token;
-  bool m_error;
-  unsigned long m_parse_depth;
+  bool m_error = false;
+  unsigned long m_parse_depth = 0;
   unsigned long m_max_parse_depth;
 };
 
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
index 7539e7b..ade2b05 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
@@ -12,7 +12,8 @@
 class CXFA_FMParserTest : public FXGCUnitTest {};
 
 TEST_F(CXFA_FMParserTest, Empty) {
-  CXFA_FMParser parser(heap(), L"");
+  CXFA_FMLexer lexer(L"");
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   EXPECT_FALSE(parser.HasError());
@@ -25,7 +26,8 @@
 }
 
 TEST_F(CXFA_FMParserTest, CommentOnlyIsError) {
-  CXFA_FMParser parser(heap(), L"; Just comment");
+  CXFA_FMLexer lexer(L"; Just comment");
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   // TODO(dsinclair): This isn't allowed per the spec.
@@ -56,7 +58,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), L"; Just comment\n12");
+  CXFA_FMLexer lexer(L"; Just comment\n12");
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   EXPECT_FALSE(parser.HasError());
@@ -125,7 +128,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   EXPECT_FALSE(parser.HasError());
@@ -137,24 +141,27 @@
 }
 
 TEST_F(CXFA_FMParserTest, MaxParseDepth) {
-  CXFA_FMParser parser(heap(), L"foo(bar[baz(fizz[0])])");
+  CXFA_FMLexer lexer(L"foo(bar[baz(fizz[0])])");
+  CXFA_FMParser parser(heap(), &lexer);
   parser.SetMaxParseDepthForTest(5);
   EXPECT_EQ(nullptr, parser.Parse());
   EXPECT_TRUE(parser.HasError());
 }
 
 TEST_F(CXFA_FMParserTest, chromium752201) {
-  CXFA_FMParser parser(heap(),
-                       LR"***(fTep a
+  CXFA_FMLexer lexer(
+      LR"***(fTep a
 .#
 fo@ =[=l)***");
+
+  CXFA_FMParser parser(heap(), &lexer);
   EXPECT_EQ(nullptr, parser.Parse());
   EXPECT_TRUE(parser.HasError());
 }
 
 TEST_F(CXFA_FMParserTest, MultipleAssignmentIsNotAllowed) {
-  CXFA_FMParser parser(heap(), L"(a=(b=t))=u");
-
+  CXFA_FMLexer lexer(L"(a=(b=t))=u");
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(!ast);
   EXPECT_TRUE(parser.HasError());
@@ -187,7 +194,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   EXPECT_FALSE(parser.HasError());
@@ -225,7 +233,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast);
   EXPECT_FALSE(parser.HasError());
@@ -242,7 +251,8 @@
   param1 * param2
 endfunc)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
   EXPECT_TRUE(parser.HasError());
@@ -250,8 +260,8 @@
 
 TEST_F(CXFA_FMParserTest, ParseBadIfExpression) {
   const wchar_t input[] = L"if ( then";
-
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
   EXPECT_TRUE(parser.HasError());
@@ -262,7 +272,8 @@
       LR"***(if ($ ne -1) then"
 elseif( then)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
   EXPECT_TRUE(parser.HasError());
@@ -272,14 +283,16 @@
   const wchar_t input[] = L"a <> b <> c <> d <> e <> f <> g <> h <> i <> j";
 
   {
-    CXFA_FMParser parser(heap(), input);
+    CXFA_FMLexer lexer(input);
+    CXFA_FMParser parser(heap(), &lexer);
     CXFA_FMAST* ast = parser.Parse();
     ASSERT_TRUE(ast);
     EXPECT_TRUE(!parser.HasError());
   }
 
   {
-    CXFA_FMParser parser(heap(), input);
+    CXFA_FMLexer lexer(input);
+    CXFA_FMParser parser(heap(), &lexer);
     parser.SetMaxParseDepthForTest(5);
     CXFA_FMAST* ast = parser.Parse();
     ASSERT_TRUE(ast == nullptr);
@@ -310,7 +323,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   EXPECT_FALSE(parser.HasError());
 
@@ -351,7 +365,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   EXPECT_FALSE(parser.HasError());
 
@@ -382,7 +397,8 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   EXPECT_FALSE(parser.HasError());
 
@@ -415,9 +431,11 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   EXPECT_FALSE(parser.HasError());
+
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
   ASSERT_TRUE(buf.has_value());
@@ -447,9 +465,11 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   EXPECT_FALSE(parser.HasError());
+
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
   ASSERT_TRUE(buf.has_value());
@@ -479,9 +499,11 @@
 return pfm_rt.get_val(pfm_ret);
 }).call(this);)***";
 
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   EXPECT_FALSE(parser.HasError());
+
   CXFA_FMToJavaScriptDepth::Reset();
   Optional<CFX_WideTextBuf> buf = ast->ToJavaScript();
   ASSERT_TRUE(buf.has_value());
@@ -490,8 +512,8 @@
 
 TEST_F(CXFA_FMParserTest, ParseFunctionCallMissingCommas) {
   const wchar_t input[] = L"P.x(!foo!bar!baz)";
-
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
   EXPECT_TRUE(parser.HasError());
@@ -499,8 +521,8 @@
 
 TEST_F(CXFA_FMParserTest, ParseFunctionCallTrailingComma) {
   const wchar_t input[] = L"P.x(foo,bar,baz,)";
-
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
   EXPECT_TRUE(parser.HasError());
@@ -508,8 +530,8 @@
 
 TEST_F(CXFA_FMParserTest, ParseFunctionCallExtraComma) {
   const wchar_t input[] = L"P.x(foo,bar,,baz)";
-
-  CXFA_FMParser parser(heap(), input);
+  CXFA_FMLexer lexer(input);
+  CXFA_FMParser parser(heap(), &lexer);
   CXFA_FMAST* ast = parser.Parse();
   ASSERT_TRUE(ast == nullptr);
   EXPECT_TRUE(parser.HasError());