|  | // 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/formcalc/cxfa_fmexpression.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <utility> | 
|  |  | 
|  | #include "core/fxcrt/autorestorer.h" | 
|  | #include "core/fxcrt/cfx_widetextbuf.h" | 
|  | #include "core/fxcrt/fx_extension.h" | 
|  | #include "fxjs/gc/container_trace.h" | 
|  | #include "third_party/base/check.h" | 
|  | #include "v8/include/cppgc/visitor.h" | 
|  | #include "xfa/fxfa/formcalc/cxfa_fmtojavascriptdepth.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | const wchar_t kLessEqual[] = L" <= "; | 
|  | const wchar_t kGreaterEqual[] = L" >= "; | 
|  | const wchar_t kPlusEqual[] = L" += "; | 
|  | const wchar_t kMinusEqual[] = L" -= "; | 
|  |  | 
|  | const wchar_t* const kBuiltInFuncs[] = { | 
|  | 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 kBuiltInFuncsMaxLen = 12; | 
|  |  | 
|  | struct XFA_FMSOMMethod { | 
|  | const wchar_t* m_wsSomMethodName;  // Ok, POD struct. | 
|  | uint32_t m_dParameters; | 
|  | }; | 
|  |  | 
|  | const XFA_FMSOMMethod kFMSomMethods[] = { | 
|  | {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(const WideString& ident) { | 
|  | if (ident.IsEmpty() || ident[0] != L'!') | 
|  | return ident; | 
|  | return L"pfm__excl__" + ident.Last(ident.GetLength() - 1); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | CXFA_FMExpression::CXFA_FMExpression() = default; | 
|  |  | 
|  | CXFA_FMExpression::~CXFA_FMExpression() = default; | 
|  |  | 
|  | void CXFA_FMExpression::Trace(cppgc::Visitor* visitor) const {} | 
|  |  | 
|  | CXFA_FMSimpleExpression::CXFA_FMSimpleExpression(XFA_FM_TOKEN op) : m_op(op) {} | 
|  |  | 
|  | CXFA_FMSimpleExpression::~CXFA_FMSimpleExpression() = default; | 
|  |  | 
|  | CXFA_FMChainableExpression::CXFA_FMChainableExpression( | 
|  | XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMSimpleExpression(op), m_pExp1(pExp1), m_pExp2(pExp2) {} | 
|  |  | 
|  | CXFA_FMChainableExpression::~CXFA_FMChainableExpression() = default; | 
|  |  | 
|  | void CXFA_FMChainableExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMSimpleExpression::Trace(visitor); | 
|  | visitor->Trace(m_pExp1); | 
|  | visitor->Trace(m_pExp2); | 
|  | } | 
|  |  | 
|  | CXFA_FMNullExpression::CXFA_FMNullExpression() | 
|  | : CXFA_FMSimpleExpression(TOKnull) {} | 
|  |  | 
|  | CXFA_FMNullExpression::~CXFA_FMNullExpression() = default; | 
|  |  | 
|  | 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(WideString wsNumber) | 
|  | : CXFA_FMSimpleExpression(TOKnumber), m_wsNumber(std::move(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(WideString wsString) | 
|  | : CXFA_FMSimpleExpression(TOKstring), m_wsString(std::move(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( | 
|  | WideString wsIdentifier) | 
|  | : CXFA_FMSimpleExpression(TOKidentifier), | 
|  | m_wsIdentifier(std::move(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, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMChainableExpression(op, pExp1, 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::kInferred)) | 
|  | 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::kInferred)) | 
|  | 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, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMChainableExpression(op, pExp1, 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::kInferred)) | 
|  | return false; | 
|  | *js << ", "; | 
|  | if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << ")"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMLogicalOrExpression::CXFA_FMLogicalOrExpression( | 
|  | XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"log_or_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMLogicalOrExpression::~CXFA_FMLogicalOrExpression() = default; | 
|  |  | 
|  | CXFA_FMLogicalAndExpression::CXFA_FMLogicalAndExpression( | 
|  | XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"log_and_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMLogicalAndExpression::~CXFA_FMLogicalAndExpression() = default; | 
|  |  | 
|  | CXFA_FMEqualExpression::CXFA_FMEqualExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"eq_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMEqualExpression::~CXFA_FMEqualExpression() = default; | 
|  |  | 
|  | CXFA_FMNotEqualExpression::CXFA_FMNotEqualExpression( | 
|  | XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"neq_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMNotEqualExpression::~CXFA_FMNotEqualExpression() = default; | 
|  |  | 
|  | CXFA_FMGtExpression::CXFA_FMGtExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"gt_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMGtExpression::~CXFA_FMGtExpression() = default; | 
|  |  | 
|  | CXFA_FMGeExpression::CXFA_FMGeExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"ge_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMGeExpression::~CXFA_FMGeExpression() = default; | 
|  |  | 
|  | CXFA_FMLtExpression::CXFA_FMLtExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"lt_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMLtExpression::~CXFA_FMLtExpression() = default; | 
|  |  | 
|  | CXFA_FMLeExpression::CXFA_FMLeExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"le_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMLeExpression::~CXFA_FMLeExpression() = default; | 
|  |  | 
|  | CXFA_FMPlusExpression::CXFA_FMPlusExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"plus_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMPlusExpression::~CXFA_FMPlusExpression() = default; | 
|  |  | 
|  | CXFA_FMMinusExpression::CXFA_FMMinusExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"minus_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMMinusExpression::~CXFA_FMMinusExpression() = default; | 
|  |  | 
|  | CXFA_FMMulExpression::CXFA_FMMulExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"mul_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMMulExpression::~CXFA_FMMulExpression() = default; | 
|  |  | 
|  | CXFA_FMDivExpression::CXFA_FMDivExpression(XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp1, | 
|  | CXFA_FMSimpleExpression* pExp2) | 
|  | : CXFA_FMBinExpression(L"div_op", op, pExp1, pExp2) {} | 
|  |  | 
|  | CXFA_FMDivExpression::~CXFA_FMDivExpression() = default; | 
|  |  | 
|  | CXFA_FMUnaryExpression::CXFA_FMUnaryExpression(const WideString& opName, | 
|  | XFA_FM_TOKEN op, | 
|  | CXFA_FMSimpleExpression* pExp) | 
|  | : CXFA_FMSimpleExpression(op), m_OpName(opName), m_pExp(pExp) {} | 
|  |  | 
|  | CXFA_FMUnaryExpression::~CXFA_FMUnaryExpression() = default; | 
|  |  | 
|  | void CXFA_FMUnaryExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMSimpleExpression::Trace(visitor); | 
|  | visitor->Trace(m_pExp); | 
|  | } | 
|  |  | 
|  | 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 << "("; | 
|  | if (!m_pExp->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << ")"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMPosExpression::CXFA_FMPosExpression(CXFA_FMSimpleExpression* pExp) | 
|  | : CXFA_FMUnaryExpression(L"pos_op", TOKplus, pExp) {} | 
|  |  | 
|  | CXFA_FMPosExpression::~CXFA_FMPosExpression() = default; | 
|  |  | 
|  | CXFA_FMNegExpression::CXFA_FMNegExpression(CXFA_FMSimpleExpression* pExp) | 
|  | : CXFA_FMUnaryExpression(L"neg_op", TOKminus, pExp) {} | 
|  |  | 
|  | CXFA_FMNegExpression::~CXFA_FMNegExpression() = default; | 
|  |  | 
|  | CXFA_FMNotExpression::CXFA_FMNotExpression(CXFA_FMSimpleExpression* pExp) | 
|  | : CXFA_FMUnaryExpression(L"log_not_op", TOKksnot, pExp) {} | 
|  |  | 
|  | CXFA_FMNotExpression::~CXFA_FMNotExpression() = default; | 
|  |  | 
|  | CXFA_FMCallExpression::CXFA_FMCallExpression( | 
|  | CXFA_FMSimpleExpression* pExp, | 
|  | std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pArguments, | 
|  | bool bIsSomMethod) | 
|  | : CXFA_FMSimpleExpression(TOKcall), | 
|  | m_pExp(pExp), | 
|  | m_Arguments(std::move(pArguments)), | 
|  | m_bIsSomMethod(bIsSomMethod) {} | 
|  |  | 
|  | CXFA_FMCallExpression::~CXFA_FMCallExpression() = default; | 
|  |  | 
|  | void CXFA_FMCallExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMSimpleExpression::Trace(visitor); | 
|  | visitor->Trace(m_pExp); | 
|  | ContainerTrace(visitor, m_Arguments); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMCallExpression::IsBuiltInFunc(CFX_WideTextBuf* funcName) const { | 
|  | if (funcName->GetLength() > kBuiltInFuncsMaxLen) | 
|  | return false; | 
|  |  | 
|  | WideString str = funcName->MakeString(); | 
|  | const wchar_t* const* pMatchResult = | 
|  | std::lower_bound(std::begin(kBuiltInFuncs), std::end(kBuiltInFuncs), str, | 
|  | [](const wchar_t* iter, const WideString& val) -> bool { | 
|  | return val.CompareNoCase(iter) > 0; | 
|  | }); | 
|  | if (pMatchResult != std::end(kBuiltInFuncs) && | 
|  | !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(kFMSomMethods), std::end(kFMSomMethods), methodName, | 
|  | [](const XFA_FMSOMMethod iter, const WideString& val) { | 
|  | return val.Compare(iter.m_wsSomMethodName) > 0; | 
|  | }); | 
|  | if (result != std::end(kFMSomMethods) && | 
|  | methodName == 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::kInferred)) | 
|  | 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::kInferred)) | 
|  | 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::kInferred)) | 
|  | 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::kInferred)) | 
|  | 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::kInferred)) | 
|  | return false; | 
|  | if (expr != m_Arguments.back()) | 
|  | *js << ", "; | 
|  | } | 
|  | } | 
|  | *js << ")"; | 
|  | if (isEvalFunc) | 
|  | *js << ")"; | 
|  |  | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMDotAccessorExpression::CXFA_FMDotAccessorExpression( | 
|  | CXFA_FMSimpleExpression* pAccessor, | 
|  | XFA_FM_TOKEN op, | 
|  | WideString wsIdentifier, | 
|  | CXFA_FMSimpleExpression* pIndexExp) | 
|  | : CXFA_FMChainableExpression(op, pAccessor, pIndexExp), | 
|  | m_wsIdentifier(std::move(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("; | 
|  |  | 
|  | CXFA_FMSimpleExpression* exp1 = GetFirstExpression(); | 
|  | if (exp1) { | 
|  | // Write directly to the buffer with each recursion. Creating | 
|  | // and copying temporaries here becomes expensive when there | 
|  | // is deep recursion, even though we may need to re-create the | 
|  | // same thing again below. See https://crbug.com/1274018. | 
|  | if (!exp1->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | } else { | 
|  | *js << "null"; | 
|  | } | 
|  | *js << ", \""; | 
|  | if (exp1 && exp1->GetOperatorToken() == TOKidentifier) { | 
|  | if (!exp1->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | } | 
|  | *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::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ")"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMIndexExpression::CXFA_FMIndexExpression( | 
|  | AccessorIndex accessorIndex, | 
|  | CXFA_FMSimpleExpression* pIndexExp, | 
|  | bool bIsStarIndex) | 
|  | : CXFA_FMSimpleExpression(TOKlbracket), | 
|  | m_pExp(pIndexExp), | 
|  | m_accessorIndex(accessorIndex), | 
|  | m_bIsStarIndex(bIsStarIndex) {} | 
|  |  | 
|  | CXFA_FMIndexExpression::~CXFA_FMIndexExpression() = default; | 
|  |  | 
|  | void CXFA_FMIndexExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMSimpleExpression::Trace(visitor); | 
|  | visitor->Trace(m_pExp); | 
|  | } | 
|  |  | 
|  | 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 AccessorIndex::kNoIndex: | 
|  | *js << "0"; | 
|  | break; | 
|  | case AccessorIndex::kNoRelativeIndex: | 
|  | *js << "1"; | 
|  | break; | 
|  | case AccessorIndex::kPositiveIndex: | 
|  | *js << "2"; | 
|  | break; | 
|  | case AccessorIndex::kNegativeIndex: | 
|  | *js << "3"; | 
|  | break; | 
|  | } | 
|  | if (m_bIsStarIndex) | 
|  | return !CXFA_IsTooBig(*js); | 
|  |  | 
|  | *js << ", "; | 
|  | if (m_pExp) { | 
|  | if (!m_pExp->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | } else { | 
|  | *js << "0"; | 
|  | } | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMDotDotAccessorExpression::CXFA_FMDotDotAccessorExpression( | 
|  | CXFA_FMSimpleExpression* pAccessor, | 
|  | XFA_FM_TOKEN op, | 
|  | WideString wsIdentifier, | 
|  | CXFA_FMSimpleExpression* pIndexExp) | 
|  | : CXFA_FMChainableExpression(op, pAccessor, pIndexExp), | 
|  | m_wsIdentifier(std::move(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::kInferred)) | 
|  | return false; | 
|  | *js << ", " | 
|  | << "\""; | 
|  | if (exp1->GetOperatorToken() == TOKidentifier) { | 
|  | if (!exp1->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | CXFA_FMSimpleExpression* exp2 = GetSecondExpression(); | 
|  | *js << "\", \"" << m_wsIdentifier << "\", "; | 
|  | if (!exp2->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << ")"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMMethodCallExpression::CXFA_FMMethodCallExpression( | 
|  | CXFA_FMSimpleExpression* pAccessorExp1, | 
|  | CXFA_FMSimpleExpression* pCallExp) | 
|  | : CXFA_FMChainableExpression(TOKdot, pAccessorExp1, 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; | 
|  |  | 
|  | *js << "(function() {\n"; | 
|  | *js << "  return pfm_method_runner("; | 
|  | if (!GetFirstExpression()->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ", function(obj) {\n"; | 
|  | *js << "    return obj."; | 
|  | if (!GetSecondExpression()->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ";\n"; | 
|  | *js << "  });\n"; | 
|  | *js << "}).call(this)"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition( | 
|  | WideString wsName, | 
|  | std::vector<WideString>&& arguments, | 
|  | std::vector<cppgc::Member<CXFA_FMExpression>>&& expressions) | 
|  | : m_wsName(std::move(wsName)), | 
|  | m_pArguments(std::move(arguments)), | 
|  | m_pExpressions(std::move(expressions)) { | 
|  | DCHECK(!m_wsName.IsEmpty()); | 
|  | } | 
|  |  | 
|  | CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default; | 
|  |  | 
|  | void CXFA_FMFunctionDefinition::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | ContainerTrace(visitor, m_pExpressions); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | if (m_wsName.IsEmpty()) | 
|  | return false; | 
|  |  | 
|  | *js << "function " << IdentifierToName(m_wsName) << "("; | 
|  | for (const auto& identifier : m_pArguments) { | 
|  | if (identifier != m_pArguments.front()) | 
|  | *js << ", "; | 
|  |  | 
|  | *js << IdentifierToName(identifier); | 
|  | } | 
|  | *js << ") {\n"; | 
|  |  | 
|  | *js << "var pfm_ret = null;\n"; | 
|  | for (const auto& expr : m_pExpressions) { | 
|  | ReturnType ret_type = expr == m_pExpressions.back() ? ReturnType::kImplied | 
|  | : ReturnType::kInferred; | 
|  | if (!expr->ToJavaScript(js, ret_type)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | *js << "return pfm_ret;\n"; | 
|  | *js << "}\n"; | 
|  |  | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMAST::CXFA_FMAST( | 
|  | std::vector<cppgc::Member<CXFA_FMExpression>> expressions) | 
|  | : expressions_(std::move(expressions)) {} | 
|  |  | 
|  | CXFA_FMAST::~CXFA_FMAST() = default; | 
|  |  | 
|  | void CXFA_FMAST::Trace(cppgc::Visitor* visitor) const { | 
|  | ContainerTrace(visitor, expressions_); | 
|  | } | 
|  |  | 
|  | absl::optional<CFX_WideTextBuf> CXFA_FMAST::ToJavaScript() const { | 
|  | CFX_WideTextBuf js; | 
|  | if (expressions_.empty()) { | 
|  | js << "// comments only"; | 
|  | return js; | 
|  | } | 
|  |  | 
|  | js << "(function() {\n"; | 
|  | js << "let pfm_method_runner = function(obj, cb) {\n"; | 
|  | js << "  if (pfm_rt.is_ary(obj)) {\n"; | 
|  | js << "    let pfm_method_return = null;\n"; | 
|  | js << "    for (var idx = obj.length -1; idx > 1; idx--) {\n"; | 
|  | js << "      pfm_method_return = cb(obj[idx]);\n"; | 
|  | js << "    }\n"; | 
|  | js << "    return pfm_method_return;\n"; | 
|  | js << "  }\n"; | 
|  | js << "  return cb(obj);\n"; | 
|  | js << "};\n"; | 
|  | js << "var pfm_ret = null;\n"; | 
|  | for (const auto& expr : expressions_) { | 
|  | CXFA_FMAssignExpression::ReturnType ret_type = | 
|  | expr == expressions_.back() | 
|  | ? CXFA_FMAssignExpression::ReturnType::kImplied | 
|  | : CXFA_FMAssignExpression::ReturnType::kInferred; | 
|  | if (!expr->ToJavaScript(&js, ret_type)) | 
|  | return absl::nullopt; | 
|  | } | 
|  | js << "return pfm_rt.get_val(pfm_ret);\n"; | 
|  | js << "}).call(this);"; | 
|  |  | 
|  | if (CXFA_IsTooBig(js)) | 
|  | return absl::nullopt; | 
|  |  | 
|  | return js; | 
|  | } | 
|  |  | 
|  | CXFA_FMVarExpression::CXFA_FMVarExpression(WideString wsName, | 
|  | CXFA_FMSimpleExpression* pInit) | 
|  | : m_wsName(std::move(wsName)), m_pInit(pInit) {} | 
|  |  | 
|  | CXFA_FMVarExpression::~CXFA_FMVarExpression() = default; | 
|  |  | 
|  | void CXFA_FMVarExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | visitor->Trace(m_pInit); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | WideString tempName = IdentifierToName(m_wsName); | 
|  | *js << "var " << tempName << " = "; | 
|  | if (m_pInit) { | 
|  | if (!m_pInit->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ";\n"; | 
|  | *js << tempName << " = pfm_rt.var_filter(" << tempName << ");\n"; | 
|  | } else { | 
|  | *js << "\"\";\n"; | 
|  | } | 
|  |  | 
|  | if (type == ReturnType::kImplied) | 
|  | *js << "pfm_ret = " << tempName << ";\n"; | 
|  |  | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMExpExpression::CXFA_FMExpExpression(CXFA_FMSimpleExpression* pExpression) | 
|  | : m_pExpression(pExpression) {} | 
|  |  | 
|  | CXFA_FMExpExpression::~CXFA_FMExpExpression() = default; | 
|  |  | 
|  | void CXFA_FMExpExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | visitor->Trace(m_pExpression); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | if (type == ReturnType::kInferred) { | 
|  | bool ret = m_pExpression->ToJavaScript(js, ReturnType::kInferred); | 
|  | if (m_pExpression->GetOperatorToken() != TOKassign) | 
|  | *js << ";\n"; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | if (m_pExpression->GetOperatorToken() == TOKassign) | 
|  | return m_pExpression->ToJavaScript(js, ReturnType::kImplied); | 
|  |  | 
|  | if (m_pExpression->GetOperatorToken() == TOKstar || | 
|  | m_pExpression->GetOperatorToken() == TOKdotstar || | 
|  | m_pExpression->GetOperatorToken() == TOKdotscream || | 
|  | m_pExpression->GetOperatorToken() == TOKdotdot || | 
|  | m_pExpression->GetOperatorToken() == TOKdot) { | 
|  | *js << "pfm_ret = pfm_rt.get_val("; | 
|  | if (!m_pExpression->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ");\n"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | *js << "pfm_ret = "; | 
|  | if (!m_pExpression->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ";\n"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMBlockExpression::CXFA_FMBlockExpression( | 
|  | std::vector<cppgc::Member<CXFA_FMExpression>>&& pExpressionList) | 
|  | : m_ExpressionList(std::move(pExpressionList)) {} | 
|  |  | 
|  | CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default; | 
|  |  | 
|  | void CXFA_FMBlockExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | ContainerTrace(visitor, m_ExpressionList); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | *js << "{\n"; | 
|  | for (const auto& expr : m_ExpressionList) { | 
|  | if (type == ReturnType::kInferred) { | 
|  | if (!expr->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | } else { | 
|  | ReturnType ret_type = expr == m_ExpressionList.back() | 
|  | ? ReturnType::kImplied | 
|  | : ReturnType::kInferred; | 
|  | if (!expr->ToJavaScript(js, ret_type)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | *js << "}\n"; | 
|  |  | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMDoExpression::CXFA_FMDoExpression(CXFA_FMExpression* pList) | 
|  | : m_pList(pList) {} | 
|  |  | 
|  | CXFA_FMDoExpression::~CXFA_FMDoExpression() = default; | 
|  |  | 
|  | void CXFA_FMDoExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | visitor->Trace(m_pList); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | return m_pList->ToJavaScript(js, type); | 
|  | } | 
|  |  | 
|  | CXFA_FMIfExpression::CXFA_FMIfExpression( | 
|  | CXFA_FMSimpleExpression* pExpression, | 
|  | CXFA_FMExpression* pIfExpression, | 
|  | std::vector<cppgc::Member<CXFA_FMIfExpression>>&& pElseIfExpressions, | 
|  | CXFA_FMExpression* pElseExpression) | 
|  | : m_pExpression(pExpression), | 
|  | m_pIfExpression(pIfExpression), | 
|  | m_pElseIfExpressions(std::move(pElseIfExpressions)), | 
|  | m_pElseExpression(pElseExpression) { | 
|  | DCHECK(m_pExpression); | 
|  | } | 
|  |  | 
|  | CXFA_FMIfExpression::~CXFA_FMIfExpression() = default; | 
|  |  | 
|  | void CXFA_FMIfExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | visitor->Trace(m_pExpression); | 
|  | visitor->Trace(m_pIfExpression); | 
|  | ContainerTrace(visitor, m_pElseIfExpressions); | 
|  | visitor->Trace(m_pElseExpression); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | if (type == ReturnType::kImplied) | 
|  | *js << "pfm_ret = 0;\n"; | 
|  |  | 
|  | *js << "if (pfm_rt.get_val("; | 
|  | if (!m_pExpression->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << "))\n"; | 
|  |  | 
|  | if (CXFA_IsTooBig(*js)) | 
|  | return false; | 
|  |  | 
|  | if (m_pIfExpression) { | 
|  | if (!m_pIfExpression->ToJavaScript(js, type)) | 
|  | return false; | 
|  | if (CXFA_IsTooBig(*js)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | for (auto& expr : m_pElseIfExpressions) { | 
|  | *js << "else "; | 
|  | if (!expr->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (m_pElseExpression) { | 
|  | *js << "else "; | 
|  | if (!m_pElseExpression->ToJavaScript(js, type)) | 
|  | return false; | 
|  | } | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMWhileExpression::CXFA_FMWhileExpression( | 
|  | CXFA_FMSimpleExpression* pCondition, | 
|  | CXFA_FMExpression* pExpression) | 
|  | : m_pCondition(pCondition), m_pExpression(pExpression) {} | 
|  |  | 
|  | CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default; | 
|  |  | 
|  | void CXFA_FMWhileExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | visitor->Trace(m_pCondition); | 
|  | visitor->Trace(m_pExpression); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | if (type == ReturnType::kImplied) | 
|  | *js << "pfm_ret = 0;\n"; | 
|  |  | 
|  | *js << "while ("; | 
|  | if (!m_pCondition->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  |  | 
|  | *js << ")\n"; | 
|  | if (CXFA_IsTooBig(*js)) | 
|  | return false; | 
|  |  | 
|  | if (!m_pExpression->ToJavaScript(js, type)) | 
|  | return false; | 
|  |  | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMBreakExpression::CXFA_FMBreakExpression() : CXFA_FMExpression() {} | 
|  |  | 
|  | CXFA_FMBreakExpression::~CXFA_FMBreakExpression() = default; | 
|  |  | 
|  | bool CXFA_FMBreakExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | *js << "pfm_ret = 0;\nbreak;\n"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMContinueExpression::CXFA_FMContinueExpression() : CXFA_FMExpression() {} | 
|  |  | 
|  | CXFA_FMContinueExpression::~CXFA_FMContinueExpression() = default; | 
|  |  | 
|  | bool CXFA_FMContinueExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | *js << "pfm_ret = 0;\ncontinue;\n"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMForExpression::CXFA_FMForExpression(WideString wsVariant, | 
|  | CXFA_FMSimpleExpression* pAssignment, | 
|  | CXFA_FMSimpleExpression* pAccessor, | 
|  | int32_t iDirection, | 
|  | CXFA_FMSimpleExpression* pStep, | 
|  | CXFA_FMExpression* pList) | 
|  | : m_wsVariant(std::move(wsVariant)), | 
|  | m_bDirection(iDirection == 1), | 
|  | m_pAssignment(pAssignment), | 
|  | m_pAccessor(pAccessor), | 
|  | m_pStep(pStep), | 
|  | m_pList(pList) {} | 
|  |  | 
|  | CXFA_FMForExpression::~CXFA_FMForExpression() = default; | 
|  |  | 
|  | void CXFA_FMForExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | visitor->Trace(m_pAssignment); | 
|  | visitor->Trace(m_pAccessor); | 
|  | visitor->Trace(m_pStep); | 
|  | visitor->Trace(m_pList); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | if (type == ReturnType::kImplied) | 
|  | *js << "pfm_ret = 0;\n"; | 
|  |  | 
|  | *js << "{\n"; | 
|  |  | 
|  | WideString tmpName = IdentifierToName(m_wsVariant); | 
|  | *js << "var " << tmpName << " = null;\n"; | 
|  |  | 
|  | *js << "for (" << tmpName << " = pfm_rt.get_val("; | 
|  | if (!m_pAssignment->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << "); "; | 
|  |  | 
|  | *js << tmpName << (m_bDirection ? kLessEqual : kGreaterEqual); | 
|  | *js << "pfm_rt.get_val("; | 
|  | if (!m_pAccessor->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << "); "; | 
|  |  | 
|  | *js << tmpName << (m_bDirection ? kPlusEqual : kMinusEqual); | 
|  | if (m_pStep) { | 
|  | *js << "pfm_rt.get_val("; | 
|  | if (!m_pStep->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | *js << ")"; | 
|  | } else { | 
|  | *js << "1"; | 
|  | } | 
|  | *js << ")\n"; | 
|  | if (CXFA_IsTooBig(*js)) | 
|  | return false; | 
|  |  | 
|  | if (!m_pList->ToJavaScript(js, type)) | 
|  | return false; | 
|  |  | 
|  | *js << "}\n"; | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | CXFA_FMForeachExpression::CXFA_FMForeachExpression( | 
|  | WideString wsIdentifier, | 
|  | std::vector<cppgc::Member<CXFA_FMSimpleExpression>>&& pAccessors, | 
|  | CXFA_FMExpression* pList) | 
|  | : m_wsIdentifier(std::move(wsIdentifier)), | 
|  | m_pAccessors(std::move(pAccessors)), | 
|  | m_pList(pList) {} | 
|  |  | 
|  | CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default; | 
|  |  | 
|  | void CXFA_FMForeachExpression::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FMExpression::Trace(visitor); | 
|  | ContainerTrace(visitor, m_pAccessors); | 
|  | visitor->Trace(m_pList); | 
|  | } | 
|  |  | 
|  | bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf* js, | 
|  | ReturnType type) const { | 
|  | CXFA_FMToJavaScriptDepth depthManager; | 
|  | if (CXFA_IsTooBig(*js) || !depthManager.IsWithinMaxDepth()) | 
|  | return false; | 
|  |  | 
|  | if (type == ReturnType::kImplied) | 
|  | *js << "pfm_ret = 0;\n"; | 
|  |  | 
|  | *js << "{\n"; | 
|  |  | 
|  | WideString tmpName = IdentifierToName(m_wsIdentifier); | 
|  | *js << "var " << tmpName << " = null;\n"; | 
|  | *js << "var pfm_ary = pfm_rt.concat_obj("; | 
|  | for (const auto& expr : m_pAccessors) { | 
|  | if (!expr->ToJavaScript(js, ReturnType::kInferred)) | 
|  | return false; | 
|  | if (expr != m_pAccessors.back()) | 
|  | *js << ", "; | 
|  | } | 
|  | *js << ");\n"; | 
|  |  | 
|  | *js << "var pfm_ary_idx = 0;\n"; | 
|  | *js << "while(pfm_ary_idx < pfm_ary.length)\n{\n"; | 
|  | *js << tmpName << " = pfm_ary[pfm_ary_idx++];\n"; | 
|  | if (!m_pList->ToJavaScript(js, type)) | 
|  | return false; | 
|  |  | 
|  | *js << "}\n";  // while | 
|  | *js << "}\n";  // block | 
|  | return !CXFA_IsTooBig(*js); | 
|  | } | 
|  |  | 
|  | bool CXFA_IsTooBig(const CFX_WideTextBuf& js) { | 
|  | return js.GetSize() >= 256 * 1024 * 1024; | 
|  | } |