blob: b67f94fc1081be5ed22f263ab243936b7221cb13 [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_fmparser.h"
#include <memory>
#include <utility>
#include <vector>
#include "core/fxcrt/autorestorer.h"
#include "third_party/base/ptr_util.h"
namespace {
constexpr unsigned int kMaxParseDepth = 1250;
constexpr unsigned int kMaxPostExpressions = 16384;
} // namespace
CXFA_FMParser::CXFA_FMParser(const WideStringView& wsFormcalc)
: m_error(false), m_parse_depth(0), m_max_parse_depth(kMaxParseDepth) {
m_lexer = pdfium::MakeUnique<CXFA_FMLexer>(wsFormcalc);
m_token = m_lexer->NextToken();
}
CXFA_FMParser::~CXFA_FMParser() {}
std::unique_ptr<CXFA_FMFunctionDefinition> CXFA_FMParser::Parse() {
auto expressions = ParseExpressionList();
if (HasError())
return nullptr;
std::vector<WideStringView> arguments;
return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
true, L"", std::move(arguments), std::move(expressions));
}
bool CXFA_FMParser::NextToken() {
if (HasError())
return false;
m_token = m_lexer->NextToken();
while (!HasError() && m_token.m_type == TOKreserver)
m_token = m_lexer->NextToken();
return !HasError();
}
bool CXFA_FMParser::CheckThenNext(XFA_FM_TOKEN op) {
if (HasError())
return false;
if (m_token.m_type != op) {
m_error = true;
return false;
}
return NextToken();
}
bool CXFA_FMParser::IncrementParseDepthAndCheck() {
return ++m_parse_depth < m_max_parse_depth;
}
std::vector<std::unique_ptr<CXFA_FMExpression>>
CXFA_FMParser::ParseExpressionList() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return std::vector<std::unique_ptr<CXFA_FMExpression>>();
std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
while (!HasError()) {
if (m_token.m_type == TOKeof || m_token.m_type == TOKendfunc ||
m_token.m_type == TOKendif || m_token.m_type == TOKelseif ||
m_token.m_type == TOKelse || m_token.m_type == TOKendwhile ||
m_token.m_type == TOKendfor || m_token.m_type == TOKend ||
m_token.m_type == TOKendfunc || m_token.m_type == TOKreserver) {
break;
}
std::unique_ptr<CXFA_FMExpression> expr =
m_token.m_type == TOKfunc ? ParseFunction() : ParseExpression();
if (!expr) {
m_error = true;
return std::vector<std::unique_ptr<CXFA_FMExpression>>();
}
expressions.push_back(std::move(expr));
}
return expressions;
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseFunction() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
WideStringView ident;
std::vector<WideStringView> arguments;
std::vector<std::unique_ptr<CXFA_FMExpression>> expressions;
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
} else {
ident = m_token.m_string;
if (!NextToken())
return nullptr;
}
if (!CheckThenNext(TOKlparen))
return nullptr;
if (m_token.m_type == TOKrparen) {
if (!NextToken())
return nullptr;
} else {
while (1) {
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
arguments.push_back(m_token.m_string);
if (!NextToken())
return nullptr;
if (m_token.m_type == TOKcomma) {
if (!NextToken())
return nullptr;
continue;
}
if (m_token.m_type == TOKrparen) {
if (!NextToken())
return nullptr;
} else {
if (!CheckThenNext(TOKrparen))
return nullptr;
}
break;
}
}
if (!CheckThenNext(TOKdo))
return nullptr;
if (m_token.m_type == TOKendfunc) {
if (!NextToken())
return nullptr;
} else {
expressions = ParseExpressionList();
if (!expressions.size() || !CheckThenNext(TOKendfunc))
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMFunctionDefinition>(
false, ident, std::move(arguments), std::move(expressions));
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMExpression> expr;
switch (m_token.m_type) {
case TOKvar:
expr = ParseDeclarationExpression();
break;
case TOKnull:
case TOKnumber:
case TOKstring:
case TOKplus:
case TOKminus:
case TOKksnot:
case TOKidentifier:
case TOKlparen:
expr = ParseExpExpression();
break;
case TOKif:
expr = ParseIfExpression();
break;
case TOKwhile:
expr = ParseWhileExpression();
break;
case TOKfor:
expr = ParseForExpression();
break;
case TOKforeach:
expr = ParseForeachExpression();
break;
case TOKdo:
expr = ParseDoExpression();
break;
case TOKbreak:
expr = pdfium::MakeUnique<CXFA_FMBreakExpression>();
if (!NextToken())
return nullptr;
break;
case TOKcontinue:
expr = pdfium::MakeUnique<CXFA_FMContinueExpression>();
if (!NextToken())
return nullptr;
break;
default:
m_error = true;
return nullptr;
}
return expr;
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDeclarationExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
WideStringView ident;
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
ident = m_token.m_string;
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> expr;
if (m_token.m_type == TOKassign) {
if (!NextToken())
return nullptr;
expr = ParseSimpleExpression();
if (!expr)
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMVarExpression>(ident, std::move(expr));
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseSimpleExpression() {
if (HasError())
return nullptr;
return ParseLogicalOrExpression();
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseExpExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
if (!pExp1)
return nullptr;
if (m_token.m_type == TOKassign) {
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pExp2 = ParseSimpleExpression();
if (!pExp2)
return nullptr;
pExp1 = pdfium::MakeUnique<CXFA_FMAssignExpression>(
TOKassign, std::move(pExp1), std::move(pExp2));
}
return pdfium::MakeUnique<CXFA_FMExpExpression>(std::move(pExp1));
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseLogicalOrExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseLogicalAndExpression();
if (!e1)
return nullptr;
for (;;) {
switch (m_token.m_type) {
case TOKor:
case TOKksor: {
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e2(
ParseLogicalAndExpression());
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMLogicalOrExpression>(
TOKor, std::move(e1), std::move(e2));
continue;
}
default:
break;
}
break;
}
return e1;
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseLogicalAndExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseEqualityExpression();
if (!e1)
return nullptr;
for (;;) {
switch (m_token.m_type) {
case TOKand:
case TOKksand: {
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e2 = ParseEqualityExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMLogicalAndExpression>(
TOKand, std::move(e1), std::move(e2));
continue;
}
default:
break;
}
break;
}
return e1;
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseEqualityExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseRelationalExpression();
if (!e1)
return nullptr;
for (;;) {
std::unique_ptr<CXFA_FMSimpleExpression> e2;
switch (m_token.m_type) {
case TOKeq:
case TOKkseq:
if (!NextToken())
return nullptr;
e2 = ParseRelationalExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMEqualExpression>(TOKeq, std::move(e1),
std::move(e2));
continue;
case TOKne:
case TOKksne:
if (!NextToken())
return nullptr;
e2 = ParseRelationalExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMNotEqualExpression>(TOKne, std::move(e1),
std::move(e2));
continue;
default:
break;
}
break;
}
return e1;
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseRelationalExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseAddtiveExpression();
if (!e1)
return nullptr;
for (;;) {
std::unique_ptr<CXFA_FMSimpleExpression> e2;
switch (m_token.m_type) {
case TOKlt:
case TOKkslt:
if (!NextToken())
return nullptr;
e2 = ParseAddtiveExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMLtExpression>(TOKlt, std::move(e1),
std::move(e2));
continue;
case TOKgt:
case TOKksgt:
if (!NextToken())
return nullptr;
e2 = ParseAddtiveExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMGtExpression>(TOKgt, std::move(e1),
std::move(e2));
continue;
case TOKle:
case TOKksle:
if (!NextToken())
return nullptr;
e2 = ParseAddtiveExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMLeExpression>(TOKle, std::move(e1),
std::move(e2));
continue;
case TOKge:
case TOKksge:
if (!NextToken())
return nullptr;
e2 = ParseAddtiveExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMGeExpression>(TOKge, std::move(e1),
std::move(e2));
continue;
default:
break;
}
break;
}
return e1;
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseAddtiveExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseMultiplicativeExpression();
if (!e1)
return nullptr;
for (;;) {
std::unique_ptr<CXFA_FMSimpleExpression> e2;
switch (m_token.m_type) {
case TOKplus:
if (!NextToken())
return nullptr;
e2 = ParseMultiplicativeExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMPlusExpression>(TOKplus, std::move(e1),
std::move(e2));
continue;
case TOKminus:
if (!NextToken())
return nullptr;
e2 = ParseMultiplicativeExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMMinusExpression>(TOKminus, std::move(e1),
std::move(e2));
continue;
default:
break;
}
break;
}
return e1;
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseMultiplicativeExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseUnaryExpression();
if (!e1)
return nullptr;
for (;;) {
std::unique_ptr<CXFA_FMSimpleExpression> e2;
switch (m_token.m_type) {
case TOKmul:
if (!NextToken())
return nullptr;
e2 = ParseUnaryExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMMulExpression>(TOKmul, std::move(e1),
std::move(e2));
continue;
case TOKdiv:
if (!NextToken())
return nullptr;
e2 = ParseUnaryExpression();
if (!e2)
return nullptr;
e1 = pdfium::MakeUnique<CXFA_FMDivExpression>(TOKdiv, std::move(e1),
std::move(e2));
continue;
default:
break;
}
break;
}
return e1;
}
std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseUnaryExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> expr;
switch (m_token.m_type) {
case TOKplus:
if (!NextToken())
return nullptr;
expr = ParseUnaryExpression();
if (!expr)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMPosExpression>(std::move(expr));
break;
case TOKminus:
if (!NextToken())
return nullptr;
expr = ParseUnaryExpression();
if (!expr)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMNegExpression>(std::move(expr));
break;
case TOKksnot:
if (!NextToken())
return nullptr;
expr = ParseUnaryExpression();
if (!expr)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMNotExpression>(std::move(expr));
break;
default:
expr = ParsePrimaryExpression();
if (!expr)
return nullptr;
break;
}
return expr;
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParsePrimaryExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> expr = ParseLiteral();
if (expr)
return NextToken() ? std::move(expr) : nullptr;
switch (m_token.m_type) {
case TOKidentifier: {
WideStringView wsIdentifier(m_token.m_string);
if (!NextToken())
return nullptr;
if (m_token.m_type == TOKlbracket) {
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
if (!s)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
nullptr, TOKdot, wsIdentifier, std::move(s));
if (!expr)
return nullptr;
if (!NextToken())
return nullptr;
} else {
expr = pdfium::MakeUnique<CXFA_FMIdentifierExpression>(wsIdentifier);
}
break;
}
case TOKlparen:
expr = ParseParenExpression();
if (!expr)
return nullptr;
break;
default:
m_error = true;
return nullptr;
}
expr = ParsePostExpression(std::move(expr));
if (!expr)
return nullptr;
return expr;
}
// Literal := String | Number | Null
std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseLiteral() {
switch (m_token.m_type) {
case TOKnumber:
return pdfium::MakeUnique<CXFA_FMNumberExpression>(m_token.m_string);
case TOKstring:
return pdfium::MakeUnique<CXFA_FMStringExpression>(m_token.m_string);
case TOKnull:
return pdfium::MakeUnique<CXFA_FMNullExpression>();
default:
return nullptr;
}
}
std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParsePostExpression(
std::unique_ptr<CXFA_FMSimpleExpression> expr) {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
size_t expr_count = 0;
while (1) {
++expr_count;
// Limit the number of expressions allowed in the post expression statement.
// If we don't do this then its possible to generate a stack overflow
// by having a very large number of things like .. expressions.
if (expr_count > kMaxPostExpressions)
return nullptr;
switch (m_token.m_type) {
case TOKlparen: {
if (!NextToken())
return nullptr;
std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
if (m_token.m_type != TOKrparen) {
while (m_token.m_type != TOKrparen) {
std::unique_ptr<CXFA_FMSimpleExpression> simple_expr =
ParseSimpleExpression();
if (!simple_expr)
return nullptr;
expressions.push_back(std::move(simple_expr));
if (m_token.m_type == TOKcomma) {
if (!NextToken())
return nullptr;
} else if (m_token.m_type == TOKeof ||
m_token.m_type == TOKreserver) {
break;
}
}
if (m_token.m_type != TOKrparen) {
m_error = true;
return nullptr;
}
}
expr = pdfium::MakeUnique<CXFA_FMCallExpression>(
std::move(expr), std::move(expressions), false);
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKlbracket)
continue;
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
if (!s)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKcall, L"", std::move(s));
break;
}
case TOKdot: {
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
WideStringView tempStr = m_token.m_string;
if (!NextToken())
return nullptr;
if (m_token.m_type == TOKlparen) {
std::unique_ptr<CXFA_FMSimpleExpression> pExpCall;
if (!NextToken())
return nullptr;
std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> expressions;
if (m_token.m_type != TOKrparen) {
while (m_token.m_type != TOKrparen) {
std::unique_ptr<CXFA_FMSimpleExpression> exp =
ParseSimpleExpression();
if (!exp)
return nullptr;
expressions.push_back(std::move(exp));
if (m_token.m_type == TOKcomma) {
if (!NextToken())
return nullptr;
} else if (m_token.m_type == TOKeof ||
m_token.m_type == TOKreserver) {
break;
}
}
if (m_token.m_type != TOKrparen) {
m_error = true;
return nullptr;
}
}
std::unique_ptr<CXFA_FMSimpleExpression> pIdentifier =
pdfium::MakeUnique<CXFA_FMIdentifierExpression>(tempStr);
pExpCall = pdfium::MakeUnique<CXFA_FMCallExpression>(
std::move(pIdentifier), std::move(expressions), true);
expr = pdfium::MakeUnique<CXFA_FMMethodCallExpression>(
std::move(expr), std::move(pExpCall));
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKlbracket)
continue;
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
if (!s)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKcall, L"", std::move(s));
} else if (m_token.m_type == TOKlbracket) {
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
if (!s)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKdot, tempStr, std::move(s));
} else {
std::unique_ptr<CXFA_FMSimpleExpression> s =
pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
nullptr, false);
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKdot, tempStr, std::move(s));
continue;
}
} break;
case TOKdotdot: {
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
WideStringView tempStr = m_token.m_string;
if (!NextToken())
return nullptr;
if (m_token.m_type == TOKlbracket) {
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
if (!s)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
std::move(expr), TOKdotdot, tempStr, std::move(s));
} else {
std::unique_ptr<CXFA_FMSimpleExpression> s =
pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
nullptr, false);
expr = pdfium::MakeUnique<CXFA_FMDotDotAccessorExpression>(
std::move(expr), TOKdotdot, tempStr, std::move(s));
continue;
}
} break;
case TOKdotscream: {
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
WideStringView tempStr = m_token.m_string;
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKlbracket) {
std::unique_ptr<CXFA_FMSimpleExpression> s =
pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
nullptr, false);
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKdotscream, tempStr, std::move(s));
continue;
}
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseIndexExpression();
if (!s)
return nullptr;
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKdotscream, tempStr, std::move(s));
break;
}
case TOKdotstar: {
std::unique_ptr<CXFA_FMSimpleExpression> s =
pdfium::MakeUnique<CXFA_FMIndexExpression>(ACCESSOR_NO_INDEX,
nullptr, false);
expr = pdfium::MakeUnique<CXFA_FMDotAccessorExpression>(
std::move(expr), TOKdotstar, L"*", std::move(s));
break;
}
default:
return expr;
}
if (!NextToken())
return nullptr;
}
return expr;
}
std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseIndexExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> s;
XFA_FM_AccessorIndex accessorIndex = ACCESSOR_NO_RELATIVEINDEX;
std::unique_ptr<CXFA_FMSimpleExpression> pExp;
if (m_token.m_type == TOKmul) {
pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>(accessorIndex,
std::move(s), true);
if (!pExp || !NextToken())
return nullptr;
if (m_token.m_type != TOKrbracket) {
m_error = true;
return nullptr;
}
return pExp;
}
if (m_token.m_type == TOKplus) {
accessorIndex = ACCESSOR_POSITIVE_INDEX;
if (!NextToken())
return nullptr;
} else if (m_token.m_type == TOKminus) {
accessorIndex = ACCESSOR_NEGATIVE_INDEX;
if (!NextToken())
return nullptr;
}
s = ParseSimpleExpression();
if (!s)
return nullptr;
if (m_token.m_type != TOKrbracket) {
m_error = true;
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMIndexExpression>(accessorIndex, std::move(s),
false);
}
std::unique_ptr<CXFA_FMSimpleExpression> CXFA_FMParser::ParseParenExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (!CheckThenNext(TOKlparen))
return nullptr;
if (m_token.m_type == TOKrparen) {
m_error = true;
return nullptr;
}
std::unique_ptr<CXFA_FMSimpleExpression> pExp1 = ParseSimpleExpression();
if (!pExp1)
return nullptr;
if (!CheckThenNext(TOKrparen))
return nullptr;
return pExp1;
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseIfExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (!NextToken() || !CheckThenNext(TOKlparen))
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pExpression;
while (m_token.m_type != TOKrparen) {
pExpression = ParseSimpleExpression();
if (!pExpression)
return nullptr;
if (m_token.m_type != TOKcomma)
break;
if (!NextToken())
return nullptr;
}
if (!CheckThenNext(TOKrparen))
return nullptr;
if (m_token.m_type != TOKthen) {
m_error = true;
return nullptr;
}
if (!NextToken())
return nullptr;
auto exprs = ParseExpressionList();
if (exprs.empty()) {
m_error = true;
return nullptr;
}
if (m_token.m_type != TOKelseif && m_token.m_type != TOKelse &&
m_token.m_type != TOKendif) {
m_error = true;
return nullptr;
}
auto pIfExpression =
pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs));
std::unique_ptr<CXFA_FMExpression> pElseExpression;
switch (m_token.m_type) {
case TOKeof:
case TOKendif:
if (!CheckThenNext(TOKendif))
return nullptr;
break;
case TOKif:
pElseExpression = ParseIfExpression();
if (!pElseExpression || !CheckThenNext(TOKendif)) {
m_error = true;
return nullptr;
}
break;
case TOKelseif:
pElseExpression = ParseIfExpression();
if (!pElseExpression) {
m_error = true;
return nullptr;
}
break;
case TOKelse: {
if (!NextToken())
return nullptr;
auto else_exprs = ParseExpressionList();
if (else_exprs.empty() || !CheckThenNext(TOKendif)) {
m_error = true;
return nullptr;
}
pElseExpression =
pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(else_exprs));
break;
}
default:
m_error = true;
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMIfExpression>(std::move(pExpression),
std::move(pIfExpression),
std::move(pElseExpression));
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseWhileExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression();
if (!pCondition || !CheckThenNext(TOKdo))
return nullptr;
auto exprs = ParseExpressionList();
if (exprs.empty() || !CheckThenNext(TOKendwhile)) {
m_error = true;
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMWhileExpression>(
std::move(pCondition),
pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
}
std::unique_ptr<CXFA_FMSimpleExpression>
CXFA_FMParser::ParseSubassignmentInForExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
std::unique_ptr<CXFA_FMSimpleExpression> expr = ParseSimpleExpression();
if (!expr)
return nullptr;
return expr;
}
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForExpression() {
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
WideStringView wsVariant;
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
wsVariant = m_token.m_string;
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKassign) {
m_error = true;
return nullptr;
}
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pAssignment =
ParseSimpleExpression();
if (!pAssignment)
return nullptr;
int32_t iDirection = 0;
if (m_token.m_type == TOKupto) {
iDirection = 1;
} else if (m_token.m_type == TOKdownto) {
iDirection = -1;
} else {
m_error = true;
return nullptr;
}
if (!NextToken())
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pAccessor = ParseSimpleExpression();
if (!pAccessor)
return nullptr;
std::unique_ptr<CXFA_FMSimpleExpression> pStep;
if (m_token.m_type == TOKstep) {
if (!NextToken())
return nullptr;
pStep = ParseSimpleExpression();
if (!pStep)
return nullptr;
}
if (!CheckThenNext(TOKdo))
return nullptr;
auto exprs = ParseExpressionList();
if (exprs.empty() || !CheckThenNext(TOKendfor)) {
m_error = true;
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMForExpression>(
wsVariant, std::move(pAssignment), std::move(pAccessor), iDirection,
std::move(pStep),
pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
}
// Foreach := 'foreach' Identifier 'in' '(' ArgumentList ')'
// 'do' ExpressionList 'endfor'
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseForeachExpression() {
if (m_token.m_type != TOKforeach)
return nullptr;
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (!NextToken())
return nullptr;
if (m_token.m_type != TOKidentifier) {
m_error = true;
return nullptr;
}
WideStringView wsIdentifier = m_token.m_string;
if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen))
return nullptr;
std::vector<std::unique_ptr<CXFA_FMSimpleExpression>> pArgumentList;
while (m_token.m_type != TOKrparen) {
std::unique_ptr<CXFA_FMSimpleExpression> s = ParseSimpleExpression();
if (!s)
return nullptr;
pArgumentList.push_back(std::move(s));
if (m_token.m_type != TOKcomma)
break;
if (!NextToken())
return nullptr;
}
// We must have arguments.
if (pArgumentList.empty()) {
m_error = true;
return nullptr;
}
if (!CheckThenNext(TOKrparen))
return nullptr;
auto exprs = ParseExpressionList();
if (exprs.empty() || !CheckThenNext(TOKendfor)) {
m_error = true;
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMForeachExpression>(
wsIdentifier, std::move(pArgumentList),
pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
}
// Block := 'do' ExpressionList 'end'
std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseDoExpression() {
if (m_token.m_type != TOKdo)
return nullptr;
AutoRestorer<unsigned long> restorer(&m_parse_depth);
if (HasError() || !IncrementParseDepthAndCheck())
return nullptr;
if (!NextToken())
return nullptr;
auto exprs = ParseExpressionList();
if (exprs.empty() || !CheckThenNext(TOKend)) {
m_error = true;
return nullptr;
}
return pdfium::MakeUnique<CXFA_FMDoExpression>(
pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(exprs)));
}
bool CXFA_FMParser::HasError() const {
return m_error || m_token.m_type == TOKreserver;
}