| // 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" |
| |
| 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.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<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.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; |
| } |
| |
| CXFA_FMExpression* expr = |
| m_token.m_type == 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.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideString ident(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| if (!CheckThenNext(TOKlparen)) |
| return nullptr; |
| |
| std::vector<WideString> 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.emplace_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<cppgc::Member<CXFA_FMExpression>> expressions; |
| if (m_token.m_type != 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.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 = 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.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideString ident(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| |
| CXFA_FMSimpleExpression* expr = nullptr; |
| if (m_token.m_type == 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.m_type == 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 (1) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| 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 (1) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| 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 (1) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| 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 (1) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| 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 (1) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| 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 (1) { |
| if (!IncrementParseDepthAndCheck()) |
| return nullptr; |
| |
| switch (m_token.m_type) { |
| 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.m_type) { |
| 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.m_type) { |
| case TOKidentifier: { |
| WideString wsIdentifier(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| if (m_token.m_type == 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.m_type) { |
| case TOKnumber: |
| return cppgc::MakeGarbageCollected<CXFA_FMNumberExpression>( |
| m_heap->GetAllocationHandle(), WideString(m_token.m_string)); |
| case TOKstring: |
| return cppgc::MakeGarbageCollected<CXFA_FMStringExpression>( |
| m_heap->GetAllocationHandle(), WideString(m_token.m_string)); |
| 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 (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: { |
| 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.m_type != 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.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideString tempStr(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| if (m_token.m_type == TOKlparen) { |
| 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.m_type != 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.m_type == TOKlbracket) { |
| CXFA_FMSimpleExpression* s = ParseIndexExpression(); |
| if (!s) |
| return nullptr; |
| |
| expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>( |
| m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr), |
| s); |
| } else { |
| CXFA_FMSimpleExpression* s = |
| cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>( |
| m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr, |
| false); |
| expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>( |
| m_heap->GetAllocationHandle(), expr, TOKdot, std::move(tempStr), |
| s); |
| continue; |
| } |
| break; |
| } |
| case TOKdotdot: { |
| if (!NextToken()) |
| return nullptr; |
| if (m_token.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideString tempStr(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| if (m_token.m_type == TOKlbracket) { |
| CXFA_FMSimpleExpression* s = ParseIndexExpression(); |
| if (!s) |
| return nullptr; |
| |
| expr = cppgc::MakeGarbageCollected<CXFA_FMDotDotAccessorExpression>( |
| m_heap->GetAllocationHandle(), expr, TOKdotdot, |
| std::move(tempStr), s); |
| } else { |
| CXFA_FMSimpleExpression* s = |
| cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>( |
| m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr, |
| false); |
| expr = cppgc::MakeGarbageCollected<CXFA_FMDotDotAccessorExpression>( |
| m_heap->GetAllocationHandle(), expr, TOKdotdot, |
| std::move(tempStr), s); |
| continue; |
| } |
| break; |
| } |
| case TOKdotscream: { |
| if (!NextToken()) |
| return nullptr; |
| if (m_token.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideString tempStr(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| |
| if (m_token.m_type != TOKlbracket) { |
| auto* s = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>( |
| m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr, false); |
| expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>( |
| m_heap->GetAllocationHandle(), expr, TOKdotscream, |
| std::move(tempStr), s); |
| 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* s = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>( |
| m_heap->GetAllocationHandle(), ACCESSOR_NO_INDEX, nullptr, false); |
| expr = cppgc::MakeGarbageCollected<CXFA_FMDotAccessorExpression>( |
| m_heap->GetAllocationHandle(), expr, TOKdotstar, L"*", s); |
| break; |
| } |
| default: |
| return expr; |
| } |
| if (!NextToken()) |
| return nullptr; |
| } |
| return expr; |
| } |
| |
| // Argument lists are zero or more comma seperated simple expressions found |
| // between '(' and ')' |
| Optional<std::vector<cppgc::Member<CXFA_FMSimpleExpression>>> |
| CXFA_FMParser::ParseArgumentList() { |
| if (m_token.m_type != TOKlparen || !NextToken()) |
| return pdfium::nullopt; |
| |
| std::vector<cppgc::Member<CXFA_FMSimpleExpression>> expressions; |
| 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 pdfium::nullopt; |
| } |
| |
| CXFA_FMSimpleExpression* exp = ParseSimpleExpression(); |
| if (!exp) |
| return pdfium::nullopt; |
| |
| expressions.push_back(exp); |
| if (expressions.size() > kMaxPostExpressions) |
| return pdfium::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.m_type == TOKmul) { |
| auto* pExp = cppgc::MakeGarbageCollected<CXFA_FMIndexExpression>( |
| m_heap->GetAllocationHandle(), 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; |
| } |
| |
| CXFA_FMSimpleExpression* s = ParseSimpleExpression(); |
| if (!s) |
| return nullptr; |
| if (m_token.m_type != 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.m_type == 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.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( |
| 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.m_type == 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.m_type != TOKidentifier) |
| return nullptr; |
| |
| WideString wsVariant(m_token.m_string); |
| if (!NextToken()) |
| return nullptr; |
| if (!CheckThenNext(TOKassign)) |
| return nullptr; |
| |
| 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; |
| |
| CXFA_FMSimpleExpression* pAccessor = ParseSimpleExpression(); |
| if (!pAccessor) |
| return nullptr; |
| |
| CXFA_FMSimpleExpression* pStep = nullptr; |
| 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 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.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; |
| |
| WideString wsIdentifier(m_token.m_string); |
| if (!NextToken() || !CheckThenNext(TOKin) || !CheckThenNext(TOKlparen)) |
| return nullptr; |
| |
| std::vector<cppgc::Member<CXFA_FMSimpleExpression>> pArgumentList; |
| while (m_token.m_type != TOKrparen) { |
| CXFA_FMSimpleExpression* s = ParseSimpleExpression(); |
| if (!s) |
| return nullptr; |
| |
| pArgumentList.push_back(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 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.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 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.m_type == TOKreserver; |
| } |