bump product version to 5.0.4.1
[LibreOffice.git] / connectivity / source / commontools / RowFunctionParser.cxx
blobc296337b4f8043fa77a2d45f7b9d337ec0a1fa8f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
37 #if (OSL_DEBUG_LEVEL > 0)
38 #include <iostream>
39 #endif
40 #include <functional>
41 #include <algorithm>
42 #include <stack>
44 namespace connectivity
46 using namespace com::sun::star;
48 namespace
52 // EXPRESSION NODES
55 class ConstantValueExpression : public ExpressionNode
57 ORowSetValueDecoratorRef maValue;
59 public:
61 ConstantValueExpression( ORowSetValueDecoratorRef rValue ) :
62 maValue( rValue )
65 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
67 return maValue;
69 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
72 virtual ExpressionFunct getType() const SAL_OVERRIDE
74 return FUNC_CONST;
76 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) SAL_OVERRIDE
78 ODatabaseMetaDataResultSet::ORow aRet;
79 return aRet;
84 /** ExpressionNode implementation for unary
85 function over two ExpressionNodes
87 class BinaryFunctionExpression : public ExpressionNode
89 const ExpressionFunct meFunct;
90 ExpressionNodeSharedPtr mpFirstArg;
91 ExpressionNodeSharedPtr mpSecondArg;
93 public:
95 BinaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rFirstArg, const ExpressionNodeSharedPtr& rSecondArg ) :
96 meFunct( eFunct ),
97 mpFirstArg( rFirstArg ),
98 mpSecondArg( rSecondArg )
101 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
103 ORowSetValueDecoratorRef aRet;
104 switch(meFunct)
106 case ENUM_FUNC_EQUATION:
107 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue() );
108 break;
109 case ENUM_FUNC_AND:
110 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool() );
111 break;
112 case ENUM_FUNC_OR:
113 aRet = new ORowSetValueDecorator( mpFirstArg->evaluate(_aRow )->getValue().getBool() || mpSecondArg->evaluate(_aRow )->getValue().getBool() );
114 break;
115 default:
116 break;
118 return aRet;
120 virtual void fill(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
122 switch(meFunct)
124 case ENUM_FUNC_EQUATION:
125 (*mpFirstArg->evaluate(_aRow )) = mpSecondArg->evaluate(_aRow )->getValue();
126 break;
127 default:
128 break;
131 virtual ExpressionFunct getType() const SAL_OVERRIDE
133 return meFunct;
135 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ ) SAL_OVERRIDE
137 ODatabaseMetaDataResultSet::ORow aRet;
138 return aRet;
145 // FUNCTION PARSER
149 typedef const sal_Char* StringIteratorT;
151 struct ParserContext
153 typedef ::std::stack< ExpressionNodeSharedPtr > OperandStack;
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;
163 typedef ::boost::shared_ptr< ParserContext > ParserContextSharedPtr;
165 /** Generate apriori constant value
168 class ConstantFunctor
170 ParserContextSharedPtr mpContext;
172 public:
174 ConstantFunctor( const ParserContextSharedPtr& rContext ) :
175 mpContext( rContext )
178 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
180 OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
181 mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( sVal ) ) ) );
185 /** Generate parse-dependent-but-then-constant value
187 class IntConstantFunctor
189 ParserContextSharedPtr mpContext;
191 public:
192 IntConstantFunctor( const ParserContextSharedPtr& rContext ) :
193 mpContext( rContext )
196 void operator()( sal_Int32 n ) const
198 mpContext->maOperandStack.push( ExpressionNodeSharedPtr( new ConstantValueExpression( new ORowSetValueDecorator( n ) ) ) );
202 /** Implements a binary function over two ExpressionNodes
204 @tpl Generator
205 Generator functor, to generate an ExpressionNode of
206 appropriate type
209 class BinaryFunctionFunctor
211 const ExpressionFunct meFunct;
212 ParserContextSharedPtr mpContext;
214 public:
216 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
217 meFunct( eFunct ),
218 mpContext( rContext )
222 void operator()( StringIteratorT, StringIteratorT ) const
224 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
226 if( rNodeStack.size() < 2 )
227 throw ParseError( "Not enough arguments for binary operator" );
229 // retrieve arguments
230 ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
231 rNodeStack.pop();
232 ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
233 rNodeStack.pop();
235 // create combined ExpressionNode
236 ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
237 // check for constness
238 rNodeStack.push( pNode );
241 /** ExpressionNode implementation for unary
242 function over one ExpressionNode
244 class UnaryFunctionExpression : public ExpressionNode
246 const ExpressionFunct meFunct;
247 ExpressionNodeSharedPtr mpArg;
249 public:
250 UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
251 meFunct( eFunct ),
252 mpArg( rArg )
255 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const SAL_OVERRIDE
257 return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
259 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const SAL_OVERRIDE
262 virtual ExpressionFunct getType() const SAL_OVERRIDE
264 return meFunct;
266 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ ) SAL_OVERRIDE
268 ODatabaseMetaDataResultSet::ORow aRet;
269 return aRet;
273 class UnaryFunctionFunctor
275 const ExpressionFunct meFunct;
276 ParserContextSharedPtr mpContext;
278 public :
280 UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
281 meFunct( eFunct ),
282 mpContext( rContext )
285 void operator()( StringIteratorT, StringIteratorT ) const
288 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
290 if( rNodeStack.size() < 1 )
291 throw ParseError( "Not enough arguments for unary operator" );
293 // retrieve arguments
294 ExpressionNodeSharedPtr pArg( rNodeStack.top() );
295 rNodeStack.pop();
297 rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
301 /* This class implements the following grammar (more or
302 less literally written down below, only slightly
303 obfuscated by the parser actions):
305 basic_expression =
306 number |
307 '(' additive_expression ')'
309 unary_expression =
310 basic_expression
312 multiplicative_expression =
313 unary_expression ( ( '*' unary_expression )* |
314 ( '/' unary_expression )* )
316 additive_expression =
317 multiplicative_expression ( ( '+' multiplicative_expression )* |
318 ( '-' multiplicative_expression )* )
321 class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
323 public:
324 /** Create an arithmetic expression grammar
326 @param rParserContext
327 Contains context info for the parser
329 ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
330 mpParserContext( rParserContext )
334 template< typename ScannerT > class definition
336 public:
337 // grammar definition
338 definition( const ExpressionGrammar& self )
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;
353 typedef inhibit_case<strlit<> > token_t;
354 token_t COLUMN = as_lower_d[ "column" ];
355 token_t OR_ = as_lower_d[ "or" ];
356 token_t AND_ = as_lower_d[ "and" ];
358 integer =
359 int_p
360 [IntConstantFunctor(self.getContext())];
362 argument =
363 integer
364 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
365 [ ConstantFunctor(self.getContext()) ]
368 unaryFunction =
369 (COLUMN >> '(' >> integer >> ')' )
370 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ]
373 assignment =
374 unaryFunction >> ch_p('=') >> argument
375 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ]
378 andExpression =
379 assignment
380 | ( '(' >> orExpression >> ')' )
381 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ]
384 orExpression =
385 andExpression
386 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ]
389 basicExpression =
390 orExpression
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);
402 const ::boost::spirit::rule< ScannerT >& start() const
404 return basicExpression;
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;
417 const ParserContextSharedPtr& getContext() const
419 return mpParserContext;
422 private:
423 ParserContextSharedPtr mpParserContext; // might get modified during parsing
426 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
427 const ParserContextSharedPtr& getParserContext()
429 static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
431 // clear node stack (since we reuse the static object, that's
432 // the whole point here)
433 while( !lcl_parserContext->maOperandStack.empty() )
434 lcl_parserContext->maOperandStack.pop();
436 return lcl_parserContext;
438 #endif
441 ExpressionNodeSharedPtr FunctionParser::parseFunction( const OUString& _sFunction)
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 OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
449 StringIteratorT aStart( rAsciiFunction.getStr() );
450 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
452 ParserContextSharedPtr pContext;
454 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
455 // static parser context, because the actual
456 // Spirit parser is also a static object
457 pContext = getParserContext();
458 #else
459 pContext.reset( new ParserContext() );
460 #endif
462 ExpressionGrammar aExpressionGrammer( pContext );
464 const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
465 ::boost::spirit::parse( aStart,
466 aEnd,
467 aExpressionGrammer,
468 ::boost::spirit::space_p ) );
470 #if (OSL_DEBUG_LEVEL > 0)
471 ::std::cout.flush(); // needed to keep stdout and cout in sync
472 #endif
474 // input fully congested by the parser?
475 if( !aParseInfo.full )
476 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
478 // parser's state stack now must contain exactly _one_ ExpressionNode,
479 // which represents our formula.
480 if( pContext->maOperandStack.size() != 1 )
481 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
483 return pContext->maOperandStack.top();
487 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */