bump product version to 4.1.6.2
[LibreOffice.git] / connectivity / source / commontools / RowFunctionParser.cxx
blob9f1c7c2ed1a608f8b2745ffc06005e1b61fc9df1
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
50 //////////////////////
51 //////////////////////
52 // EXPRESSION NODES
53 //////////////////////
54 //////////////////////
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
67 return maValue;
69 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
72 virtual ExpressionFunct getType() const
74 return FUNC_CONST;
76 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
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
103 ORowSetValueDecoratorRef aRet;
104 switch(meFunct)
106 case ENUM_FUNC_EQUATION:
107 aRet = new ORowSetValueDecorator(sal_Bool(mpFirstArg->evaluate(_aRow )->getValue() == mpSecondArg->evaluate(_aRow )->getValue()) );
108 break;
109 case ENUM_FUNC_AND:
110 aRet = new ORowSetValueDecorator( sal_Bool(mpFirstArg->evaluate(_aRow )->getValue().getBool() && mpSecondArg->evaluate(_aRow )->getValue().getBool()) );
111 break;
112 case ENUM_FUNC_OR:
113 aRet = new ORowSetValueDecorator( sal_Bool(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
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
133 return meFunct;
135 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /*pOptionalArg*/, sal_uInt32 /*nFlags*/ )
137 ODatabaseMetaDataResultSet::ORow aRet;
138 return aRet;
143 ////////////////////////
144 ////////////////////////
145 // FUNCTION PARSER
146 ////////////////////////
147 ////////////////////////
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 ) ) ) );
200 void operator()( StringIteratorT rFirst,StringIteratorT rSecond) const
202 OUString sVal( rFirst, rSecond - rFirst, RTL_TEXTENCODING_UTF8 );
203 (void)sVal;
207 /** Implements a binary function over two ExpressionNodes
209 @tpl Generator
210 Generator functor, to generate an ExpressionNode of
211 appropriate type
214 class BinaryFunctionFunctor
216 const ExpressionFunct meFunct;
217 ParserContextSharedPtr mpContext;
219 public:
221 BinaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
222 meFunct( eFunct ),
223 mpContext( rContext )
227 void operator()( StringIteratorT, StringIteratorT ) const
229 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
231 if( rNodeStack.size() < 2 )
232 throw ParseError( "Not enough arguments for binary operator" );
234 // retrieve arguments
235 ExpressionNodeSharedPtr pSecondArg( rNodeStack.top() );
236 rNodeStack.pop();
237 ExpressionNodeSharedPtr pFirstArg( rNodeStack.top() );
238 rNodeStack.pop();
240 // create combined ExpressionNode
241 ExpressionNodeSharedPtr pNode = ExpressionNodeSharedPtr( new BinaryFunctionExpression( meFunct, pFirstArg, pSecondArg ) );
242 // check for constness
243 rNodeStack.push( pNode );
246 /** ExpressionNode implementation for unary
247 function over one ExpressionNode
249 class UnaryFunctionExpression : public ExpressionNode
251 const ExpressionFunct meFunct;
252 ExpressionNodeSharedPtr mpArg;
254 public:
255 UnaryFunctionExpression( const ExpressionFunct eFunct, const ExpressionNodeSharedPtr& rArg ) :
256 meFunct( eFunct ),
257 mpArg( rArg )
260 virtual ORowSetValueDecoratorRef evaluate(const ODatabaseMetaDataResultSet::ORow& _aRow ) const
262 return _aRow[mpArg->evaluate(_aRow )->getValue().getInt32()];
264 virtual void fill(const ODatabaseMetaDataResultSet::ORow& /*_aRow*/ ) const
267 virtual ExpressionFunct getType() const
269 return meFunct;
271 virtual ODatabaseMetaDataResultSet::ORow fillNode( std::vector< RowEquation >& /*rEquations*/, ExpressionNode* /* pOptionalArg */, sal_uInt32 /* nFlags */ )
273 ODatabaseMetaDataResultSet::ORow aRet;
274 return aRet;
278 class UnaryFunctionFunctor
280 const ExpressionFunct meFunct;
281 ParserContextSharedPtr mpContext;
283 public :
285 UnaryFunctionFunctor( const ExpressionFunct eFunct, const ParserContextSharedPtr& rContext ) :
286 meFunct( eFunct ),
287 mpContext( rContext )
290 void operator()( StringIteratorT, StringIteratorT ) const
293 ParserContext::OperandStack& rNodeStack( mpContext->maOperandStack );
295 if( rNodeStack.size() < 1 )
296 throw ParseError( "Not enough arguments for unary operator" );
298 // retrieve arguments
299 ExpressionNodeSharedPtr pArg( rNodeStack.top() );
300 rNodeStack.pop();
302 rNodeStack.push( ExpressionNodeSharedPtr( new UnaryFunctionExpression( meFunct, pArg ) ) );
306 /* This class implements the following grammar (more or
307 less literally written down below, only slightly
308 obfuscated by the parser actions):
310 basic_expression =
311 number |
312 '(' additive_expression ')'
314 unary_expression =
315 basic_expression
317 multiplicative_expression =
318 unary_expression ( ( '*' unary_expression )* |
319 ( '/' unary_expression )* )
321 additive_expression =
322 multiplicative_expression ( ( '+' multiplicative_expression )* |
323 ( '-' multiplicative_expression )* )
326 class ExpressionGrammar : public ::boost::spirit::grammar< ExpressionGrammar >
328 public:
329 /** Create an arithmetic expression grammar
331 @param rParserContext
332 Contains context info for the parser
334 ExpressionGrammar( const ParserContextSharedPtr& rParserContext ) :
335 mpParserContext( rParserContext )
339 template< typename ScannerT > class definition
341 public:
342 // grammar definition
343 definition( const ExpressionGrammar& self )
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;
358 typedef inhibit_case<strlit<> > token_t;
359 token_t COLUMN = as_lower_d[ "column" ];
360 token_t OR_ = as_lower_d[ "or" ];
361 token_t AND_ = as_lower_d[ "and" ];
363 integer =
364 int_p
365 [IntConstantFunctor(self.getContext())];
367 argument =
368 integer
369 | lexeme_d[ +( range_p('a','z') | range_p('A','Z') | range_p('0','9') ) ]
370 [ ConstantFunctor(self.getContext()) ]
373 unaryFunction =
374 (COLUMN >> '(' >> integer >> ')' )
375 [ UnaryFunctionFunctor( UNARY_FUNC_COLUMN, self.getContext()) ]
378 assignment =
379 unaryFunction >> ch_p('=') >> argument
380 [ BinaryFunctionFunctor( ENUM_FUNC_EQUATION, self.getContext()) ]
383 andExpression =
384 assignment
385 | ( '(' >> orExpression >> ')' )
386 | ( assignment >> AND_ >> assignment ) [ BinaryFunctionFunctor( ENUM_FUNC_AND, self.getContext()) ]
389 orExpression =
390 andExpression
391 | ( orExpression >> OR_ >> andExpression ) [ BinaryFunctionFunctor( ENUM_FUNC_OR, self.getContext()) ]
394 basicExpression =
395 orExpression
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);
407 const ::boost::spirit::rule< ScannerT >& start() const
409 return basicExpression;
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;
422 const ParserContextSharedPtr& getContext() const
424 return mpParserContext;
427 private:
428 ParserContextSharedPtr mpParserContext; // might get modified during parsing
431 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
432 const ParserContextSharedPtr& getParserContext()
434 static ParserContextSharedPtr lcl_parserContext( new ParserContext() );
436 // clear node stack (since we reuse the static object, that's
437 // the whole point here)
438 while( !lcl_parserContext->maOperandStack.empty() )
439 lcl_parserContext->maOperandStack.pop();
441 return lcl_parserContext;
443 #endif
446 ExpressionNodeSharedPtr FunctionParser::parseFunction( const OUString& _sFunction)
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 OString& rAsciiFunction(
452 OUStringToOString( _sFunction, RTL_TEXTENCODING_ASCII_US ) );
454 StringIteratorT aStart( rAsciiFunction.getStr() );
455 StringIteratorT aEnd( rAsciiFunction.getStr()+rAsciiFunction.getLength() );
457 ParserContextSharedPtr pContext;
459 #ifdef BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE
460 // static parser context, because the actual
461 // Spirit parser is also a static object
462 pContext = getParserContext();
463 #else
464 pContext.reset( new ParserContext() );
465 #endif
467 ExpressionGrammar aExpressionGrammer( pContext );
469 const ::boost::spirit::parse_info<StringIteratorT> aParseInfo(
470 ::boost::spirit::parse( aStart,
471 aEnd,
472 aExpressionGrammer,
473 ::boost::spirit::space_p ) );
475 OSL_DEBUG_ONLY(::std::cout.flush()); // needed to keep stdout and cout in sync
477 // input fully congested by the parser?
478 if( !aParseInfo.full )
479 throw ParseError( "RowFunctionParser::parseFunction(): string not fully parseable" );
481 // parser's state stack now must contain exactly _one_ ExpressionNode,
482 // which represents our formula.
483 if( pContext->maOperandStack.size() != 1 )
484 throw ParseError( "RowFunctionParser::parseFunction(): incomplete or empty expression" );
486 return pContext->maOperandStack.top();
490 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */