| // 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 = 256; |
| constexpr unsigned int kMaxExpressionListSize = 10000; |
| |
| } // namespace |
| |
| CXFA_FMParser::CXFA_FMParser(WideStringView wsFormcalc) |
| : m_lexer(pdfium::MakeUnique<CXFA_FMLexer>(wsFormcalc)), |
| m_error(false), |
| m_parse_depth(0), |
| m_max_parse_depth(kMaxParseDepth) {} |
| |
| CXFA_FMParser::~CXFA_FMParser() = default; |
| |
| std::unique_ptr<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 pdfium::MakeUnique<CXFA_FMAST>(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>>(); |
| } |
| |
| if (expressions.size() >= kMaxExpressionListSize) { |
| m_error = true; |
| return std::vector<std::unique_ptr<CXFA_FMExpression>>(); |
| } |
| |
| 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_FMExpression> CXFA_FMParser::ParseFunction() { |
| AutoRestorer<unsigned long> restorer(&m_parse_depth); |
| if (HasError() || !IncrementParseDepthAndCheck()) |
| return nullptr; |
| if (!CheckThenNext(TOKfunc)) |
| return nullptr; |
| if (m_token.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideStringView ident = m_token.m_string; |
| if (!NextToken()) |
| return nullptr; |
| if (!CheckThenNext(TOKlparen)) |
| return nullptr; |
| |
| std::vector<WideStringView> arguments; |
| bool last_was_comma = false; |
| while (1) { |
| if (m_token.m_type == TOKrparen) |
| break; |
| if (m_token.m_type != TOKidentifier) |
| return nullptr; |
| |
| last_was_comma = false; |
| |
| arguments.push_back(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| if (m_token.m_type != 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<std::unique_ptr<CXFA_FMExpression>> expressions; |
| if (m_token.m_type != TOKendfunc) |
| expressions = ParseExpressionList(); |
| |
| if (!CheckThenNext(TOKendfunc)) |
| return nullptr; |
| |
| return pdfium::MakeUnique<CXFA_FMFunctionDefinition>( |
| ident, std::move(arguments), std::move(expressions)); |
| } |
| |
| // Expression := IfExpression | WhileExpression | ForExpression | |
| // ForEachExpression | AssignmentExpression | |
| // DeclarationExpression | SimpleExpression |
| 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: |
| 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_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) |
| 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)); |
| } |
| |
| // SimpleExpression := LogicalOrExpression |
| std::unique_ptr<CXFA_FMSimpleExpression> |
| CXFA_FMParser::ParseSimpleExpression() { |
| if (HasError()) |
| return nullptr; |
| |
| return ParseLogicalOrExpression(); |
| } |
| |
| // Exp := SimpleExpression ( '=' SimpleExpression )? |
| 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)); |
| } |
| |
| // LogicalOr := LogicalAndExpression | |
| // LogicalOrExpression LogicalOrOperator LogicalAndExpression |
| 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; |
| |
| // TODO(dsinclair): Is this for() needed? |
| for (;;) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| 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; |
| } |
| |
| // LogicalAnd := EqualityExpression | |
| // LogicalAndExpression LogicalAndOperator EqualityExpression |
| 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; |
| |
| // TODO(dsinclair): Is this for() needed? |
| for (;;) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| 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; |
| } |
| |
| // Equality := RelationExpression | |
| // EqualityExpression EqulaityOperator RelationalExpression |
| 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; |
| |
| // TODO(dsinclair): Is this for() needed? |
| for (;;) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| case TOKeq: |
| case TOKkseq: { |
| if (!NextToken()) |
| return nullptr; |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> 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; |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> e2 = |
| ParseRelationalExpression(); |
| if (!e2) |
| return nullptr; |
| |
| e1 = pdfium::MakeUnique<CXFA_FMNotEqualExpression>(TOKne, std::move(e1), |
| std::move(e2)); |
| continue; |
| } |
| default: |
| break; |
| } |
| break; |
| } |
| return e1; |
| } |
| |
| // Relational := AdditiveExpression | |
| // RelationalExpression RelationalOperator AdditiveExpression |
| 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 = ParseAdditiveExpression(); |
| if (!e1) |
| return nullptr; |
| |
| // TODO(dsinclair): Is this for() needed? |
| for (;;) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> e2; |
| switch (m_token.m_type) { |
| case TOKlt: |
| case TOKkslt: |
| if (!NextToken()) |
| return nullptr; |
| |
| e2 = ParseAdditiveExpression(); |
| 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 = ParseAdditiveExpression(); |
| 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 = ParseAdditiveExpression(); |
| 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 = ParseAdditiveExpression(); |
| if (!e2) |
| return nullptr; |
| |
| e1 = pdfium::MakeUnique<CXFA_FMGeExpression>(TOKge, std::move(e1), |
| std::move(e2)); |
| continue; |
| default: |
| break; |
| } |
| break; |
| } |
| return e1; |
| } |
| |
| // Additive := MultiplicativeExpression | |
| // AdditiveExpression AdditiveOperator MultiplicativeExpression |
| std::unique_ptr<CXFA_FMSimpleExpression> |
| CXFA_FMParser::ParseAdditiveExpression() { |
| AutoRestorer<unsigned long> restorer(&m_parse_depth); |
| if (HasError() || !IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> e1 = ParseMultiplicativeExpression(); |
| if (!e1) |
| return nullptr; |
| |
| // TODO(dsinclair): Is this for() needed? |
| for (;;) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| 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; |
| } |
| |
| // Multiplicative := UnaryExpression | |
| // MultiplicateExpression MultiplicativeOperator UnaryExpression |
| 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; |
| |
| // TODO(dsinclair): Is this for() needed? |
| for (;;) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| 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; |
| } |
| |
| // Unary := PrimaryExpression | UnaryOperator UnaryExpression |
| 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: |
| return ParsePrimaryExpression(); |
| } |
| return expr; |
| } |
| |
| // Primary := Literal | FunctionCall | Accessor ('.*' )? | |
| // '(' SimpleExpression ')' |
| 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: |
| return nullptr; |
| } |
| return ParsePostExpression(std::move(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; |
| } |
| } |
| |
| // TODO(dsinclair): Make this match up to the grammar |
| // I believe this is parsing the accessor ( '.' | '..' | '.#' ) |
| 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: { |
| std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>> |
| expressions = ParseArgumentList(); |
| if (!expressions) |
| 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, WideStringView(), 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<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>> |
| expressions = ParseArgumentList(); |
| if (!expressions) |
| return nullptr; |
| |
| auto pIdentifier = |
| pdfium::MakeUnique<CXFA_FMIdentifierExpression>(tempStr); |
| auto 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, WideStringView(), 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) |
| 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) |
| 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; |
| } |
| |
| // Argument lists are zero or more comma seperated simple expressions found |
| // between '(' and ')' |
| std::unique_ptr<std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>> |
| CXFA_FMParser::ParseArgumentList() { |
| if (m_token.m_type != TOKlparen || !NextToken()) |
| return nullptr; |
| |
| auto expressions = pdfium::MakeUnique< |
| std::vector<std::unique_ptr<CXFA_FMSimpleExpression>>>(); |
| bool first_arg = true; |
| while (m_token.m_type != TOKrparen) { |
| if (first_arg) { |
| first_arg = false; |
| } else { |
| if (m_token.m_type != TOKcomma || !NextToken()) |
| return nullptr; |
| } |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> exp = ParseSimpleExpression(); |
| if (!exp) |
| return nullptr; |
| |
| expressions->push_back(std::move(exp)); |
| if (expressions->size() > kMaxPostExpressions) |
| return nullptr; |
| } |
| |
| return expressions; |
| } |
| |
| // Index := '[' ('*' | '+' SimpleExpression | '-' SimpleExpression) ']' |
| std::unique_ptr<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.m_type == TOKmul) { |
| auto pExp = pdfium::MakeUnique<CXFA_FMIndexExpression>( |
| 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<CXFA_FMSimpleExpression> s = ParseSimpleExpression(); |
| if (!s) |
| return nullptr; |
| if (m_token.m_type != TOKrbracket) |
| return nullptr; |
| |
| return pdfium::MakeUnique<CXFA_FMIndexExpression>(accessorIndex, std::move(s), |
| false); |
| } |
| |
| // Paren := '(' SimpleExpression ')' |
| 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) |
| return nullptr; |
| |
| std::unique_ptr<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' |
| std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseIfExpression() { |
| AutoRestorer<unsigned long> restorer(&m_parse_depth); |
| if (HasError() || !IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| if (!CheckThenNext(TOKif)) |
| return nullptr; |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression(); |
| if (!pCondition) |
| return nullptr; |
| if (!CheckThenNext(TOKthen)) |
| return nullptr; |
| |
| auto pIfExpressions = |
| pdfium::MakeUnique<CXFA_FMBlockExpression>(ParseExpressionList()); |
| |
| std::vector<std::unique_ptr<CXFA_FMIfExpression>> pElseIfExpressions; |
| while (m_token.m_type == TOKelseif) { |
| if (!NextToken()) |
| return nullptr; |
| |
| auto elseIfCondition = ParseParenExpression(); |
| if (!elseIfCondition) |
| return nullptr; |
| if (!CheckThenNext(TOKthen)) |
| return nullptr; |
| |
| auto elseIfExprs = ParseExpressionList(); |
| pElseIfExpressions.push_back(pdfium::MakeUnique<CXFA_FMIfExpression>( |
| std::move(elseIfCondition), |
| pdfium::MakeUnique<CXFA_FMBlockExpression>(std::move(elseIfExprs)), |
| std::vector<std::unique_ptr<CXFA_FMIfExpression>>(), nullptr)); |
| } |
| |
| std::unique_ptr<CXFA_FMExpression> pElseExpression; |
| if (m_token.m_type == TOKelse) { |
| if (!NextToken()) |
| return nullptr; |
| |
| pElseExpression = |
| pdfium::MakeUnique<CXFA_FMBlockExpression>(ParseExpressionList()); |
| } |
| if (!CheckThenNext(TOKendif)) |
| return nullptr; |
| |
| return pdfium::MakeUnique<CXFA_FMIfExpression>( |
| std::move(pCondition), std::move(pIfExpressions), |
| std::move(pElseIfExpressions), std::move(pElseExpression)); |
| } |
| |
| // While := 'while' '(' SimpleExpression ')' 'do' ExpressionList 'endwhile' |
| std::unique_ptr<CXFA_FMExpression> CXFA_FMParser::ParseWhileExpression() { |
| AutoRestorer<unsigned long> restorer(&m_parse_depth); |
| if (HasError() || !IncrementParseDepthAndCheck()) |
| return nullptr; |
| if (!CheckThenNext(TOKwhile)) |
| return nullptr; |
| |
| std::unique_ptr<CXFA_FMSimpleExpression> pCondition = ParseParenExpression(); |
| if (!pCondition || !CheckThenNext(TOKdo)) |
| return nullptr; |
| |
| auto exprs = ParseExpressionList(); |
| if (!CheckThenNext(TOKendwhile)) |
| return nullptr; |
| |
| return pdfium::MakeUnique<CXFA_FMWhileExpression>( |
| std::move(pCondition), |
| pdfium::MakeUnique<CXFA_FMBlockExpression>(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_FMExpression> CXFA_FMParser::ParseForExpression() { |
| AutoRestorer<unsigned long> 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<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 |
| 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 (!CheckThenNext(TOKendfor)) |
| 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 (!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<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()) |
| return nullptr; |
| if (!CheckThenNext(TOKrparen)) |
| return nullptr; |
| |
| auto exprs = ParseExpressionList(); |
| if (!CheckThenNext(TOKendfor)) |
| 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 (!CheckThenNext(TOKdo)) |
| return nullptr; |
| |
| auto exprs = ParseExpressionList(); |
| if (!CheckThenNext(TOKend)) |
| 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; |
| } |