LCOV - code coverage report
Current view: top level - core - qgsexpressionparser.yy (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 34 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                          qgsexpressionparser.yy
       3                 :            :                           --------------------
       4                 :            :     begin                : August 2011
       5                 :            :     copyright            : (C) 2011 by Martin Dobias
       6                 :            :     email                : wonder.sk at gmail dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : 
      16                 :            : %{
      17                 :            : #include <qglobal.h>
      18                 :            : #include <QList>
      19                 :            : #include <cstdlib>
      20                 :            : #include "qgslogger.h"
      21                 :            : #include "expression/qgsexpression.h"
      22                 :            : #include "expression/qgsexpressionnode.h"
      23                 :            : #include "expression/qgsexpressionnodeimpl.h"
      24                 :            : #include "expression/qgsexpressionfunction.h"
      25                 :            : 
      26                 :            : #ifdef _MSC_VER
      27                 :            : #  pragma warning( disable: 4065 )  // switch statement contains 'default' but no 'case' labels
      28                 :            : #  pragma warning( disable: 4702 )  // unreachable code
      29                 :            : #endif
      30                 :            : 
      31                 :            : // don't redeclare malloc/free
      32                 :            : #define YYINCLUDED_STDLIB_H 1
      33                 :            : 
      34                 :            : // maximum number of errors encountered before parser aborts
      35                 :            : #define MAX_ERRORS 10
      36                 :            : 
      37                 :            : struct expression_parser_context;
      38                 :            : #include "qgsexpressionparser.hpp"
      39                 :            : 
      40                 :            : //! from lexer
      41                 :            : typedef void* yyscan_t;
      42                 :            : typedef struct yy_buffer_state* YY_BUFFER_STATE;
      43                 :            : extern int exp_lex_init(yyscan_t* scanner);
      44                 :            : extern int exp_lex_destroy(yyscan_t scanner);
      45                 :            : extern int exp_lex(YYSTYPE* yylval_param, YYLTYPE* yyloc, yyscan_t yyscanner);
      46                 :            : extern YY_BUFFER_STATE exp__scan_string(const char* buffer, yyscan_t scanner);
      47                 :            : 
      48                 :            : /** returns parsed tree, otherwise returns nullptr and sets parserErrorMsg
      49                 :            :     (interface function to be called from QgsExpression)
      50                 :            :   */
      51                 :            : QgsExpressionNode* parseExpression(const QString& str, QString& parserErrorMsg, QList<QgsExpression::ParserError>& parserError);
      52                 :            : 
      53                 :            : /** error handler for bison */
      54                 :            : void exp_error(YYLTYPE* yyloc, expression_parser_context* parser_ctx, const char* msg);
      55                 :            : 
      56                 :          0 : struct expression_parser_context
      57                 :            : {
      58                 :            :   // lexer context
      59                 :            :   yyscan_t flex_scanner;
      60                 :            : 
      61                 :            :   // List of all errors.
      62                 :            :   QList<QgsExpression::ParserError> parserErrors;
      63                 :            :   QString errorMsg;
      64                 :            :   // Current parser error.
      65                 :          0 :   QgsExpression::ParserError::ParserErrorType currentErrorType = QgsExpression::ParserError::Unknown;
      66                 :            :   // root node of the expression
      67                 :            :   QgsExpressionNode* rootNode;
      68                 :            : };
      69                 :            : 
      70                 :            : #define scanner parser_ctx->flex_scanner
      71                 :            : 
      72                 :            : // we want verbose error messages
      73                 :            : #define YYERROR_VERBOSE 1
      74                 :            : 
      75                 :            : #define BINOP(x, y, z)  new QgsExpressionNodeBinaryOperator(x, y, z)
      76                 :            : 
      77                 :          0 : void addParserLocation(YYLTYPE* yyloc, QgsExpressionNode *node)
      78                 :            : {
      79                 :          0 :   node->parserFirstLine = yyloc->first_line;
      80                 :          0 :   node->parserFirstColumn = yyloc->first_column;
      81                 :          0 :   node->parserLastLine = yyloc->last_line;
      82                 :          0 :   node->parserLastColumn = yyloc->last_column;
      83                 :          0 : }
      84                 :            : 
      85                 :            : %}
      86                 :            : 
      87                 :            : // make the parser reentrant
      88                 :            : %locations
      89                 :            : %define api.pure
      90                 :            : %lex-param {void * scanner}
      91                 :            : %parse-param {expression_parser_context* parser_ctx}
      92                 :            : 
      93                 :            : %union
      94                 :            : {
      95                 :            :   QgsExpressionNode* node;
      96                 :            :   QgsExpressionNode::NodeList* nodelist;
      97                 :            :   QgsExpressionNode::NamedNode* namednode;
      98                 :            :   double numberFloat;
      99                 :            :   int    numberInt;
     100                 :            :   qlonglong numberInt64;
     101                 :            :   bool   boolVal;
     102                 :            :   QString* text;
     103                 :            :   QgsExpressionNodeBinaryOperator::BinaryOperator b_op;
     104                 :            :   QgsExpressionNodeUnaryOperator::UnaryOperator u_op;
     105                 :            :   QgsExpressionNodeCondition::WhenThen* whenthen;
     106                 :            :   QgsExpressionNodeCondition::WhenThenList* whenthenlist;
     107                 :            : }
     108                 :            : 
     109                 :            : %start root
     110                 :            : 
     111                 :            : 
     112                 :            : //
     113                 :            : // token definitions
     114                 :            : //
     115                 :            : 
     116                 :            : // operator tokens
     117                 :            : %token <b_op> OR AND EQ NE LE GE LT GT REGEXP LIKE IS PLUS MINUS MUL DIV INTDIV MOD CONCAT POW
     118                 :            : %token <u_op> NOT
     119                 :            : %token IN
     120                 :            : 
     121                 :            : // literals
     122                 :            : %token <numberFloat> NUMBER_FLOAT
     123                 :            : %token <numberInt> NUMBER_INT
     124                 :            : %token <numberInt64> NUMBER_INT64
     125                 :            : %token <boolVal> BOOLEAN
     126                 :            : %token NULLVALUE
     127                 :            : 
     128                 :            : // tokens for conditional expressions
     129                 :            : %token CASE WHEN THEN ELSE END
     130                 :            : 
     131                 :            : %token <text> STRING QUOTED_COLUMN_REF NAME SPECIAL_COL VARIABLE NAMED_NODE
     132                 :            : 
     133                 :            : %token COMMA
     134                 :            : 
     135                 :            : %token Unknown_CHARACTER
     136                 :            : 
     137                 :            : //
     138                 :            : // definition of non-terminal types
     139                 :            : //
     140                 :            : 
     141                 :            : %type <node> expression
     142                 :            : %type <nodelist> exp_list
     143                 :            : %type <whenthen> when_then_clause
     144                 :            : %type <whenthenlist> when_then_clauses
     145                 :            : %type <namednode> named_node
     146                 :            : 
     147                 :            : // debugging
     148                 :            : %define parse.error verbose
     149                 :            : 
     150                 :            : //
     151                 :            : // operator precedence
     152                 :            : //
     153                 :            : 
     154                 :            : // left associativity means that 1+2+3 translates to (1+2)+3
     155                 :            : // the order of operators here determines their precedence
     156                 :            : 
     157                 :            : %left OR
     158                 :            : %left AND
     159                 :            : %right NOT
     160                 :            : %left EQ NE LE GE LT GT REGEXP LIKE IS IN
     161                 :            : %left PLUS MINUS
     162                 :            : %left MUL DIV INTDIV MOD
     163                 :            : %right POW
     164                 :            : %left CONCAT
     165                 :            : 
     166                 :            : %right UMINUS  // fictitious symbol (for unary minus)
     167                 :            : 
     168                 :            : %left COMMA
     169                 :            : %left '['
     170                 :            : 
     171                 :            : %destructor { delete $$; } <node>
     172                 :            : %destructor { delete $$; } <nodelist>
     173                 :            : %destructor { delete $$; } <namednode>
     174                 :            : %destructor { delete $$; } <text>
     175                 :            : %destructor { delete $$; } <whenthen>
     176                 :            : %destructor { delete $$; } <whenthenlist>
     177                 :            : 
     178                 :            : %%
     179                 :            : 
     180                 :            : root: expression { parser_ctx->rootNode = $1; }
     181                 :            :     | error expression
     182                 :            :         {
     183                 :            :             delete $2;
     184                 :            :             if ( parser_ctx->parserErrors.count() < MAX_ERRORS )
     185                 :            :               yyerrok;
     186                 :            :             else
     187                 :            :               YYABORT;
     188                 :            :         }
     189                 :            :    ;
     190                 :            : 
     191                 :            : expression:
     192                 :            :       expression AND expression       { $$ = BINOP($2, $1, $3); }
     193                 :            :     | expression OR expression        { $$ = BINOP($2, $1, $3); }
     194                 :            :     | expression EQ expression        { $$ = BINOP($2, $1, $3); }
     195                 :            :     | expression NE expression        { $$ = BINOP($2, $1, $3); }
     196                 :            :     | expression LE expression        { $$ = BINOP($2, $1, $3); }
     197                 :            :     | expression GE expression        { $$ = BINOP($2, $1, $3); }
     198                 :            :     | expression LT expression        { $$ = BINOP($2, $1, $3); }
     199                 :            :     | expression GT expression        { $$ = BINOP($2, $1, $3); }
     200                 :            :     | expression REGEXP expression    { $$ = BINOP($2, $1, $3); }
     201                 :            :     | expression LIKE expression      { $$ = BINOP($2, $1, $3); }
     202                 :            :     | expression IS expression        { $$ = BINOP($2, $1, $3); }
     203                 :            :     | expression PLUS expression      { $$ = BINOP($2, $1, $3); }
     204                 :            :     | expression MINUS expression     { $$ = BINOP($2, $1, $3); }
     205                 :            :     | expression MUL expression       { $$ = BINOP($2, $1, $3); }
     206                 :            :     | expression INTDIV expression    { $$ = BINOP($2, $1, $3); }
     207                 :            :     | expression DIV expression       { $$ = BINOP($2, $1, $3); }
     208                 :            :     | expression MOD expression       { $$ = BINOP($2, $1, $3); }
     209                 :            :     | expression POW expression       { $$ = BINOP($2, $1, $3); }
     210                 :            :     | expression CONCAT expression    { $$ = BINOP($2, $1, $3); }
     211                 :            :     | NOT expression                  { $$ = new QgsExpressionNodeUnaryOperator($1, $2); }
     212                 :            :     | '(' expression ')'              { $$ = $2; }
     213                 :            :     | NAME '(' exp_list ')'
     214                 :            :         {
     215                 :            :           int fnIndex = QgsExpression::functionIndex(*$1);
     216                 :            :           delete $1;
     217                 :            :           if (fnIndex == -1)
     218                 :            :           {
     219                 :            :             QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionUnknown;
     220                 :            :             parser_ctx->currentErrorType = errorType;
     221                 :            :             exp_error(&yyloc, parser_ctx, QObject::tr( "Function is not known" ).toUtf8().constData() );
     222                 :            :             delete $3;
     223                 :            :             YYERROR;
     224                 :            :           }
     225                 :            :           QString paramError;
     226                 :            :           if ( !QgsExpressionNodeFunction::validateParams( fnIndex, $3, paramError ) )
     227                 :            :           {
     228                 :            :             QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionInvalidParams;
     229                 :            :             parser_ctx->currentErrorType = errorType;
     230                 :            :             exp_error( &yyloc, parser_ctx, paramError.toLocal8Bit().constData() );
     231                 :            :             delete $3;
     232                 :            :             YYERROR;
     233                 :            :           }
     234                 :            :           QgsExpressionFunction* func = QgsExpression::Functions()[fnIndex];
     235                 :            :           if ( func->params() != -1
     236                 :            :                && !( func->params() >= $3->count()
     237                 :            :                && func->minParams() <= $3->count() ) )
     238                 :            :           {
     239                 :            :             QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionWrongArgs;
     240                 :            :             parser_ctx->currentErrorType = errorType;
     241                 :            :             QString expectedMessage;
     242                 :            :             if ( func->params() == func->minParams() )
     243                 :            :             {
     244                 :            :                expectedMessage = QObject::tr( "Expected %1 but got %2." ).arg( QString::number( func->params() ), QString::number( $3->count() ) );
     245                 :            :             }
     246                 :            :             else
     247                 :            :             {
     248                 :            :                expectedMessage = QObject::tr( "Expected between %1 and %2 parameters but %3 were provided." ).arg( QString::number( func->minParams() ), QString::number( func->params() ), QString::number( $3->count() ) );
     249                 :            :             }
     250                 :            :             exp_error(&yyloc, parser_ctx, QObject::tr( "%1 function is called with wrong number of arguments. %2" ).arg( QgsExpression::Functions()[fnIndex]->name(), expectedMessage ).toUtf8().constData() );
     251                 :            :             delete $3;
     252                 :            :             YYERROR;
     253                 :            :           }
     254                 :            : 
     255                 :            :           $$ = new QgsExpressionNodeFunction(fnIndex, $3);
     256                 :            :           addParserLocation(&@1, $$);
     257                 :            :         }
     258                 :            : 
     259                 :            :     | NAME '(' ')'
     260                 :            :         {
     261                 :            :           int fnIndex = QgsExpression::functionIndex(*$1);
     262                 :            :           delete $1;
     263                 :            :           if (fnIndex == -1)
     264                 :            :           {
     265                 :            :             QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionUnknown;
     266                 :            :             parser_ctx->currentErrorType = errorType;
     267                 :            :             exp_error(&yyloc, parser_ctx, QObject::tr( "Function is not known" ).toUtf8().constData() );
     268                 :            :             YYERROR;
     269                 :            :           }
     270                 :            :           // 0 parameters is expected, -1 parameters means leave it to the
     271                 :            :           // implementation
     272                 :            :           if ( QgsExpression::Functions()[fnIndex]->minParams() > 0 )
     273                 :            :           {
     274                 :            : 
     275                 :            :             QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionWrongArgs;
     276                 :            :             parser_ctx->currentErrorType = errorType;
     277                 :            :             exp_error(&yyloc, parser_ctx, QObject::tr( "%1 function is called with wrong number of arguments" ).arg( QgsExpression::Functions()[fnIndex]->name() ).toLocal8Bit().constData() );
     278                 :            :             YYERROR;
     279                 :            :           }
     280                 :            :           $$ = new QgsExpressionNodeFunction(fnIndex, new QgsExpressionNode::NodeList());
     281                 :            :           addParserLocation(&@1, $$);
     282                 :            :         }
     283                 :            : 
     284                 :            :     | expression IN '(' exp_list ')'     { $$ = new QgsExpressionNodeInOperator($1, $4, false);  }
     285                 :            :     | expression NOT IN '(' exp_list ')' { $$ = new QgsExpressionNodeInOperator($1, $5, true); }
     286                 :            : 
     287                 :            :     | expression '[' expression ']' { $$ = new QgsExpressionNodeIndexOperator( $1, $3 ); }
     288                 :            : 
     289                 :            :     | PLUS expression %prec UMINUS { $$ = $2; }
     290                 :            :     | MINUS expression %prec UMINUS { $$ = new QgsExpressionNodeUnaryOperator( QgsExpressionNodeUnaryOperator::uoMinus, $2); }
     291                 :            : 
     292                 :            :     | CASE when_then_clauses END      { $$ = new QgsExpressionNodeCondition($2); }
     293                 :            :     | CASE when_then_clauses ELSE expression END  { $$ = new QgsExpressionNodeCondition($2,$4); }
     294                 :            : 
     295                 :            :     // columns
     296                 :            :     | NAME                  { $$ = new QgsExpressionNodeColumnRef( *$1 ); delete $1; }
     297                 :            :     | QUOTED_COLUMN_REF                  { $$ = new QgsExpressionNodeColumnRef( *$1 ); delete $1; }
     298                 :            : 
     299                 :            :     // special columns (actually functions with no arguments)
     300                 :            :     | SPECIAL_COL
     301                 :            :         {
     302                 :            :           int fnIndex = QgsExpression::functionIndex(*$1);
     303                 :            :           if (fnIndex >= 0)
     304                 :            :           {
     305                 :            :             $$ = new QgsExpressionNodeFunction( fnIndex, nullptr );
     306                 :            :           }
     307                 :            :           else
     308                 :            :           {
     309                 :            :             QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionUnknown;
     310                 :            :             parser_ctx->currentErrorType = errorType;
     311                 :            :             exp_error(&yyloc, parser_ctx, QObject::tr( "%1 function is not known" ).arg( *$1 ).toLocal8Bit().constData());
     312                 :            :             YYERROR;
     313                 :            :           }
     314                 :            :           delete $1;
     315                 :            :         }
     316                 :            : 
     317                 :            :     // variables
     318                 :            :     | VARIABLE
     319                 :            :         {
     320                 :            :           // @var is equivalent to var( "var" )
     321                 :            :           QgsExpressionNode::NodeList* args = new QgsExpressionNode::NodeList();
     322                 :            :           QgsExpressionNodeLiteral* literal = new QgsExpressionNodeLiteral( QString( *$1 ).mid( 1 ) );
     323                 :            :           args->append( literal );
     324                 :            :           $$ = new QgsExpressionNodeFunction( QgsExpression::functionIndex( "var" ), args );
     325                 :            :           delete $1;
     326                 :            :         }
     327                 :            : 
     328                 :            :     //  literals
     329                 :            :     | NUMBER_FLOAT                { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
     330                 :            :     | NUMBER_INT                  { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
     331                 :            :     | NUMBER_INT64                { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
     332                 :            :     | BOOLEAN                     { $$ = new QgsExpressionNodeLiteral( QVariant($1) ); }
     333                 :            :     | STRING                      { $$ = new QgsExpressionNodeLiteral( QVariant(*$1) ); delete $1; }
     334                 :            :     | NULLVALUE                   { $$ = new QgsExpressionNodeLiteral( QVariant() ); }
     335                 :            : ;
     336                 :            : 
     337                 :            : named_node:
     338                 :            :     NAMED_NODE expression { $$ = new QgsExpressionNode::NamedNode( *$1, $2 ); delete $1; }
     339                 :            :    ;
     340                 :            : 
     341                 :            : exp_list:
     342                 :            :       exp_list COMMA expression
     343                 :            :        {
     344                 :            :          if ( $1->hasNamedNodes() )
     345                 :            :          {
     346                 :            :            QgsExpression::ParserError::ParserErrorType errorType = QgsExpression::ParserError::FunctionNamedArgsError;
     347                 :            :            parser_ctx->currentErrorType = errorType;
     348                 :            :            exp_error(&yyloc, parser_ctx, QObject::tr( "All parameters following a named parameter must also be named." ).toUtf8().constData() );
     349                 :            :            delete $1;
     350                 :            :            YYERROR;
     351                 :            :          }
     352                 :            :          else
     353                 :            :          {
     354                 :            :            $$ = $1; $1->append($3);
     355                 :            :          }
     356                 :            :        }
     357                 :            :     | exp_list COMMA named_node { $$ = $1; $1->append($3); }
     358                 :            :     | expression              { $$ = new QgsExpressionNode::NodeList(); $$->append($1); }
     359                 :            :     | named_node              { $$ = new QgsExpressionNode::NodeList(); $$->append($1); }
     360                 :            :    ;
     361                 :            : 
     362                 :            : when_then_clauses:
     363                 :            :       when_then_clauses when_then_clause  { $$ = $1; $1->append($2); }
     364                 :            :     | when_then_clause                    { $$ = new QgsExpressionNodeCondition::WhenThenList(); $$->append($1); }
     365                 :            :    ;
     366                 :            : 
     367                 :            : when_then_clause:
     368                 :            :       WHEN expression THEN expression     { $$ = new QgsExpressionNodeCondition::WhenThen($2,$4); }
     369                 :            :    ;
     370                 :            : 
     371                 :            : %%
     372                 :            : 
     373                 :            : 
     374                 :            : // returns parsed tree, otherwise returns nullptr and sets parserErrorMsg
     375                 :          0 : QgsExpressionNode* parseExpression(const QString& str, QString& parserErrorMsg, QList<QgsExpression::ParserError> &parserErrors)
     376                 :            : {
     377                 :          0 :   expression_parser_context ctx;
     378                 :          0 :   ctx.rootNode = 0;
     379                 :            : 
     380                 :          0 :   exp_lex_init(&ctx.flex_scanner);
     381                 :          0 :   exp__scan_string(str.toUtf8().constData(), ctx.flex_scanner);
     382                 :          0 :   int res = exp_parse(&ctx);
     383                 :          0 :   exp_lex_destroy(ctx.flex_scanner);
     384                 :            : 
     385                 :            :   // list should be empty when parsing was OK
     386                 :          0 :   if (res == 0 && ctx.parserErrors.count() == 0) // success?
     387                 :            :   {
     388                 :          0 :     return ctx.rootNode;
     389                 :            :   }
     390                 :            :   else // error?
     391                 :            :   {
     392                 :          0 :     parserErrorMsg = ctx.errorMsg;
     393                 :          0 :     parserErrors = ctx.parserErrors;
     394                 :          0 :     delete ctx.rootNode;
     395                 :          0 :     return nullptr;
     396                 :            :   }
     397                 :          0 : }
     398                 :            : 
     399                 :            : 
     400                 :          0 : void exp_error(YYLTYPE* yyloc,expression_parser_context* parser_ctx, const char* msg)
     401                 :            : {
     402                 :          0 :   QgsExpression::ParserError error = QgsExpression::ParserError();
     403                 :          0 :   error.firstColumn = yyloc->first_column;
     404                 :          0 :   error.firstLine = yyloc->first_line;
     405                 :          0 :   error.lastColumn = yyloc->last_column;
     406                 :          0 :   error.lastLine = yyloc->last_line;
     407                 :          0 :   error.errorMsg = msg;
     408                 :          0 :   error.errorType = parser_ctx->currentErrorType;
     409                 :          0 :   parser_ctx->parserErrors.append(error);
     410                 :            :   // Reset the current error type for the next error.
     411                 :          0 :   parser_ctx->currentErrorType = QgsExpression::ParserError::Unknown;
     412                 :            : 
     413                 :          0 :   parser_ctx->errorMsg = parser_ctx->errorMsg + "\n" + msg;
     414                 :          0 : }

Generated by: LCOV version 1.14