LCOV - code coverage report
Current view: top level - libreoffice/connectivity/source/commontools - RowFunctionParser.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1 136 0.7 %
Date: 2012-12-17 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 :     ConstantValueExpression( ORowSetValueDecoratorRef rValue ) :
      62           0 :         maValue( rValue )
      63             :     {
      64           0 :     }
      65           0 :     virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
      66             :     {
      67           0 :         return maValue;
      68             :     }
      69           0 :     virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
      70             :     {
      71           0 :     }
      72           0 :     virtual ExpressionFunct getType() const
      73             :     {
      74           0 :         return FUNC_CONST;
      75             :     }
      76           0 :     virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
      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
     102             :     {
     103           0 :         ORowSetValueDecoratorRef aRet;
     104           0 :         switch(meFunct)
     105             :         {
     106             :             case ENUM_FUNC_EQUATION:
     107           0 :                 aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
     108           0 :                 break;
     109             :             case ENUM_FUNC_AND:
     110           0 :                 aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
     111           0 :                 break;
     112             :             case ENUM_FUNC_OR:
     113           0 :                 aRet = new ORowSetValueDecorator( sal_Bool(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
     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
     132             :     {
     133           0 :         return meFunct;
     134             :     }
     135           0 :     virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
     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 :     ConstantFunctor( const ParserContextSharedPtr& rContext ) :
     175           0 :         mpContext( rContext )
     176             :     {
     177           0 :     }
     178           0 :     void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
     179             :     {
     180           0 :         rtl::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 :     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             :     void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
     201             :     {
     202             :         rtl::OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
     203             :         (void)sVal;
     204             :     }
     205             : };
     206             : 
     207             : /** Implements a binary function over two ExpressionNodes
     208             : 
     209             :     @tpl Generator
     210             :     Generator functor, to generate an ExpressionNode of
     211             :     appropriate type
     212             : 
     213             :     */
     214           0 : class BinaryFunctionFunctor
     215             : {
     216             :     const ExpressionFunct   meFunct;
     217             :     ParserContextSharedPtr  mpContext;
     218             : 
     219             : public:
     220             : 
     221           0 :     BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
     222             :         meFunct( eFunct ),
     223           0 :         mpContext( rContext )
     224             :     {
     225           0 :     }
     226             : 
     227           0 :     void operator()( StringIteratorT, StringIteratorT ) const
     228             :     {
     229           0 :         ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
     230             : 
     231           0 :         if( rNodeStack.size() < 2 )
     232           0 :             throw ParseError( "Not enough arguments for binary operator" );
     233             : 
     234             :         // retrieve arguments
     235           0 :         ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
     236           0 :         rNodeStack.pop();
     237           0 :         ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
     238           0 :         rNodeStack.pop();
     239             : 
     240             :         // create combined ExpressionNode
     241           0 :         ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
     242             :         // check for constness
     243           0 :         rNodeStack.push( pNode );
     244           0 :     }
     245             : };
     246             : /** ExpressionNode implementation for unary
     247             :     function over one ExpressionNode
     248             :     */
     249           0 : class UnaryFunctionExpression : public ExpressionNode
     250             : {
     251             :     const ExpressionFunct   meFunct;
     252             :     ExpressionNodeSharedPtr mpArg;
     253             : 
     254             : public:
     255           0 :     UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
     256             :         meFunct( eFunct ),
     257           0 :         mpArg( rArg )
     258             :     {
     259           0 :     }
     260           0 :     virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
     261             :     {
     262           0 :         return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
     263             :     }
     264           0 :     virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
     265             :     {
     266           0 :     }
     267           0 :     virtual ExpressionFunct getType() const
     268             :     {
     269           0 :         return meFunct;
     270             :     }
     271           0 :     virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
     272             :     {
     273           0 :         ODatabaseMetaDataResultSet::ORow aRet;
     274           0 :         return aRet;
     275             :     }
     276             : };
     277             : 
     278           0 : class UnaryFunctionFunctor
     279             : {
     280             :     const ExpressionFunct   meFunct;
     281             :     ParserContextSharedPtr  mpContext;
     282             : 
     283             : public :
     284             : 
     285           0 :     UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
     286             :         meFunct( eFunct ),
     287           0 :         mpContext( rContext )
     288             :     {
     289           0 :     }
     290           0 :     void operator()( StringIteratorT, StringIteratorT ) const
     291             :     {
     292             : 
     293           0 :         ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
     294             : 
     295           0 :         if( rNodeStack.size() < 1 )
     296           0 :             throw ParseError( "Not enough arguments for unary operator" );
     297             : 
     298             :         // retrieve arguments
     299           0 :         ExpressionNodeSharedPtr pArg( rNodeStack.top() );
     300           0 :         rNodeStack.pop();
     301             : 
     302           0 :         rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
     303           0 :     }
     304             : };
     305             : 
     306             : /* This class implements the following grammar (more or
     307             :     less literally written down below, only slightly
     308             :     obfuscated by the parser actions):
     309             : 
     310             :     basic_expression =
     311             :                        number |
     312             :                        '(' additive_expression ')'
     313             : 
     314             :     unary_expression =
     315             :                     basic_expression
     316             : 
     317             :     multiplicative_expression =
     318             :                        unary_expression ( ( '*' unary_expression )* |
     319             :                                         ( '/' unary_expression )* )
     320             : 
     321             :     additive_expression =
     322             :                        multiplicative_expression ( ( '+' multiplicative_expression )* |
     323             :                                                    ( '-' multiplicative_expression )* )
     324             : 
     325             :     */
     326           0 : class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
     327             : {
     328             : public:
     329             :     /** Create an arithmetic expression grammar
     330             : 
     331             :         @param rParserContext
     332             :         Contains context info for the parser
     333             :         */
     334           0 :     ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
     335           0 :         mpParserContext( rParserContext )
     336             :     {
     337           0 :     }
     338             : 
     339           0 :     template< typename ScannerT > class definition
     340             :     {
     341             :     public:
     342             :         // grammar definition
     343           0 :         definition( const ExpressionGrammar& self )
     344           0 :         {
     345             :             using ::boost::spirit::str_p;
     346             :             using ::boost::spirit::space_p;
     347             :             using ::boost::spirit::range_p;
     348             :             using ::boost::spirit::lexeme_d;
     349             :             using ::boost::spirit::real_parser;
     350             :             using ::boost::spirit::chseq_p;
     351             :             using ::boost::spirit::ch_p;
     352             :             using ::boost::spirit::int_p;
     353             :             using ::boost::spirit::as_lower_d;
     354             :             using ::boost::spirit::strlit;
     355             :             using ::boost::spirit::inhibit_case;
     356             : 
     357             : 
     358             :             typedef inhibit_case<strlit<> > token_t;
     359           0 :             token_t COLUMN  = as_lower_d[ "column" ];
     360           0 :             token_t OR_     = as_lower_d[ "or" ];
     361           0 :             token_t AND_    = as_lower_d[ "and" ];
     362             : 
     363           0 :             integer =
     364             :                     int_p
     365             :                                 [IntConstantFunctor(self.getContext())];
     366             : 
     367           0 :             argument =
     368             :                     integer
     369             :                 |    lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
     370             :                                 [ ConstantFunctor(self.getContext()) ]
     371             :                ;
     372             : 
     373           0 :             unaryFunction =
     374             :                     (COLUMN >> '(' >> integer >> ')' )
     375             :                                 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN,  self.getContext()) ]
     376             :                 ;
     377             : 
     378           0 :             assignment =
     379             :                     unaryFunction >> ch_p('=') >> argument
     380             :                                 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION,  self.getContext()) ]
     381             :                ;
     382             : 
     383           0 :             andExpression =
     384             :                     assignment
     385             :                 |   ( '(' >> orExpression >> ')' )
     386             :                 |   ( assignment >> AND_ >> assignment )  [ BinaryFunctionFunctor( ENUM_FUNC_AND,  self.getContext()) ]
     387             :                 ;
     388             : 
     389           0 :             orExpression =
     390             :                     andExpression
     391             :                 |   ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR,  self.getContext()) ]
     392             :                 ;
     393             : 
     394           0 :             basicExpression =
     395             :                     orExpression
     396             :                 ;
     397             : 
     398             :             BOOST_SPIRIT_DEBUG_RULE(basicExpression);
     399             :             BOOST_SPIRIT_DEBUG_RULE(unaryFunction);
     400             :             BOOST_SPIRIT_DEBUG_RULE(assignment);
     401             :             BOOST_SPIRIT_DEBUG_RULE(argument);
     402             :             BOOST_SPIRIT_DEBUG_RULE(integer);
     403             :             BOOST_SPIRIT_DEBUG_RULE(orExpression);
     404             :             BOOST_SPIRIT_DEBUG_RULE(andExpression);
     405           0 :         }
     406             : 
     407           0 :         const ::boost::spirit::rule< ScannerT >& start() const
     408             :         {
     409           0 :             return basicExpression;
     410             :         }
     411             : 
     412             :     private:
     413             :         // the constituents of the Spirit arithmetic expression grammar.
     414             :         // For the sake of readability, without 'ma' prefix.
     415             :         ::boost::spirit::rule< ScannerT >   basicExpression;
     416             :         ::boost::spirit::rule< ScannerT >   unaryFunction;
     417             :         ::boost::spirit::rule< ScannerT >   assignment;
     418             :         ::boost::spirit::rule< ScannerT >   integer,argument;
     419             :         ::boost::spirit::rule< ScannerT >   orExpression,andExpression;
     420             :     };
     421             : 
     422           0 :     const ParserContextSharedPtr& getContext() const
     423             :     {
     424           0 :         return mpParserContext;
     425             :     }
     426             : 
     427             : private:
     428             :     ParserContextSharedPtr          mpParserContext; // might get modified during parsing
     429             : };
     430             : 
     431             : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     432           0 : const ParserContextSharedPtr& getParserContext()
     433             : {
     434           0 :     static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
     435             : 
     436             :     // clear node stack (since we reuse the static object, that's
     437             :     // the whole point here)
     438           0 :     while( !lcl_parserContext->maOperandStack.empty() )
     439           0 :         lcl_parserContext->maOperandStack.pop();
     440             : 
     441           0 :     return lcl_parserContext;
     442             : }
     443             : #endif
     444             : }
     445             : 
     446           0 : ExpressionNodeSharedPtr FunctionParser::parseFunction( const ::rtl::OUString& _sFunction)
     447             : {
     448             :     // TODO(Q1): Check if a combination of the RTL_UNICODETOTEXT_FLAGS_*
     449             :     // gives better conversion robustness here (we might want to map space
     450             :     // etc. to ASCII space here)
     451             :     const ::rtl::OString& rAsciiFunction(
     452           0 :         rtl::OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
     453             : 
     454           0 :     StringIteratorT aStart( rAsciiFunction.getStr() );
     455           0 :     StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
     456             : 
     457           0 :     ParserContextSharedPtr pContext;
     458             : 
     459             : #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
     460             :     // static parser context, because the actual
     461             :     // Spirit parser is also a static object
     462           0 :     pContext = getParserContext();
     463             : #else
     464             :     pContext.reset( new ParserContext() );
     465             : #endif
     466             : 
     467           0 :     ExpressionGrammar aExpressionGrammer( pContext );
     468             : 
     469             :     const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
     470             :             ::boost::spirit::parse( aStart,
     471             :                                     aEnd,
     472             :                                     aExpressionGrammer,
     473           0 :                                     ::boost::spirit::space_p ) );
     474             : 
     475             :     OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
     476             : 
     477             :     // input fully congested by the parser?
     478           0 :     if( !aParseInfo.full )
     479           0 :         throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
     480             : 
     481             :     // parser's state stack now must contain exactly _one_ ExpressionNode,
     482             :     // which represents our formula.
     483           0 :     if( pContext->maOperandStack.size() != 1 )
     484           0 :         throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
     485             : 
     486           0 :     return pContext->maOperandStack.top();
     487             : }
     488          75 : }
     489             : 
     490             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10