blob: a4dee6353b6cd7443ca11355911d3c6bfe2a3395 [file] [log] [blame]
// 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_fmexpression.h"
#include <utility>
#include "core/fxcrt/cfx_widetextbuf.h"
#include "xfa/fxfa/fm2js/cxfa_fmsimpleexpression.h"
#include "xfa/fxfa/fm2js/cxfa_fmtojavascriptdepth.h"
namespace {
const wchar_t kLessEqual[] = L" <= ";
const wchar_t kGreaterEqual[] = L" >= ";
const wchar_t kPlusEqual[] = L" += ";
const wchar_t kMinusEqual[] = L" -= ";
} // namespace
CXFA_FMExpression::CXFA_FMExpression() = default;
CXFA_FMFunctionDefinition::CXFA_FMFunctionDefinition(
bool isGlobal,
const WideStringView& wsName,
std::vector<WideStringView>&& arguments,
std::vector<std::unique_ptr<CXFA_FMExpression>>&& expressions)
: CXFA_FMExpression(),
m_wsName(wsName),
m_pArguments(std::move(arguments)),
m_pExpressions(std::move(expressions)),
m_isGlobal(isGlobal) {}
CXFA_FMFunctionDefinition::~CXFA_FMFunctionDefinition() = default;
bool CXFA_FMFunctionDefinition::ToJavaScript(CFX_WideTextBuf& js,
ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (type == ReturnType::kImplied)
return !CXFA_IsTooBig(js) && depthManager.IsWithinMaxDepth();
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
if (m_isGlobal && m_pExpressions.empty()) {
js << L"// comments only";
return !CXFA_IsTooBig(js);
}
if (m_isGlobal)
js << L"(\n";
js << L"function ";
if (!m_wsName.IsEmpty() && m_wsName[0] == L'!') {
WideString tempName =
L"pfm__excl__" + m_wsName.Right(m_wsName.GetLength() - 1);
js << tempName;
} else {
js << m_wsName;
}
js << L"(";
bool bNeedComma = false;
for (const auto& identifier : m_pArguments) {
if (bNeedComma)
js << L", ";
if (identifier[0] == L'!') {
WideString tempIdentifier =
L"pfm__excl__" + identifier.Right(identifier.GetLength() - 1);
js << tempIdentifier;
} else {
js << identifier;
}
bNeedComma = true;
}
js << L")\n{\n";
js << L"var pfm_ret = null;\n";
for (const auto& expr : m_pExpressions) {
ReturnType ret_type = expr == m_pExpressions.back() ? ReturnType::kImplied
: ReturnType::kInfered;
if (!expr->ToJavaScript(js, ret_type))
return false;
}
js << L"return ";
if (m_isGlobal)
js << L"pfm_rt.get_val(pfm_ret);\n";
else
js << L"pfm_ret;\n";
js << L"}\n";
if (m_isGlobal)
js << L").call(this);\n";
return !CXFA_IsTooBig(js);
}
CXFA_FMVarExpression::CXFA_FMVarExpression(
const WideStringView& wsName,
std::unique_ptr<CXFA_FMSimpleExpression> pInit)
: CXFA_FMExpression(), m_wsName(wsName), m_pInit(std::move(pInit)) {}
CXFA_FMVarExpression::~CXFA_FMVarExpression() = default;
bool CXFA_FMVarExpression::ToJavaScript(CFX_WideTextBuf& js, ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
WideString tempName(m_wsName);
if (m_wsName[0] == L'!')
tempName = L"pfm__excl__" + m_wsName.Right(m_wsName.GetLength() - 1);
js << L"var " << tempName << L" = ";
if (m_pInit) {
if (!m_pInit->ToJavaScript(js, ReturnType::kInfered))
return false;
js << tempName << L" = pfm_rt.var_filter(" << tempName << L");\n";
} else {
js << L"\"\";\n";
}
if (type == ReturnType::kImplied)
js << L"pfm_ret = " << tempName << L";\n";
return !CXFA_IsTooBig(js);
}
CXFA_FMExpExpression::CXFA_FMExpExpression(
std::unique_ptr<CXFA_FMSimpleExpression> pExpression)
: CXFA_FMExpression(), m_pExpression(std::move(pExpression)) {}
CXFA_FMExpExpression::~CXFA_FMExpExpression() = default;
bool CXFA_FMExpExpression::ToJavaScript(CFX_WideTextBuf& js, ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
if (type == ReturnType::kInfered) {
bool ret = m_pExpression->ToJavaScript(js, ReturnType::kInfered);
if (m_pExpression->GetOperatorToken() != TOKassign)
js << L";\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 << L"pfm_ret = pfm_rt.get_val(";
if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
return false;
js << L");\n";
return !CXFA_IsTooBig(js);
}
js << L"pfm_ret = ";
if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
return false;
js << L";\n";
return !CXFA_IsTooBig(js);
}
CXFA_FMBlockExpression::CXFA_FMBlockExpression(
std::vector<std::unique_ptr<CXFA_FMExpression>>&& pExpressionList)
: CXFA_FMExpression(), m_ExpressionList(std::move(pExpressionList)) {}
CXFA_FMBlockExpression::~CXFA_FMBlockExpression() = default;
bool CXFA_FMBlockExpression::ToJavaScript(CFX_WideTextBuf& js,
ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
js << L"{\n";
for (const auto& expr : m_ExpressionList) {
if (type == ReturnType::kInfered) {
if (!expr->ToJavaScript(js, ReturnType::kInfered))
return false;
} else {
ReturnType ret_type = expr == m_ExpressionList.back()
? ReturnType::kImplied
: ReturnType::kInfered;
if (!expr->ToJavaScript(js, ret_type))
return false;
}
}
js << L"}\n";
return !CXFA_IsTooBig(js);
}
CXFA_FMDoExpression::CXFA_FMDoExpression(
std::unique_ptr<CXFA_FMExpression> pList)
: CXFA_FMExpression(), m_pList(std::move(pList)) {}
CXFA_FMDoExpression::~CXFA_FMDoExpression() = default;
bool CXFA_FMDoExpression::ToJavaScript(CFX_WideTextBuf& js, ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
return m_pList->ToJavaScript(js, type);
}
CXFA_FMIfExpression::CXFA_FMIfExpression(
std::unique_ptr<CXFA_FMSimpleExpression> pExpression,
std::unique_ptr<CXFA_FMExpression> pIfExpression,
std::unique_ptr<CXFA_FMExpression> pElseExpression)
: CXFA_FMExpression(),
m_pExpression(std::move(pExpression)),
m_pIfExpression(std::move(pIfExpression)),
m_pElseExpression(std::move(pElseExpression)) {}
CXFA_FMIfExpression::~CXFA_FMIfExpression() = default;
bool CXFA_FMIfExpression::ToJavaScript(CFX_WideTextBuf& js, ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
if (type == ReturnType::kImplied)
js << L"pfm_ret = 0;\n";
js << L"if (";
if (m_pExpression) {
js << L"pfm_rt.get_val(";
if (!m_pExpression->ToJavaScript(js, ReturnType::kInfered))
return false;
js << L")";
}
js << L")\n";
if (CXFA_IsTooBig(js))
return false;
if (m_pIfExpression) {
if (!m_pIfExpression->ToJavaScript(js, type))
return false;
if (CXFA_IsTooBig(js))
return false;
}
if (m_pElseExpression) {
js << L"else\n{\n";
if (!m_pElseExpression->ToJavaScript(js, type))
return false;
js << L"}\n";
}
return !CXFA_IsTooBig(js);
}
CXFA_FMWhileExpression::CXFA_FMWhileExpression(
std::unique_ptr<CXFA_FMSimpleExpression> pCondition,
std::unique_ptr<CXFA_FMExpression> pExpression)
: CXFA_FMExpression(),
m_pCondition(std::move(pCondition)),
m_pExpression(std::move(pExpression)) {}
CXFA_FMWhileExpression::~CXFA_FMWhileExpression() = default;
bool CXFA_FMWhileExpression::ToJavaScript(CFX_WideTextBuf& js,
ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
if (type == ReturnType::kImplied)
js << L"pfm_ret = 0;\n";
js << L"while (";
if (!m_pCondition->ToJavaScript(js, ReturnType::kInfered))
return false;
js << L")\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) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
js << L"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) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
js << L"pfm_ret = 0;\ncontinue;\n";
return !CXFA_IsTooBig(js);
}
CXFA_FMForExpression::CXFA_FMForExpression(
const WideStringView& wsVariant,
std::unique_ptr<CXFA_FMSimpleExpression> pAssignment,
std::unique_ptr<CXFA_FMSimpleExpression> pAccessor,
int32_t iDirection,
std::unique_ptr<CXFA_FMSimpleExpression> pStep,
std::unique_ptr<CXFA_FMExpression> pList)
: CXFA_FMExpression(),
m_wsVariant(wsVariant),
m_pAssignment(std::move(pAssignment)),
m_pAccessor(std::move(pAccessor)),
m_bDirection(iDirection == 1),
m_pStep(std::move(pStep)),
m_pList(std::move(pList)) {}
CXFA_FMForExpression::~CXFA_FMForExpression() = default;
bool CXFA_FMForExpression::ToJavaScript(CFX_WideTextBuf& js, ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
if (type == ReturnType::kImplied)
js << L"pfm_ret = 0;\n";
js << L"{\n";
WideString tmpName;
if (m_wsVariant[0] == L'!')
tmpName = L"pfm__excl__" + m_wsVariant.Right(m_wsVariant.GetLength() - 1);
else
tmpName = m_wsVariant;
js << L"var " << tmpName << L" = null;\n";
CFX_WideTextBuf assign_txt;
if (!m_pAssignment->ToJavaScript(assign_txt, ReturnType::kInfered))
return false;
CFX_WideTextBuf accessor_txt;
if (!m_pAccessor->ToJavaScript(accessor_txt, ReturnType::kInfered))
return false;
js << L"for (" << tmpName << L" = pfm_rt.get_val(" << assign_txt << L"); ";
js << tmpName << (m_bDirection ? kLessEqual : kGreaterEqual);
js << L"pfm_rt.get_val(" << accessor_txt << L"); ";
js << tmpName << (m_bDirection ? kPlusEqual : kMinusEqual);
if (m_pStep) {
CFX_WideTextBuf step_txt;
if (!m_pStep->ToJavaScript(step_txt, ReturnType::kInfered))
return false;
js << L"pfm_rt.get_val(" << step_txt << L")";
} else {
js << L"1";
}
js << L")\n";
if (CXFA_IsTooBig(js))
return false;
if (!m_pList->ToJavaScript(js, type))
return false;
js << L"}\n";
return !CXFA_IsTooBig(js);
}
CXFA_FMForeachExpression::CXFA_FMForeachExpression(
const WideStringView& wsIdentifier,
std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>&& pAccessors,
std::unique_ptr<CXFA_FMExpression> pList)
: CXFA_FMExpression(),
m_wsIdentifier(wsIdentifier),
m_pAccessors(std::move(pAccessors)),
m_pList(std::move(pList)) {}
CXFA_FMForeachExpression::~CXFA_FMForeachExpression() = default;
bool CXFA_FMForeachExpression::ToJavaScript(CFX_WideTextBuf& js,
ReturnType type) {
CXFA_FMToJavaScriptDepth depthManager;
if (CXFA_IsTooBig(js) || !depthManager.IsWithinMaxDepth())
return false;
if (type == ReturnType::kImplied)
js << L"pfm_ret = 0;\n";
js << L"{\n";
WideString tmpName;
if (m_wsIdentifier[0] == L'!') {
tmpName =
L"pfm__excl__" + m_wsIdentifier.Right(m_wsIdentifier.GetLength() - 1);
} else {
tmpName = m_wsIdentifier;
}
js << L"var " << tmpName << L" = null;\n";
js << L"var pfm_ary = pfm_rt.concat_obj(";
for (const auto& expr : m_pAccessors) {
if (!expr->ToJavaScript(js, ReturnType::kInfered))
return false;
if (expr != m_pAccessors.back())
js << L", ";
}
js << L");\n";
js << L"var pfm_ary_idx = 0;\n";
js << L"while(pfm_ary_idx < pfm_ary.length)\n{\n";
js << tmpName << L" = pfm_ary[pfm_ary_idx++];\n";
if (!m_pList->ToJavaScript(js, type))
return false;
js << L"}\n"; // while
js << L"}\n"; // block
return !CXFA_IsTooBig(js);
}