// 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 #include #include #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(wsFormcalc); m_token = m_lexer->NextToken(); } CXFA_FMParser::~CXFA_FMParser() {} std::unique_ptr CXFA_FMParser::Parse() { auto expressions = ParseExpressionList(); if (HasError()) return nullptr; return pdfium::MakeUnique(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> CXFA_FMParser::ParseExpressionList() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return std::vector>(); std::vector> 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 expr = m_token.m_type == TOKfunc ? ParseFunction() : ParseExpression(); if (!expr) { m_error = true; return std::vector>(); } expressions.push_back(std::move(expr)); } return expressions; } // Func := 'func' Identifier '(' ParameterList ')' do ExpressionList 'endfunc' // ParamterList := (Not actually defined in the grammar) ..... // (Identifier (',' Identifier)*)? std::unique_ptr CXFA_FMParser::ParseFunction() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; WideStringView ident; std::vector> expressions; if (!CheckThenNext(TOKfunc)) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; ident = m_token.m_string; if (!NextToken()) return nullptr; if (!CheckThenNext(TOKlparen)) return nullptr; std::vector arguments; if (m_token.m_type == TOKrparen) { if (!NextToken()) return nullptr; } else { while (1) { if (m_token.m_type != TOKidentifier) 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 (!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( ident, std::move(arguments), std::move(expressions)); } // Expression := IfExpression | WhileExpression | ForExpression | // ForEachExpression | AssignmentExpression | // DeclarationExpression | SimpleExpression std::unique_ptr CXFA_FMParser::ParseExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr 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(); if (!NextToken()) return nullptr; break; case TOKcontinue: expr = pdfium::MakeUnique(); 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. std::unique_ptr CXFA_FMParser::ParseDeclarationExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; WideStringView ident; if (!NextToken()) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; ident = m_token.m_string; if (!NextToken()) return nullptr; std::unique_ptr expr; if (m_token.m_type == TOKassign) { if (!NextToken()) return nullptr; expr = ParseSimpleExpression(); if (!expr) return nullptr; } return pdfium::MakeUnique(ident, std::move(expr)); } // SimpleExpression := LogicalOrExpression std::unique_ptr CXFA_FMParser::ParseSimpleExpression() { if (HasError()) return nullptr; return ParseLogicalOrExpression(); } // Exp := SimpleExpression ( '=' SimpleExpression )? std::unique_ptr CXFA_FMParser::ParseExpExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr pExp1 = ParseSimpleExpression(); if (!pExp1) return nullptr; if (m_token.m_type == TOKassign) { if (!NextToken()) return nullptr; std::unique_ptr pExp2 = ParseSimpleExpression(); if (!pExp2) return nullptr; pExp1 = pdfium::MakeUnique( TOKassign, std::move(pExp1), std::move(pExp2)); } return pdfium::MakeUnique(std::move(pExp1)); } // LogicalOr := LogicalAndExpression | // LogicalOrExpression LogicalOrOperator LogicalAndExpression std::unique_ptr CXFA_FMParser::ParseLogicalOrExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr e1 = ParseLogicalAndExpression(); if (!e1) return nullptr; // TODO(dsinclair): Is this for() needed? for (;;) { switch (m_token.m_type) { case TOKor: case TOKksor: { if (!NextToken()) return nullptr; std::unique_ptr e2( ParseLogicalAndExpression()); if (!e2) return nullptr; e1 = pdfium::MakeUnique( TOKor, std::move(e1), std::move(e2)); continue; } default: break; } break; } return e1; } // LogicalAnd := EqualityExpression | // LogicalAndExpression LogicalAndOperator EqualityExpression std::unique_ptr CXFA_FMParser::ParseLogicalAndExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr e1 = ParseEqualityExpression(); if (!e1) return nullptr; // TODO(dsinclair): Is this for() needed? for (;;) { switch (m_token.m_type) { case TOKand: case TOKksand: { if (!NextToken()) return nullptr; std::unique_ptr e2 = ParseEqualityExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique( TOKand, std::move(e1), std::move(e2)); continue; } default: break; } break; } return e1; } // Equality := RelationExpression | // EqualityExpression EqulaityOperator RelationalExpression std::unique_ptr CXFA_FMParser::ParseEqualityExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr e1 = ParseRelationalExpression(); if (!e1) return nullptr; // TODO(dsinclair): Is this for() needed? for (;;) { std::unique_ptr e2; switch (m_token.m_type) { case TOKeq: case TOKkseq: if (!NextToken()) return nullptr; e2 = ParseRelationalExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique(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(TOKne, std::move(e1), std::move(e2)); continue; default: break; } break; } return e1; } // Relational := AdditiveExpression | // RelationalExpression RelationalOperator AdditiveExpression std::unique_ptr CXFA_FMParser::ParseRelationalExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr e1 = ParseAddtiveExpression(); if (!e1) return nullptr; // TODO(dsinclair): Is this for() needed? for (;;) { std::unique_ptr e2; switch (m_token.m_type) { case TOKlt: case TOKkslt: if (!NextToken()) return nullptr; e2 = ParseAddtiveExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique(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(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(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(TOKge, std::move(e1), std::move(e2)); continue; default: break; } break; } return e1; } // Additive := MultiplicativeExpression | // AdditiveExpression AdditiveOperator MultiplicativeExpression std::unique_ptr CXFA_FMParser::ParseAddtiveExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr e1 = ParseMultiplicativeExpression(); if (!e1) return nullptr; // TODO(dsinclair): Is this for() needed? for (;;) { std::unique_ptr e2; switch (m_token.m_type) { case TOKplus: if (!NextToken()) return nullptr; e2 = ParseMultiplicativeExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique(TOKplus, std::move(e1), std::move(e2)); continue; case TOKminus: if (!NextToken()) return nullptr; e2 = ParseMultiplicativeExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique(TOKminus, std::move(e1), std::move(e2)); continue; default: break; } break; } return e1; } // Multiplicative := UnaryExpression | // MultiplicateExpression MultiplicativeOperator UnaryExpression std::unique_ptr CXFA_FMParser::ParseMultiplicativeExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr e1 = ParseUnaryExpression(); if (!e1) return nullptr; // TODO(dsinclair): Is this for() needed? for (;;) { std::unique_ptr e2; switch (m_token.m_type) { case TOKmul: if (!NextToken()) return nullptr; e2 = ParseUnaryExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique(TOKmul, std::move(e1), std::move(e2)); continue; case TOKdiv: if (!NextToken()) return nullptr; e2 = ParseUnaryExpression(); if (!e2) return nullptr; e1 = pdfium::MakeUnique(TOKdiv, std::move(e1), std::move(e2)); continue; default: break; } break; } return e1; } // Unary := PrimaryExpression | UnaryOperator UnaryExpression std::unique_ptr CXFA_FMParser::ParseUnaryExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr expr; switch (m_token.m_type) { case TOKplus: if (!NextToken()) return nullptr; expr = ParseUnaryExpression(); if (!expr) return nullptr; expr = pdfium::MakeUnique(std::move(expr)); break; case TOKminus: if (!NextToken()) return nullptr; expr = ParseUnaryExpression(); if (!expr) return nullptr; expr = pdfium::MakeUnique(std::move(expr)); break; case TOKksnot: if (!NextToken()) return nullptr; expr = ParseUnaryExpression(); if (!expr) return nullptr; expr = pdfium::MakeUnique(std::move(expr)); break; default: return ParsePrimaryExpression(); } return expr; } // Primary := Literal | FunctionCall | Accessor ('.*' )? | // '(' SimpleExpression ')' std::unique_ptr CXFA_FMParser::ParsePrimaryExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; std::unique_ptr 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 s = ParseIndexExpression(); if (!s) return nullptr; expr = pdfium::MakeUnique( nullptr, TOKdot, wsIdentifier, std::move(s)); if (!expr) return nullptr; if (!NextToken()) return nullptr; } else { expr = pdfium::MakeUnique(wsIdentifier); } break; } case TOKlparen: expr = ParseParenExpression(); if (!expr) return nullptr; break; default: return nullptr; } return ParsePostExpression(std::move(expr)); } // Literal := String | Number | Null std::unique_ptr CXFA_FMParser::ParseLiteral() { switch (m_token.m_type) { case TOKnumber: return pdfium::MakeUnique(m_token.m_string); case TOKstring: return pdfium::MakeUnique(m_token.m_string); case TOKnull: return pdfium::MakeUnique(); default: return nullptr; } } // TODO(dsinclair): Make this match up to the grammar // I believe this is parsing the accessor ( '.' | '..' | '.#' ) std::unique_ptr CXFA_FMParser::ParsePostExpression( std::unique_ptr expr) { AutoRestorer 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> expressions; if (m_token.m_type != TOKrparen) { while (m_token.m_type != TOKrparen) { std::unique_ptr 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) return nullptr; } expr = pdfium::MakeUnique( std::move(expr), std::move(expressions), false); if (!NextToken()) return nullptr; if (m_token.m_type != TOKlbracket) continue; std::unique_ptr s = ParseIndexExpression(); if (!s) return nullptr; expr = pdfium::MakeUnique( std::move(expr), TOKcall, L"", std::move(s)); break; } case TOKdot: { if (!NextToken()) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; WideStringView tempStr = m_token.m_string; if (!NextToken()) return nullptr; if (m_token.m_type == TOKlparen) { std::unique_ptr pExpCall; if (!NextToken()) return nullptr; std::vector> expressions; if (m_token.m_type != TOKrparen) { while (m_token.m_type != TOKrparen) { std::unique_ptr 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) return nullptr; } std::unique_ptr pIdentifier = pdfium::MakeUnique(tempStr); pExpCall = pdfium::MakeUnique( std::move(pIdentifier), std::move(expressions), true); expr = pdfium::MakeUnique( std::move(expr), std::move(pExpCall)); if (!NextToken()) return nullptr; if (m_token.m_type != TOKlbracket) continue; std::unique_ptr s = ParseIndexExpression(); if (!s) return nullptr; expr = pdfium::MakeUnique( std::move(expr), TOKcall, L"", std::move(s)); } else if (m_token.m_type == TOKlbracket) { std::unique_ptr s = ParseIndexExpression(); if (!s) return nullptr; expr = pdfium::MakeUnique( std::move(expr), TOKdot, tempStr, std::move(s)); } else { std::unique_ptr s = pdfium::MakeUnique(ACCESSOR_NO_INDEX, nullptr, false); expr = pdfium::MakeUnique( std::move(expr), TOKdot, tempStr, std::move(s)); continue; } } break; case TOKdotdot: { if (!NextToken()) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; WideStringView tempStr = m_token.m_string; if (!NextToken()) return nullptr; if (m_token.m_type == TOKlbracket) { std::unique_ptr s = ParseIndexExpression(); if (!s) return nullptr; expr = pdfium::MakeUnique( std::move(expr), TOKdotdot, tempStr, std::move(s)); } else { std::unique_ptr s = pdfium::MakeUnique(ACCESSOR_NO_INDEX, nullptr, false); expr = pdfium::MakeUnique( std::move(expr), TOKdotdot, tempStr, std::move(s)); continue; } } break; case TOKdotscream: { if (!NextToken()) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; WideStringView tempStr = m_token.m_string; if (!NextToken()) return nullptr; if (m_token.m_type != TOKlbracket) { std::unique_ptr s = pdfium::MakeUnique(ACCESSOR_NO_INDEX, nullptr, false); expr = pdfium::MakeUnique( std::move(expr), TOKdotscream, tempStr, std::move(s)); continue; } std::unique_ptr s = ParseIndexExpression(); if (!s) return nullptr; expr = pdfium::MakeUnique( std::move(expr), TOKdotscream, tempStr, std::move(s)); break; } case TOKdotstar: { std::unique_ptr s = pdfium::MakeUnique(ACCESSOR_NO_INDEX, nullptr, false); expr = pdfium::MakeUnique( std::move(expr), TOKdotstar, L"*", std::move(s)); break; } default: return expr; } if (!NextToken()) return nullptr; } return expr; } // Index := '[' ('*' | '+' SimpleExpression | '-' SimpleExpression) ']' std::unique_ptr CXFA_FMParser::ParseIndexExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKlbracket)) return nullptr; if (m_token.m_type == TOKmul) { auto pExp = pdfium::MakeUnique( ACCESSOR_NO_RELATIVEINDEX, nullptr, true); if (!pExp || !NextToken()) return nullptr; // TODO(dsinclair): This should CheckThenNext(TOKrbracket) but need to clean // up the callsites. if (m_token.m_type != TOKrbracket) return nullptr; return pExp; } XFA_FM_AccessorIndex accessorIndex = ACCESSOR_NO_RELATIVEINDEX; 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; } std::unique_ptr s = ParseSimpleExpression(); if (!s) return nullptr; if (m_token.m_type != TOKrbracket) return nullptr; return pdfium::MakeUnique(accessorIndex, std::move(s), false); } // Paren := '(' SimpleExpression ')' std::unique_ptr CXFA_FMParser::ParseParenExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKlparen)) return nullptr; if (m_token.m_type == TOKrparen) return nullptr; std::unique_ptr 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' std::unique_ptr CXFA_FMParser::ParseIfExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKif)) return nullptr; std::unique_ptr pCondition = ParseParenExpression(); if (!CheckThenNext(TOKthen)) return nullptr; auto pIfExpressions = pdfium::MakeUnique(ParseExpressionList()); std::vector> pElseIfExpressions; while (m_token.m_type == TOKelseif) { if (!NextToken()) return nullptr; auto elseIfCondition = ParseParenExpression(); if (!CheckThenNext(TOKthen)) return nullptr; auto elseIfExprs = ParseExpressionList(); pElseIfExpressions.push_back(pdfium::MakeUnique( std::move(elseIfCondition), pdfium::MakeUnique(std::move(elseIfExprs)), std::vector>(), nullptr)); } std::unique_ptr pElseExpression; if (m_token.m_type == TOKelse) { if (!NextToken()) return nullptr; pElseExpression = pdfium::MakeUnique(ParseExpressionList()); } if (!CheckThenNext(TOKendif)) return nullptr; return pdfium::MakeUnique( std::move(pCondition), std::move(pIfExpressions), std::move(pElseIfExpressions), std::move(pElseExpression)); } // While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile' std::unique_ptr CXFA_FMParser::ParseWhileExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKwhile)) return nullptr; std::unique_ptr pCondition = ParseParenExpression(); if (!pCondition || !CheckThenNext(TOKdo)) return nullptr; auto exprs = ParseExpressionList(); if (exprs.empty() || !CheckThenNext(TOKendwhile)) return nullptr; return pdfium::MakeUnique( std::move(pCondition), pdfium::MakeUnique(std::move(exprs))); } // For := 'for' Assignment 'upto' Accessor ('step' SimpleExpression)? // 'do' ExpressionList 'endfor' | // 'for' Assignment 'downto' Accessor ('step' SimpleExpression)? // 'do' ExpressionList 'endfor' std::unique_ptr CXFA_FMParser::ParseForExpression() { AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKfor)) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; WideStringView wsVariant = m_token.m_string; if (!NextToken()) return nullptr; if (!CheckThenNext(TOKassign)) return nullptr; std::unique_ptr 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 return nullptr; if (!NextToken()) return nullptr; std::unique_ptr pAccessor = ParseSimpleExpression(); if (!pAccessor) return nullptr; std::unique_ptr 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)) return nullptr; return pdfium::MakeUnique( wsVariant, std::move(pAssignment), std::move(pAccessor), iDirection, std::move(pStep), pdfium::MakeUnique(std::move(exprs))); } // Foreach := 'foreach' Identifier 'in' '(' ArgumentList ')' // 'do' ExpressionList 'endfor' std::unique_ptr CXFA_FMParser::ParseForeachExpression() { if (m_token.m_type != TOKforeach) return nullptr; AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKforeach)) return nullptr; if (m_token.m_type != TOKidentifier) return nullptr; WideStringView wsIdentifier = m_token.m_string; if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen)) return nullptr; std::vector> pArgumentList; while (m_token.m_type != TOKrparen) { std::unique_ptr 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()) return nullptr; if (!CheckThenNext(TOKrparen)) return nullptr; auto exprs = ParseExpressionList(); if (exprs.empty() || !CheckThenNext(TOKendfor)) return nullptr; return pdfium::MakeUnique( wsIdentifier, std::move(pArgumentList), pdfium::MakeUnique(std::move(exprs))); } // Block := 'do' ExpressionList 'end' std::unique_ptr CXFA_FMParser::ParseDoExpression() { if (m_token.m_type != TOKdo) return nullptr; AutoRestorer restorer(&m_parse_depth); if (HasError() || !IncrementParseDepthAndCheck()) return nullptr; if (!CheckThenNext(TOKdo)) return nullptr; auto exprs = ParseExpressionList(); if (exprs.empty() || !CheckThenNext(TOKend)) return nullptr; return pdfium::MakeUnique( pdfium::MakeUnique(std::move(exprs))); } bool CXFA_FMParser::HasError() const { return m_error || m_token.m_type == TOKreserver; }