1104 lines
33 KiB
C++
1104 lines
33 KiB
C++
// Copyright 2014 The PDFium Authors
|
|
// 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_fmparser.h"
|
|
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "core/fxcrt/autorestorer.h"
|
|
#include "v8/include/cppgc/heap.h"
|
|
|
|
namespace {
|
|
|
|
constexpr unsigned int kMaxParseDepth = 1250;
|
|
constexpr unsigned int kMaxPostExpressions = 256;
|
|
constexpr unsigned int kMaxExpressionListSize = 10000;
|
|
|
|
} // namespace
|
|
|
|
CXFA_FMParser::CXFA_FMParser(cppgc::Heap* pHeap, CXFA_FMLexer* pLexer)
|
|
: m_heap(pHeap), m_lexer(pLexer), m_max_parse_depth(kMaxParseDepth) {}
|
|
|
|
CXFA_FMParser::~CXFA_FMParser() = default;
|
|
|
|
CXFA_FMAST* CXFA_FMParser::Parse() {
|
|
m_token = m_lexer->NextToken();
|
|
if (HasError())
|
|
return nullptr;
|
|
|
|
auto expressions = ParseExpressionList();
|
|
if (HasError())
|
|
return nullptr;
|
|
|
|
// We failed to parse all of the input so something has gone wrong.
|
|
if (!m_lexer->IsComplete())
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMAST>(m_heap->GetAllocationHandle(),
|
|
std::move(expressions));
|
|
}
|
|
|
|
bool CXFA_FMParser::NextToken() {
|
|
if (HasError())
|
|
return false;
|
|
|
|
m_token = m_lexer->NextToken();
|
|
while (!HasError() && m_token.GetType() == TOKreserver)
|
|
m_token = m_lexer->NextToken();
|
|
return !HasError();
|
|
}
|
|
|
|
bool CXFA_FMParser::CheckThenNext(XFA_FM_TOKEN op) {
|
|
if (HasError())
|
|
return false;
|
|
|
|
if (m_token.GetType() != op) {
|
|
m_error = true;
|
|
return false;
|
|
}
|
|
return NextToken();
|
|
}
|
|
|
|
bool CXFA_FMParser::IncrementParseDepthAndCheck() {
|
|
return ++m_parse_depth < m_max_parse_depth;
|
|
}
|
|
|
|
std::vector<cppgc::Member<CXFA_FMExpression>>
|
|
CXFA_FMParser::ParseExpressionList() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return std::vector<cppgc::Member<CXFA_FMExpression>>();
|
|
|
|
std::vector<cppgc::Member<CXFA_FMExpression>> expressions;
|
|
while (!HasError()) {
|
|
if (m_token.GetType() == TOKeof || m_token.GetType() == TOKendfunc ||
|
|
m_token.GetType() == TOKendif || m_token.GetType() == TOKelseif ||
|
|
m_token.GetType() == TOKelse || m_token.GetType() == TOKendwhile ||
|
|
m_token.GetType() == TOKendfor || m_token.GetType() == TOKend ||
|
|
m_token.GetType() == TOKendfunc || m_token.GetType() == TOKreserver) {
|
|
break;
|
|
}
|
|
|
|
CXFA_FMExpression* expr =
|
|
m_token.GetType() == TOKfunc ? ParseFunction() : ParseExpression();
|
|
if (!expr) {
|
|
m_error = true;
|
|
return std::vector<cppgc::Member<CXFA_FMExpression>>();
|
|
}
|
|
if (expressions.size() >= kMaxExpressionListSize) {
|
|
m_error = true;
|
|
return std::vector<cppgc::Member<CXFA_FMExpression>>();
|
|
}
|
|
expressions.push_back(expr);
|
|
}
|
|
return expressions;
|
|
}
|
|
|
|
// Func := 'func' Identifier '(' ParameterList ')' do ExpressionList 'endfunc'
|
|
// ParamterList := (Not actually defined in the grammar) .....
|
|
// (Identifier (',' Identifier)*)?
|
|
CXFA_FMExpression* CXFA_FMParser::ParseFunction() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKfunc))
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString ident(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKlparen))
|
|
return nullptr;
|
|
|
|
std::vector<WideString> arguments;
|
|
bool last_was_comma = false;
|
|
while (true) {
|
|
if (m_token.GetType() == TOKrparen)
|
|
break;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
last_was_comma = false;
|
|
|
|
arguments.emplace_back(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKcomma)
|
|
continue;
|
|
|
|
last_was_comma = true;
|
|
if (!NextToken())
|
|
return nullptr;
|
|
}
|
|
if (last_was_comma || !CheckThenNext(TOKrparen))
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKdo))
|
|
return nullptr;
|
|
|
|
std::vector<cppgc::Member<CXFA_FMExpression>> expressions;
|
|
if (m_token.GetType() != TOKendfunc)
|
|
expressions = ParseExpressionList();
|
|
|
|
if (!CheckThenNext(TOKendfunc))
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMFunctionDefinition>(
|
|
m_heap->GetAllocationHandle(), std::move(ident), std::move(arguments),
|
|
std::move(expressions));
|
|
}
|
|
|
|
// Expression := IfExpression | WhileExpression | ForExpression |
|
|
// ForEachExpression | AssignmentExpression |
|
|
// DeclarationExpression | SimpleExpression
|
|
CXFA_FMExpression* CXFA_FMParser::ParseExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMExpression* expr = nullptr;
|
|
switch (m_token.GetType()) {
|
|
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 = cppgc::MakeGarbageCollected<CXFA_FMBreakExpression>(
|
|
m_heap->GetAllocationHandle());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
break;
|
|
case TOKcontinue:
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMContinueExpression>(
|
|
m_heap->GetAllocationHandle());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
break;
|
|
default:
|
|
return nullptr;
|
|
}
|
|
return expr;
|
|
}
|
|
|
|
// Declaration := 'var' Variable | 'var' Variable '=' SimpleExpression |
|
|
// 'Func' Identifier '(' ParameterList ')' do ExpressionList 'EndFunc'
|
|
// TODO(dsinclair): We appear to be handling the 'func' case elsewhere.
|
|
CXFA_FMExpression* CXFA_FMParser::ParseDeclarationExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
if (!NextToken() || m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString ident(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* expr = nullptr;
|
|
if (m_token.GetType() == TOKassign) {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
expr = ParseSimpleExpression();
|
|
if (!expr)
|
|
return nullptr;
|
|
}
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMVarExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(ident), expr);
|
|
}
|
|
|
|
// SimpleExpression := LogicalOrExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseSimpleExpression() {
|
|
if (HasError())
|
|
return nullptr;
|
|
|
|
return ParseLogicalOrExpression();
|
|
}
|
|
|
|
// Exp := SimpleExpression ( '=' SimpleExpression )?
|
|
CXFA_FMExpression* CXFA_FMParser::ParseExpExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pExp1 = ParseSimpleExpression();
|
|
if (!pExp1)
|
|
return nullptr;
|
|
|
|
if (m_token.GetType() == TOKassign) {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pExp2 = ParseSimpleExpression();
|
|
if (!pExp2)
|
|
return nullptr;
|
|
|
|
pExp1 = cppgc::MakeGarbageCollected<CXFA_FMAssignExpression>(
|
|
m_heap->GetAllocationHandle(), TOKassign, pExp1, pExp2);
|
|
}
|
|
return cppgc::MakeGarbageCollected<CXFA_FMExpExpression>(
|
|
m_heap->GetAllocationHandle(), pExp1);
|
|
}
|
|
|
|
// LogicalOr := LogicalAndExpression |
|
|
// LogicalOrExpression LogicalOrOperator LogicalAndExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseLogicalOrExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* e1 = ParseLogicalAndExpression();
|
|
if (!e1)
|
|
return nullptr;
|
|
|
|
while (true) {
|
|
if (!IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKor:
|
|
case TOKksor: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseLogicalAndExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMLogicalOrExpression>(
|
|
m_heap->GetAllocationHandle(), TOKor, e1, e2);
|
|
break;
|
|
}
|
|
default:
|
|
return e1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// LogicalAnd := EqualityExpression |
|
|
// LogicalAndExpression LogicalAndOperator EqualityExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseLogicalAndExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* e1 = ParseEqualityExpression();
|
|
if (!e1)
|
|
return nullptr;
|
|
|
|
while (true) {
|
|
if (!IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKand:
|
|
case TOKksand: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseEqualityExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMLogicalAndExpression>(
|
|
m_heap->GetAllocationHandle(), TOKand, e1, e2);
|
|
break;
|
|
}
|
|
default:
|
|
return e1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Equality := RelationExpression |
|
|
// EqualityExpression EqulaityOperator RelationalExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseEqualityExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* e1 = ParseRelationalExpression();
|
|
if (!e1)
|
|
return nullptr;
|
|
|
|
while (true) {
|
|
if (!IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKeq:
|
|
case TOKkseq: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseRelationalExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMEqualExpression>(
|
|
m_heap->GetAllocationHandle(), TOKeq, e1, e2);
|
|
break;
|
|
}
|
|
case TOKne:
|
|
case TOKksne: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseRelationalExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMNotEqualExpression>(
|
|
m_heap->GetAllocationHandle(), TOKne, e1, e2);
|
|
break;
|
|
}
|
|
default:
|
|
return e1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Relational := AdditiveExpression |
|
|
// RelationalExpression RelationalOperator AdditiveExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseRelationalExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* e1 = ParseAdditiveExpression();
|
|
if (!e1)
|
|
return nullptr;
|
|
|
|
while (true) {
|
|
if (!IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKlt:
|
|
case TOKkslt: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMLtExpression>(
|
|
m_heap->GetAllocationHandle(), TOKlt, e1, e2);
|
|
break;
|
|
}
|
|
case TOKgt:
|
|
case TOKksgt: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMGtExpression>(
|
|
m_heap->GetAllocationHandle(), TOKgt, e1, e2);
|
|
break;
|
|
}
|
|
case TOKle:
|
|
case TOKksle: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMLeExpression>(
|
|
m_heap->GetAllocationHandle(), TOKle, e1, e2);
|
|
break;
|
|
}
|
|
case TOKge:
|
|
case TOKksge: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseAdditiveExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMGeExpression>(
|
|
m_heap->GetAllocationHandle(), TOKge, e1, e2);
|
|
break;
|
|
}
|
|
default:
|
|
return e1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Additive := MultiplicativeExpression |
|
|
// AdditiveExpression AdditiveOperator MultiplicativeExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseAdditiveExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* e1 = ParseMultiplicativeExpression();
|
|
if (!e1)
|
|
return nullptr;
|
|
|
|
while (true) {
|
|
if (!IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKplus: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseMultiplicativeExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMPlusExpression>(
|
|
m_heap->GetAllocationHandle(), TOKplus, e1, e2);
|
|
break;
|
|
}
|
|
case TOKminus: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseMultiplicativeExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMMinusExpression>(
|
|
m_heap->GetAllocationHandle(), TOKminus, e1, e2);
|
|
break;
|
|
}
|
|
default:
|
|
return e1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Multiplicative := UnaryExpression |
|
|
// MultiplicateExpression MultiplicativeOperator UnaryExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseMultiplicativeExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* e1 = ParseUnaryExpression();
|
|
if (!e1)
|
|
return nullptr;
|
|
|
|
while (true) {
|
|
if (!IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKmul: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseUnaryExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMMulExpression>(
|
|
m_heap->GetAllocationHandle(), TOKmul, e1, e2);
|
|
break;
|
|
}
|
|
case TOKdiv: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* e2 = ParseUnaryExpression();
|
|
if (!e2)
|
|
return nullptr;
|
|
e1 = cppgc::MakeGarbageCollected<CXFA_FMDivExpression>(
|
|
m_heap->GetAllocationHandle(), TOKdiv, e1, e2);
|
|
break;
|
|
}
|
|
default:
|
|
return e1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unary := PrimaryExpression | UnaryOperator UnaryExpression
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseUnaryExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKplus: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* expr = ParseUnaryExpression();
|
|
if (!expr)
|
|
return nullptr;
|
|
return cppgc::MakeGarbageCollected<CXFA_FMPosExpression>(
|
|
m_heap->GetAllocationHandle(), expr);
|
|
}
|
|
case TOKminus: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* expr = ParseUnaryExpression();
|
|
if (!expr)
|
|
return nullptr;
|
|
return cppgc::MakeGarbageCollected<CXFA_FMNegExpression>(
|
|
m_heap->GetAllocationHandle(), expr);
|
|
}
|
|
case TOKksnot: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
CXFA_FMSimpleExpression* expr = ParseUnaryExpression();
|
|
if (!expr)
|
|
return nullptr;
|
|
return cppgc::MakeGarbageCollected<CXFA_FMNotExpression>(
|
|
m_heap->GetAllocationHandle(), expr);
|
|
}
|
|
default:
|
|
return ParsePrimaryExpression();
|
|
}
|
|
}
|
|
|
|
// Primary := Literal | FunctionCall | Accessor ('.*' )? |
|
|
// '(' SimpleExpression ')'
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParsePrimaryExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* expr = ParseLiteral();
|
|
if (expr)
|
|
return NextToken() ? expr : nullptr;
|
|
|
|
switch (m_token.GetType()) {
|
|
case TOKidentifier: {
|
|
WideString wsIdentifier(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() == TOKlbracket) {
|
|
CXFA_FMSimpleExpression* s = ParseIndexExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), nullptr, TOKdot,
|
|
std::move(wsIdentifier), s);
|
|
if (!expr)
|
|
return nullptr;
|
|
if (!NextToken())
|
|
return nullptr;
|
|
} else {
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMIdentifierExpression>(
|
|
m_heap->GetAllocationHandle(), wsIdentifier);
|
|
}
|
|
break;
|
|
}
|
|
case TOKlparen: {
|
|
expr = ParseParenExpression();
|
|
if (!expr)
|
|
return nullptr;
|
|
break;
|
|
}
|
|
default:
|
|
return nullptr;
|
|
}
|
|
return ParsePostExpression(expr);
|
|
}
|
|
|
|
// Literal := String | Number | Null
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseLiteral() {
|
|
switch (m_token.GetType()) {
|
|
case TOKnumber:
|
|
return cppgc::MakeGarbageCollected<CXFA_FMNumberExpression>(
|
|
m_heap->GetAllocationHandle(), WideString(m_token.GetString()));
|
|
case TOKstring:
|
|
return cppgc::MakeGarbageCollected<CXFA_FMStringExpression>(
|
|
m_heap->GetAllocationHandle(), WideString(m_token.GetString()));
|
|
case TOKnull:
|
|
return cppgc::MakeGarbageCollected<CXFA_FMNullExpression>(
|
|
m_heap->GetAllocationHandle());
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// TODO(dsinclair): Make this match up to the grammar
|
|
// I believe this is parsing the accessor ( '.' | '..' | '.#' )
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParsePostExpression(
|
|
CXFA_FMSimpleExpression* expr) {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
size_t expr_count = 0;
|
|
while (true) {
|
|
++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.GetType()) {
|
|
case TOKlparen: {
|
|
absl::optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
|
|
expressions = ParseArgumentList();
|
|
if (!expressions.has_value())
|
|
return nullptr;
|
|
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMCallExpression>(
|
|
m_heap->GetAllocationHandle(), expr, std::move(expressions.value()),
|
|
false);
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKlbracket)
|
|
continue;
|
|
|
|
CXFA_FMSimpleExpression* s = ParseIndexExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKcall, WideString(), s);
|
|
break;
|
|
}
|
|
case TOKdot: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString tempStr(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() == TOKlparen) {
|
|
absl::optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
|
|
expressions = ParseArgumentList();
|
|
if (!expressions.has_value())
|
|
return nullptr;
|
|
|
|
auto* pIdentifier =
|
|
cppgc::MakeGarbageCollected<CXFA_FMIdentifierExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(tempStr));
|
|
auto* pExpCall = cppgc::MakeGarbageCollected<CXFA_FMCallExpression>(
|
|
m_heap->GetAllocationHandle(), pIdentifier,
|
|
std::move(expressions.value()), true);
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMMethodCallExpression>(
|
|
m_heap->GetAllocationHandle(), expr, pExpCall);
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKlbracket)
|
|
continue;
|
|
|
|
CXFA_FMSimpleExpression* s = ParseIndexExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKcall, WideString(), s);
|
|
} else if (m_token.GetType() == TOKlbracket) {
|
|
CXFA_FMSimpleExpression* s = ParseIndexExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr),
|
|
s);
|
|
} else {
|
|
auto* subexpr = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
|
|
m_heap->GetAllocationHandle(),
|
|
CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false);
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr),
|
|
subexpr);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case TOKdotdot: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString tempStr(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() == TOKlbracket) {
|
|
CXFA_FMSimpleExpression* s = ParseIndexExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdotdot,
|
|
std::move(tempStr), s);
|
|
} else {
|
|
auto* subexpr = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
|
|
m_heap->GetAllocationHandle(),
|
|
CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false);
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdotdot,
|
|
std::move(tempStr), subexpr);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case TOKdotscream: {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString tempStr(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
if (m_token.GetType() != TOKlbracket) {
|
|
auto* subexpr = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
|
|
m_heap->GetAllocationHandle(),
|
|
CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false);
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdotscream,
|
|
std::move(tempStr), subexpr);
|
|
continue;
|
|
}
|
|
|
|
CXFA_FMSimpleExpression* s = ParseIndexExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdotscream,
|
|
std::move(tempStr), s);
|
|
break;
|
|
}
|
|
case TOKdotstar: {
|
|
auto* subexpr = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
|
|
m_heap->GetAllocationHandle(),
|
|
CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false);
|
|
expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>(
|
|
m_heap->GetAllocationHandle(), expr, TOKdotstar, L"*", subexpr);
|
|
break;
|
|
}
|
|
default:
|
|
return expr;
|
|
}
|
|
if (!NextToken())
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// Argument lists are zero or more comma seperated simple expressions found
|
|
// between '(' and ')'
|
|
absl::optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>>
|
|
CXFA_FMParser::ParseArgumentList() {
|
|
if (m_token.GetType() != TOKlparen || !NextToken())
|
|
return absl::nullopt;
|
|
|
|
std::vector<cppgc::Member<CXFA_FMSimpleExpression>> expressions;
|
|
bool first_arg = true;
|
|
while (m_token.GetType() != TOKrparen) {
|
|
if (first_arg) {
|
|
first_arg = false;
|
|
} else {
|
|
if (m_token.GetType() != TOKcomma || !NextToken())
|
|
return absl::nullopt;
|
|
}
|
|
|
|
CXFA_FMSimpleExpression* exp = ParseSimpleExpression();
|
|
if (!exp)
|
|
return absl::nullopt;
|
|
|
|
expressions.push_back(exp);
|
|
if (expressions.size() > kMaxPostExpressions)
|
|
return absl::nullopt;
|
|
}
|
|
|
|
return expressions;
|
|
}
|
|
|
|
// Index := '[' ('*' | '+' SimpleExpression | '-' SimpleExpression) ']'
|
|
CXFA_FMSimpleExpression* CXFA_FMParser::ParseIndexExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKlbracket))
|
|
return nullptr;
|
|
|
|
if (m_token.GetType() == TOKmul) {
|
|
auto* pExp = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
|
|
m_heap->GetAllocationHandle(),
|
|
CXFA_FMIndexExpression::AccessorIndex::kNoRelativeIndex, nullptr, true);
|
|
if (!pExp || !NextToken())
|
|
return nullptr;
|
|
|
|
// TODO(dsinclair): This should CheckThenNext(TOKrbracket) but need to clean
|
|
// up the callsites.
|
|
if (m_token.GetType() != TOKrbracket)
|
|
return nullptr;
|
|
return pExp;
|
|
}
|
|
|
|
CXFA_FMIndexExpression::AccessorIndex accessorIndex =
|
|
CXFA_FMIndexExpression::AccessorIndex::kNoRelativeIndex;
|
|
if (m_token.GetType() == TOKplus) {
|
|
accessorIndex = CXFA_FMIndexExpression::AccessorIndex::kPositiveIndex;
|
|
if (!NextToken())
|
|
return nullptr;
|
|
} else if (m_token.GetType() == TOKminus) {
|
|
accessorIndex = CXFA_FMIndexExpression::AccessorIndex::kNegativeIndex;
|
|
if (!NextToken())
|
|
return nullptr;
|
|
}
|
|
|
|
CXFA_FMSimpleExpression* s = ParseSimpleExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKrbracket)
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>(
|
|
m_heap->GetAllocationHandle(), accessorIndex, s, false);
|
|
}
|
|
|
|
// Paren := '(' SimpleExpression ')'
|
|
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.GetType() == TOKrparen)
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pExp1 = ParseSimpleExpression();
|
|
if (!pExp1)
|
|
return nullptr;
|
|
|
|
if (!CheckThenNext(TOKrparen))
|
|
return nullptr;
|
|
return pExp1;
|
|
}
|
|
|
|
// If := 'if' '(' SimpleExpression ')' 'then' ExpressionList
|
|
// ('elseif' '(' SimpleExpression ')' 'then' ExpressionList)*
|
|
// ('else' ExpressionList)?
|
|
// 'endif'
|
|
CXFA_FMExpression* CXFA_FMParser::ParseIfExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
|
|
if (!CheckThenNext(TOKif))
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pCondition = ParseParenExpression();
|
|
if (!pCondition)
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKthen))
|
|
return nullptr;
|
|
|
|
auto* pIfExpressions = cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), ParseExpressionList());
|
|
|
|
std::vector<cppgc::Member<CXFA_FMIfExpression>> pElseIfExpressions;
|
|
while (m_token.GetType() == TOKelseif) {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
auto* elseIfCondition = ParseParenExpression();
|
|
if (!elseIfCondition)
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKthen))
|
|
return nullptr;
|
|
|
|
auto elseIfExprs = ParseExpressionList();
|
|
pElseIfExpressions.push_back(
|
|
cppgc::MakeGarbageCollected<CXFA_FMIfExpression>(
|
|
m_heap->GetAllocationHandle(), elseIfCondition,
|
|
cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(elseIfExprs)),
|
|
std::vector<cppgc::Member<CXFA_FMIfExpression>>(), nullptr));
|
|
}
|
|
|
|
CXFA_FMExpression* pElseExpression = nullptr;
|
|
if (m_token.GetType() == TOKelse) {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
pElseExpression = cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), ParseExpressionList());
|
|
}
|
|
if (!CheckThenNext(TOKendif))
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMIfExpression>(
|
|
m_heap->GetAllocationHandle(), pCondition, pIfExpressions,
|
|
std::move(pElseIfExpressions), pElseExpression);
|
|
}
|
|
|
|
// While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile'
|
|
CXFA_FMExpression* CXFA_FMParser::ParseWhileExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKwhile))
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pCondition = ParseParenExpression();
|
|
if (!pCondition || !CheckThenNext(TOKdo))
|
|
return nullptr;
|
|
|
|
auto exprs = ParseExpressionList();
|
|
if (!CheckThenNext(TOKendwhile))
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMWhileExpression>(
|
|
m_heap->GetAllocationHandle(), pCondition,
|
|
cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(exprs)));
|
|
}
|
|
|
|
// For := 'for' Assignment 'upto' Accessor ('step' SimpleExpression)?
|
|
// 'do' ExpressionList 'endfor' |
|
|
// 'for' Assignment 'downto' Accessor ('step' SimpleExpression)?
|
|
// 'do' ExpressionList 'endfor'
|
|
CXFA_FMExpression* CXFA_FMParser::ParseForExpression() {
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKfor))
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString wsVariant(m_token.GetString());
|
|
if (!NextToken())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKassign))
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pAssignment = ParseSimpleExpression();
|
|
if (!pAssignment)
|
|
return nullptr;
|
|
|
|
int32_t iDirection = 0;
|
|
if (m_token.GetType() == TOKupto)
|
|
iDirection = 1;
|
|
else if (m_token.GetType() == TOKdownto)
|
|
iDirection = -1;
|
|
else
|
|
return nullptr;
|
|
|
|
if (!NextToken())
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pAccessor = ParseSimpleExpression();
|
|
if (!pAccessor)
|
|
return nullptr;
|
|
|
|
CXFA_FMSimpleExpression* pStep = nullptr;
|
|
if (m_token.GetType() == TOKstep) {
|
|
if (!NextToken())
|
|
return nullptr;
|
|
pStep = ParseSimpleExpression();
|
|
if (!pStep)
|
|
return nullptr;
|
|
}
|
|
if (!CheckThenNext(TOKdo))
|
|
return nullptr;
|
|
|
|
auto exprs = ParseExpressionList();
|
|
if (!CheckThenNext(TOKendfor))
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMForExpression>(
|
|
m_heap->GetAllocationHandle(), wsVariant, pAssignment, pAccessor,
|
|
iDirection, pStep,
|
|
cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(exprs)));
|
|
}
|
|
|
|
// Foreach := 'foreach' Identifier 'in' '(' ArgumentList ')'
|
|
// 'do' ExpressionList 'endfor'
|
|
CXFA_FMExpression* CXFA_FMParser::ParseForeachExpression() {
|
|
if (m_token.GetType() != TOKforeach)
|
|
return nullptr;
|
|
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKforeach))
|
|
return nullptr;
|
|
if (m_token.GetType() != TOKidentifier)
|
|
return nullptr;
|
|
|
|
WideString wsIdentifier(m_token.GetString());
|
|
if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen))
|
|
return nullptr;
|
|
|
|
std::vector<cppgc::Member<CXFA_FMSimpleExpression>> pArgumentList;
|
|
while (m_token.GetType() != TOKrparen) {
|
|
CXFA_FMSimpleExpression* s = ParseSimpleExpression();
|
|
if (!s)
|
|
return nullptr;
|
|
|
|
pArgumentList.push_back(s);
|
|
if (m_token.GetType() != TOKcomma)
|
|
break;
|
|
if (!NextToken())
|
|
return nullptr;
|
|
}
|
|
// We must have arguments.
|
|
if (pArgumentList.empty())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKrparen))
|
|
return nullptr;
|
|
|
|
auto exprs = ParseExpressionList();
|
|
if (!CheckThenNext(TOKendfor))
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMForeachExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(wsIdentifier),
|
|
std::move(pArgumentList),
|
|
cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(exprs)));
|
|
}
|
|
|
|
// Block := 'do' ExpressionList 'end'
|
|
CXFA_FMExpression* CXFA_FMParser::ParseDoExpression() {
|
|
if (m_token.GetType() != TOKdo)
|
|
return nullptr;
|
|
|
|
AutoRestorer<unsigned long> restorer(&m_parse_depth);
|
|
if (HasError() || !IncrementParseDepthAndCheck())
|
|
return nullptr;
|
|
if (!CheckThenNext(TOKdo))
|
|
return nullptr;
|
|
|
|
auto exprs = ParseExpressionList();
|
|
if (!CheckThenNext(TOKend))
|
|
return nullptr;
|
|
|
|
return cppgc::MakeGarbageCollected<CXFA_FMDoExpression>(
|
|
m_heap->GetAllocationHandle(),
|
|
cppgc::MakeGarbageCollected<CXFA_FMBlockExpression>(
|
|
m_heap->GetAllocationHandle(), std::move(exprs)));
|
|
}
|
|
|
|
bool CXFA_FMParser::HasError() const {
|
|
return m_error || m_token.GetType() == TOKreserver;
|
|
}
|