LCOV - code coverage report
Current view: top level - connectivity/source/commontools - RowFunctionParser.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 146 0.7 %
Date: 2015-06-13 12:38:46 Functions: 2 49 4.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : 
      21             : // Makes parser a static resource,
      22             : // we're synchronized externally.
      23             : // But watch out, the parser might have
      24             : // state not visible to this code!
      25             : #define BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
      26             : #if OSL_DEBUG_LEVEL >= 2 && defined(DBG_UTIL)
      27             : #include <typeinfo>
      28             : #define BOOST_SPIRIT_DEBUG
      29             : #endif
      30             : #include <boost/spirit/include/classic_core.hpp>
      31             : #include "RowFunctionParser.hxx"
      32             : #include <rtl/ustring.hxx>
      33             : #include <tools/fract.hxx>
      34             : 
      35             : 
      36             : 
      37             : #if (OSL_DEBUG_LEVEL > 0)
      38             : #include <iostream>
      39             : #endif
      40             : #include <functional>
      41             : #include <algorithm>
      42             : #include <stack>
      43             : 
      44             : namespace connectivity
      45             : {
      46             : using namespace com::sun::star;
      47             : 
      48             : namespace
      49             : {
      50             : 
      51             : 
      52             : // EXPRESSION NODES
      53             : 
      54             : 
      55           0 : class ConstantValueExpression : public ExpressionNode
      56             : {
      57             :     ORowSetValueDecoratorRef maValue;
      58             : 
      59             : public:
      60             : 
      61           0 :     explicit ConstantValueExpression( ORowSetValueDecoratorRef rValue ) :
      62           0 :         maValue( rValue )
      63             :     {
      64           0 :     }
      65           0 :     virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
      66             :     {
      67           0 :         return maValue;
      68             :     }
      69           0 :     virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
      70             :     {
      71           0 :     }
      72           0 :     virtual ExpressionFunct getType() const SAL_OVERRIDE
      73             :     {
      74           0 :         return FUNC_CONST;
      75             :     }
      76           0 :     virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) SAL_OVERRIDE
      77             :     {
      78           0 :         ODatabaseMetaDataResultSet::ORow aRet;
      79           0 :         return aRet;
      80             :     }
      81             : };
      82             : 
      83             : 
      84             : /** ExpressionNode implementation for unary
      85             :     function over two ExpressionNodes
      86             :     */
      87           0 : class BinaryFunctionExpression : public ExpressionNode
      88             : {
      89             :     const ExpressionFunct   meFunct;
      90             :     ExpressionNodeSharedPtr mpFirstArg;
      91             :     ExpressionNodeSharedPtr mpSecondArg;
      92             : 
      93             : public:
      94             : 
      95           0 :     BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) :
      96             :         meFunct( eFunct ),
      97             :         mpFirstArg( rFirstArg ),
      98           0 :         mpSecondArg( rSecondArg )
      99             :     {
     100           0 :     }
     101           0 :     virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
     102             :     {
     103           0 :         ORowSetValueDecoratorRef aRet;
     104           0 :         switch(meFunct)
     105             :         {
     106             :             case ENUM_FUNC_EQUATION:
     107           0 :                 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() );
     108           0 :                 break;
     109             :             case ENUM_FUNC_AND:
     110           0 :                 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() );
     111           0 :                 break;
     112             :             case ENUM_FUNC_OR:
     113           0 :                 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() );
     114           0 :                 break;
     115             :             default:
     116           0 :                 break;
     117             :         }
     118           0 :         return aRet;
     119             :     }
     120           0 :     virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
     121             :     {
     122           0 :         switch(meFunct)
     123             :         {
     124             :             case ENUM_FUNC_EQUATION:
     125           0 :                 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
     126           0 :                 break;
     127             :             default:
     128           0 :                 break;
     129             :         }
     130           0 :     }
     131           0 :     virtual ExpressionFunct getType() const SAL_OVERRIDE
     132             :     {
     133           0 :         return meFunct;
     134             :     }
     135           0 :     virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) SAL_OVERRIDE
     136             :     {
     137           0 :         ODatabaseMetaDataResultSet::ORow aRet;
     138           0 :         return aRet;
     139             :     }
     140             : };
     141             : 
     142             : 
     143             : 
     144             : 
     145             : // FUNCTION PARSER
     146             : 
     147             : 
     148             : 
     149             : typedef const sal_Char* StringIteratorT;
     150             : 
     151           0 : struct ParserContext
     152             : {
     153             :     typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
     154             : 
     155             :     // stores a stack of not-yet-evaluated operands. This is used
     156             :     // by the operators (i.e. '+', '*', 'sin' etc.) to pop their
     157             :     // arguments from. If all arguments to an operator are constant,
     158             :     // the operator pushes a precalculated result on the stack, and
     159             :     // a composite ExpressionNode otherwise.
     160             :     OperandStack                            maOperandStack;
     161             : };
     162             : 
     163             : typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
     164             : 
     165             : /** Generate apriori constant value
     166             :     */
     167             : 
     168           0 : class ConstantFunctor
     169             : {
     170             :     ParserContextSharedPtr          mpContext;
     171             : 
     172             : public:
     173             : 
     174           0 :     explicit ConstantFunctor( const ParserContextSharedPtr& rContext ) :
     175           0 :         mpContext( rContext )
     176             :     {
     177           0 :     }
     178           0 :     void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
     179             :     {
     180           0 :         OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
     181           0 :         mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) );
     182           0 :     }
     183             : };
     184             : 
     185             : /** Generate parse-dependent-but-then-constant value
     186             :     */
     187           0 : class IntConstantFunctor
     188             : {
     189             :     ParserContextSharedPtr  mpContext;
     190             : 
     191             : public:
     192           0 :     explicit IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
     193           0 :         mpContext( rContext )
     194             :     {
     195           0 :     }
     196           0 :     void operator()( sal_Int32 n ) const
     197             :     {
     198           0 :         mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) );
     199           0 :     }
     200             : };
     201             : 
     202             : /** Implements a binary function over two ExpressionNodes
     203             : 
     204             :     @tpl Generator
     205             :     Generator functor, to generate an ExpressionNode of
     206             :     appropriate type
     207             : 
     208             :     */
     209           0 : class BinaryFunctionFunctor
     210             : {
     211             :     const ExpressionFunct   meFunct;
     212             :     ParserContextSharedPtr  mpContext;
     213             : 
     214             : public:
     215             : 
     216           0 :     BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
     217             :         meFunct( eFunct ),
     218           0 :         mpContext( rContext )
     219             :     {
     220           0 :     }
     221             : 
     222           0 :     void operator()( StringIteratorT, StringIteratorT ) const
     223             :     {
     224           0 :         ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
     225             : 
     226           0 :         if( rNodeStack.size() < 2 )
     227           0 :             throw ParseError( "Not enough arguments for binary operator" );
     228             : 
     229             :         // retrieve arguments
     230           0 :         ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
     231           0 :         rNodeStack.pop();
     232           0 :         ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
     233           0 :         rNodeStack.pop();
     234             : 
     235             :         // create combined ExpressionNode
     236           0 :         ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
     237             :         // check for constness
     238           0 :         rNodeStack.push( pNode );
     239           0 :     }
     240             : };
     241             : /** ExpressionNode implementation for unary
     242             :     function over one ExpressionNode
     243             :     */
     244           0 : class UnaryFunctionExpression : public ExpressionNode
     245             : {
     246             :     const ExpressionFunct   meFunct;
     247             :     ExpressionNodeSharedPtr mpArg;
     248             : 
     249             : public:
     250           0 :     UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
     251             :         meFunct( eFunct ),
     252           0 :         mpArg( rArg )
     253             :     {
     254           0 :     }
     255           0 :     virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
     256             :     {
     257           0 :         return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
     258             :     }
     259           0 :     virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
     260             :     {
     261           0 :     }
     262           0 :     virtual ExpressionFunct getType() const SAL_OVERRIDE
     263             :     {
     264           0 :         return meFunct;
     265             :     }
     266           0 :     virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) SAL_OVERRIDE
     267             :     {
     268           0 :         ODatabaseMetaDataResultSet::ORow aRet;
     269           0 :         return aRet;
     270             :     }
     271             : };
     272             : 
     273           0 : class UnaryFunctionFunctor
     274             : {
     275             :     const ExpressionFunct   meFunct;
     276             :     ParserContextSharedPtr  mpContext;
     277             : 
     278             : public :
     279             : 
     280           0 :     UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
     281             :         meFunct( eFunct ),
     282           0 :         mpContext( rContext )
     283             :     {
     284           0 :     }
     285           0 :     void operator()( StringIteratorT, StringIteratorT ) const
     286             :     {
     287             : 
     288           0 :         ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
     289             : 
     290           0 :         if( rNodeStack.size() < 1 )
     291           0 :             throw ParseError( "Not enough arguments for unary operator" );
     292             : 
     293             :         // retrieve arguments
     294           0 :         ExpressionNodeSharedPtr pArg( rNodeStack.top() );
     295           0 :         rNodeStack.pop();
     296             : 
     297           0 :         rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
     298           0 :     }
     299             : };
     300             : 
     301             : /* This class implements the following grammar (more or
     302             :     less literally written down below, only slightly
     303             :     obfuscated by the parser actions):
     304             : 
     305             :     basic_expression =
     306             :                        number |
     307             :                        '(' additive_expression ')'
     308             : 
     309             :     unary_expression =
     310             :                     basic_expression
     311             : 
     312             :     multiplicative_expression =
     313             :                        unary_expression ( ( '*' unary_expression )* |
     314             :                                         ( '/' unary_expression )* )
     315             : 
     316             :     additive_expression =
     317             :                        multiplicative_expression ( ( '+' multiplicative_expression )* |
     318             :                                                    ( '-' multiplicative_expression )* )
     319             : 
     320             :     */
     321           0 : class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
     322             : {
     323             : public:
     324             :     /** Create an arithmetic expression grammar
     325             : 
     326             :         @param rParserContext
     327             :         Contains context info for the parser
     328             :         */
     329           0 :     explicit ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
     330           0 :         mpParserContext( rParserContext )
     331             :     {
     332           0 :     }
     333             : 
     334           0 :     template< typename ScannerT > class definition
     335             :     {
     336             :     public:
     337             :         // grammar definition
     338           0 :         explicit definition( const ExpressionGrammar& self )
     339           0 :         {
     340             :             using ::boost::spirit::str_p;
     341             :             using ::boost::spirit::space_p;
     342             :             using ::boost::spirit::range_p;
     343             :             using ::boost::spirit::lexeme_d;
     344             :             using ::boost::spirit::real_parser;
     345             :             using ::boost::spirit::chseq_p;
     346             :             using ::boost::spirit::ch_p;
     347             :             using ::boost::spirit::int_p;
     348             :             using ::boost::spirit::as_lower_d;
     349             :             using ::boost::spirit::strlit;
     350             :             using ::boost::spirit::inhibit_case;
     351             : 
     352             : 
     353             :             typedef inhibit_case<strlit<> > token_t;
     354           0 :             token_t COLUMN  = as_lower_d[ "column" ];
     355           0 :             token_t OR_     = as_lower_d[ "or" ];
     356           0 :             token_t AND_    = as_lower_d[ "and" ];
     357             : 
     358           0 :             integer =
     359             :                     int_p
     360           0 :                                 [IntConstantFunctor(self.getContext())];
     361             : 
     362           0 :             argument =
     363             :                     integer
     364           0 :                 |    lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
     365           0 :                                 [ ConstantFunctor(self.getContext()) ]
     366             :                ;
     367             : 
     368           0 :             unaryFunction =
     369           0 :                     (COLUMN >> '(' >> integer >> ')' )
     370           0 :                                 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN,  self.getContext()) ]
     371             :                 ;
     372             : 
     373           0 :             assignment =
     374           0 :                     unaryFunction >> ch_p('=') >> argument
     375           0 :                                 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION,  self.getContext()) ]
     376             :                ;
     377             : 
     378           0 :             andExpression =
     379             :                     assignment
     380           0 :                 |   ( '(' >> orExpression >> ')' )
     381           0 :                 |   ( assignment >> AND_ >> assignment )  [ BinaryFunctionFunctor( ENUM_FUNC_AND,  self.getContext()) ]
     382             :                 ;
     383             : 
     384           0 :             orExpression =
     385             :                     andExpression
     386           0 :                 |   ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR,  self.getContext()) ]
     387             :                 ;
     388             : 
     389           0 :             basicExpression =
     390             :                     orExpression
     391             :                 ;
     392             : 
     393             :             BOOST_SPIRIT_DEBUG_RULE(basicExpression);
     394             :             BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
     395             :             BOOST_SPIRIT_DEBUG_RULE(assignment);
     396             :             BOOST_SPIRIT_DEBUG_RULE(argument);
     397             :             BOOST_SPIRIT_DEBUG_RULE(integer);
     398             :             BOOST_SPIRIT_DEBUG_RULE(orExpression);
     399             :             BOOST_SPIRIT_DEBUG_RULE(andExpression);
     400           0 :         }
     401             : 
     402           0 :         const ::boost::spirit::rule< ScannerT >& start() const
     403             :         {
     404           0 :             return basicExpression;
     405             :         }
     406             : 
     407             :     private:
     408             :         // the constituents of the Spirit arithmetic expression grammar.
     409             :         // For the sake of readability, without 'ma' prefix.
     410             :         ::boost::spirit::rule< ScannerT >   basicExpression;
     411             :         ::boost::spirit::rule< ScannerT >   unaryFunction;
     412             :         ::boost::spirit::rule< ScannerT >   assignment;
     413             :         ::boost::spirit::rule< ScannerT >   integer,argument;
     414             :         ::boost::spirit::rule< ScannerT >   orExpression,andExpression;
     415             :     };
     416             : 
     417           0 :     const ParserContextSharedPtr& getContext() const
     418             :     {
     419           0 :         return mpParserContext;
     420             :     }
     421             : 
     422             : private:
     423             :     ParserContextSharedPtr          mpParserContext; // might get modified during parsing
     424             : };
     425             : 
     426             : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     427           0 : const ParserContextSharedPtr& getParserContext()
     428             : {
     429           0 :     static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
     430             : 
     431             :     // clear node stack (since we reuse the static object, that's
     432             :     // the whole point here)
     433           0 :     while( !lcl_parserContext->maOperandStack.empty() )
     434           0 :         lcl_parserContext->maOperandStack.pop();
     435             : 
     436           0 :     return lcl_parserContext;
     437             : }
     438             : #endif
     439             : }
     440             : 
     441           0 : ExpressionNodeSharedPtr FunctionParser::parseFunction( const OUString& _sFunction)
     442             : {
     443             :     // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
     444             :     // gives better conversion robustness here (we might want to map space
     445             :     // etc. to ASCII space here)
     446             :     const OString& rAsciiFunction(
     447           0 :         OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
     448             : 
     449           0 :     StringIteratorT aStart( rAsciiFunction.getStr() );
     450           0 :     StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
     451             : 
     452           0 :     ParserContextSharedPtr pContext;
     453             : 
     454             : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     455             :     // static parser context, because the actual
     456             :     // Spirit parser is also a static object
     457           0 :     pContext = getParserContext();
     458             : #else
     459             :     pContext.reset( new ParserContext() );
     460             : #endif
     461             : 
     462           0 :     ExpressionGrammar aExpressionGrammer( pContext );
     463             : 
     464             :     const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
     465             :             ::boost::spirit::parse( aStart,
     466             :                                     aEnd,
     467             :                                     aExpressionGrammer,
     468           0 :                                     ::boost::spirit::space_p ) );
     469             : 
     470             : #if (OSL_DEBUG_LEVEL > 0)
     471             :     ::std::cout.flush(); // needed to keep stdout and cout in sync
     472             : #endif
     473             : 
     474             :     // input fully congested by the parser?
     475           0 :     if( !aParseInfo.full )
     476           0 :         throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
     477             : 
     478             :     // parser's state stack now must contain exactly _one_ ExpressionNode,
     479             :     // which represents our formula.
     480           0 :     if( pContext->maOperandStack.size() != 1 )
     481           0 :         throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
     482             : 
     483           0 :     return pContext->maOperandStack.top();
     484             : }
     485         441 : }
     486             : 
     487             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11