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