[formcalc] Simplify function signature parsing

This CL refactors the signature parsing for formcalc functions.

Change-Id: I69634968ab1cbd9698a3ce3ae321e14bafe918c6
Reviewed-on: https://pdfium-review.googlesource.com/27930
Commit-Queue: dsinclair <dsinclair@chromium.org>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser.cpp b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
index a91cab3..09cbee5 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser.cpp
@@ -94,56 +94,52 @@
   AutoRestorer<unsigned long> restorer(&m_parse_depth);
   if (HasError() || !IncrementParseDepthAndCheck())
     return nullptr;
-
-  WideStringView ident;
-  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
   if (!CheckThenNext(TOKfunc))
     return nullptr;
-
   if (m_token.m_type != TOKidentifier)
     return nullptr;
 
-  ident = m_token.m_string;
+  WideStringView ident = m_token.m_string;
   if (!NextToken())
     return nullptr;
   if (!CheckThenNext(TOKlparen))
     return nullptr;
 
   std::vector<WideStringView> arguments;
-  if (m_token.m_type == TOKrparen) {
+  bool last_was_comma = false;
+  while (1) {
+    if (m_token.m_type == TOKrparen)
+      break;
+    if (m_token.m_type != TOKidentifier)
+      return nullptr;
+
+    last_was_comma = false;
+
+    arguments.push_back(m_token.m_string);
     if (!NextToken())
       return nullptr;
-  } else {
-    while (1) {
-      if (m_token.m_type != TOKidentifier)
-        return nullptr;
+    if (m_token.m_type != TOKcomma)
+      continue;
 
-      arguments.push_back(m_token.m_string);
-      if (!NextToken())
-        return nullptr;
-      if (m_token.m_type == TOKcomma) {
-        if (!NextToken())
-          return nullptr;
-        continue;
-      }
-      if (!CheckThenNext(TOKrparen))
-        return nullptr;
-
-      break;
-    }
+    last_was_comma = true;
+    if (!NextToken())
+      return nullptr;
   }
-
+  if (last_was_comma || !CheckThenNext(TOKrparen))
+    return nullptr;
   if (!CheckThenNext(TOKdo))
     return nullptr;
-  if (m_token.m_type == TOKendfunc) {
-    if (!NextToken())
-      return nullptr;
-  } else {
+
+  std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
+  if (m_token.m_type != TOKendfunc) {
     expressions = ParseExpressionList();
-    if (!expressions.size() || !CheckThenNext(TOKendfunc))
+    if (expressions.empty())
       return nullptr;
   }
 
+  if (!CheckThenNext(TOKendfunc))
+    return nullptr;
+
   return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
       ident, std::move(arguments), std::move(expressions));
 }
diff --git a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
index d1e5919..52de964 100644
--- a/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
+++ b/xfa/fxfa/fm2js/cxfa_fmparser_unittest.cpp
@@ -206,3 +206,15 @@
   EXPECT_TRUE(ast->ToJavaScript(buf));
   EXPECT_EQ(ret, buf.AsStringView());
 }
+
+TEST(CXFA_FMParserTest, ParseFuncWithBadParamsList) {
+  const wchar_t input[] = {
+      L"func MyFunction(param1,) do\n"
+      L"  param1 * param2\n"
+      L"endfunc"};
+
+  auto parser = pdfium::MakeUnique<CXFA_FMParser>(input);
+  std::unique_ptr<CXFA_FMAST> ast = parser->Parse();
+  ASSERT_TRUE(ast == nullptr);
+  EXPECT_TRUE(parser->HasError());
+}