// 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 #include #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(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> CXFA_FMParser::ParseExpressionList() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return std::vector>(); std::vector> 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>(); } if (expressions.size() >= kMaxExpressionListSize) { m_error = true; return std::vector>(); } 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 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 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> expressions; if (m_token.GetType() != TOKendfunc) expressions = ParseExpressionList(); if (!CheckThenNext(TOKendfunc)) return nullptr; return cppgc::MakeGarbageCollected( 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 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( m_heap->GetAllocationHandle()); if (!NextToken()) return nullptr; break; case TOKcontinue: expr = cppgc::MakeGarbageCollected( 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 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( 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 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( m_heap->GetAllocationHandle(), TOKassign, pExp1, pExp2); } return cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), pExp1); } // LogicalOr := LogicalAndExpression | // LogicalOrExpression LogicalOrOperator LogicalAndExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseLogicalOrExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), TOKor, e1, e2); break; } default: return e1; } } } // LogicalAnd := EqualityExpression | // LogicalAndExpression LogicalAndOperator EqualityExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseLogicalAndExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), TOKand, e1, e2); break; } default: return e1; } } } // Equality := RelationExpression | // EqualityExpression EqulaityOperator RelationalExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseEqualityExpression() { AutoRestorer 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( 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( m_heap->GetAllocationHandle(), TOKne, e1, e2); break; } default: return e1; } } } // Relational := AdditiveExpression | // RelationalExpression RelationalOperator AdditiveExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseRelationalExpression() { AutoRestorer 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( 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( 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( 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( m_heap->GetAllocationHandle(), TOKge, e1, e2); break; } default: return e1; } } } // Additive := MultiplicativeExpression | // AdditiveExpression AdditiveOperator MultiplicativeExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseAdditiveExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), TOKplus, e1, e2); break; } case TOKminus: { if (!NextToken()) return nullptr; CXFA_FMSimpleExpression* e2 = ParseMultiplicativeExpression(); if (!e2) return nullptr; e1 = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), TOKminus, e1, e2); break; } default: return e1; } } } // Multiplicative := UnaryExpression | // MultiplicateExpression MultiplicativeOperator UnaryExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseMultiplicativeExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), TOKmul, e1, e2); break; } case TOKdiv: { if (!NextToken()) return nullptr; CXFA_FMSimpleExpression* e2 = ParseUnaryExpression(); if (!e2) return nullptr; e1 = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), TOKdiv, e1, e2); break; } default: return e1; } } } // Unary := PrimaryExpression | UnaryOperator UnaryExpression CXFA_FMSimpleExpression* CXFA_FMParser::ParseUnaryExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), expr); } case TOKminus: { if (!NextToken()) return nullptr; CXFA_FMSimpleExpression* expr = ParseUnaryExpression(); if (!expr) return nullptr; return cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), expr); } case TOKksnot: { if (!NextToken()) return nullptr; CXFA_FMSimpleExpression* expr = ParseUnaryExpression(); if (!expr) return nullptr; return cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), expr); } default: return ParsePrimaryExpression(); } } // Primary := Literal | FunctionCall | Accessor ('.*' )? | // '(' SimpleExpression ')' CXFA_FMSimpleExpression* CXFA_FMParser::ParsePrimaryExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), nullptr, TOKdot, std::move(wsIdentifier), s); if (!expr) return nullptr; if (!NextToken()) return nullptr; } else { expr = cppgc::MakeGarbageCollected( 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( m_heap->GetAllocationHandle(), WideString(m_token.GetString())); case TOKstring: return cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), WideString(m_token.GetString())); case TOKnull: return cppgc::MakeGarbageCollected( 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 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>> expressions = ParseArgumentList(); if (!expressions.has_value()) return nullptr; expr = cppgc::MakeGarbageCollected( 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( 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>> expressions = ParseArgumentList(); if (!expressions.has_value()) return nullptr; auto* pIdentifier = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), std::move(tempStr)); auto* pExpCall = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), pIdentifier, std::move(expressions.value()), true); expr = cppgc::MakeGarbageCollected( 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( m_heap->GetAllocationHandle(), expr, TOKcall, WideString(), s); } else if (m_token.GetType() == TOKlbracket) { CXFA_FMSimpleExpression* s = ParseIndexExpression(); if (!s) return nullptr; expr = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr), s); } else { auto* subexpr = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false); expr = cppgc::MakeGarbageCollected( 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( m_heap->GetAllocationHandle(), expr, TOKdotdot, std::move(tempStr), s); } else { auto* subexpr = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false); expr = cppgc::MakeGarbageCollected( 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( m_heap->GetAllocationHandle(), CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false); expr = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), expr, TOKdotscream, std::move(tempStr), subexpr); continue; } CXFA_FMSimpleExpression* s = ParseIndexExpression(); if (!s) return nullptr; expr = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), expr, TOKdotscream, std::move(tempStr), s); break; } case TOKdotstar: { auto* subexpr = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), CXFA_FMIndexExpression::AccessorIndex::kNoIndex, nullptr, false); expr = cppgc::MakeGarbageCollected( 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>> CXFA_FMParser::ParseArgumentList() { if (m_token.GetType() != TOKlparen || !NextToken()) return absl::nullopt; std::vector> 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 restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKlbracket)) return nullptr; if (m_token.GetType() == TOKmul) { auto* pExp = cppgc::MakeGarbageCollected( 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( m_heap->GetAllocationHandle(), accessorIndex, s, false); } // Paren := '(' SimpleExpression ')' CXFA_FMSimpleExpression* CXFA_FMParser::ParseParenExpression() { AutoRestorer 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 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( m_heap->GetAllocationHandle(), ParseExpressionList()); std::vector> 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( m_heap->GetAllocationHandle(), elseIfCondition, cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), std::move(elseIfExprs)), std::vector>(), nullptr)); } CXFA_FMExpression* pElseExpression = nullptr; if (m_token.GetType() == TOKelse) { if (!NextToken()) return nullptr; pElseExpression = cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), ParseExpressionList()); } if (!CheckThenNext(TOKendif)) return nullptr; return cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), pCondition, pIfExpressions, std::move(pElseIfExpressions), pElseExpression); } // While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile' CXFA_FMExpression* CXFA_FMParser::ParseWhileExpression() { AutoRestorer 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( m_heap->GetAllocationHandle(), pCondition, cppgc::MakeGarbageCollected( 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 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( m_heap->GetAllocationHandle(), wsVariant, pAssignment, pAccessor, iDirection, pStep, cppgc::MakeGarbageCollected( 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 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> 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( m_heap->GetAllocationHandle(), std::move(wsIdentifier), std::move(pArgumentList), cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), std::move(exprs))); } // Block := 'do' ExpressionList 'end' CXFA_FMExpression* CXFA_FMParser::ParseDoExpression() { if (m_token.GetType() != TOKdo) return nullptr; AutoRestorer 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( m_heap->GetAllocationHandle(), cppgc::MakeGarbageCollected( m_heap->GetAllocationHandle(), std::move(exprs))); } bool CXFA_FMParser::HasError() const { return m_error || m_token.GetType() == TOKreserver; }