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());
-}